X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FTask.c;h=92b5c2594f707a5c7e8214ea9391f26e8bb8f262;hb=9e6162f9d0102d1f5738bf78258b24ea5a647ea4;hp=80e5f695572ebd5d0aacd620033b8f315d08f293;hpb=e53c9fc74a3c847801e82394d6be6633b981ad76;p=ghc-hetmet.git diff --git a/ghc/rts/Task.c b/ghc/rts/Task.c index 80e5f69..92b5c25 100644 --- a/ghc/rts/Task.c +++ b/ghc/rts/Task.c @@ -10,11 +10,12 @@ * 'native thread-friendly' builds. * * The SMP build lets multiple tasks concurrently execute STG code, - * all sharing vital internal RTS data structures in a controlled manner. + * all sharing vital internal RTS data structures in a controlled manner + * (see details elsewhere...ToDo: fill in ref!) * * The 'threads' build has at any one time only one task executing STG * code, other tasks are either busy executing code outside the RTS - * (e.g., a ccall) or waiting for their turn to (again) evaluate some + * (e.g., a C call) or waiting for their turn to (again) evaluate some * STG code. A task relinquishes its RTS token when it is asked to * evaluate an external (C) call. * @@ -26,11 +27,24 @@ #include "Task.h" #include "Stats.h" #include "RtsFlags.h" +#include "Schedule.h" -static TaskInfo* taskTable; -static nat maxTasks; /* upper bound / the number of tasks created. */ -static nat taskCount; /* number of tasks currently created */ +/* There's not all that much code that is shared between the + * SMP and threads version of the 'task manager.' A sign + * that the code ought to be structured differently..(Maybe ToDo). + */ +/* + * The following Task Manager-local variables are assumed to be + * accessed with the RTS lock in hand. + */ +#if defined(SMP) +static TaskInfo* taskTable; +#endif +/* upper bound / the number of tasks created. */ +static nat maxTasks; +/* number of tasks currently created */ +static nat taskCount; #if defined(SMP) void @@ -58,20 +72,6 @@ startTaskManager( nat maxCount, void (*taskStart)(void) ) initialized = 1; } } -#else -void -startTaskManager( nat maxCount, void (*taskStart)(void) ) -{ - /* In the threaded case, maxCount is used to limit the - the creation of worker tasks. Tasks are created lazily, i.e., - when the current task gives up the token on executing - STG code. - */ - maxTasks = maxCount; - taskCount = 0; -} - -#endif void startTask ( void (*taskStart)(void) ) @@ -84,24 +84,22 @@ startTask ( void (*taskStart)(void) ) barf("startTask: Can't create new task"); } -#if defined(SMP) taskTable[taskCount].id = tid; taskTable[taskCount].mut_time = 0.0; taskTable[taskCount].mut_etime = 0.0; taskTable[taskCount].gc_time = 0.0; taskTable[taskCount].gc_etime = 0.0; taskTable[taskCount].elapsedtimestart = stat_getElapsedTime(); -#endif IF_DEBUG(scheduler,fprintf(stderr,"scheduler: Started task: %ld\n",tid);); return; } -#if defined(SMP) void stopTaskManager () { nat i; + OSThreadId tid = osThreadId(); /* Don't want to use pthread_cancel, since we'd have to install * these silly exception handlers (pthread_cleanup_{push,pop}) around @@ -122,9 +120,12 @@ stopTaskManager () #endif /* Send 'em all a SIGHUP. That should shut 'em up. */ - await_death = maxCount; + await_death = maxCount - 1; for (i = 0; i < maxCount; i++) { - pthread_kill(taskTable[i].id,SIGTERM); + /* don't cancel the thread running this piece of code. */ + if ( taskTable[i].id != tid ) { + pthread_kill(taskTable[i].id,SIGTERM); + } } while (await_death > 0) { sched_yield(); @@ -132,19 +133,66 @@ stopTaskManager () return; } + #else +/************ THREADS version *****************/ + void -stopTaskManager () +startTaskManager( nat maxCount, + void (*taskStart)(void) STG_UNUSED ) +{ + /* In the threaded case, maxCount is used to limit the + the creation of worker tasks. Tasks are created lazily, i.e., + when the current task gives up the token on executing + STG code. + */ + maxTasks = maxCount; + taskCount = 0; +} + +void +startTask ( void (*taskStart)(void) ) { + int r; + OSThreadId tid; + + /* If more than one worker thread is known to be blocked waiting + on thread_ready_cond, don't create a new one. + */ + if ( rts_n_waiting_tasks > 0) { + IF_DEBUG(scheduler,fprintf(stderr, + "scheduler: startTask: %d tasks waiting, not creating new one.\n", + rts_n_waiting_tasks);); + // the task will run as soon as a capability is available, + // so there's no need to wake it. + return; + } + /* If the task limit has been reached, just return. */ + if (maxTasks > 0 && taskCount == maxTasks) { + IF_DEBUG(scheduler,fprintf(stderr,"scheduler: startTask: task limit (%d) reached, not creating new one.\n",maxTasks)); + return; + } + + + r = createOSThread(&tid,taskStart); + if (r != 0) { + barf("startTask: Can't create new task"); + } + taskCount++; + + IF_DEBUG(scheduler,fprintf(stderr,"scheduler: startTask: new task %ld (total_count: %d; waiting: %d)\n", tid, taskCount, rts_n_waiting_tasks);); + return; } -#endif -nat -getTaskCount () + + +void +stopTaskManager () { - return taskCount; + } +#endif #endif /* RTS_SUPPORTS_THREADS */