[project @ 2002-02-06 01:26:14 by sof]
authorsof <unknown>
Wed, 6 Feb 2002 01:26:14 +0000 (01:26 +0000)
committersof <unknown>
Wed, 6 Feb 2002 01:26:14 +0000 (01:26 +0000)
- 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).

ghc/rts/Task.c
ghc/rts/Task.h

index 80e5f69..19ae799 100644 (file)
  * '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.
  *
 #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 ()
 {
index a2d0ca7..5841f95 100644 (file)
@@ -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 );