diff options
Diffstat (limited to 'rts')
-rw-r--r-- | rts/Prelude.h | 1 | ||||
-rw-r--r-- | rts/RtsStartup.c | 1 | ||||
-rw-r--r-- | rts/Schedule.c | 40 | ||||
-rw-r--r-- | rts/Stable.c | 46 | ||||
-rw-r--r-- | rts/Updates.h | 4 | ||||
-rw-r--r-- | rts/ghc.mk | 11 | ||||
-rw-r--r-- | rts/sm/Evac.c | 17 | ||||
-rw-r--r-- | rts/sm/GCAux.c | 8 | ||||
-rw-r--r-- | rts/win32/ThrIOManager.c | 326 | ||||
-rw-r--r-- | rts/win32/libHSbase.def | 1 |
10 files changed, 240 insertions, 215 deletions
diff --git a/rts/Prelude.h b/rts/Prelude.h index dcd7b94da4..89e80a0a3d 100644 --- a/rts/Prelude.h +++ b/rts/Prelude.h @@ -93,6 +93,7 @@ PRELUDE_INFO(base_GHCziStable_StablePtr_con_info); #define runSparks_closure DLL_IMPORT_DATA_REF(base_GHCziConcziSync_runSparks_closure) #define ensureIOManagerIsRunning_closure DLL_IMPORT_DATA_REF(base_GHCziConcziIO_ensureIOManagerIsRunning_closure) +#define ioManagerCapabilitiesChanged_closure DLL_IMPORT_DATA_REF(base_GHCziConcziIO_ioManagerCapabilitiesChanged_closure) #define runHandlers_closure DLL_IMPORT_DATA_REF(base_GHCziConcziSignal_runHandlers_closure) #define flushStdHandles_closure DLL_IMPORT_DATA_REF(base_GHCziTopHandler_flushStdHandles_closure) diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c index e83d047695..7b7d488e2b 100644 --- a/rts/RtsStartup.c +++ b/rts/RtsStartup.c @@ -207,6 +207,7 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config) getStablePtr((StgPtr)runSparks_closure); getStablePtr((StgPtr)ensureIOManagerIsRunning_closure); + getStablePtr((StgPtr)ioManagerCapabilitiesChanged_closure); #ifndef mingw32_HOST_OS getStablePtr((StgPtr)runHandlers_closure); #endif diff --git a/rts/Schedule.c b/rts/Schedule.c index f39ef96273..abd317cc62 100644 --- a/rts/Schedule.c +++ b/rts/Schedule.c @@ -133,7 +133,7 @@ static void scheduleYield (Capability **pcap, Task *task); #if defined(THREADED_RTS) static nat requestSync (Capability **pcap, Task *task, nat sync_type); static void acquireAllCapabilities(Capability *cap, Task *task); -static void releaseAllCapabilities(Capability *cap, Task *task); +static void releaseAllCapabilities(nat n, Capability *cap, Task *task); static void startWorkerTasks (nat from USED_IF_THREADS, nat to USED_IF_THREADS); #endif static void scheduleStartSignalHandlers (Capability *cap); @@ -1411,11 +1411,11 @@ static void acquireAllCapabilities(Capability *cap, Task *task) task->cap = cap; } -static void releaseAllCapabilities(Capability *cap, Task *task) +static void releaseAllCapabilities(nat n, Capability *cap, Task *task) { nat i; - for (i = 0; i < n_capabilities; i++) { + for (i = 0; i < n; i++) { if (cap->no != i) { task->cap = &capabilities[i]; releaseCapability(&capabilities[i]); @@ -1437,7 +1437,6 @@ scheduleDoGC (Capability **pcap, Task *task USED_IF_THREADS, rtsBool heap_census; nat collect_gen; #ifdef THREADED_RTS - rtsBool idle_cap[n_capabilities]; rtsBool gc_type; nat i, sync; StgTSO *tso; @@ -1499,6 +1498,13 @@ scheduleDoGC (Capability **pcap, Task *task USED_IF_THREADS, } } while (sync); + // don't declare this until after we have sync'd, because + // n_capabilities may change. + rtsBool idle_cap[n_capabilities]; +#ifdef DEBUG + unsigned int old_n_capabilities = n_capabilities; +#endif + interruptAllCapabilities(); // The final shutdown GC is always single-threaded, because it's @@ -1686,6 +1692,10 @@ delete_threads_and_gc: } #if defined(THREADED_RTS) + + // If n_capabilities has changed during GC, we're in trouble. + ASSERT(n_capabilities == old_n_capabilities); + if (gc_type == SYNC_GC_PAR) { releaseGCThreads(cap); @@ -1732,7 +1742,7 @@ delete_threads_and_gc: #if defined(THREADED_RTS) if (gc_type == SYNC_GC_SEQ) { // release our stash of capabilities. - releaseAllCapabilities(cap, task); + releaseAllCapabilities(n_capabilities, cap, task); } #endif @@ -1957,6 +1967,7 @@ setNumCapabilities (nat new_n_capabilities USED_IF_THREADS) StgTSO* t; nat g, n; Capability *old_capabilities = NULL; + nat old_n_capabilities = n_capabilities; if (new_n_capabilities == enabled_capabilities) return; @@ -2050,17 +2061,17 @@ setNumCapabilities (nat new_n_capabilities USED_IF_THREADS) } } - // We're done: release the original Capabilities - releaseAllCapabilities(cap,task); - - // Start worker tasks on the new Capabilities - startWorkerTasks(n_capabilities, new_n_capabilities); - - // finally, update n_capabilities + // update n_capabilities before things start running if (new_n_capabilities > n_capabilities) { n_capabilities = enabled_capabilities = new_n_capabilities; } + // Start worker tasks on the new Capabilities + startWorkerTasks(old_n_capabilities, new_n_capabilities); + + // We're done: release the original Capabilities + releaseAllCapabilities(old_n_capabilities, cap,task); + // We can't free the old array until now, because we access it // while updating pointers in updateCapabilityRefs(). if (old_capabilities) { @@ -2068,10 +2079,7 @@ setNumCapabilities (nat new_n_capabilities USED_IF_THREADS) } // Notify IO manager that the number of capabilities has changed. - rts_evalIO( - &cap, - &base_GHCziConcziIO_ioManagerCapabilitiesChanged_closure, - NULL); + rts_evalIO(&cap, ioManagerCapabilitiesChanged_closure, NULL); rts_unlock(cap); diff --git a/rts/Stable.c b/rts/Stable.c index e1807faa72..0dade10105 100644 --- a/rts/Stable.c +++ b/rts/Stable.c @@ -278,28 +278,36 @@ freeStablePtr(StgStablePtr sp) /* * get at the real stuff...remove indirections. - * It untags pointers before dereferencing and - * retags the real stuff with its tag (if there - * is any) when returning. - * - * ToDo: move to a better home. */ -static -StgClosure* -removeIndirections(StgClosure* p) +static StgClosure* +removeIndirections (StgClosure* p) { - StgWord tag = GET_CLOSURE_TAG(p); - StgClosure* q = UNTAG_CLOSURE(p); - - while (get_itbl(q)->type == IND || - get_itbl(q)->type == IND_STATIC || - get_itbl(q)->type == IND_PERM) { - q = ((StgInd *)q)->indirectee; - tag = GET_CLOSURE_TAG(q); - q = UNTAG_CLOSURE(q); - } + StgClosure* q; + + while (1) + { + q = UNTAG_CLOSURE(p); + + switch (get_itbl(q)->type) { + case IND: + case IND_STATIC: + case IND_PERM: + p = ((StgInd *)q)->indirectee; + continue; + + case BLACKHOLE: + p = ((StgInd *)q)->indirectee; + if (GET_CLOSURE_TAG(p) != 0) { + continue; + } else { + break; + } - return TAG_CLOSURE(tag,q); + default: + break; + } + return p; + } } StgWord diff --git a/rts/Updates.h b/rts/Updates.h index b4ff7d131b..1bd742a746 100644 --- a/rts/Updates.h +++ b/rts/Updates.h @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------------- * - * (c) The GHC Team, 1998-2004 + * (c) The GHC Team, 1998-2013 * * Performing updates. * @@ -46,7 +46,7 @@ \ OVERWRITING_CLOSURE(p1); \ StgInd_indirectee(p1) = p2; \ - prim %write_barrier(); \ + prim_write_barrier; \ SET_INFO(p1, stg_BLACKHOLE_info); \ LDV_RECORD_CREATE(p1); \ bd = Bdescr(p1); \ diff --git a/rts/ghc.mk b/rts/ghc.mk index 7cbb96ef0a..a4c7acb8b7 100644 --- a/rts/ghc.mk +++ b/rts/ghc.mk @@ -153,8 +153,6 @@ endif $(call distdir-way-opts,rts,dist,$1) $(call c-suffix-rules,rts,dist,$1,YES) $(call cmm-suffix-rules,rts,dist,$1) -$(call hs-suffix-rules-srcdir,rts,dist,$1,.) -# hs-suffix-rules-srcdir is needed when BootingFromHc to get the .hc rules rts_$1_LIB_NAME = libHSrts$$($1_libsuf) rts_$1_LIB = rts/dist/build/$$(rts_$1_LIB_NAME) @@ -224,6 +222,8 @@ endef # And expand the above for each way: $(foreach way,$(rts_WAYS),$(eval $(call build-rts-way,$(way)))) +$(eval $(call distdir-opts,rts,dist)) + #----------------------------------------------------------------------------- # Flags for compiling every file @@ -281,11 +281,6 @@ ifeq "$(UseLibFFIForAdjustors)" "YES" rts_CC_OPTS += -DUSE_LIBFFI_FOR_ADJUSTORS endif -# Mac OS X: make sure we compile for the right OS version -rts_CC_OPTS += $(MACOSX_DEPLOYMENT_CC_OPTS) -rts_HC_OPTS += $(addprefix -optc, $(MACOSX_DEPLOYMENT_CC_OPTS)) -rts_LD_OPTS += $(addprefix -optl, $(MACOSX_DEPLOYMENT_LD_OPTS)) - # We *want* type-checking of hand-written cmm. rts_HC_OPTS += -dcmm-lint @@ -547,9 +542,7 @@ endif $(eval $(call manual-package-config,rts)) -ifneq "$(BootingFromHc)" "YES" rts/package.conf.inplace : $(includes_H_CONFIG) $(includes_H_PLATFORM) -endif # ----------------------------------------------------------------------------- # installing diff --git a/rts/sm/Evac.c b/rts/sm/Evac.c index 4dfbad7e37..35d849e005 100644 --- a/rts/sm/Evac.c +++ b/rts/sm/Evac.c @@ -35,7 +35,7 @@ StgWord64 whitehole_spin = 0; #define HEAP_ALLOCED_GC(p) HEAP_ALLOCED(p) #endif -#if !defined(PARALLEL_GC) +#if !defined(PARALLEL_GC) || defined(PROFILING) #define copy_tag_nolock(p, info, src, size, stp, tag) \ copy_tag(p, info, src, size, stp, tag) #endif @@ -113,6 +113,17 @@ copy_tag(StgClosure **p, const StgInfoTable *info, const StgInfoTable *new_info; new_info = (const StgInfoTable *)cas((StgPtr)&src->header.info, (W_)info, MK_FORWARDING_PTR(to)); if (new_info != info) { +#ifdef PROFILING + // We copied this object at the same time as another + // thread. We'll evacuate the object again and the copy + // we just made will be discarded at the next GC, but we + // may have copied it after the other thread called + // SET_EVACUAEE_FOR_LDV(), which would confuse the LDV + // profiler when it encounters this closure in + // processHeapClosureForDead. So we reset the LDVW field + // here. + LDVW(to) = 0; +#endif return evacuate(p); // does the failed_to_evac stuff } else { *p = TAG_CLOSURE(tag,(StgClosure*)to); @@ -126,11 +137,13 @@ copy_tag(StgClosure **p, const StgInfoTable *info, #ifdef PROFILING // We store the size of the just evacuated object in the LDV word so that // the profiler can guess the position of the next object later. + // This is safe only if we are sure that no other thread evacuates + // the object again, so we cannot use copy_tag_nolock when PROFILING. SET_EVACUAEE_FOR_LDV(from, size); #endif } -#if defined(PARALLEL_GC) +#if defined(PARALLEL_GC) && !defined(PROFILING) STATIC_INLINE void copy_tag_nolock(StgClosure **p, const StgInfoTable *info, StgClosure *src, nat size, nat gen_no, StgWord tag) diff --git a/rts/sm/GCAux.c b/rts/sm/GCAux.c index 3df36d7449..29c1e9d604 100644 --- a/rts/sm/GCAux.c +++ b/rts/sm/GCAux.c @@ -93,6 +93,14 @@ isAlive(StgClosure *p) p = ((StgInd *)q)->indirectee; continue; + case BLACKHOLE: + p = ((StgInd*)q)->indirectee; + if (GET_CLOSURE_TAG(p) != 0) { + continue; + } else { + return NULL; + } + default: // dead. return NULL; diff --git a/rts/win32/ThrIOManager.c b/rts/win32/ThrIOManager.c index 41a1505de0..c4974016c1 100644 --- a/rts/win32/ThrIOManager.c +++ b/rts/win32/ThrIOManager.c @@ -1,167 +1,159 @@ -/* -----------------------------------------------------------------------------
- *
- * (c) The GHC Team, 1998-2006
- *
- * The IO manager thread in THREADED_RTS.
- * See also libraries/base/GHC/Conc.lhs.
- *
- * ---------------------------------------------------------------------------*/
-
-#include "Rts.h"
-#include "IOManager.h"
-#include "Prelude.h"
-#include <windows.h>
-
-// Here's the Event that we use to wake up the IO manager thread
-static HANDLE io_manager_event = INVALID_HANDLE_VALUE;
-
-// must agree with values in GHC.Conc:
-#define IO_MANAGER_WAKEUP 0xffffffff
-#define IO_MANAGER_DIE 0xfffffffe
-// spurios wakeups are returned as zero.
-// console events are ((event<<1) | 1)
-
-#if defined(THREADED_RTS)
-
-#define EVENT_BUFSIZ 256
-Mutex event_buf_mutex;
-StgWord32 event_buf[EVENT_BUFSIZ];
-nat next_event;
-
-#endif
-
-HANDLE
-getIOManagerEvent (void)
-{
- // This function has to exist even in the non-THREADED_RTS,
- // because code in GHC.Conc refers to it. It won't ever be called
- // unless we're in the threaded RTS, however.
-#ifdef THREADED_RTS
- HANDLE hRes;
-
- ACQUIRE_LOCK(&event_buf_mutex);
-
- if (io_manager_event == INVALID_HANDLE_VALUE) {
- hRes = CreateEvent ( NULL, // no security attrs
- TRUE, // manual reset
- FALSE, // initial state,
- NULL ); // event name: NULL for private events
- if (hRes == NULL) {
- sysErrorBelch("getIOManagerEvent");
- stg_exit(EXIT_FAILURE);
- }
- io_manager_event = hRes;
- } else {
- hRes = io_manager_event;
- }
-
- RELEASE_LOCK(&event_buf_mutex);
- return hRes;
-#else
- return NULL;
-#endif
-}
-
-
-HsWord32
-readIOManagerEvent (void)
-{
- // This function must exist even in non-THREADED_RTS,
- // see getIOManagerEvent() above.
-#if defined(THREADED_RTS)
- HsWord32 res;
-
- ACQUIRE_LOCK(&event_buf_mutex);
-
- if (io_manager_event != INVALID_HANDLE_VALUE) {
- if (next_event == 0) {
- res = 0; // no event to return
- } else {
- res = (HsWord32)(event_buf[--next_event]);
- if (next_event == 0) {
- if (!ResetEvent(io_manager_event)) {
- sysErrorBelch("readIOManagerEvent");
- stg_exit(EXIT_FAILURE);
- }
- }
- }
- } else {
- res = 0;
- }
-
- RELEASE_LOCK(&event_buf_mutex);
-
- // debugBelch("readIOManagerEvent: %d\n", res);
- return res;
-#else
- return 0;
-#endif
-}
-
-void
-sendIOManagerEvent (HsWord32 event)
-{
-#if defined(THREADED_RTS)
- ACQUIRE_LOCK(&event_buf_mutex);
-
- // debugBelch("sendIOManagerEvent: %d\n", event);
- if (io_manager_event != INVALID_HANDLE_VALUE) {
- if (next_event == EVENT_BUFSIZ) {
- errorBelch("event buffer overflowed; event dropped");
- } else {
- if (!SetEvent(io_manager_event)) {
- sysErrorBelch("sendIOManagerEvent");
- stg_exit(EXIT_FAILURE);
- }
- event_buf[next_event++] = (StgWord32)event;
- }
- }
-
- RELEASE_LOCK(&event_buf_mutex);
-#endif
-}
-
-void
-ioManagerWakeup (void)
-{
- sendIOManagerEvent(IO_MANAGER_WAKEUP);
-}
-
-#if defined(THREADED_RTS)
-void
-ioManagerDie (void)
-{
- sendIOManagerEvent(IO_MANAGER_DIE);
- // IO_MANAGER_DIE must be idempotent, as it is called
- // repeatedly by shutdownCapability(). Try conc059(threaded1) to
- // illustrate the problem.
- ACQUIRE_LOCK(&event_buf_mutex);
- io_manager_event = INVALID_HANDLE_VALUE;
- RELEASE_LOCK(&event_buf_mutex);
- // ToDo: wait for the IO manager to pick up the event, and
- // then release the Event and Mutex objects we've allocated.
-}
-
-void
-ioManagerStart (void)
-{
- initMutex(&event_buf_mutex);
- next_event = 0;
-
- // Make sure the IO manager thread is running
- Capability *cap;
- if (io_manager_event == INVALID_HANDLE_VALUE) {
- cap = rts_lock();
-#if defined(COMPILING_WINDOWS_DLL)
-# if defined(x86_64_HOST_ARCH)
- rts_evalIO(&cap,__imp_base_GHCziConcziIO_ensureIOManagerIsRunning_closure,NULL);
-# else
- rts_evalIO(&cap,_imp__base_GHCziConcziIO_ensureIOManagerIsRunning_closure,NULL);
-# endif
-#else
- rts_evalIO(&cap,&base_GHCziConcziIO_ensureIOManagerIsRunning_closure,NULL);
-#endif
- rts_unlock(cap);
- }
-}
-#endif
+/* ----------------------------------------------------------------------------- + * + * (c) The GHC Team, 1998-2006 + * + * The IO manager thread in THREADED_RTS. + * See also libraries/base/GHC/Conc.lhs. + * + * ---------------------------------------------------------------------------*/ + +#include "Rts.h" +#include "IOManager.h" +#include "Prelude.h" +#include <windows.h> + +// Here's the Event that we use to wake up the IO manager thread +static HANDLE io_manager_event = INVALID_HANDLE_VALUE; + +// must agree with values in GHC.Conc: +#define IO_MANAGER_WAKEUP 0xffffffff +#define IO_MANAGER_DIE 0xfffffffe +// spurios wakeups are returned as zero. +// console events are ((event<<1) | 1) + +#if defined(THREADED_RTS) + +#define EVENT_BUFSIZ 256 +Mutex event_buf_mutex; +StgWord32 event_buf[EVENT_BUFSIZ]; +nat next_event; + +#endif + +HANDLE +getIOManagerEvent (void) +{ + // This function has to exist even in the non-THREADED_RTS, + // because code in GHC.Conc refers to it. It won't ever be called + // unless we're in the threaded RTS, however. +#ifdef THREADED_RTS + HANDLE hRes; + + ACQUIRE_LOCK(&event_buf_mutex); + + if (io_manager_event == INVALID_HANDLE_VALUE) { + hRes = CreateEvent ( NULL, // no security attrs + TRUE, // manual reset + FALSE, // initial state, + NULL ); // event name: NULL for private events + if (hRes == NULL) { + sysErrorBelch("getIOManagerEvent"); + stg_exit(EXIT_FAILURE); + } + io_manager_event = hRes; + } else { + hRes = io_manager_event; + } + + RELEASE_LOCK(&event_buf_mutex); + return hRes; +#else + return NULL; +#endif +} + + +HsWord32 +readIOManagerEvent (void) +{ + // This function must exist even in non-THREADED_RTS, + // see getIOManagerEvent() above. +#if defined(THREADED_RTS) + HsWord32 res; + + ACQUIRE_LOCK(&event_buf_mutex); + + if (io_manager_event != INVALID_HANDLE_VALUE) { + if (next_event == 0) { + res = 0; // no event to return + } else { + res = (HsWord32)(event_buf[--next_event]); + if (next_event == 0) { + if (!ResetEvent(io_manager_event)) { + sysErrorBelch("readIOManagerEvent"); + stg_exit(EXIT_FAILURE); + } + } + } + } else { + res = 0; + } + + RELEASE_LOCK(&event_buf_mutex); + + // debugBelch("readIOManagerEvent: %d\n", res); + return res; +#else + return 0; +#endif +} + +void +sendIOManagerEvent (HsWord32 event) +{ +#if defined(THREADED_RTS) + ACQUIRE_LOCK(&event_buf_mutex); + + // debugBelch("sendIOManagerEvent: %d\n", event); + if (io_manager_event != INVALID_HANDLE_VALUE) { + if (next_event == EVENT_BUFSIZ) { + errorBelch("event buffer overflowed; event dropped"); + } else { + if (!SetEvent(io_manager_event)) { + sysErrorBelch("sendIOManagerEvent"); + stg_exit(EXIT_FAILURE); + } + event_buf[next_event++] = (StgWord32)event; + } + } + + RELEASE_LOCK(&event_buf_mutex); +#endif +} + +void +ioManagerWakeup (void) +{ + sendIOManagerEvent(IO_MANAGER_WAKEUP); +} + +#if defined(THREADED_RTS) +void +ioManagerDie (void) +{ + sendIOManagerEvent(IO_MANAGER_DIE); + // IO_MANAGER_DIE must be idempotent, as it is called + // repeatedly by shutdownCapability(). Try conc059(threaded1) to + // illustrate the problem. + ACQUIRE_LOCK(&event_buf_mutex); + io_manager_event = INVALID_HANDLE_VALUE; + RELEASE_LOCK(&event_buf_mutex); + // ToDo: wait for the IO manager to pick up the event, and + // then release the Event and Mutex objects we've allocated. +} + +void +ioManagerStart (void) +{ + initMutex(&event_buf_mutex); + next_event = 0; + + // Make sure the IO manager thread is running + Capability *cap; + if (io_manager_event == INVALID_HANDLE_VALUE) { + cap = rts_lock(); + rts_evalIO(&cap,ensureIOManagerIsRunning_closure,NULL); + rts_unlock(cap); + } +} +#endif diff --git a/rts/win32/libHSbase.def b/rts/win32/libHSbase.def index 5dd1ce7180..119237b652 100644 --- a/rts/win32/libHSbase.def +++ b/rts/win32/libHSbase.def @@ -27,6 +27,7 @@ EXPORTS base_GHCziPtr_FunPtr_con_info base_GHCziConcziIO_ensureIOManagerIsRunning_closure + base_GHCziConcziIO_ioManagerCapabilitiesChanged_closure base_GHCziConcziSync_runSparks_closure base_GHCziTopHandler_flushStdHandles_closure |