Skip to content

Commit

Permalink
Fixed: Fatal errors from worker thread
Browse files Browse the repository at this point in the history
The busy worker thread will now start sleeping indefinitely when an
error occurs. The main thread will kill it and proceed to shut down
the engine after showing the error dialog.
  • Loading branch information
skyjake committed Apr 8, 2012
1 parent 42f2be3 commit b7579e9
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 11 deletions.
8 changes: 7 additions & 1 deletion doomsday/engine/portable/include/concurrency.h
Expand Up @@ -83,9 +83,15 @@ thread_t Sys_StartThread(systhreadfunc_t startpos, void* parm);
void Thread_Sleep(int milliseconds);

/**
* Wait for a thread to stop. If the thread does not stop after @a timeoutMs,
* it will be forcibly terminated.
*
* @param handle Thread handle.
* @param timeoutMs How long to wait until the thread terminates.
*
* @return Return value of the thread.
*/
int Sys_WaitThread(thread_t handle);
int Sys_WaitThread(thread_t handle, int timeoutMs);

/**
* @param handle Handle to the thread to return the id of.
Expand Down
4 changes: 4 additions & 0 deletions doomsday/engine/portable/src/busytask.cpp
Expand Up @@ -79,6 +79,10 @@ int BusyTask_Run(int mode, const char* taskName, busyworkerfunc_t worker, void*
return result;
}

/**
* Ends the busy event loop and sets its return value. The loop callback, which
* during busy mode points to the busy loop callback, is reset to NULL.
*/
void BusyTask_ExitWithValue(int result)
{
// After the event loop is gone, we don't want any loop callbacks until the
Expand Down
12 changes: 9 additions & 3 deletions doomsday/engine/portable/src/con_busy.c
Expand Up @@ -61,6 +61,7 @@ static timespan_t busyTime;
static timespan_t accumulatedBusyTime; // Never cleared.
static volatile boolean busyDone;
static volatile boolean busyDoneCopy;
static boolean busyTaskEndedWithError;
static char busyError[256];
static fontid_t busyFont = 0;
static int busyFontHgt; // Height of the font.
Expand Down Expand Up @@ -115,6 +116,7 @@ void BusyTask_Begin(BusyTask* task)
// Load any textures needed in this mode.
Con_BusyPrepareResources();

busyTaskEndedWithError = false;
busyInited = true;

// Start the busy worker thread, which will proces things in the
Expand All @@ -139,16 +141,19 @@ void BusyTask_Begin(BusyTask* task)
}

/**
* Exits the busy mode event loop.
* Exits the busy mode event loop. Called in the main thread, does not return
* until the worker thread is stopped.
*/
static void BusyTask_Exit(void)
{
int result;

LIBDENG_ASSERT_IN_MAIN_THREAD();

busyDone = true;

// Make sure the worker finishes before we continue.
result = Sys_WaitThread(busyThread);
result = Sys_WaitThread(busyThread, busyTaskEndedWithError? 100 : 5000);
busyThread = NULL;

BusyTask_ExitWithValue(result);
Expand All @@ -174,7 +179,7 @@ void BusyTask_End(BusyTask* task)
// The window drawer will be restored later to the appropriate function.
Window_SetDrawFunc(Window_Main(), 0);

if(busyError[0])
if(busyTaskEndedWithError)
{
Con_AbnormalShutdown(busyError);
}
Expand All @@ -200,6 +205,7 @@ void BusyTask_End(BusyTask* task)

void Con_BusyWorkerError(const char* message)
{
busyTaskEndedWithError = true;
strncpy(busyError, message, sizeof(busyError) - 1);
Con_BusyWorkerEnd();
}
Expand Down
8 changes: 5 additions & 3 deletions doomsday/engine/portable/src/con_main.c
Expand Up @@ -2102,7 +2102,8 @@ void Con_Error(const char* error, ...)
Con_BusyWorkerError(buff);
if(Con_InBusyWorker())
{
BusyTask_ExitWithValue(1);
// We should not continue to execute the worker any more.
for(;;) Thread_Sleep(10000);
}
}
else
Expand All @@ -2117,8 +2118,9 @@ void Con_AbnormalShutdown(const char* message)
DisplayMode_Shutdown();

// Be a bit more graphic.
Sys_ShowCursor(true);
Sys_ShowCursor(true);
Window_TrapMouse(Window_Main(), false);
//Sys_ShowCursor(true);

if(message) // Only show if a message given.
{
// Make sure all the buffered stuff goes into the file.
Expand Down
34 changes: 31 additions & 3 deletions doomsday/engine/portable/src/concurrency.cpp
Expand Up @@ -27,6 +27,7 @@
#include <QApplication>
#include <QDebug>
#include <de/Time>
#include <de/Log>
#include <assert.h>

static uint mainThreadId = 0; ///< ID of the main thread.
Expand All @@ -36,13 +37,25 @@ CallbackThread::CallbackThread(systhreadfunc_t func, void* param)
{
qDebug() << "CallbackThread:" << this << "created.";

// Only used if the thread needs to be shut down forcibly.
setTerminationEnabled(true);

// Cleanup at app exit time for threads whose exit value hasn't been checked.
connect(qApp, SIGNAL(destroyed()), this, SLOT(deleteNow()));
}

CallbackThread::~CallbackThread()
{
qDebug() << "CallbackThread:" << this << "deleted.";
if(isRunning())
{
qDebug() << "CallbackThread:" << this << "forcibly stopping, deleting.";
terminate();
wait(1000);
}
else
{
qDebug() << "CallbackThread:" << this << "deleted.";
}
}

void CallbackThread::deleteNow()
Expand Down Expand Up @@ -86,11 +99,26 @@ thread_t Sys_StartThread(systhreadfunc_t startpos, void *parm)
return t;
}

int Sys_WaitThread(thread_t handle)
void Thread_KillAbnormally(thread_t handle)
{
QThread* t = reinterpret_cast<QThread*>(handle);
if(!handle)
{
t = QThread::currentThread();
}
assert(t);
t->terminate();
}

int Sys_WaitThread(thread_t handle, int timeoutMs)
{
CallbackThread* t = reinterpret_cast<CallbackThread*>(handle);
assert(static_cast<QThread*>(t) != QThread::currentThread());
t->wait(10000); // 10 seconds at most
t->wait(timeoutMs);
if(!t->isFinished())
{
LOG_WARNING("Thread did not stop in time, forcibly killing it.");
}
t->deleteLater(); // get rid of it
return t->exitValue();
}
Expand Down
2 changes: 1 addition & 1 deletion doomsday/engine/portable/src/gl_texmanager.c
Expand Up @@ -1379,7 +1379,7 @@ void GL_ReleaseTextures(void)
void GL_PruneTextureVariantSpecifications(void)
{
int numPruned = 0;
if(!initedOk) return;
if(!initedOk || Sys_IsShuttingDown()) return;

numPruned += pruneUnusedVariantSpecifications(TST_GENERAL);
numPruned += pruneUnusedVariantSpecifications(TST_DETAIL);
Expand Down

0 comments on commit b7579e9

Please sign in to comment.