[project @ 2005-10-20 11:45:19 by simonmar]
authorsimonmar <unknown>
Thu, 20 Oct 2005 11:45:19 +0000 (11:45 +0000)
committersimonmar <unknown>
Thu, 20 Oct 2005 11:45:19 +0000 (11:45 +0000)
changes to exitScheduler(): instead of waiting for all the tasks to
stop, which is unreasonable, we just wait for the run queue to drain.
This is much quicker, but not ideal (see comments).

ghc/rts/Schedule.c
ghc/rts/Task.c

index cbbc21e..b78f9d2 100644 (file)
@@ -2697,9 +2697,62 @@ exitScheduler( void )
 {
     interrupted = rtsTrue;
     shutting_down_scheduler = rtsTrue;
+
 #if defined(RTS_SUPPORTS_THREADS)
     if (threadIsTask(osThreadId())) { taskStop(); }
     stopTaskManager();
+    //
+    // What can we do here?  There are a bunch of worker threads, it
+    // might be nice to let them exit cleanly.  There may be some main
+    // threads in the run queue; we should let them return to their
+    // callers with an Interrupted state.  We can't in general wait
+    // for all the running Tasks to stop, because some might be off in
+    // a C call that is blocked.
+    // 
+    // Letting the run queue drain is the safest thing.  That lets any
+    // main threads return that can return, and cleans up all the
+    // runnable threads.  Then we grab all the Capabilities to stop
+    // anything unexpected happening while we shut down.
+    //
+    // ToDo: this doesn't let us get the time stats from the worker
+    // tasks, because they haven't called taskStop().
+    //
+    ACQUIRE_LOCK(&sched_mutex);
+    { 
+       nat i;
+       for (i = 1000; i > 0; i--) {
+           if (EMPTY_RUN_QUEUE()) {
+               IF_DEBUG(scheduler, sched_belch("run queue is empty"));
+               break;
+           }
+           IF_DEBUG(scheduler, sched_belch("yielding"));
+           RELEASE_LOCK(&sched_mutex);
+           prodWorker();
+           yieldThread();
+           ACQUIRE_LOCK(&sched_mutex);
+       }
+    }
+
+#ifdef SMP
+    {
+       Capability *cap;
+       int n_capabilities = RtsFlags.ParFlags.nNodes; 
+       Capability *caps[n_capabilities];
+       nat i;
+
+       while (n_capabilities > 0) {
+           IF_DEBUG(scheduler, sched_belch("exitScheduler: grabbing all the capabilies (%d left)", n_capabilities));
+           waitForReturnCapability(&sched_mutex, &cap);
+           n_capabilities--;
+           caps[n_capabilities] = cap;
+       }
+    }
+#else
+    {
+       Capability *cap;
+       waitForReturnCapability(&sched_mutex, &cap);
+    }
+#endif
 #endif
 }
 
index 46cfa26..0d75df8 100644 (file)
@@ -84,36 +84,7 @@ expandTaskTable (void)
 void
 stopTaskManager (void)
 {
-    nat i;
-
     IF_DEBUG(scheduler, sched_belch("stopping task manager, %d tasks still running", tasksRunning));
-    for (i = 1000; i > 0; i--) {
-       if (tasksRunning == 0) {
-           IF_DEBUG(scheduler, sched_belch("all tasks stopped"));
-           return;
-       }
-       IF_DEBUG(scheduler, sched_belch("yielding"));
-       prodWorker();
-       yieldThread();
-    }
-    IF_DEBUG(scheduler, sched_belch("%d tasks still running, exiting anyway", tasksRunning));
-
-    /* 
-       OLD CODE follows:
-    */
-#if old_code
-    /* Send 'em all a SIGHUP.  That should shut 'em up. */
-    awaitDeath = taskCount==0 ? 0 : taskCount-1;
-    for (i = 0; i < taskCount; i++) {
-       /* don't cancel the thread running this piece of code. */
-       if ( taskTable[i].id != tid ) {
-           pthread_kill(taskTable[i].id,SIGTERM);
-       }
-    }
-    while (awaitDeath > 0) {
-       sched_yield();
-    }
-#endif // old_code
 }