From 4f0f4342c0268e239fd8bb6bd98ad2583b3485dd Mon Sep 17 00:00:00 2001 From: simonmar Date: Thu, 20 Oct 2005 11:45:19 +0000 Subject: [PATCH 1/1] [project @ 2005-10-20 11:45:19 by simonmar] 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 | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ ghc/rts/Task.c | 29 ---------------------------- 2 files changed, 53 insertions(+), 29 deletions(-) diff --git a/ghc/rts/Schedule.c b/ghc/rts/Schedule.c index cbbc21e..b78f9d2 100644 --- a/ghc/rts/Schedule.c +++ b/ghc/rts/Schedule.c @@ -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 } diff --git a/ghc/rts/Task.c b/ghc/rts/Task.c index 46cfa26..0d75df8 100644 --- a/ghc/rts/Task.c +++ b/ghc/rts/Task.c @@ -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 } -- 1.7.10.4