1
0
Fork 0
mirror of https://gitlab.com/sortix/sortix.git synced 2023-02-13 20:55:38 -05:00

Recover kernel log during emergencies.

This commit is contained in:
Jonas 'Sortie' Termansen 2013-11-11 22:21:56 +01:00
parent eb831479fb
commit a0e2934c8c
12 changed files with 503 additions and 111 deletions

View file

@ -38,12 +38,14 @@ extern size_t (*device_width)(void*);
extern size_t (*device_height)(void*); extern size_t (*device_height)(void*);
extern bool (*device_sync)(void*); extern bool (*device_sync)(void*);
extern void* device_pointer; extern void* device_pointer;
extern bool (*emergency_device_is_impaired)(void*);
void Init(size_t (*callback)(void*, const char*, size_t), extern bool (*emergency_device_recoup)(void*);
size_t (*widthfunc)(void*), extern void (*emergency_device_reset)(void*);
size_t (*heightfunc)(void*), extern size_t (*emergency_device_callback)(void*, const char*, size_t);
bool (*syncfunc)(void*), extern size_t (*emergency_device_width)(void*);
void* user); extern size_t (*emergency_device_height)(void*);
extern bool (*emergency_device_sync)(void*);
extern void* emergency_device_pointer;
inline void Flush() inline void Flush()
{ {

View file

@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012. Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
This file is part of Sortix. This file is part of Sortix.
@ -74,6 +74,9 @@ public:
virtual void SetCursorEnabled(bool enablecursor) = 0; virtual void SetCursorEnabled(bool enablecursor) = 0;
virtual TextPos GetCursorPos() const = 0; virtual TextPos GetCursorPos() const = 0;
virtual void SetCursorPos(TextPos cursorpos) = 0; virtual void SetCursorPos(TextPos cursorpos) = 0;
virtual bool EmergencyIsImpaired() = 0;
virtual bool EmergencyRecoup() = 0;
virtual void EmergencyReset() = 0;
}; };
@ -91,6 +94,11 @@ public:
TextBuffer* Acquire(); TextBuffer* Acquire();
void Release(TextBuffer* textbuf); void Release(TextBuffer* textbuf);
void Replace(TextBuffer* newtextbuf, bool deletebuf = true); void Replace(TextBuffer* newtextbuf, bool deletebuf = true);
bool EmergencyIsImpaired();
bool EmergencyRecoup();
void EmergencyReset();
TextBuffer* EmergencyAcquire();
void EmergencyRelease(TextBuffer* textbuf);
private: private:
kthread_mutex_t mutex; kthread_mutex_t mutex;

View file

@ -135,6 +135,42 @@ static bool TextTermSync(void* user)
return ((TextTerminal*) user)->Sync(); return ((TextTerminal*) user)->Sync();
} }
static bool EmergencyTextTermIsImpaired(void* user)
{
return ((TextTerminal*) user)->EmergencyIsImpaired();
}
static bool EmergencyTextTermRecoup(void* user)
{
return ((TextTerminal*) user)->EmergencyRecoup();
}
static void EmergencyTextTermReset(void* user)
{
((TextTerminal*) user)->EmergencyReset();
}
static
size_t EmergencyPrintToTextTerminal(void* user, const char* str, size_t len)
{
return ((TextTerminal*) user)->EmergencyPrint(str, len);
}
static size_t EmergencyTextTermWidth(void* user)
{
return ((TextTerminal*) user)->EmergencyWidth();
}
static size_t EmergencyTextTermHeight(void* user)
{
return ((TextTerminal*) user)->EmergencyHeight();
}
static bool EmergencyTextTermSync(void* user)
{
return ((TextTerminal*) user)->EmergencySync();
}
addr_t initrd; addr_t initrd;
size_t initrdsize; size_t initrdsize;
Ref<TextBufferHandle> textbufhandle; Ref<TextBufferHandle> textbufhandle;
@ -167,9 +203,22 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
// Setup a text terminal instance. // Setup a text terminal instance.
TextTerminal textterm(textbufhandle); TextTerminal textterm(textbufhandle);
// Register the text terminal as the kernel log and initialize it. // Register the text terminal as the kernel log.
Log::Init(PrintToTextTerminal, TextTermWidth, TextTermHeight, TextTermSync, Log::device_callback = PrintToTextTerminal;
&textterm); Log::device_width = TextTermWidth;
Log::device_height = TextTermHeight;
Log::device_sync = TextTermSync;
Log::device_pointer = &textterm;
// Register the emergency kernel log.
Log::emergency_device_is_impaired = EmergencyTextTermIsImpaired;
Log::emergency_device_recoup = EmergencyTextTermRecoup;
Log::emergency_device_reset = EmergencyTextTermReset;
Log::emergency_device_callback = EmergencyPrintToTextTerminal;
Log::emergency_device_width = EmergencyTextTermWidth;
Log::emergency_device_height = EmergencyTextTermHeight;
Log::emergency_device_sync = EmergencyTextTermSync;
Log::emergency_device_pointer = &textterm;
// Display the boot welcome screen. // Display the boot welcome screen.
DoWelcome(); DoWelcome();

View file

@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012. Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
This file is part of Sortix. This file is part of Sortix.
@ -83,6 +83,7 @@ LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat,
goto cleanup_queue; goto cleanup_queue;
memcpy(font, VGA::GetFont(), fontsize); memcpy(font, VGA::GetFont(), fontsize);
ret->execute_lock = KTHREAD_MUTEX_INITIALIZER;
ret->queue_lock = KTHREAD_MUTEX_INITIALIZER; ret->queue_lock = KTHREAD_MUTEX_INITIALIZER;
ret->queue_not_full = KTHREAD_COND_INITIALIZER; ret->queue_not_full = KTHREAD_COND_INITIALIZER;
ret->queue_not_empty = KTHREAD_COND_INITIALIZER; ret->queue_not_empty = KTHREAD_COND_INITIALIZER;
@ -120,6 +121,7 @@ LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat,
ret->cursorpos = TextPos(0, 0); ret->cursorpos = TextPos(0, 0);
for ( size_t y = 0; y < yres; y++ ) for ( size_t y = 0; y < yres; y++ )
memset(lfb + scansize * y, 0, lfbformat/8UL * xres); memset(lfb + scansize * y, 0, lfbformat/8UL * xres);
ret->emergency_state = false;
if ( !RunKernelThread(kernel_process, LFBTextBuffer__RenderThread, ret) ) if ( !RunKernelThread(kernel_process, LFBTextBuffer__RenderThread, ret) )
{ {
@ -304,6 +306,18 @@ void LFBTextBuffer::RenderRange(TextPos from, TextPos to)
void LFBTextBuffer::IssueCommand(TextBufferCmd* cmd) void LFBTextBuffer::IssueCommand(TextBufferCmd* cmd)
{ {
if ( emergency_state )
{
bool exit_requested = false;
bool sync_requested = false;
bool pause_requested = false;
TextPos render_from(columns - 1, rows - 1);
TextPos render_to(0, 0);
ExecuteCommand(cmd, exit_requested, sync_requested, pause_requested, render_from, render_to);
if ( !IsTextPosBeforeTextPos(render_to, render_from) )
RenderRange(render_from, render_to);
return;
}
ScopedLock lock(&queue_lock); ScopedLock lock(&queue_lock);
while ( queue_used == queue_length ) while ( queue_used == queue_length )
kthread_cond_wait(&queue_not_full, &queue_lock); kthread_cond_wait(&queue_not_full, &queue_lock);
@ -314,6 +328,8 @@ void LFBTextBuffer::IssueCommand(TextBufferCmd* cmd)
void LFBTextBuffer::StopRendering() void LFBTextBuffer::StopRendering()
{ {
if ( emergency_state )
return;
TextBufferCmd cmd; TextBufferCmd cmd;
cmd.type = TEXTBUFCMD_PAUSE; cmd.type = TEXTBUFCMD_PAUSE;
IssueCommand(&cmd); IssueCommand(&cmd);
@ -324,6 +340,8 @@ void LFBTextBuffer::StopRendering()
void LFBTextBuffer::ResumeRendering() void LFBTextBuffer::ResumeRendering()
{ {
if ( emergency_state )
return;
ScopedLock lock(&queue_lock); ScopedLock lock(&queue_lock);
queue_is_paused = false; queue_is_paused = false;
kthread_cond_signal(&queue_resume); kthread_cond_signal(&queue_resume);
@ -496,65 +514,31 @@ void LFBTextBuffer::DoFill(TextPos from, TextPos to, uint16_t fillwith,
attrs[i] = fillattr; attrs[i] = fillattr;
} }
void LFBTextBuffer::RenderThread() bool LFBTextBuffer::IsCommandIdempotent(const TextBufferCmd* cmd) const
{ {
queue_is_paused = false; switch ( cmd->type )
size_t offset = 0;
size_t amount = 0;
bool exit_requested = false;
bool sync_requested = false;
bool pause_requested = false;
while ( true )
{ {
kthread_mutex_lock(&queue_lock); case TEXTBUFCMD_EXIT: return true;
case TEXTBUFCMD_SYNC: return true;
if ( queue_used == queue_length && amount ) case TEXTBUFCMD_PAUSE: return true;
kthread_cond_signal(&queue_not_full); case TEXTBUFCMD_CHAR: return true;
case TEXTBUFCMD_ATTR: return true;
queue_used -= amount; case TEXTBUFCMD_CURSOR_SET_ENABLED: return true;
queue_offset = (queue_offset + amount) % queue_length; case TEXTBUFCMD_CURSOR_MOVE: return true;
case TEXTBUFCMD_MOVE: return false;
if ( !queue_used ) case TEXTBUFCMD_FILL: return true;
{ case TEXTBUFCMD_SCROLL: return false;
if ( exit_requested ) default: return false;
{
queue_thread = false;
kthread_cond_signal(&queue_exit);
kthread_mutex_unlock(&queue_lock);
return;
} }
}
if ( sync_requested ) void LFBTextBuffer::ExecuteCommand(TextBufferCmd* cmd,
{ bool& exit_requested,
kthread_cond_signal(&queue_sync); bool& sync_requested,
sync_requested = false; bool& pause_requested,
} TextPos& render_from,
TextPos& render_to)
if ( pause_requested ) {
{
queue_is_paused = true;
kthread_cond_signal(&queue_paused);
while ( queue_is_paused )
kthread_cond_wait(&queue_resume, &queue_lock);
pause_requested = false;
}
}
while ( !queue_used )
kthread_cond_wait(&queue_not_empty, &queue_lock);
amount = queue_used;
offset = queue_offset;
kthread_mutex_unlock(&queue_lock);
TextPos render_from(columns - 1, rows - 1);
TextPos render_to(0, 0);
for ( size_t i = 0; i < amount; i++ )
{
TextBufferCmd* cmd = &queue[(offset + i) % queue_length];
switch ( cmd->type ) switch ( cmd->type )
{ {
case TEXTBUFCMD_EXIT: case TEXTBUFCMD_EXIT:
@ -636,11 +620,134 @@ void LFBTextBuffer::RenderThread()
render_to = {columns-1, rows-1}; render_to = {columns-1, rows-1};
} break; } break;
} }
}
void LFBTextBuffer::RenderThread()
{
queue_is_paused = false;
size_t offset = 0;
size_t amount = 0;
bool exit_requested = false;
bool sync_requested = false;
bool pause_requested = false;
while ( true )
{
kthread_mutex_lock(&queue_lock);
if ( queue_used == queue_length && amount )
kthread_cond_signal(&queue_not_full);
queue_used -= amount;
queue_offset = (queue_offset + amount) % queue_length;
if ( !queue_used )
{
if ( exit_requested )
{
queue_thread = false;
kthread_cond_signal(&queue_exit);
kthread_mutex_unlock(&queue_lock);
return;
} }
if ( sync_requested )
{
kthread_cond_signal(&queue_sync);
sync_requested = false;
}
if ( pause_requested )
{
queue_is_paused = true;
kthread_cond_signal(&queue_paused);
while ( queue_is_paused )
kthread_cond_wait(&queue_resume, &queue_lock);
pause_requested = false;
}
}
while ( !queue_used )
kthread_cond_wait(&queue_not_empty, &queue_lock);
amount = queue_used;
offset = queue_offset;
kthread_mutex_unlock(&queue_lock);
execute_amount = amount;
kthread_mutex_lock(&execute_lock);
TextPos render_from(columns - 1, rows - 1);
TextPos render_to(0, 0);
for ( size_t i = 0; i < amount; i++ )
{
TextBufferCmd* cmd = &queue[(offset + i) % queue_length];
ExecuteCommand(cmd, exit_requested, sync_requested, pause_requested, render_from, render_to);
}
kthread_mutex_unlock(&execute_lock);
if ( !IsTextPosBeforeTextPos(render_to, render_from) ) if ( !IsTextPosBeforeTextPos(render_to, render_from) )
RenderRange(render_from, render_to); RenderRange(render_from, render_to);
} }
} }
bool LFBTextBuffer::EmergencyIsImpaired()
{
return !emergency_state;
}
bool LFBTextBuffer::EmergencyRecoup()
{
if ( !emergency_state )
emergency_state = true;
if ( !kthread_mutex_trylock(&queue_lock) )
return false;
kthread_mutex_unlock(&queue_lock);
if ( !kthread_mutex_trylock(&execute_lock) )
{
for ( size_t i = 0; i < execute_amount; i++ )
{
TextBufferCmd* cmd = &queue[(queue_offset + i) % queue_length];
if ( !IsCommandIdempotent(cmd) )
return false;
}
}
else
kthread_mutex_unlock(&execute_lock);
TextPos render_from(0, 0);
TextPos render_to(columns - 1, rows - 1);
for ( size_t i = 0; i < queue_used; i++ )
{
bool exit_requested = false;
bool sync_requested = false;
bool pause_requested = false;
TextBufferCmd* cmd = &queue[(queue_offset + i) % queue_length];
ExecuteCommand(cmd, exit_requested, sync_requested, pause_requested,
render_from, render_to);
}
queue_used = 0;
queue_offset = 0;
RenderRange(render_from, render_to);
return true;
}
void LFBTextBuffer::EmergencyReset()
{
// TODO: Reset everything here!
Fill(TextPos{0, 0}, TextPos{columns-1, rows-1}, TextChar{0, 0}, 0);
SetCursorPos(TextPos{0, 0});
}
} // namespace Sortix } // namespace Sortix

View file

@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012. Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
This file is part of Sortix. This file is part of Sortix.
@ -83,6 +83,9 @@ public:
virtual void SetCursorEnabled(bool enablecursor); virtual void SetCursorEnabled(bool enablecursor);
virtual TextPos GetCursorPos() const; virtual TextPos GetCursorPos() const;
virtual void SetCursorPos(TextPos newcursorpos); virtual void SetCursorPos(TextPos newcursorpos);
virtual bool EmergencyIsImpaired();
virtual bool EmergencyRecoup();
virtual void EmergencyReset();
public: public:
virtual void RenderThread(); virtual void RenderThread();
@ -102,8 +105,16 @@ private:
void IssueCommand(TextBufferCmd* cmd); void IssueCommand(TextBufferCmd* cmd);
void StopRendering(); void StopRendering();
void ResumeRendering(); void ResumeRendering();
bool IsCommandIdempotent(const TextBufferCmd* cmd) const;
void ExecuteCommand(TextBufferCmd* cmd,
bool& exit_requested,
bool& sync_requested,
bool& pause_requested,
TextPos& render_from,
TextPos& render_to);
private: private:
kthread_mutex_t execute_lock;
kthread_mutex_t queue_lock; kthread_mutex_t queue_lock;
kthread_cond_t queue_not_full; kthread_cond_t queue_not_full;
kthread_cond_t queue_not_empty; kthread_cond_t queue_not_empty;
@ -131,6 +142,8 @@ private:
uint32_t lfbformat; uint32_t lfbformat;
bool cursorenabled; bool cursorenabled;
TextPos cursorpos; TextPos cursorpos;
bool emergency_state;
size_t execute_amount;
}; };

View file

@ -37,19 +37,14 @@ size_t (*device_width)(void*) = NULL;
size_t (*device_height)(void*) = NULL; size_t (*device_height)(void*) = NULL;
bool (*device_sync)(void*) = NULL; bool (*device_sync)(void*) = NULL;
void* device_pointer = NULL; void* device_pointer = NULL;
bool (*emergency_device_is_impaired)(void*) = NULL;
void Init(size_t (*callback)(void*, const char*, size_t), bool (*emergency_device_recoup)(void*) = NULL;
size_t (*widthfunc)(void*), void (*emergency_device_reset)(void*) = NULL;
size_t (*heightfunc)(void*), size_t (*emergency_device_callback)(void*, const char*, size_t) = NULL;
bool (*syncfunc)(void*), size_t (*emergency_device_width)(void*) = NULL;
void* user) size_t (*emergency_device_height)(void*) = NULL;
{ bool (*emergency_device_sync)(void*) = NULL;
device_callback = callback; void* emergency_device_pointer = NULL;
device_width = widthfunc;
device_height = heightfunc;
device_sync = syncfunc;
device_pointer = user;
}
} // namespace Log } // namespace Log
} // namespace Sortix } // namespace Sortix

View file

@ -41,6 +41,7 @@ const bool longpanic = true;
static bool panicing = false; static bool panicing = false;
static bool doublepanic = false; static bool doublepanic = false;
static bool logrecovering = false;
static void PanicLogoLong() static void PanicLogoLong()
{ {
@ -54,8 +55,53 @@ static void PanicLogoShort()
void PanicInit() void PanicInit()
{ {
// This is a kernel emergency. We will need to disable preemption, such that
// this is the only thread running. This means that we cannot acquire locks
// and the data protected by them may be inconsistent.
Interrupt::Disable(); Interrupt::Disable();
// Detect whether a panic happened during the log recovery.
if ( logrecovering )
{
// Oh no! We paniced during the log recovery that we will do momentarily
// - this means that there probably isn't anything we can do but halt.
HaltKernel();
}
logrecovering = true;
// The kernel log normally uses locks internally and the console may be
// rendered by a background thread. This means that we cannot use the normal
// kernel log, but that we rather need to switch to the kernel emergency
// log, which is able to cope with the potential inconsistencies.
Log::device_callback = Log::emergency_device_callback;
Log::device_width = Log::emergency_device_width;
Log::device_height = Log::emergency_device_height;
Log::device_sync = Log::emergency_device_sync;
Log::device_pointer = Log::emergency_device_pointer;
// Check whether the panic condition left the kernel log unharmed.
if ( !Log::emergency_device_is_impaired(Log::emergency_device_pointer) )
{
// The kernel log device transitioned ideally to the emergency state.
}
// Attempt to repair inconsistent state of the emergency log device.
else if ( Log::emergency_device_recoup(Log::emergency_device_pointer) )
{
// The kernel log was successfully repaired and is ready for use in the
// current emergency state.
}
// It was not possible to repair the emergency device properly, so instead
// we will need to perform a hard reset of the emergency device.
else
{
Log::emergency_device_reset(Log::emergency_device_pointer);
// The kernel log was successfully repaired and is ready for use in the
// current emergency state.
}
// Handle the case where the panic code caused another system crash. // Handle the case where the panic code caused another system crash.
if ( panicing ) if ( panicing )
{ {

View file

@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012. Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
This file is part of Sortix. This file is part of Sortix.
@ -71,6 +71,41 @@ void TextBufferHandle::Release(TextBuffer* textbuf)
kthread_cond_signal(&unusedcond); kthread_cond_signal(&unusedcond);
} }
bool TextBufferHandle::EmergencyIsImpaired()
{
if ( !kthread_mutex_trylock(&mutex) )
return true;
kthread_mutex_unlock(&mutex);
return false;
}
bool TextBufferHandle::EmergencyRecoup()
{
if ( !EmergencyIsImpaired() )
return true;
mutex = KTHREAD_MUTEX_INITIALIZER;
return true;
}
void TextBufferHandle::EmergencyReset()
{
}
TextBuffer* TextBufferHandle::EmergencyAcquire()
{
// This is during a kernel emergency where preemption has been disabled and
// this is the only thread running.
return textbuf ? textbuf : def;
}
void TextBufferHandle::EmergencyRelease(TextBuffer* textbuf)
{
// This is during a kernel emergency where preemption has been disabled and
// this is the only thread running. We don't maintain the reference count
// during this state, so this is a no-operation.
(void) textbuf;
}
void TextBufferHandle::Replace(TextBuffer* newtextbuf, bool deletebuf) void TextBufferHandle::Replace(TextBuffer* newtextbuf, bool deletebuf)
{ {
ScopedLock lock(&mutex); ScopedLock lock(&mutex);

View file

@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
This file is part of Sortix. This file is part of Sortix.
@ -102,6 +102,116 @@ bool TextTerminal::Sync()
return true; return true;
} }
bool TextTerminal::EmergencyIsImpaired()
{
// This is during a kernel emergency where preemption has been disabled and
// this is the only thread running.
if ( !kthread_mutex_trylock(&termlock) )
return true;
kthread_mutex_unlock(&termlock);
if ( textbufhandle->EmergencyIsImpaired() )
return true;
TextBuffer* textbuf = textbufhandle->EmergencyAcquire();
bool textbuf_was_impaired = textbuf->EmergencyIsImpaired();
textbufhandle->EmergencyRelease(textbuf);
if ( textbuf_was_impaired )
return true;
return false;
}
bool TextTerminal::EmergencyRecoup()
{
// This is during a kernel emergency where preemption has been disabled and
// this is the only thread running.
if ( !kthread_mutex_trylock(&termlock) )
return false;
kthread_mutex_unlock(&termlock);
if ( textbufhandle->EmergencyIsImpaired() &&
!textbufhandle->EmergencyRecoup() )
return false;
TextBuffer* textbuf = textbufhandle->EmergencyAcquire();
bool textbuf_failure = textbuf->EmergencyIsImpaired() &&
!textbuf->EmergencyRecoup();
textbufhandle->EmergencyRelease(textbuf);
if ( !textbuf_failure )
return false;
return true;
}
void TextTerminal::EmergencyReset()
{
// This is during a kernel emergency where preemption has been disabled and
// this is the only thread running.
textbufhandle->EmergencyReset();
TextBuffer* textbuf = textbufhandle->EmergencyAcquire();
textbuf->EmergencyReset();
textbufhandle->EmergencyRelease(textbuf);
this->termlock = KTHREAD_MUTEX_INITIALIZER;
Reset();
}
size_t TextTerminal::EmergencyPrint(const char* string, size_t stringlen)
{
// This is during a kernel emergency where preemption has been disabled and
// this is the only thread running. Another thread may have been interrupted
// while it held the terminal lock. The best case is if the terminal lock is
// currently unused, which would mean everything is safe.
TextBuffer* textbuf = textbufhandle->EmergencyAcquire();
for ( size_t i = 0; i < stringlen; i++ )
PutChar(textbuf, string[i]);
UpdateCursor(textbuf);
textbufhandle->EmergencyRelease(textbuf);
return stringlen;
}
size_t TextTerminal::EmergencyWidth() const
{
// This is during a kernel emergency where preemption has been disabled and
// this is the only thread running. Another thread may have been interrupted
// while it held the terminal lock. The best case is if the terminal lock is
// currently unused, which would mean everything is safe.
TextBuffer* textbuf = textbufhandle->EmergencyAcquire();
size_t width = textbuf->Width();
textbufhandle->EmergencyRelease(textbuf);
return width;
}
size_t TextTerminal::EmergencyHeight() const
{
// This is during a kernel emergency where preemption has been disabled and
// this is the only thread running. Another thread may have been interrupted
// while it held the terminal lock. The best case is if the terminal lock is
// currently unused, which would mean everything is safe.
TextBuffer* textbuf = textbufhandle->EmergencyAcquire();
size_t height = textbuf->Height();
textbufhandle->EmergencyRelease(textbuf);
return height;
}
bool TextTerminal::EmergencySync()
{
// This is during a kernel emergency where preemption has been disabled and
// this is the only thread running. There is no need to synchronize the
// text buffer here as there is no background thread rendering the console.
return true;
}
void TextTerminal::PutChar(TextBuffer* textbuf, char c) void TextTerminal::PutChar(TextBuffer* textbuf, char c)
{ {
if ( ansimode ) if ( ansimode )

View file

@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
This file is part of Sortix. This file is part of Sortix.
@ -41,6 +41,13 @@ public:
size_t Width() const; size_t Width() const;
size_t Height() const; size_t Height() const;
bool Sync(); bool Sync();
bool EmergencyIsImpaired();
bool EmergencyRecoup();
void EmergencyReset();
size_t EmergencyPrint(const char* string, size_t stringlen);
size_t EmergencyWidth() const;
size_t EmergencyHeight() const;
bool EmergencySync();
private: private:
void PutChar(TextBuffer* textbuf, char c); void PutChar(TextBuffer* textbuf, char c);

View file

@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012. Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
This file is part of Sortix. This file is part of Sortix.
@ -192,4 +192,21 @@ void VGATextBuffer::UpdateCursor()
VGA::SetCursor(width, height-1); VGA::SetCursor(width, height-1);
} }
bool VGATextBuffer::EmergencyIsImpaired()
{
return false;
}
bool VGATextBuffer::EmergencyRecoup()
{
return true;
}
void VGATextBuffer::EmergencyReset()
{
return;
Fill(TextPos{0, 0}, TextPos{width-1, height-1}, TextChar{0, 0}, 0);
SetCursorPos(TextPos{0, 0});
}
} // namespace Sortix } // namespace Sortix

View file

@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012. Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
This file is part of Sortix. This file is part of Sortix.
@ -48,6 +48,9 @@ public:
virtual void SetCursorEnabled(bool enablecursor); virtual void SetCursorEnabled(bool enablecursor);
virtual TextPos GetCursorPos() const; virtual TextPos GetCursorPos() const;
virtual void SetCursorPos(TextPos cursorpos); virtual void SetCursorPos(TextPos cursorpos);
virtual bool EmergencyIsImpaired();
virtual bool EmergencyRecoup();
virtual void EmergencyReset();
private: private:
bool UsablePosition(TextPos pos) const; bool UsablePosition(TextPos pos) const;