Task *suspended_ccalling_tasks;
// One mutable list per generation, so we don't need to take any
- // locks when updating an old-generation thunk. These
- // mini-mut-lists are moved onto the respective gen->mut_list at
- // each GC.
+ // locks when updating an old-generation thunk. This also lets us
+ // keep track of which closures this CPU has been mutating, so we
+ // can traverse them using the right thread during GC and avoid
+ // unnecessarily moving the data from one cache to another.
bdescr **mut_lists;
+ bdescr **saved_mut_lists; // tmp use during GC
// Context switch flag. We used to have one global flag, now one
// per capability. Locks required : none (conflicts are harmless)
// Converts a *StgRegTable into a *Capability.
//
-#define OFFSET(s_type, field) ((size_t)&(((s_type*)0)->field))
-
INLINE_HEADER Capability *
regTableToCapability (StgRegTable *reg)
{
- return (Capability *)((void *)((unsigned char*)reg - OFFSET(Capability,r)));
+ return (Capability *)((void *)((unsigned char*)reg - STG_FIELD_OFFSET(Capability,r)));
}
// Initialise the available capabilities.
// cause all capabilities to context switch as soon as possible.
void setContextSwitches(void);
+INLINE_HEADER void contextSwitchCapability(Capability *cap);
// Free all capabilities
void freeCapabilities (void);
{ return discardSparks(cap->sparks); }
#endif
+INLINE_HEADER void
+contextSwitchCapability (Capability *cap)
+{
+ // setting HpLim to NULL ensures that the next heap check will
+ // fail, and the thread will return to the scheduler.
+ cap->r.rHpLim = NULL;
+ // But just in case it didn't work (the target thread might be
+ // modifying HpLim at the same time), we set the end-of-block
+ // context-switch flag too:
+ cap->context_switch = 1;
+}
+
#endif /* CAPABILITY_H */