summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2010-03-25 10:46:17 +0000
committerSimon Marlow <marlowsd@gmail.com>2010-03-25 10:46:17 +0000
commit813f208a7c04bc740a43cb29ee248b9599415b40 (patch)
treea2e413f97ec078940dba3f1a3abd4e7814161814
parent484511cebe6055c13bedf6b9c773f96ae9d63dc3 (diff)
downloadhaskell-813f208a7c04bc740a43cb29ee248b9599415b40.tar.gz
comments and formatting only
-rw-r--r--rts/HeapStackCheck.cmm132
1 files changed, 71 insertions, 61 deletions
diff --git a/rts/HeapStackCheck.cmm b/rts/HeapStackCheck.cmm
index ba672bf805..5bdf600a1c 100644
--- a/rts/HeapStackCheck.cmm
+++ b/rts/HeapStackCheck.cmm
@@ -21,45 +21,55 @@ import LeaveCriticalSection;
/* Stack/Heap Check Failure
* ------------------------
*
- * On discovering that a stack or heap check has failed, we do the following:
+ * Both heap and stack check failures end up in the same place, so
+ * that we can share the code for the failure case when a proc needs
+ * both a stack check and a heap check (a common case).
*
- * - If HpLim==0, indicating that we should context-switch, we yield
- * to the scheduler (return ThreadYielding).
+ * So when we get here, we have to tell the difference between a stack
+ * check failure and a heap check failure. The code for the checks
+ * looks like this:
+
+ if (Sp - 16 < SpLim) goto c1Tf;
+ Hp = Hp + 16;
+ if (Hp > HpLim) goto c1Th;
+ ...
+ c1Th:
+ HpAlloc = 16;
+ goto c1Tf;
+ c1Tf: jump stg_gc_enter_1 ();
+
+ * Note that Sp is not decremented by the check, whereas Hp is. The
+ * reasons for this seem to be largely historic, I can't think of a
+ * good reason not to decrement Sp at the check too. (--SDM)
*
- * Note that we must leave no slop in the heap (this is a requirement
- * for LDV profiling, at least), so if we just had a heap-check
- * failure, then we must retract Hp by HpAlloc. How do we know
- * whether there was a heap-check failure? HpLim might be zero, and
- * yet we got here as a result of a stack-check failure. Hence, we
- * require that HpAlloc is only non-zero if there was a heap-check
- * failure, otherwise it is zero, so we can always safely subtract
- * HpAlloc from Hp.
+ * Note that HpLim may be set to zero arbitrarily by the timer signal
+ * or another processor to trigger a context switch via heap check
+ * failure.
*
- * Hence, HpAlloc is zeroed in LOAD_THREAD_STATE().
+ * The job of these fragments (stg_gc_enter_1 and friends) is to
+ * 1. Leave no slop in the heap, so Hp must be retreated if it was
+ * incremented by the check. No-slop is a requirement for LDV
+ * profiling, at least.
+ * 2. If a heap check failed, try to grab another heap block from
+ * the nursery and continue.
+ * 3. otherwise, return to the scheduler with StackOverflow,
+ * HeapOverflow, or ThreadYielding as appropriate.
*
- * - If the context_switch flag is set (the backup plan if setting HpLim
- * to 0 didn't trigger a context switch), we yield to the scheduler
- * (return ThreadYielding).
+ * We can tell whether Hp was incremented, because HpAlloc is
+ * non-zero: HpAlloc is required to be zero at all times unless a
+ * heap-check just failed, which is why the stack-check failure case
+ * does not set HpAlloc (see code fragment above). So that covers (1).
+ * HpAlloc is zeroed in LOAD_THREAD_STATE().
*
- * - If Hp > HpLim, we've had a heap check failure. This means we've
- * come to the end of the current heap block, so we try to chain
- * another block on with ExtendNursery().
+ * If Hp > HpLim, then either (a) we have reached the end of the
+ * current heap block, or (b) HpLim == 0 and we should yield. Hence
+ * check Hp > HpLim first, and then HpLim == 0 to decide whether to
+ * return ThreadYielding or try to grab another heap block from the
+ * nursery.
*
- * - If this succeeds, we carry on without returning to the
- * scheduler.
- *
- * - If it fails, we return to the scheduler claiming HeapOverflow
- * so that a garbage collection can be performed.
- *
- * - If Hp <= HpLim, it must have been a stack check that failed. In
- * which case, we return to the scheduler claiming StackOverflow, the
- * scheduler will either increase the size of our stack, or raise
- * an exception if the stack is already too big.
- *
- * The effect of checking for context switch only in the heap/stack check
- * failure code is that we'll switch threads after the current thread has
- * reached the end of its heap block. If a thread isn't allocating
- * at all, it won't yield. Hopefully this won't be a problem in practice.
+ * If Hp <= HpLim, then this must be a StackOverflow. The scheduler
+ * will either increase the size of our stack, or raise an exception if
+ * the stack is already too big.
*/
#define PRE_RETURN(why,what_next) \
@@ -71,35 +81,35 @@ import LeaveCriticalSection;
* ThreadRunGHC thread.
*/
-#define GC_GENERIC \
- DEBUG_ONLY(foreign "C" heapCheckFail()); \
- if (Hp > HpLim) { \
- Hp = Hp - HpAlloc/*in bytes*/; \
- if (HpLim == 0) { \
- R1 = ThreadYielding; \
- goto sched; \
- } \
- if (HpAlloc <= BLOCK_SIZE \
- && bdescr_link(CurrentNursery) != NULL) { \
- HpAlloc = 0; \
- CLOSE_NURSERY(); \
- CurrentNursery = bdescr_link(CurrentNursery); \
- OPEN_NURSERY(); \
+#define GC_GENERIC \
+ DEBUG_ONLY(foreign "C" heapCheckFail()); \
+ if (Hp > HpLim) { \
+ Hp = Hp - HpAlloc/*in bytes*/; \
+ if (HpLim == 0) { \
+ R1 = ThreadYielding; \
+ goto sched; \
+ } \
+ if (HpAlloc <= BLOCK_SIZE \
+ && bdescr_link(CurrentNursery) != NULL) { \
+ HpAlloc = 0; \
+ CLOSE_NURSERY(); \
+ CurrentNursery = bdescr_link(CurrentNursery); \
+ OPEN_NURSERY(); \
if (Capability_context_switch(MyCapability()) != 0 :: CInt) { \
- R1 = ThreadYielding; \
- goto sched; \
- } else { \
- jump %ENTRY_CODE(Sp(0)); \
- } \
- } else { \
- R1 = HeapOverflow; \
- goto sched; \
- } \
- } else { \
- R1 = StackOverflow; \
- } \
- sched: \
- PRE_RETURN(R1,ThreadRunGHC); \
+ R1 = ThreadYielding; \
+ goto sched; \
+ } else { \
+ jump %ENTRY_CODE(Sp(0)); \
+ } \
+ } else { \
+ R1 = HeapOverflow; \
+ goto sched; \
+ } \
+ } else { \
+ R1 = StackOverflow; \
+ } \
+ sched: \
+ PRE_RETURN(R1,ThreadRunGHC); \
jump stg_returnToSched;
#define HP_GENERIC \