Commit 1fb38442 authored by Simon Marlow's avatar Simon Marlow

Refactoring and tidy up

This is a port of some of the changes from my private local-GC branch
(which is still in darcs, I haven't converted it to git yet).  There
are a couple of small functional differences in the GC stats: first,
per-thread GC timings should now be more accurate, and secondly we now
report average and maximum pause times. e.g. from minimax +RTS -N8 -s:

                                    Tot time (elapsed)  Avg pause  Max pause
  Gen  0      2755 colls,  2754 par   13.16s    0.93s     0.0003s    0.0150s
  Gen  1       769 colls,   769 par    3.71s    0.26s     0.0003s    0.0059s
parent 7bf5bf37
...@@ -842,11 +842,9 @@ freeCapabilities (void) ...@@ -842,11 +842,9 @@ freeCapabilities (void)
------------------------------------------------------------------------ */ ------------------------------------------------------------------------ */
void void
markSomeCapabilities (evac_fn evac, void *user, nat i0, nat delta, markCapability (evac_fn evac, void *user, Capability *cap,
rtsBool no_mark_sparks USED_IF_THREADS) rtsBool no_mark_sparks USED_IF_THREADS)
{ {
nat i;
Capability *cap;
InCall *incall; InCall *incall;
// Each GC thread is responsible for following roots from the // Each GC thread is responsible for following roots from the
...@@ -854,39 +852,31 @@ markSomeCapabilities (evac_fn evac, void *user, nat i0, nat delta, ...@@ -854,39 +852,31 @@ markSomeCapabilities (evac_fn evac, void *user, nat i0, nat delta,
// or fewer Capabilities as GC threads, but just in case there // or fewer Capabilities as GC threads, but just in case there
// are more, we mark every Capability whose number is the GC // are more, we mark every Capability whose number is the GC
// thread's index plus a multiple of the number of GC threads. // thread's index plus a multiple of the number of GC threads.
for (i = i0; i < n_capabilities; i += delta) { evac(user, (StgClosure **)(void *)&cap->run_queue_hd);
cap = &capabilities[i]; evac(user, (StgClosure **)(void *)&cap->run_queue_tl);
evac(user, (StgClosure **)(void *)&cap->run_queue_hd);
evac(user, (StgClosure **)(void *)&cap->run_queue_tl);
#if defined(THREADED_RTS) #if defined(THREADED_RTS)
evac(user, (StgClosure **)(void *)&cap->inbox); evac(user, (StgClosure **)(void *)&cap->inbox);
#endif #endif
for (incall = cap->suspended_ccalls; incall != NULL; for (incall = cap->suspended_ccalls; incall != NULL;
incall=incall->next) { incall=incall->next) {
evac(user, (StgClosure **)(void *)&incall->suspended_tso); evac(user, (StgClosure **)(void *)&incall->suspended_tso);
} }
#if defined(THREADED_RTS) #if defined(THREADED_RTS)
if (!no_mark_sparks) { if (!no_mark_sparks) {
traverseSparkQueue (evac, user, cap); traverseSparkQueue (evac, user, cap);
}
#endif
} }
#endif
#if !defined(THREADED_RTS) // Free STM structures for this Capability
evac(user, (StgClosure **)(void *)&blocked_queue_hd); stmPreGCHook(cap);
evac(user, (StgClosure **)(void *)&blocked_queue_tl);
evac(user, (StgClosure **)(void *)&sleeping_queue);
#endif
} }
void void
markCapabilities (evac_fn evac, void *user) markCapabilities (evac_fn evac, void *user)
{ {
markSomeCapabilities(evac, user, 0, 1, rtsFalse); nat n;
for (n = 0; n < n_capabilities; n++) {
markCapability(evac, user, &capabilities[n], rtsFalse);
}
} }
/* -----------------------------------------------------------------------------
Messages
-------------------------------------------------------------------------- */
...@@ -278,9 +278,11 @@ INLINE_HEADER void contextSwitchCapability(Capability *cap); ...@@ -278,9 +278,11 @@ INLINE_HEADER void contextSwitchCapability(Capability *cap);
void freeCapabilities (void); void freeCapabilities (void);
// For the GC: // For the GC:
void markSomeCapabilities (evac_fn evac, void *user, nat i0, nat delta, void markCapability (evac_fn evac, void *user, Capability *cap,
rtsBool no_mark_sparks); rtsBool no_mark_sparks USED_IF_THREADS);
void markCapabilities (evac_fn evac, void *user); void markCapabilities (evac_fn evac, void *user);
void traverseSparkQueues (evac_fn evac, void *user); void traverseSparkQueues (evac_fn evac, void *user);
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
......
...@@ -879,17 +879,12 @@ static StgBool check_read_only(StgTRecHeader *trec STG_UNUSED) { ...@@ -879,17 +879,12 @@ static StgBool check_read_only(StgTRecHeader *trec STG_UNUSED) {
/************************************************************************/ /************************************************************************/
void stmPreGCHook() { void stmPreGCHook (Capability *cap) {
nat i;
lock_stm(NO_TREC); lock_stm(NO_TREC);
TRACE("stmPreGCHook"); TRACE("stmPreGCHook");
for (i = 0; i < n_capabilities; i ++) { cap->free_tvar_watch_queues = END_STM_WATCH_QUEUE;
Capability *cap = &capabilities[i]; cap->free_trec_chunks = END_STM_CHUNK_LIST;
cap -> free_tvar_watch_queues = END_STM_WATCH_QUEUE; cap->free_trec_headers = NO_TREC;
cap -> free_trec_chunks = END_STM_CHUNK_LIST;
cap -> free_trec_headers = NO_TREC;
}
unlock_stm(NO_TREC); unlock_stm(NO_TREC);
} }
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
-------------- --------------
*/ */
void stmPreGCHook(void); void stmPreGCHook(Capability *cap);
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
......
...@@ -2069,6 +2069,16 @@ freeScheduler( void ) ...@@ -2069,6 +2069,16 @@ freeScheduler( void )
#endif #endif
} }
void markScheduler (evac_fn evac USED_IF_NOT_THREADS,
void *user USED_IF_NOT_THREADS)
{
#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
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
performGC performGC
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
void initScheduler (void); void initScheduler (void);
void exitScheduler (rtsBool wait_foreign); void exitScheduler (rtsBool wait_foreign);
void freeScheduler (void); void freeScheduler (void);
void markScheduler (evac_fn evac, void *user);
// Place a new thread on the run queue of the current Capability // Place a new thread on the run queue of the current Capability
void scheduleThread (Capability *cap, StgTSO *tso); void scheduleThread (Capability *cap, StgTSO *tso);
......
This diff is collapsed.
...@@ -13,13 +13,18 @@ ...@@ -13,13 +13,18 @@
#include "BeginPrivate.h" #include "BeginPrivate.h"
struct gc_thread_;
void stat_startInit(void); void stat_startInit(void);
void stat_endInit(void); void stat_endInit(void);
void stat_startGC(void); void stat_startGC(struct gc_thread_ *gct);
void stat_endGC (lnat alloc, lnat live, void stat_endGC (struct gc_thread_ *gct, lnat alloc, lnat live,
lnat copied, lnat gen, lnat copied, nat gen,
lnat max_copied, lnat avg_copied, lnat slop); lnat max_copied, lnat avg_copied, lnat slop);
void stat_gcWorkerThreadStart (struct gc_thread_ *gct);
void stat_gcWorkerThreadDone (struct gc_thread_ *gct);
#ifdef PROFILING #ifdef PROFILING
void stat_startRP(void); void stat_startRP(void);
......
...@@ -318,25 +318,30 @@ void ...@@ -318,25 +318,30 @@ void
taskTimeStamp (Task *task USED_IF_THREADS) taskTimeStamp (Task *task USED_IF_THREADS)
{ {
#if defined(THREADED_RTS) #if defined(THREADED_RTS)
Ticks currentElapsedTime, currentUserTime, elapsedGCTime; Ticks currentElapsedTime, currentUserTime;
currentUserTime = getThreadCPUTime(); currentUserTime = getThreadCPUTime();
currentElapsedTime = getProcessElapsedTime(); currentElapsedTime = getProcessElapsedTime();
// XXX this is wrong; we want elapsed GC time since the task->mut_time =
// Task started.
elapsedGCTime = stat_getElapsedGCTime();
task->mut_time =
currentUserTime - task->muttimestart - task->gc_time; currentUserTime - task->muttimestart - task->gc_time;
task->mut_etime = task->mut_etime =
currentElapsedTime - task->elapsedtimestart - elapsedGCTime; currentElapsedTime - task->elapsedtimestart - task->gc_etime;
if (task->gc_time < 0) { task->gc_time = 0; }
if (task->gc_etime < 0) { task->gc_etime = 0; }
if (task->mut_time < 0) { task->mut_time = 0; } if (task->mut_time < 0) { task->mut_time = 0; }
if (task->mut_etime < 0) { task->mut_etime = 0; } if (task->mut_etime < 0) { task->mut_etime = 0; }
#endif #endif
} }
void
taskDoneGC (Task *task, Ticks cpu_time, Ticks elapsed_time)
{
task->gc_time += cpu_time;
task->gc_etime += elapsed_time;
}
#if defined(THREADED_RTS) #if defined(THREADED_RTS)
void void
......
...@@ -207,6 +207,9 @@ void workerTaskStop (Task *task); ...@@ -207,6 +207,9 @@ void workerTaskStop (Task *task);
// //
void taskTimeStamp (Task *task); void taskTimeStamp (Task *task);
// The current Task has finished a GC, record the amount of time spent.
void taskDoneGC (Task *task, Ticks cpu_time, Ticks elapsed_time);
// Put the task back on the free list, mark it stopped. Used by // Put the task back on the free list, mark it stopped. Used by
// forkProcess(). // forkProcess().
// //
......
...@@ -942,6 +942,8 @@ compact(StgClosure *static_objects) ...@@ -942,6 +942,8 @@ compact(StgClosure *static_objects)
// 1. thread the roots // 1. thread the roots
markCapabilities((evac_fn)thread_root, NULL); markCapabilities((evac_fn)thread_root, NULL);
markScheduler((evac_fn)thread_root, NULL);
// the weak pointer lists... // the weak pointer lists...
if (weak_ptr_list != NULL) { if (weak_ptr_list != NULL) {
thread((void *)&weak_ptr_list); thread((void *)&weak_ptr_list);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "Storage.h" #include "Storage.h"
#include "GC.h" #include "GC.h"
#include "GCThread.h" #include "GCThread.h"
#include "GCTDecl.h"
#include "GCUtils.h" #include "GCUtils.h"
#include "Compact.h" #include "Compact.h"
#include "MarkStack.h" #include "MarkStack.h"
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "GC.h" #include "GC.h"
#include "GCThread.h" #include "GCThread.h"
#include "GCTDecl.h"
#include "Compact.h" #include "Compact.h"
#include "Evac.h" #include "Evac.h"
#include "Scav.h" #include "Scav.h"
...@@ -146,8 +147,8 @@ static void start_gc_threads (void); ...@@ -146,8 +147,8 @@ static void start_gc_threads (void);
static void scavenge_until_all_done (void); static void scavenge_until_all_done (void);
static StgWord inc_running (void); static StgWord inc_running (void);
static StgWord dec_running (void); static StgWord dec_running (void);
static void wakeup_gc_threads (nat n_threads, nat me); static void wakeup_gc_threads (nat me);
static void shutdown_gc_threads (nat n_threads, nat me); static void shutdown_gc_threads (nat me);
static void collect_gct_blocks (void); static void collect_gct_blocks (void);
#if 0 && defined(DEBUG) #if 0 && defined(DEBUG)
...@@ -177,7 +178,7 @@ GarbageCollect (rtsBool force_major_gc, ...@@ -177,7 +178,7 @@ GarbageCollect (rtsBool force_major_gc,
generation *gen; generation *gen;
lnat live_blocks, live_words, allocated, max_copied, avg_copied; lnat live_blocks, live_words, allocated, max_copied, avg_copied;
gc_thread *saved_gct; gc_thread *saved_gct;
nat g, t, n; nat g, n;
// necessary if we stole a callee-saves register for gct: // necessary if we stole a callee-saves register for gct:
saved_gct = gct; saved_gct = gct;
...@@ -198,11 +199,11 @@ GarbageCollect (rtsBool force_major_gc, ...@@ -198,11 +199,11 @@ GarbageCollect (rtsBool force_major_gc,
ASSERT(sizeof(gen_workspace) == 16 * sizeof(StgWord)); ASSERT(sizeof(gen_workspace) == 16 * sizeof(StgWord));
// otherwise adjust the padding in gen_workspace. // otherwise adjust the padding in gen_workspace.
// tell the stats department that we've started a GC // this is the main thread
stat_startGC(); SET_GCT(gc_threads[cap->no]);
// tell the STM to discard any cached closures it's hoping to re-use // tell the stats department that we've started a GC
stmPreGCHook(); stat_startGC(gct);
// lock the StablePtr table // lock the StablePtr table
stablePtrPreGC(); stablePtrPreGC();
...@@ -277,11 +278,6 @@ GarbageCollect (rtsBool force_major_gc, ...@@ -277,11 +278,6 @@ GarbageCollect (rtsBool force_major_gc,
// check sanity *before* GC // check sanity *before* GC
IF_DEBUG(sanity, checkSanity(rtsFalse /* before GC */, major_gc)); IF_DEBUG(sanity, checkSanity(rtsFalse /* before GC */, major_gc));
// Initialise all our gc_thread structures
for (t = 0; t < n_gc_threads; t++) {
init_gc_thread(gc_threads[t]);
}
// Initialise all the generations/steps that we're collecting. // Initialise all the generations/steps that we're collecting.
for (g = 0; g <= N; g++) { for (g = 0; g <= N; g++) {
prepare_collected_gen(&generations[g]); prepare_collected_gen(&generations[g]);
...@@ -291,6 +287,9 @@ GarbageCollect (rtsBool force_major_gc, ...@@ -291,6 +287,9 @@ GarbageCollect (rtsBool force_major_gc,
prepare_uncollected_gen(&generations[g]); prepare_uncollected_gen(&generations[g]);
} }
// Prepare this gc_thread
init_gc_thread(gct);
/* Allocate a mark stack if we're doing a major collection. /* Allocate a mark stack if we're doing a major collection.
*/ */
if (major_gc && oldest_gen->mark) { if (major_gc && oldest_gen->mark) {
...@@ -305,17 +304,6 @@ GarbageCollect (rtsBool force_major_gc, ...@@ -305,17 +304,6 @@ GarbageCollect (rtsBool force_major_gc,
mark_sp = NULL; mark_sp = NULL;
} }
// this is the main thread
#ifdef THREADED_RTS
if (n_gc_threads == 1) {
SET_GCT(gc_threads[0]);
} else {
SET_GCT(gc_threads[cap->no]);
}
#else
SET_GCT(gc_threads[0]);
#endif
/* ----------------------------------------------------------------------- /* -----------------------------------------------------------------------
* follow all the roots that we know about: * follow all the roots that we know about:
*/ */
...@@ -325,7 +313,9 @@ SET_GCT(gc_threads[0]); ...@@ -325,7 +313,9 @@ SET_GCT(gc_threads[0]);
// NB. do this after the mutable lists have been saved above, otherwise // NB. do this after the mutable lists have been saved above, otherwise
// the other GC threads will be writing into the old mutable lists. // the other GC threads will be writing into the old mutable lists.
inc_running(); inc_running();
wakeup_gc_threads(n_gc_threads, gct->thread_index); wakeup_gc_threads(gct->thread_index);
traceEventGcWork(gct->cap);
// scavenge the capability-private mutable lists. This isn't part // scavenge the capability-private mutable lists. This isn't part
// of markSomeCapabilities() because markSomeCapabilities() can only // of markSomeCapabilities() because markSomeCapabilities() can only
...@@ -340,7 +330,7 @@ SET_GCT(gc_threads[0]); ...@@ -340,7 +330,7 @@ SET_GCT(gc_threads[0]);
#endif #endif
} }
} else { } else {
scavenge_capability_mut_lists(&capabilities[gct->thread_index]); scavenge_capability_mut_lists(gct->cap);
} }
// follow roots from the CAF list (used by GHCi) // follow roots from the CAF list (used by GHCi)
...@@ -349,8 +339,16 @@ SET_GCT(gc_threads[0]); ...@@ -349,8 +339,16 @@ SET_GCT(gc_threads[0]);
// follow all the roots that the application knows about. // follow all the roots that the application knows about.
gct->evac_gen_no = 0; gct->evac_gen_no = 0;
markSomeCapabilities(mark_root, gct, gct->thread_index, n_gc_threads, if (n_gc_threads == 1) {
rtsTrue/*prune sparks*/); for (n = 0; n < n_capabilities; n++) {
markCapability(mark_root, gct, &capabilities[n],
rtsTrue/*don't mark sparks*/);
}
} else {
markCapability(mark_root, gct, cap, rtsTrue/*don't mark sparks*/);
}
markScheduler(mark_root, gct);
#if defined(RTS_USER_SIGNALS) #if defined(RTS_USER_SIGNALS)
// mark the signal handlers (signals should be already blocked) // mark the signal handlers (signals should be already blocked)
...@@ -385,7 +383,7 @@ SET_GCT(gc_threads[0]); ...@@ -385,7 +383,7 @@ SET_GCT(gc_threads[0]);
break; break;
} }
shutdown_gc_threads(n_gc_threads, gct->thread_index); shutdown_gc_threads(gct->thread_index);
// Now see which stable names are still alive. // Now see which stable names are still alive.
gcStablePtrTable(); gcStablePtrTable();
...@@ -396,7 +394,7 @@ SET_GCT(gc_threads[0]); ...@@ -396,7 +394,7 @@ SET_GCT(gc_threads[0]);
pruneSparkQueue(&capabilities[n]); pruneSparkQueue(&capabilities[n]);
} }
} else { } else {
pruneSparkQueue(&capabilities[gct->thread_index]); pruneSparkQueue(gct->cap);
} }
#endif #endif
...@@ -713,7 +711,8 @@ SET_GCT(gc_threads[0]); ...@@ -713,7 +711,8 @@ SET_GCT(gc_threads[0]);
#endif #endif
// ok, GC over: tell the stats department what happened. // ok, GC over: tell the stats department what happened.
stat_endGC(allocated, live_words, copied, N, max_copied, avg_copied, stat_endGC(gct, allocated, live_words,
copied, N, max_copied, avg_copied,
live_blocks * BLOCK_SIZE_W - live_words /* slop */); live_blocks * BLOCK_SIZE_W - live_words /* slop */);
// Guess which generation we'll collect *next* time // Guess which generation we'll collect *next* time
...@@ -787,6 +786,8 @@ new_gc_thread (nat n, gc_thread *t) ...@@ -787,6 +786,8 @@ new_gc_thread (nat n, gc_thread *t)
nat g; nat g;
gen_workspace *ws; gen_workspace *ws;
t->cap = &capabilities[n];
#ifdef THREADED_RTS #ifdef THREADED_RTS
t->id = 0; t->id = 0;
initSpinLock(&t->gc_spin); initSpinLock(&t->gc_spin);
...@@ -970,8 +971,6 @@ scavenge_until_all_done (void) ...@@ -970,8 +971,6 @@ scavenge_until_all_done (void)
loop: loop:
traceEventGcWork(&capabilities[gct->thread_index]);
#if defined(THREADED_RTS) #if defined(THREADED_RTS)
if (n_gc_threads > 1) { if (n_gc_threads > 1) {
scavenge_loop(); scavenge_loop();
...@@ -987,7 +986,7 @@ loop: ...@@ -987,7 +986,7 @@ loop:
// scavenge_loop() only exits when there's no work to do // scavenge_loop() only exits when there's no work to do
r = dec_running(); r = dec_running();
traceEventGcIdle(&capabilities[gct->thread_index]); traceEventGcIdle(gct->cap);
debugTrace(DEBUG_gc, "%d GC threads still running", r); debugTrace(DEBUG_gc, "%d GC threads still running", r);
...@@ -995,6 +994,7 @@ loop: ...@@ -995,6 +994,7 @@ loop:
// usleep(1); // usleep(1);
if (any_work()) { if (any_work()) {
inc_running(); inc_running();
traceEventGcWork(gct->cap);
goto loop; goto loop;
} }
// any_work() does not remove the work from the queue, it // any_work() does not remove the work from the queue, it
...@@ -1003,7 +1003,7 @@ loop: ...@@ -1003,7 +1003,7 @@ loop:
// scavenge_loop() to perform any pending work. // scavenge_loop() to perform any pending work.
} }
traceEventGcDone(&capabilities[gct->thread_index]); traceEventGcDone(gct->cap);
} }
#if defined(THREADED_RTS) #if defined(THREADED_RTS)
...@@ -1019,6 +1019,8 @@ gcWorkerThread (Capability *cap) ...@@ -1019,6 +1019,8 @@ gcWorkerThread (Capability *cap)
gct = gc_threads[cap->no]; gct = gc_threads[cap->no];
gct->id = osThreadId(); gct->id = osThreadId();
stat_gcWorkerThreadStart(gct);
// Wait until we're told to wake up // Wait until we're told to wake up
RELEASE_SPIN_LOCK(&gct->mut_spin); RELEASE_SPIN_LOCK(&gct->mut_spin);
gct->wakeup = GC_THREAD_STANDING_BY; gct->wakeup = GC_THREAD_STANDING_BY;
...@@ -1032,12 +1034,15 @@ gcWorkerThread (Capability *cap) ...@@ -1032,12 +1034,15 @@ gcWorkerThread (Capability *cap)
} }
papi_thread_start_gc1_count(gct->papi_events); papi_thread_start_gc1_count(gct->papi_events);
#endif #endif
init_gc_thread(gct);
traceEventGcWork(gct->cap);
// Every thread evacuates some roots. // Every thread evacuates some roots.
gct->evac_gen_no = 0; gct->evac_gen_no = 0;
markSomeCapabilities(mark_root, gct, gct->thread_index, n_gc_threads, markCapability(mark_root, gct, cap, rtsTrue/*prune sparks*/);
rtsTrue/*prune sparks*/); scavenge_capability_mut_lists(cap);
scavenge_capability_mut_lists(&capabilities[gct->thread_index]);
scavenge_until_all_done(); scavenge_until_all_done();
...@@ -1064,6 +1069,9 @@ gcWorkerThread (Capability *cap) ...@@ -1064,6 +1069,9 @@ gcWorkerThread (Capability *cap)
ACQUIRE_SPIN_LOCK(&gct->mut_spin); ACQUIRE_SPIN_LOCK(&gct->mut_spin);
debugTrace(DEBUG_gc, "GC thread %d on my way...", gct->thread_index); debugTrace(DEBUG_gc, "GC thread %d on my way...", gct->thread_index);
// record the time spent doing GC in the Task structure
stat_gcWorkerThreadDone(gct);
SET_GCT(saved_gct); SET_GCT(saved_gct);
} }
...@@ -1113,11 +1121,14 @@ start_gc_threads (void) ...@@ -1113,11 +1121,14 @@ start_gc_threads (void)
} }
static void static void
wakeup_gc_threads (nat n_threads USED_IF_THREADS, nat me USED_IF_THREADS) wakeup_gc_threads (nat me USED_IF_THREADS)
{ {
#if defined(THREADED_RTS) #if defined(THREADED_RTS)
nat i; nat i;
for (i=0; i < n_threads; i++) {
if (n_gc_threads == 1) return;
for (i=0; i < n_gc_threads; i++) {
if (i == me) continue; if (i == me) continue;
inc_running(); inc_running();
debugTrace(DEBUG_gc, "waking up gc thread %d", i); debugTrace(DEBUG_gc, "waking up gc thread %d", i);
...@@ -1134,11 +1145,14 @@ wakeup_gc_threads (nat n_threads USED_IF_THREADS, nat me USED_IF_THREADS) ...@@ -1134,11 +1145,14 @@ wakeup_gc_threads (nat n_threads USED_IF_THREADS, nat me USED_IF_THREADS)
// standby state, otherwise they may still be executing inside // standby state, otherwise they may still be executing inside
// any_work(), and may even remain awake until the next GC starts. // any_work(), and may even remain awake until the next GC starts.
static void static void
shutdown_gc_threads (nat n_threads USED_IF_THREADS, nat me USED_IF_THREADS) shutdown_gc_threads (nat me USED_IF_THREADS)
{ {
#if defined(THREADED_RTS) #if defined(THREADED_RTS)
nat i; nat i;
for (i=0; i < n_threads; i++) {
if (n_gc_threads == 1) return;
for (i=0; i < n_gc_threads; i++) {
if (i == me) continue; if (i == me) continue;
while (gc_threads[i]->wakeup != GC_THREAD_WAITING_TO_CONTINUE) { write_barrier(); } while (gc_threads[i]->wakeup != GC_THREAD_WAITING_TO_CONTINUE) { write_barrier(); }
} }
...@@ -1373,7 +1387,7 @@ init_gc_thread (gc_thread *t) ...@@ -1373,7 +1387,7 @@ init_gc_thread (gc_thread *t)
t->static_objects = END_OF_STATIC_LIST; t->static_objects = END_OF_STATIC_LIST;
t->scavenged_static_objects = END_OF_STATIC_LIST; t->scavenged_static_objects = END_OF_STATIC_LIST;
t->scan_bd = NULL; t->scan_bd = NULL;
t->mut_lists = capabilities[t->thread_index].mut_lists; t->mut_lists = t->cap->mut_lists;
t->evac_gen_no = 0; t->evac_gen_no = 0;
t->failed_to_evac = rtsFalse; t->failed_to_evac = rtsFalse;
t->eager_promotion = rtsTrue; t->eager_promotion = rtsTrue;
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include "Capability.h" #include "Capability.h"
#include "Trace.h" #include "Trace.h"
#include "Schedule.h" #include "Schedule.h"
// DO NOT include "GCThread.h", we don't want the register variable // DO NOT include "GCTDecl.h", we don't want the register variable
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
isAlive determines whether the given closure is still alive (after isAlive determines whether the given closure is still alive (after
......
/* -----------------------------------------------------------------------------
*
* (c) The GHC Team 1998-2009
*
* Documentation on the architecture of the Garbage Collector can be
* found in the online commentary:
*
* http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Storage/GC
*
* ---------------------------------------------------------------------------*/
#ifndef SM_GCTDECL_H
#define SM_GCTDECL_H
#include "BeginPrivate.h"
/* -----------------------------------------------------------------------------
The gct variable is thread-local and points to the current thread's
gc_thread structure. It is heavily accessed, so we try to put gct
into a global register variable if possible; if we don't have a
register then use gcc's __thread extension to create a thread-local
variable.
-------------------------------------------------------------------------- */
#if defined(THREADED_RTS)
#define GLOBAL_REG_DECL(type,name,reg) register type name REG(reg);
#define SET_GCT(to) gct = (to)