summaryrefslogtreecommitdiff
path: root/rts
diff options
context:
space:
mode:
Diffstat (limited to 'rts')
-rw-r--r--rts/Prelude.h1
-rw-r--r--rts/RtsStartup.c1
-rw-r--r--rts/Schedule.c40
-rw-r--r--rts/Stable.c46
-rw-r--r--rts/Updates.h4
-rw-r--r--rts/ghc.mk11
-rw-r--r--rts/sm/Evac.c17
-rw-r--r--rts/sm/GCAux.c8
-rw-r--r--rts/win32/ThrIOManager.c326
-rw-r--r--rts/win32/libHSbase.def1
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