#include "PosixSource.h"
#include "Rts.h"
-#include "RtsUtils.h"
-#include "RtsFlags.h"
-#include "STM.h"
-#include "OSThreads.h"
+
#include "Capability.h"
#include "Schedule.h"
#include "Sparks.h"
#include "Trace.h"
-#include "GC.h"
+#include "sm/GC.h" // for gcWorkerThread()
+#include "STM.h"
+#include "RtsUtils.h"
// one global capability, this is the Capability for non-threaded
// builds, and for +RTS -N1
Capability MainCapability;
-nat n_capabilities;
+nat n_capabilities = 0;
Capability *capabilities = NULL;
// Holds the Capability which last became free. This is used so that
// an in-call has a chance of quickly finding a free Capability.
// Maintaining a global free list of Capabilities would require global
// locking, so we don't do that.
-Capability *last_free_capability;
+Capability *last_free_capability = NULL;
/* GC indicator, in scope for the scheduler, init'ed to false */
volatile StgWord waiting_for_gc = 0;
+/* Let foreign code get the current Capability -- assuming there is one!
+ * This is useful for unsafe foreign calls because they are called with
+ * the current Capability held, but they are not passed it. For example,
+ * see see the integer-gmp package which calls allocateLocal() in its
+ * stgAllocForGMP() function (which gets called by gmp functions).
+ * */
+Capability * rts_unsafeGetMyCapability (void)
+{
+#if defined(THREADED_RTS)
+ return myTask()->cap;
+#else
+ return &MainCapability;
+#endif
+}
+
#if defined(THREADED_RTS)
STATIC_INLINE rtsBool
globalWorkToDo (void)
rtsBool retry;
nat i = 0;
- if (!emptyRunQueue(cap)) {
+ if (!emptyRunQueue(cap) || cap->returning_tasks_hd != NULL) {
// If there are other threads, don't try to run any new
// sparks: sparks might be speculative, we don't want to take
// resources away from the main computation.
return 0;
}
- // first try to get a spark from our own pool.
- // We should be using reclaimSpark(), because it works without
- // needing any atomic instructions:
- // spark = reclaimSpark(cap->sparks);
- // However, measurements show that this makes at least one benchmark
- // slower (prsa) and doesn't affect the others.
- spark = tryStealSpark(cap);
- if (spark != NULL) {
- cap->sparks_converted++;
+ do {
+ retry = rtsFalse;
- // Post event for running a spark from capability's own pool.
- postEvent(cap, EVENT_RUN_SPARK, cap->r.rCurrentTSO->id, 0);
+ // first try to get a spark from our own pool.
+ // We should be using reclaimSpark(), because it works without
+ // needing any atomic instructions:
+ // spark = reclaimSpark(cap->sparks);
+ // However, measurements show that this makes at least one benchmark
+ // slower (prsa) and doesn't affect the others.
+ spark = tryStealSpark(cap);
+ if (spark != NULL) {
+ cap->sparks_converted++;
- return spark;
- }
+ // Post event for running a spark from capability's own pool.
+ traceEventRunSpark(cap, cap->r.rCurrentTSO);
- if (n_capabilities == 1) { return NULL; } // makes no sense...
+ return spark;
+ }
+ if (!emptySparkPoolCap(cap)) {
+ retry = rtsTrue;
+ }
- debugTrace(DEBUG_sched,
- "cap %d: Trying to steal work from other capabilities",
- cap->no);
+ if (n_capabilities == 1) { return NULL; } // makes no sense...
- do {
- retry = rtsFalse;
+ debugTrace(DEBUG_sched,
+ "cap %d: Trying to steal work from other capabilities",
+ cap->no);
/* visit cap.s 0..n-1 in sequence until a theft succeeds. We could
start at a random place instead of 0 as well. */
}
if (spark != NULL) {
- debugTrace(DEBUG_sched,
- "cap %d: Stole a spark from capability %d",
- cap->no, robbed->no);
cap->sparks_converted++;
- postEvent(cap, EVENT_STEAL_SPARK,
- cap->r.rCurrentTSO->id, robbed->no);
-
+ traceEventStealSpark(cap, cap->r.rCurrentTSO, robbed->no);
return spark;
}
cap->no = i;
cap->in_haskell = rtsFalse;
- cap->in_gc = rtsFalse;
cap->run_queue_hd = END_TSO_QUEUE;
cap->run_queue_tl = END_TSO_QUEUE;
#endif
cap->f.stgEagerBlackholeInfo = (W_)&__stg_EAGER_BLACKHOLE_info;
- cap->f.stgGCEnter1 = (F_)__stg_gc_enter_1;
- cap->f.stgGCFun = (F_)__stg_gc_fun;
+ cap->f.stgGCEnter1 = (StgFunPtr)__stg_gc_enter_1;
+ cap->f.stgGCFun = (StgFunPtr)__stg_gc_fun;
cap->mut_lists = stgMallocBytes(sizeof(bdescr *) *
RtsFlags.GcFlags.generations,
cap->free_trec_headers = NO_TREC;
cap->transaction_tokens = 0;
cap->context_switch = 0;
+ cap->pinned_object_block = NULL;
}
/* ---------------------------------------------------------------------------
if (cap == NULL) {
// Try last_free_capability first
cap = last_free_capability;
- if (!cap->running_task) {
+ if (cap->running_task) {
nat i;
// otherwise, search for a free capability
cap = NULL;
Capability *cap = *pCap;
if (waiting_for_gc == PENDING_GC_PAR) {
- debugTrace(DEBUG_sched, "capability %d: becoming a GC thread", cap->no);
- postEvent(cap, EVENT_GC_START, 0, 0);
+ traceEventGcStart(cap);
gcWorkerThread(cap);
- postEvent(cap, EVENT_GC_END, 0, 0);
+ traceEventGcEnd(cap);
return;
}
continue;
}
- postEvent(cap, EVENT_SHUTDOWN, 0, 0);
- debugTrace(DEBUG_sched, "capability %d is stopped.", cap->no);
+ traceEventShutdown(cap);
RELEASE_LOCK(&cap->lock);
break;
}
freeCapability (Capability *cap)
{
stgFree(cap->mut_lists);
-#if defined(THREADED_RTS) || defined(PARALLEL_HASKELL)
+ stgFree(cap->saved_mut_lists);
+#if defined(THREADED_RTS)
freeSparkPool(cap->sparks);
#endif
}
#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);
}