From: sof Date: Wed, 6 Feb 2002 01:26:14 +0000 (+0000) Subject: [project @ 2002-02-06 01:26:14 by sof] X-Git-Tag: Approximately_9120_patches~142 X-Git-Url: http://git.megacz.com/?a=commitdiff_plain;h=80c55dc792abc20e8f316f5f4f90009322be8e34;p=ghc-hetmet.git [project @ 2002-02-06 01:26:14 by sof] - in the threaded case, keep track of the number of tasks/threads that are currently waiting to enter the RTS. - taskStart(): + only start up a new thread/task if there aren't any already waiting to gain RTS access. + honour thread/task limits (if any). --- diff --git a/ghc/rts/Task.c b/ghc/rts/Task.c index 80e5f69..19ae799 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. * @@ -27,9 +28,23 @@ #include "Stats.h" #include "RtsFlags.h" +/* 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; -static nat maxTasks; /* upper bound / the number of tasks created. */ -static nat taskCount; /* number of tasks currently created */ +#endif +/* upper bound / the number of tasks created. */ +static nat maxTasks; +/* number of tasks currently created */ +static nat taskCount; +static nat tasksAvailable; #if defined(SMP) @@ -58,20 +73,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,20 +85,17 @@ 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 () { @@ -132,7 +130,100 @@ stopTaskManager () return; } + #else +/************ THREADS version *****************/ + +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; + tasksAvailable = 0; +} + +void +startTask ( void (*taskStart)(void) ) +{ + int r; + OSThreadId tid; + + /* Locks assumed: rts_mutex */ + + /* If there are threads known to be waiting to do + useful work, no need to create a new task. */ + if (tasksAvailable > 0) { + IF_DEBUG(scheduler,fprintf(stderr,"scheduler: startTask: %d tasks available, not creating new one.\n",tasksAvailable);); + 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++; + tasksAvailable++; + + IF_DEBUG(scheduler,fprintf(stderr,"scheduler: Started task (%d): %ld\n", taskCount, tid);); + return; +} + +/* + * When the RTS thread ends up performing a call-out, + * we need to know whether there'll be other tasks/threads + * to take over RTS responsibilities. The 'tasksAvailable' + * variable holds the number of threads that are _blocked + * waiting to enter the RTS_ (or soon will be). Equipped + * with that count, startTask() is able to make an informed + * decision on whether or not to create a new thread. + * + * Two functions control increments / decrements of + * 'tasksAvailable': + * + * - taskNotAvailable() : called whenever a task/thread + * has acquired the RTS lock, i.e., always called by + * a thread that holds the rts_mutex lock. + * + * - taskAvailable(): called whenever a task/thread + * is about to try to grab the RTS lock. The task manager + * and scheduler will only call this whenever it is + * in possession of the rts_mutex lock, i.e., + * - when a new task is created in startTask(). + * - when the scheduler gives up the RTS token to + * let threads waiting to return from an external + * call continue. + * + */ +void +taskNotAvailable() +{ + if (tasksAvailable > 0) { + tasksAvailable--; + } + return; +} + +void +taskAvailable() +{ + tasksAvailable++; + return; +} + + + void stopTaskManager () { @@ -140,6 +231,7 @@ stopTaskManager () } #endif + nat getTaskCount () { diff --git a/ghc/rts/Task.h b/ghc/rts/Task.h index a2d0ca7..5841f95 100644 --- a/ghc/rts/Task.h +++ b/ghc/rts/Task.h @@ -29,6 +29,11 @@ extern TaskInfo *taskIds; extern void startTaskManager ( nat maxTasks, void (*taskStart)(void) ); extern void stopTaskManager ( void ); +#if defined(THREADED_RTS) +extern void taskNotAvailable ( void ); +extern void taskAvailable ( void ); +#endif + extern void startTask ( void (*taskStart)(void) ); extern nat getTaskCount( void );