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 bool (*device_sync)(void*);
extern void* device_pointer;
void Init(size_t (*callback)(void*, const char*, size_t),
size_t (*widthfunc)(void*),
size_t (*heightfunc)(void*),
bool (*syncfunc)(void*),
void* user);
extern bool (*emergency_device_is_impaired)(void*);
extern bool (*emergency_device_recoup)(void*);
extern void (*emergency_device_reset)(void*);
extern size_t (*emergency_device_callback)(void*, const char*, size_t);
extern size_t (*emergency_device_width)(void*);
extern size_t (*emergency_device_height)(void*);
extern bool (*emergency_device_sync)(void*);
extern void* emergency_device_pointer;
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.
@ -74,6 +74,9 @@ public:
virtual void SetCursorEnabled(bool enablecursor) = 0;
virtual TextPos GetCursorPos() const = 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();
void Release(TextBuffer* textbuf);
void Replace(TextBuffer* newtextbuf, bool deletebuf = true);
bool EmergencyIsImpaired();
bool EmergencyRecoup();
void EmergencyReset();
TextBuffer* EmergencyAcquire();
void EmergencyRelease(TextBuffer* textbuf);
private:
kthread_mutex_t mutex;

View File

@ -135,6 +135,42 @@ static bool TextTermSync(void* user)
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;
size_t initrdsize;
Ref<TextBufferHandle> textbufhandle;
@ -167,9 +203,22 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
// Setup a text terminal instance.
TextTerminal textterm(textbufhandle);
// Register the text terminal as the kernel log and initialize it.
Log::Init(PrintToTextTerminal, TextTermWidth, TextTermHeight, TextTermSync,
&textterm);
// Register the text terminal as the kernel log.
Log::device_callback = PrintToTextTerminal;
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.
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.
@ -83,6 +83,7 @@ LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat,
goto cleanup_queue;
memcpy(font, VGA::GetFont(), fontsize);
ret->execute_lock = KTHREAD_MUTEX_INITIALIZER;
ret->queue_lock = KTHREAD_MUTEX_INITIALIZER;
ret->queue_not_full = 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);
for ( size_t y = 0; y < yres; y++ )
memset(lfb + scansize * y, 0, lfbformat/8UL * xres);
ret->emergency_state = false;
if ( !RunKernelThread(kernel_process, LFBTextBuffer__RenderThread, ret) )
{
@ -304,6 +306,18 @@ void LFBTextBuffer::RenderRange(TextPos from, TextPos to)
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);
while ( queue_used == queue_length )
kthread_cond_wait(&queue_not_full, &queue_lock);
@ -314,6 +328,8 @@ void LFBTextBuffer::IssueCommand(TextBufferCmd* cmd)
void LFBTextBuffer::StopRendering()
{
if ( emergency_state )
return;
TextBufferCmd cmd;
cmd.type = TEXTBUFCMD_PAUSE;
IssueCommand(&cmd);
@ -324,6 +340,8 @@ void LFBTextBuffer::StopRendering()
void LFBTextBuffer::ResumeRendering()
{
if ( emergency_state )
return;
ScopedLock lock(&queue_lock);
queue_is_paused = false;
kthread_cond_signal(&queue_resume);
@ -496,6 +514,114 @@ void LFBTextBuffer::DoFill(TextPos from, TextPos to, uint16_t fillwith,
attrs[i] = fillattr;
}
bool LFBTextBuffer::IsCommandIdempotent(const TextBufferCmd* cmd) const
{
switch ( cmd->type )
{
case TEXTBUFCMD_EXIT: return true;
case TEXTBUFCMD_SYNC: return true;
case TEXTBUFCMD_PAUSE: return true;
case TEXTBUFCMD_CHAR: return true;
case TEXTBUFCMD_ATTR: return true;
case TEXTBUFCMD_CURSOR_SET_ENABLED: return true;
case TEXTBUFCMD_CURSOR_MOVE: return true;
case TEXTBUFCMD_MOVE: return false;
case TEXTBUFCMD_FILL: return true;
case TEXTBUFCMD_SCROLL: return false;
default: return false;
}
}
void LFBTextBuffer::ExecuteCommand(TextBufferCmd* cmd,
bool& exit_requested,
bool& sync_requested,
bool& pause_requested,
TextPos& render_from,
TextPos& render_to)
{
switch ( cmd->type )
{
case TEXTBUFCMD_EXIT:
exit_requested = true;
break;
case TEXTBUFCMD_SYNC:
sync_requested = true;
break;
case TEXTBUFCMD_PAUSE:
pause_requested = true;
break;
case TEXTBUFCMD_CHAR:
{
TextPos pos(cmd->x, cmd->y);
chars[pos.y * columns + pos.x] = cmd->c;
if ( IsTextPosBeforeTextPos(pos, render_from) )
render_from = pos;
if ( IsTextPosAfterTextPos(pos, render_to) )
render_to = pos;
} break;
case TEXTBUFCMD_ATTR:
{
TextPos pos(cmd->x, cmd->y);
attrs[pos.y * columns + pos.x] = cmd->attr;
} break;
case TEXTBUFCMD_CURSOR_SET_ENABLED:
if ( cmd->b != cursorenabled )
{
cursorenabled = cmd->b;
if ( IsTextPosBeforeTextPos(cursorpos, render_from) )
render_from = cursorpos;
if ( IsTextPosAfterTextPos(cursorpos, render_to) )
render_to = cursorpos;
}
break;
case TEXTBUFCMD_CURSOR_MOVE:
{
TextPos pos(cmd->x, cmd->y);
if ( cursorpos.x != pos.x || cursorpos.y != pos.y )
{
if ( IsTextPosBeforeTextPos(cursorpos, render_from) )
render_from = cursorpos;
if ( IsTextPosAfterTextPos(cursorpos, render_to) )
render_to = cursorpos;
cursorpos = pos;
if ( IsTextPosBeforeTextPos(cursorpos, render_from) )
render_from = cursorpos;
if ( IsTextPosAfterTextPos(cursorpos, render_to) )
render_to = cursorpos;
}
} break;
case TEXTBUFCMD_MOVE:
{
TextPos to(cmd->to_x, cmd->to_y);
TextPos from(cmd->from_x, cmd->from_y);
size_t numchars = cmd->val;
DoMove(to, from, numchars);
TextPos toend = AddToPosition(to, numchars);
if ( IsTextPosBeforeTextPos(to, render_from) )
render_from = to;
if ( IsTextPosAfterTextPos(toend, render_to) )
render_to = toend;
} break;
case TEXTBUFCMD_FILL:
{
TextPos from(cmd->from_x, cmd->from_y);
TextPos to(cmd->to_x, cmd->to_y);
DoFill(from, to, cmd->c, cmd->attr);
if ( IsTextPosBeforeTextPos(from, render_from) )
render_from = from;
if ( IsTextPosAfterTextPos(to, render_to) )
render_to = to;
} break;
case TEXTBUFCMD_SCROLL:
{
ssize_t off = cmd->scroll_offset;
DoScroll(off, cmd->c);
render_from = {0, 0};
render_to = {columns-1, rows-1};
} break;
}
}
void LFBTextBuffer::RenderThread()
{
queue_is_paused = false;
@ -549,98 +675,79 @@ void LFBTextBuffer::RenderThread()
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];
switch ( cmd->type )
{
case TEXTBUFCMD_EXIT:
exit_requested = true;
break;
case TEXTBUFCMD_SYNC:
sync_requested = true;
break;
case TEXTBUFCMD_PAUSE:
pause_requested = true;
break;
case TEXTBUFCMD_CHAR:
{
TextPos pos(cmd->x, cmd->y);
chars[pos.y * columns + pos.x] = cmd->c;
if ( IsTextPosBeforeTextPos(pos, render_from) )
render_from = pos;
if ( IsTextPosAfterTextPos(pos, render_to) )
render_to = pos;
} break;
case TEXTBUFCMD_ATTR:
{
TextPos pos(cmd->x, cmd->y);
attrs[pos.y * columns + pos.x] = cmd->attr;
} break;
case TEXTBUFCMD_CURSOR_SET_ENABLED:
if ( cmd->b != cursorenabled )
{
cursorenabled = cmd->b;
if ( IsTextPosBeforeTextPos(cursorpos, render_from) )
render_from = cursorpos;
if ( IsTextPosAfterTextPos(cursorpos, render_to) )
render_to = cursorpos;
}
break;
case TEXTBUFCMD_CURSOR_MOVE:
{
TextPos pos(cmd->x, cmd->y);
if ( cursorpos.x != pos.x || cursorpos.y != pos.y )
{
if ( IsTextPosBeforeTextPos(cursorpos, render_from) )
render_from = cursorpos;
if ( IsTextPosAfterTextPos(cursorpos, render_to) )
render_to = cursorpos;
cursorpos = pos;
if ( IsTextPosBeforeTextPos(cursorpos, render_from) )
render_from = cursorpos;
if ( IsTextPosAfterTextPos(cursorpos, render_to) )
render_to = cursorpos;
}
} break;
case TEXTBUFCMD_MOVE:
{
TextPos to(cmd->to_x, cmd->to_y);
TextPos from(cmd->from_x, cmd->from_y);
size_t numchars = cmd->val;
DoMove(to, from, numchars);
TextPos toend = AddToPosition(to, numchars);
if ( IsTextPosBeforeTextPos(to, render_from) )
render_from = to;
if ( IsTextPosAfterTextPos(toend, render_to) )
render_to = toend;
} break;
case TEXTBUFCMD_FILL:
{
TextPos from(cmd->from_x, cmd->from_y);
TextPos to(cmd->to_x, cmd->to_y);
DoFill(from, to, cmd->c, cmd->attr);
if ( IsTextPosBeforeTextPos(from, render_from) )
render_from = from;
if ( IsTextPosAfterTextPos(to, render_to) )
render_to = to;
} break;
case TEXTBUFCMD_SCROLL:
{
ssize_t off = cmd->scroll_offset;
DoScroll(off, cmd->c);
render_from = {0, 0};
render_to = {columns-1, rows-1};
} break;
}
ExecuteCommand(cmd, exit_requested, sync_requested, pause_requested, render_from, render_to);
}
kthread_mutex_unlock(&execute_lock);
if ( !IsTextPosBeforeTextPos(render_to, render_from) )
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

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.
@ -83,6 +83,9 @@ public:
virtual void SetCursorEnabled(bool enablecursor);
virtual TextPos GetCursorPos() const;
virtual void SetCursorPos(TextPos newcursorpos);
virtual bool EmergencyIsImpaired();
virtual bool EmergencyRecoup();
virtual void EmergencyReset();
public:
virtual void RenderThread();
@ -102,8 +105,16 @@ private:
void IssueCommand(TextBufferCmd* cmd);
void StopRendering();
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:
kthread_mutex_t execute_lock;
kthread_mutex_t queue_lock;
kthread_cond_t queue_not_full;
kthread_cond_t queue_not_empty;
@ -131,6 +142,8 @@ private:
uint32_t lfbformat;
bool cursorenabled;
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;
bool (*device_sync)(void*) = NULL;
void* device_pointer = NULL;
void Init(size_t (*callback)(void*, const char*, size_t),
size_t (*widthfunc)(void*),
size_t (*heightfunc)(void*),
bool (*syncfunc)(void*),
void* user)
{
device_callback = callback;
device_width = widthfunc;
device_height = heightfunc;
device_sync = syncfunc;
device_pointer = user;
}
bool (*emergency_device_is_impaired)(void*) = NULL;
bool (*emergency_device_recoup)(void*) = NULL;
void (*emergency_device_reset)(void*) = NULL;
size_t (*emergency_device_callback)(void*, const char*, size_t) = NULL;
size_t (*emergency_device_width)(void*) = NULL;
size_t (*emergency_device_height)(void*) = NULL;
bool (*emergency_device_sync)(void*) = NULL;
void* emergency_device_pointer = NULL;
} // namespace Log
} // namespace Sortix

View File

@ -41,6 +41,7 @@ const bool longpanic = true;
static bool panicing = false;
static bool doublepanic = false;
static bool logrecovering = false;
static void PanicLogoLong()
{
@ -54,8 +55,53 @@ static void PanicLogoShort()
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();
// 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.
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.
@ -71,6 +71,41 @@ void TextBufferHandle::Release(TextBuffer* textbuf)
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)
{
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.
@ -102,6 +102,116 @@ bool TextTerminal::Sync()
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)
{
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.
@ -41,6 +41,13 @@ public:
size_t Width() const;
size_t Height() const;
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:
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.
@ -192,4 +192,21 @@ void VGATextBuffer::UpdateCursor()
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

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.
@ -48,6 +48,9 @@ public:
virtual void SetCursorEnabled(bool enablecursor);
virtual TextPos GetCursorPos() const;
virtual void SetCursorPos(TextPos cursorpos);
virtual bool EmergencyIsImpaired();
virtual bool EmergencyRecoup();
virtual void EmergencyReset();
private:
bool UsablePosition(TextPos pos) const;