X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2FCapability.c;h=444532480d1148e83b56a3ba784a3a0476893a29;hb=d0f4ec45fdae7aa9d37f178746fa17babc5d5134;hp=564a20f019cb1582b6c01e285bac7dbd475cd11c;hpb=e4fdc426413d178c86d3ba93702aad5eb17734bf;p=ghc-hetmet.git diff --git a/rts/Capability.c b/rts/Capability.c index 564a20f..4445324 100644 --- a/rts/Capability.c +++ b/rts/Capability.c @@ -639,7 +639,7 @@ prodOneCapability (void) * ------------------------------------------------------------------------- */ void -shutdownCapability (Capability *cap, Task *task) +shutdownCapability (Capability *cap, Task *task, rtsBool safe) { nat i; @@ -677,7 +677,7 @@ shutdownCapability (Capability *cap, Task *task) for (t = cap->spare_workers; t != NULL; t = t->next) { if (!osThreadIsAlive(t->id)) { debugTrace(DEBUG_sched, - "worker thread %p has died unexpectedly", t->id); + "worker thread %p has died unexpectedly", (void *)t->id); if (!prev) { cap->spare_workers = t->next; } else { @@ -696,8 +696,24 @@ shutdownCapability (Capability *cap, Task *task) yieldThread(); continue; } + + // If "safe", then busy-wait for any threads currently doing + // foreign calls. If we're about to unload this DLL, for + // example, we need to be sure that there are no OS threads + // that will try to return to code that has been unloaded. + // We can be a bit more relaxed when this is a standalone + // program that is about to terminate, and let safe=false. + if (cap->suspended_ccalling_tasks && safe) { + debugTrace(DEBUG_sched, + "thread(s) are involved in foreign calls, yielding"); + cap->running_task = NULL; + RELEASE_LOCK(&cap->lock); + yieldThread(); + continue; + } + debugTrace(DEBUG_sched, "capability %d is stopped.", cap->no); - freeCapability(cap); + freeCapability(cap); RELEASE_LOCK(&cap->lock); break; } @@ -743,3 +759,67 @@ freeCapability (Capability *cap) { #endif } +/* --------------------------------------------------------------------------- + Mark everything directly reachable from the Capabilities. When + using multiple GC threads, each GC thread marks all Capabilities + for which (c `mod` n == 0), for Capability c and thread n. + ------------------------------------------------------------------------ */ + +void +markSomeCapabilities (evac_fn evac, void *user, nat i0, nat delta) +{ + nat i; + Capability *cap; + Task *task; + + // Each GC thread is responsible for following roots from the + // Capability of the same number. There will usually be the same + // or fewer Capabilities as GC threads, but just in case there + // are more, we mark every Capability whose number is the GC + // thread's index plus a multiple of the number of GC threads. + for (i = i0; i < n_capabilities; i += delta) { + cap = &capabilities[i]; + evac(user, (StgClosure **)(void *)&cap->run_queue_hd); + evac(user, (StgClosure **)(void *)&cap->run_queue_tl); +#if defined(THREADED_RTS) + evac(user, (StgClosure **)(void *)&cap->wakeup_queue_hd); + evac(user, (StgClosure **)(void *)&cap->wakeup_queue_tl); +#endif + for (task = cap->suspended_ccalling_tasks; task != NULL; + task=task->next) { + debugTrace(DEBUG_sched, + "evac'ing suspended TSO %lu", (unsigned long)task->suspended_tso->id); + evac(user, (StgClosure **)(void *)&task->suspended_tso); + } + +#if defined(THREADED_RTS) + markSparkQueue (evac, user, cap); +#endif + } + +#if !defined(THREADED_RTS) + evac(user, (StgClosure **)(void *)&blocked_queue_hd); + evac(user, (StgClosure **)(void *)&blocked_queue_tl); + evac(user, (StgClosure **)(void *)&sleeping_queue); +#endif +} + +// This function is used by the compacting GC to thread all the +// pointers from spark queues. +void +traverseSparkQueues (evac_fn evac USED_IF_THREADS, void *user USED_IF_THREADS) +{ +#if defined(THREADED_RTS) + nat i; + for (i = 0; i < n_capabilities; i++) { + traverseSparkQueue (evac, user, &capabilities[i]); + } +#endif // THREADED_RTS + +} + +void +markCapabilities (evac_fn evac, void *user) +{ + markSomeCapabilities(evac, user, 0, 1); +}