*
* ---------------------------------------------------------------------------*/
-// #include "PosixSource.h"
+#include "PosixSource.h"
#include "Rts.h"
-#include "RtsFlags.h"
+#include "HsFFI.h"
+
+#include "Storage.h"
#include "RtsUtils.h"
#include "Apply.h"
-#include "OSThreads.h"
-#include "LdvProfile.h"
#include "Updates.h"
#include "Stats.h"
#include "Schedule.h"
#include "Sanity.h"
#include "BlockAlloc.h"
-#include "MBlock.h"
#include "ProfHeap.h"
-#include "SchedAPI.h"
#include "Weak.h"
#include "Prelude.h"
-#include "ParTicky.h" // ToDo: move into Rts.h
#include "RtsSignals.h"
#include "STM.h"
-#include "HsFFI.h"
-#include "Linker.h"
#if defined(RTS_GTK_FRONTPANEL)
#include "FrontPanel.h"
#endif
#include "Trace.h"
#include "RetainerProfile.h"
+#include "LdvProfile.h"
#include "RaiseAsync.h"
#include "Papi.h"
+#include "Stable.h"
#include "GC.h"
#include "GCThread.h"
static void resize_nursery (void);
static void start_gc_threads (void);
static void scavenge_until_all_done (void);
-static nat inc_running (void);
-static nat dec_running (void);
+static StgWord inc_running (void);
+static StgWord dec_running (void);
static void wakeup_gc_threads (nat n_threads, nat me);
static void shutdown_gc_threads (nat n_threads, nat me);
// tell the STM to discard any cached closures it's hoping to re-use
stmPreGCHook();
+ // lock the StablePtr table
+ stablePtrPreGC();
+
#ifdef DEBUG
mutlist_MUTVARS = 0;
mutlist_MUTARRS = 0;
n = initialise_N(force_major_gc);
#if defined(THREADED_RTS)
- work_stealing = RtsFlags.ParFlags.parGcLoadBalancing;
+ work_stealing = RtsFlags.ParFlags.parGcLoadBalancingEnabled &&
+ N >= RtsFlags.ParFlags.parGcLoadBalancingGen;
// It's not always a good idea to do load balancing in parallel
// GC. In particular, for a parallel program we don't want to
// lose locality by moving cached data into another CPU's cache
#ifdef DEBUG
// check for memory leaks if DEBUG is on
- memInventory(traceClass(DEBUG_gc));
+ memInventory(DEBUG_gc);
#endif
// check stack sanity *before* GC
#ifdef DEBUG
// check for memory leaks if DEBUG is on
- memInventory(traceClass(DEBUG_gc));
+ memInventory(DEBUG_gc);
#endif
#ifdef RTS_GTK_FRONTPANEL
slop = calcLiveBlocks() * BLOCK_SIZE_W - live;
stat_endGC(allocated, live, copied, N, max_copied, avg_copied, slop);
+ // unlock the StablePtr table
+ stablePtrPostGC();
+
// Guess which generation we'll collect *next* time
initialise_N(force_major_gc);
}
}
+void
+freeGcThreads (void)
+{
+ if (gc_threads != NULL) {
+#if defined(THREADED_RTS)
+ nat i;
+ for (i = 0; i < RtsFlags.ParFlags.nNodes; i++) {
+ stgFree (gc_threads[i]);
+ }
+ stgFree (gc_threads);
+#else
+ stgFree (gc_threads);
+#endif
+ gc_threads = NULL;
+ }
+}
+
/* ----------------------------------------------------------------------------
Start GC threads
------------------------------------------------------------------------- */
-static nat gc_running_threads;
+static volatile StgWord gc_running_threads;
-#if defined(THREADED_RTS)
-static Mutex gc_running_mutex;
-#endif
-
-static nat
+static StgWord
inc_running (void)
{
- nat n_running;
- ACQUIRE_LOCK(&gc_running_mutex);
- n_running = ++gc_running_threads;
- RELEASE_LOCK(&gc_running_mutex);
- ASSERT(n_running <= n_gc_threads);
- return n_running;
+ StgWord new;
+ new = atomic_inc(&gc_running_threads);
+ ASSERT(new <= n_gc_threads);
+ return new;
}
-static nat
+static StgWord
dec_running (void)
{
- nat n_running;
- ACQUIRE_LOCK(&gc_running_mutex);
- ASSERT(n_gc_threads != 0);
- n_running = --gc_running_threads;
- RELEASE_LOCK(&gc_running_mutex);
- return n_running;
+ ASSERT(gc_running_threads != 0);
+ return atomic_dec(&gc_running_threads);
}
static rtsBool
void
gcWorkerThread (Capability *cap)
{
+ gc_thread *saved_gct;
+
+ // necessary if we stole a callee-saves register for gct:
+ saved_gct = gct;
+
cap->in_gc = rtsTrue;
gct = gc_threads[cap->no];
gct->thread_index);
ACQUIRE_SPIN_LOCK(&gct->mut_spin);
debugTrace(DEBUG_gc, "GC thread %d on my way...", gct->thread_index);
+
+ SET_GCT(saved_gct);
}
#endif
+#if defined(THREADED_RTS)
+
void
waitForGcThreads (Capability *cap USED_IF_THREADS)
{
-#if defined(THREADED_RTS)
nat n_threads = RtsFlags.ParFlags.nNodes;
nat me = cap->no;
nat i, j;
if (!retry) break;
}
}
-#endif
}
+#endif // THREADED_RTS
+
static void
start_gc_threads (void)
{
#if defined(THREADED_RTS)
gc_running_threads = 0;
- initMutex(&gc_running_mutex);
#endif
}
#endif
}
+#if defined(THREADED_RTS)
void
releaseGCThreads (Capability *cap USED_IF_THREADS)
{
-#if defined(THREADED_RTS)
nat n_threads = RtsFlags.ParFlags.nNodes;
nat me = cap->no;
nat i;
ACQUIRE_SPIN_LOCK(&gc_threads[i]->gc_spin);
RELEASE_SPIN_LOCK(&gc_threads[i]->mut_spin);
}
-#endif
}
+#endif
/* ----------------------------------------------------------------------------
Initialise a generation that is to be collected
static void
resize_nursery (void)
{
+ lnat min_nursery = RtsFlags.GcFlags.minAllocAreaSize * n_capabilities;
+
if (RtsFlags.GcFlags.generations == 1)
{ // Two-space collector:
nat blocks;
else
{
blocks *= RtsFlags.GcFlags.oldGenFactor;
- if (blocks < RtsFlags.GcFlags.minAllocAreaSize)
+ if (blocks < min_nursery)
{
- blocks = RtsFlags.GcFlags.minAllocAreaSize;
+ blocks = min_nursery;
}
}
resizeNurseries(blocks);
(((long)RtsFlags.GcFlags.heapSizeSuggestion - (long)needed) * 100) /
(100 + (long)g0s0_pcnt_kept);
- if (blocks < (long)RtsFlags.GcFlags.minAllocAreaSize) {
- blocks = RtsFlags.GcFlags.minAllocAreaSize;
+ if (blocks < (long)min_nursery) {
+ blocks = min_nursery;
}
resizeNurseries((nat)blocks);