X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FCapability.c;h=203ca9f301a519a7a404fb583a397a3d7a601a7f;hb=0dbbf1932d550293986af6244202cb735b2cd966;hp=764357c56d41cadd40aa6ea86d522a627f2348c6;hpb=7a605453ea27e948ff931b8b016fc7c46c2c8270;p=ghc-hetmet.git diff --git a/ghc/rts/Capability.c b/ghc/rts/Capability.c index 764357c..203ca9f 100644 --- a/ghc/rts/Capability.c +++ b/ghc/rts/Capability.c @@ -10,9 +10,9 @@ * STG execution, a pointer to the capabilitity is kept in a * register (BaseReg; actually it is a pointer to cap->r). * - * Only in an SMP build will there be multiple capabilities, for - * the threaded RTS and other non-threaded builds, there is only - * one global capability, namely MainCapability. + * Only in an THREADED_RTS build will there be multiple capabilities, + * for non-threaded builds there is only one global capability, namely + * MainCapability. * * --------------------------------------------------------------------------*/ @@ -26,9 +26,9 @@ #include "Schedule.h" #include "Sparks.h" -#if !defined(SMP) -Capability MainCapability; // for non-SMP, we have one global capability -#endif +// one global capability, this is the Capability for non-threaded +// builds, and for +RTS -N1 +Capability MainCapability; nat n_capabilities; Capability *capabilities = NULL; @@ -53,19 +53,23 @@ globalWorkToDo (void) STATIC_INLINE rtsBool anyWorkForMe( Capability *cap, Task *task ) { - // If the run queue is not empty, then we only wake up the guy who - // can run the thread at the head, even if there is some other - // reason for this task to run (eg. interrupted=rtsTrue). - if (!emptyRunQueue(cap)) { - if (cap->run_queue_hd->bound == NULL) { - return (task->tso == NULL); - } else { - return (cap->run_queue_hd->bound == task); - } - } else if (task->tso == NULL && !emptySparkPoolCap(cap)) { - return rtsTrue; + if (task->tso != NULL) { + // A bound task only runs if its thread is on the run queue of + // the capability on which it was woken up. Otherwise, we + // can't be sure that we have the right capability: the thread + // might be woken up on some other capability, and task->cap + // could change under our feet. + return (!emptyRunQueue(cap) && cap->run_queue_hd->bound == task); + } else { + // A vanilla worker task runs if either (a) there is a + // lightweight thread at the head of the run queue, or (b) + // there are sparks to execute, or (c) there is some other + // global condition to check, such as threads blocked on + // blackholes. + return ((!emptyRunQueue(cap) && cap->run_queue_hd->bound == NULL) + || !emptySparkPoolCap(cap) + || globalWorkToDo()); } - return globalWorkToDo(); } #endif @@ -152,7 +156,7 @@ initCapability( Capability *cap, nat i ) /* --------------------------------------------------------------------------- * Function: initCapabilities() * - * Purpose: set up the Capability handling. For the SMP build, + * Purpose: set up the Capability handling. For the THREADED_RTS build, * we keep a table of them, the size of which is * controlled by the user via the RTS flag -N. * @@ -160,10 +164,10 @@ initCapability( Capability *cap, nat i ) void initCapabilities( void ) { -#if defined(SMP) - nat i,n; +#if defined(THREADED_RTS) + nat i; -#ifndef REG_BaseReg +#ifndef REG_Base // We can't support multiple CPUs if BaseReg is not a register if (RtsFlags.ParFlags.nNodes > 1) { errorBelch("warning: multiple CPUs not supported in this build, reverting to 1"); @@ -171,18 +175,31 @@ initCapabilities( void ) } #endif - n_capabilities = n = RtsFlags.ParFlags.nNodes; - capabilities = stgMallocBytes(n * sizeof(Capability), "initCapabilities"); + n_capabilities = RtsFlags.ParFlags.nNodes; + + if (n_capabilities == 1) { + capabilities = &MainCapability; + // THREADED_RTS must work on builds that don't have a mutable + // BaseReg (eg. unregisterised), so in this case + // capabilities[0] must coincide with &MainCapability. + } else { + capabilities = stgMallocBytes(n_capabilities * sizeof(Capability), + "initCapabilities"); + } - for (i = 0; i < n; i++) { + for (i = 0; i < n_capabilities; i++) { initCapability(&capabilities[i], i); } - IF_DEBUG(scheduler, sched_belch("allocated %d capabilities", n)); -#else + IF_DEBUG(scheduler, sched_belch("allocated %d capabilities", + n_capabilities)); + +#else /* !THREADED_RTS */ + n_capabilities = 1; capabilities = &MainCapability; initCapability(&MainCapability, 0); + #endif // There are no free capabilities to begin with. We will start @@ -263,15 +280,7 @@ releaseCapability_ (Capability* cap) return; } - // If we have an unbound thread on the run queue, or if there's - // anything else to do, give the Capability to a worker thread. - if (!emptyRunQueue(cap) || !emptySparkPoolCap(cap) || globalWorkToDo()) { - if (cap->spare_workers) { - giveCapabilityToTask(cap,cap->spare_workers); - // The worker Task pops itself from the queue; - return; - } - + if (!cap->spare_workers) { // Create a worker thread if we don't have one. If the system // is interrupted, we only create a worker task if there // are threads that need to be completed. If the system is @@ -284,6 +293,16 @@ releaseCapability_ (Capability* cap) } } + // If we have an unbound thread on the run queue, or if there's + // anything else to do, give the Capability to a worker thread. + if (!emptyRunQueue(cap) || !emptySparkPoolCap(cap) || globalWorkToDo()) { + if (cap->spare_workers) { + giveCapabilityToTask(cap,cap->spare_workers); + // The worker Task pops itself from the queue; + return; + } + } + last_free_capability = cap; IF_DEBUG(scheduler, sched_belch("freeing capability %d", cap->no)); } @@ -512,6 +531,7 @@ prodCapabilities(rtsBool all) } RELEASE_LOCK(&cap->lock); } + return; } void