[project @ 2003-12-16 13:19:01 by simonmar]
[ghc-hetmet.git] / ghc / rts / Task.c
index 80e5f69..6579abc 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 "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,79 @@ stopTaskManager ()
   
   return;
 }
+
+void
+resetTaskManagerAfterFork ()
+{
+       barf("resetTaskManagerAfterFork not implemented for SMP");
+}
+
 #else
+/************ THREADS version *****************/
+
+void
+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;
+}
+
+
+
 void
 stopTaskManager ()
 {
 
 }
-#endif
 
-nat
-getTaskCount ()
+void
+resetTaskManagerAfterFork ( void )
 {
-  return taskCount;
+       rts_n_waiting_tasks = 0;
+       taskCount = 0;
 }
+#endif
 
 
 #endif /* RTS_SUPPORTS_THREADS */