[project @ 2003-01-25 15:54:48 by wolfgang]
[ghc-hetmet.git] / ghc / includes / Updates.h
index 9209739..0820b50 100644 (file)
@@ -1,5 +1,7 @@
 /* -----------------------------------------------------------------------------
- * $Id: Updates.h,v 1.2 1998/12/02 13:21:47 simonm Exp $
+ * $Id: Updates.h,v 1.29 2003/01/25 15:54:48 wolfgang Exp $
+ *
+ * (c) The GHC Team, 1998-1999
  *
  * Definitions related to updates.
  *
@@ -8,18 +10,6 @@
 #ifndef UPDATES_H
 #define UPDATES_H
 
-/*
-  ticky-ticky wants to use permanent indirections when it's doing
-  update entry counts.
- */
-
-#ifndef TICKY_TICKY
-# define Ind_info_TO_USE &IND_info
-#else
-# define Ind_info_TO_USE ((AllFlags.doUpdEntryCounts) ? &IND_PERM_info : &IND_info
-)
-#endif
-
 /* -----------------------------------------------------------------------------
    Update a closure with an indirection.  This may also involve waking
    up a queue of blocked threads waiting on the result of this
  *       (I think the fancy version of the GC is supposed to do this too.)
  */
 
-#define UPD_IND(updclosure, heapptr)                            \
-        TICK_UPDATED_SET_UPDATED(updclosure);                  \
-        AWAKEN_BQ(updclosure);                                  \
-        SET_INFO((StgInd*)updclosure,Ind_info_TO_USE);          \
-        ((StgInd *)updclosure)->indirectee   = (StgClosure *)(heapptr)
+/* This expands to a fair chunk of code, what with waking up threads 
+ * and checking whether we're updating something in a old generation.
+ * preferably don't use this macro inline in compiled code.
+ */
 
-/* -----------------------------------------------------------------------------
-   Update a closure inplace with an infotable that expects 1 (closure)
-   argument.
-   Also may wake up BQs.
-   -------------------------------------------------------------------------- */
+#ifdef TICKY_TICKY
+# define UPD_IND(updclosure, heapptr) UPD_PERM_IND(updclosure,heapptr)
+#else
+# define UPD_IND(updclosure, heapptr) UPD_REAL_IND(updclosure,heapptr)
+#endif
+
+/* UPD_IND actually does a PERM_IND if TICKY_TICKY is on;
+   if you *really* need an IND use UPD_REAL_IND
+ */
+#ifdef SMP
+#define UPD_REAL_IND(updclosure, heapptr)                              \
+   {                                                                   \
+       const StgInfoTable *info;                                       \
+       if (Bdescr((P_)updclosure)->u.back != (bdescr *)BaseReg) {      \
+               info = LOCK_CLOSURE(updclosure);                        \
+       } else {                                                        \
+               info = updclosure->header.info;                         \
+       }                                                               \
+        AWAKEN_BQ(info,updclosure);                                    \
+       updateWithIndirection(info,                                     \
+                             (StgClosure *)updclosure,                 \
+                             (StgClosure *)heapptr);                   \
+   }
+#else
+#define UPD_REAL_IND(updclosure, heapptr)              \
+   {                                                   \
+       const StgInfoTable *info;                       \
+       info = ((StgClosure *)updclosure)->header.info; \
+        AWAKEN_BQ(info,updclosure);                    \
+       updateWithIndirection(info,                     \
+                             (StgClosure *)updclosure, \
+                             (StgClosure *)heapptr);   \
+   }
+#endif
+
+#define UPD_STATIC_IND(updclosure, heapptr)                    \
+   {                                                           \
+       const StgInfoTable *info;                               \
+       info = ((StgClosure *)updclosure)->header.info;         \
+        AWAKEN_STATIC_BQ(info,updclosure);                     \
+       updateWithStaticIndirection(info,                       \
+                                   (StgClosure *)updclosure,   \
+                                   (StgClosure *)heapptr);     \
+   }
+
+#if defined(PROFILING) || defined(TICKY_TICKY)
+#define UPD_PERM_IND(updclosure, heapptr)                      \
+   {                                                           \
+       const StgInfoTable *info;                               \
+       info = ((StgClosure *)updclosure)->header.info;         \
+        AWAKEN_BQ(info,updclosure);                            \
+       updateWithPermIndirection(info,                         \
+                                 (StgClosure *)updclosure,     \
+                                 (StgClosure *)heapptr);       \
+   }
+#endif
 
-#define UPD_INPLACE1(updclosure,info,c0)                        \
-        TICK_UPDATED_SET_UPDATED(updclosure);                  \
-        AWAKEN_BQ(updclosure);                                  \
-        SET_INFO(updclosure,info);                              \
-        payloadCPtr(updclosure,0) = (c0)
+#ifdef SMP
+#define UPD_IND_NOLOCK(updclosure, heapptr)                            \
+   {                                                                   \
+       const StgInfoTable *info;                                       \
+       info = updclosure->header.info;                                 \
+        AWAKEN_BQ(info,updclosure);                                    \
+       updateWithIndirection(info,                                     \
+                             (StgClosure *)updclosure,                 \
+                             (StgClosure *)heapptr);                   \
+   }
+#elif defined(RTS_SUPPORTS_THREADS)
+
+# ifdef TICKY_TICKY
+#  define UPD_IND_NOLOCK(updclosure, heapptr)                  \
+   {                                                           \
+       const StgInfoTable *info;                               \
+       info = ((StgClosure *)updclosure)->header.info;         \
+        AWAKEN_BQ_NOLOCK(info,updclosure);                     \
+       updateWithPermIndirection(info,                         \
+                                 (StgClosure *)updclosure,     \
+                                 (StgClosure *)heapptr);       \
+   }
+# else
+#  define UPD_IND_NOLOCK(updclosure, heapptr)          \
+   {                                                   \
+       const StgInfoTable *info;                       \
+       info = ((StgClosure *)updclosure)->header.info; \
+        AWAKEN_BQ_NOLOCK(info,updclosure);             \
+       updateWithIndirection(info,                     \
+                             (StgClosure *)updclosure, \
+                             (StgClosure *)heapptr);   \
+   }
+# endif
+
+#else
+#define UPD_IND_NOLOCK(updclosure,heapptr) UPD_IND(updclosure,heapptr)
+#endif
 
 /* -----------------------------------------------------------------------------
    Awaken any threads waiting on this computation
    -------------------------------------------------------------------------- */
 
-extern void awaken_blocked_queue(StgTSO *q);
+#if defined(PAR) 
+
+/* 
+   In a parallel setup several types of closures might have a blocking queue:
+     BLACKHOLE_BQ ... same as in the default concurrent setup; it will be
+                      reawakened via calling UPD_IND on that closure after
+                     having finished the computation of the graph
+     FETCH_ME_BQ  ... a global indirection (FETCH_ME) may be entered by a 
+                      local TSO, turning it into a FETCH_ME_BQ; it will be
+                     reawakened via calling processResume
+     RBH          ... a revertible black hole may be entered by another 
+                      local TSO, putting it onto its blocking queue; since
+                     RBHs only exist while the corresponding closure is in 
+                     transit, they will be reawakened via calling 
+                     convertToFetchMe (upon processing an ACK message)
+
+   In a parallel setup a blocking queue may contain 3 types of closures:
+     TSO           ... as in the default concurrent setup
+     BLOCKED_FETCH ... indicating that a TSO on another PE is waiting for
+                       the result of the current computation
+     CONSTR        ... an RBHSave closure (which contains data ripped out of
+                       the closure to make room for a blocking queue; since
+                      it only contains data we use the exisiting type of
+                      a CONSTR closure); this closure is the end of a 
+                      blocking queue for an RBH closure; it only exists in
+                      this kind of blocking queue and must be at the end
+                      of the queue
+*/                   
+extern void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node);
+#define DO_AWAKEN_BQ(bqe, node)  STGCALL2(awakenBlockedQueue, bqe, node);
 
-#define AWAKEN_BQ(closure)                                             \
-       if (closure->header.info == &BLACKHOLE_info) {                  \
-               StgTSO *bq = ((StgBlackHole *)closure)->blocking_queue; \
-               if (bq != (StgTSO *)&END_TSO_QUEUE_closure) {           \
-                       STGCALL1(awaken_blocked_queue, bq);             \
-               }                                                       \
+#define AWAKEN_BQ(info,closure)                                                \
+       if (info == &stg_BLACKHOLE_BQ_info ||               \
+           info == &stg_FETCH_ME_BQ_info ||                \
+           get_itbl(closure)->type == RBH) {                           \
+               DO_AWAKEN_BQ(((StgBlockingQueue *)closure)->blocking_queue, closure);                           \
        }
 
+#elif defined(GRAN)
 
-/* -----------------------------------------------------------------------------
+extern void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node);
+#define DO_AWAKEN_BQ(bq, node)  STGCALL2(awakenBlockedQueue, bq, node);
+
+/* In GranSim we don't have FETCH_ME or FETCH_ME_BQ closures, so they are
+   not checked. The rest of the code is the same as for GUM.
+*/
+#define AWAKEN_BQ(info,closure)                                                \
+       if (info == &stg_BLACKHOLE_BQ_info ||               \
+           get_itbl(closure)->type == RBH) {                           \
+               DO_AWAKEN_BQ(((StgBlockingQueue *)closure)->blocking_queue, closure);                           \
+       }
+
+
+#else /* !GRAN && !PAR */
+
+extern void awakenBlockedQueue(StgTSO *q);
+#define DO_AWAKEN_BQ(closure)          \
+        STGCALL1(awakenBlockedQueue,           \
+                ((StgBlockingQueue *)closure)->blocking_queue);
+
+#define AWAKEN_BQ(info,closure)                                                \
+       if (info == &stg_BLACKHOLE_BQ_info) {                           \
+          DO_AWAKEN_BQ(closure);                                        \
+       }
+
+#define AWAKEN_STATIC_BQ(info,closure)                                 \
+       if (info == &stg_BLACKHOLE_BQ_STATIC_info) {                    \
+          DO_AWAKEN_BQ(closure);                                        \
+       }
+
+#ifdef RTS_SUPPORTS_THREADS
+extern void awakenBlockedQueueNoLock(StgTSO *q);
+#define DO_AWAKEN_BQ_NOLOCK(closure)                                   \
+        STGCALL1(awakenBlockedQueueNoLock,                             \
+                ((StgBlockingQueue *)closure)->blocking_queue);
+
+#define AWAKEN_BQ_NOLOCK(info,closure)                                 \
+       if (info == &stg_BLACKHOLE_BQ_info) {                           \
+          DO_AWAKEN_BQ_NOLOCK(closure);                                 \
+       }
+#endif
+#endif /* GRAN || PAR */
+
+/* -------------------------------------------------------------------------
    Push an update frame on the stack.
-   -------------------------------------------------------------------------- */
+   ------------------------------------------------------------------------- */
 
 #if defined(PROFILING)
-#define PUSH_STD_CCCS(frame) frame->header.prof.ccs = CCCS
+// frame->header.prof.hp.rs = NULL (or frame-header.prof.hp.ldvw = 0) is unnecessary 
+// because it is not used anyhow.
+#define PUSH_STD_CCCS(frame) (frame->header.prof.ccs = CCCS)
 #else
 #define PUSH_STD_CCCS(frame)
 #endif
 
-extern const StgPolyInfoTable Upd_frame_info; 
+extern DLL_IMPORT_RTS const StgPolyInfoTable stg_upd_frame_info; 
+extern DLL_IMPORT_RTS const StgPolyInfoTable stg_noupd_frame_info; 
 
 #define PUSH_UPD_FRAME(target, Sp_offset)                      \
        {                                                       \
                StgUpdateFrame *__frame;                        \
-               TICK_UPDF_PUSHED();                             \
-               __frame = stgCast(StgUpdateFrame*,Sp + (Sp_offset)) - 1; \
-               SET_INFO(__frame,stgCast(StgInfoTable*,&Upd_frame_info));   \
-               __frame->link = Su;                             \
+               TICK_UPDF_PUSHED(target, GET_INFO((StgClosure*)target)); \
+               __frame = (StgUpdateFrame *)(Sp + (Sp_offset)) - 1; \
+               SET_INFO(__frame, (StgInfoTable *)&stg_upd_frame_info);   \
                __frame->updatee = (StgClosure *)(target);      \
                PUSH_STD_CCCS(__frame);                         \
-               Su = __frame;                                   \
        }
 
 /* -----------------------------------------------------------------------------
@@ -105,38 +250,29 @@ extern const StgPolyInfoTable Upd_frame_info;
 
        - for the parallel system, which can implement updates more
          easily if the updatee is always in the heap. (allegedly).
+
+   When debugging, we maintain a separate CAF list so we can tell when
+   a CAF has been garbage collected.
    -------------------------------------------------------------------------- */
    
-EI_(Caf_info);
-EF_(Caf_entry);
-
 /* ToDo: only call newCAF when debugging. */
 
 extern void newCAF(StgClosure*);
 
-#define UPD_CAF(cafptr, bhptr)                                 \
-  {                                                            \
-    SET_INFO((StgInd *)cafptr,&IND_STATIC_info);               \
-    ((StgInd *)cafptr)->indirectee   = (StgClosure *)(bhptr);  \
-    ((StgBlackHole *)(bhptr))->blocking_queue =                \
-          (StgTSO *)&END_TSO_QUEUE_closure;                    \
-    STGCALL1(newCAF,(StgClosure *)cafptr);                     \
+/* newCAF must be called before the itbl ptr is overwritten, since
+   newCAF records the old itbl ptr in order to do CAF reverting
+   (which Hugs needs to do in order that combined mode works right.)
+*/
+#define UPD_CAF(cafptr, bhptr)                                         \
+  {                                                                    \
+    LOCK_CLOSURE(cafptr);                                              \
+    STGCALL1(newCAF,(StgClosure *)cafptr);                             \
+    ((StgInd *)cafptr)->indirectee   = (StgClosure *)(bhptr);          \
+    SET_INFO((StgInd *)cafptr,(const StgInfoTable*)&stg_IND_STATIC_info);\
   }
 
 /* -----------------------------------------------------------------------------
    Update-related prototypes
    -------------------------------------------------------------------------- */
 
-extern STGFUN(Upd_frame_entry);
-
-extern const StgInfoTable PAP_info;
-STGFUN(PAP_entry);
-
-EXTFUN(stg_update_PAP);
-
-extern const StgInfoTable AP_UPD_info;
-STGFUN(AP_UPD_entry);
-
-extern const StgInfoTable raise_info;
-
 #endif /* UPDATES_H */