[project @ 1999-11-29 18:59:23 by sewardj]
[ghc-hetmet.git] / ghc / rts / Evaluator.c
index aece2e3..681cb6b 100644 (file)
@@ -5,8 +5,8 @@
  * Copyright (c) 1994-1998.
  *
  * $RCSfile: Evaluator.c,v $
- * $Revision: 1.26 $
- * $Date: 1999/11/12 17:50:04 $
+ * $Revision: 1.30 $
+ * $Date: 1999/11/29 18:59:42 $
  * ---------------------------------------------------------------------------*/
 
 #include "Rts.h"
@@ -294,7 +294,7 @@ static inline void PushTaggedRealWorld( void );
 /* static inline void PushTaggedInteger  ( mpz_ptr ); */
 static inline StgPtr grabHpUpd( nat size );
 static inline StgPtr grabHpNonUpd( nat size );
-static        StgClosure* raiseAnError   ( StgClosure* errObj );
+static        StgClosure* raiseAnError   ( StgClosure* exception );
 
 static int  enterCountI = 0;
 
@@ -501,9 +501,11 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
 
     if (
 #ifdef DEBUG
-        1 ||
+             ((++eCount) & 0x0F) == 0
+#else
+             ++eCount == 0
 #endif
-             ++eCount == 0) {
+       ) {
        if (context_switch) {
           xPushCPtr(obj); /* code to restart with */
           RETURN(ThreadYielding);
@@ -1157,7 +1159,6 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
                 }
             Case(i_PRIMOP2):
                 {
-                 /* Remember to save  */
                     int      i, trc, pc_saved;
                     void*    p;
                     StgBCO*  bco_tmp;
@@ -1175,8 +1176,8 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
                           /* we want to enter p */
                           obj = p; goto enterLoop;
                        } else {
-                          /* p is the the StgThreadReturnCode for this thread */
-                          RETURN((StgThreadReturnCode)p);
+                          /* trc is the the StgThreadReturnCode for this thread */
+                          RETURN((StgThreadReturnCode)trc);
                        };
                     }
                     Continue;
@@ -1325,14 +1326,10 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
     case CAF_BLACKHOLE:
     case SE_CAF_BLACKHOLE:
         {
-           /*was StgBlackHole* */
-            StgBlockingQueue* bh = (StgBlockingQueue*)obj;
-            /* Put ourselves on the blocking queue for this black hole and block */
-            cap->rCurrentTSO->link = bh->blocking_queue;
-            bh->blocking_queue = cap->rCurrentTSO;
-            xPushCPtr(obj); /* code to restart with */
-            barf("enter: CAF_BLACKHOLE unexpected!");
-            RETURN(ThreadBlocked);
+            /* Let the scheduler figure out what to do :-) */
+            cap->rCurrentTSO->whatNext = ThreadEnterGHC;
+            xPushCPtr(obj);
+            RETURN(ThreadYielding);
         }
     case AP_UPD:
         {
@@ -1721,22 +1718,22 @@ static inline void PopSeqFrame ( void )
     gSu = stgCast(StgSeqFrame*,gSu)->link;             
 }
 
-static inline StgClosure* raiseAnError ( StgClosure* errObj )
+static inline StgClosure* raiseAnError ( StgClosure* exception )
 {
-    StgClosure *raise_closure;
-
-    /* This closure represents the expression 'raise# E' where E
-     * is the exception raised.  It is used to overwrite all the
+    /* This closure represents the expression 'primRaise E' where E
+     * is the exception raised (:: Exception).  
+     * It is used to overwrite all the
      * thunks which are currently under evaluation.
      */
-    raise_closure = (StgClosure *)allocate(sizeofW(StgClosure)+1);
-    raise_closure->header.info = &raise_info;
-    raise_closure->payload[0] = 0xdeadbeef; /*R1.cl;*/
-
+    HaskellObj primRaiseClosure
+       = asmClosureOfObject(getHugs_AsmObject_for("primRaise"));
+    HaskellObj reraiseClosure
+       = rts_apply ( primRaiseClosure, exception );
+   
     while (1) {
         switch (get_itbl(gSu)->type) {
         case UPDATE_FRAME:
-                UPD_IND(gSu->updatee,raise_closure);
+                UPD_IND(gSu->updatee,reraiseClosure);
                 gSp = stgCast(StgStackPtr,gSu) + sizeofW(StgUpdateFrame);
                 gSu = gSu->link;
                 break;
@@ -1749,7 +1746,7 @@ static inline StgClosure* raiseAnError ( StgClosure* errObj )
                 StgClosure *handler = fp->handler;
                 gSu = fp->link; 
                 gSp += sizeofW(StgCatchFrame); /* Pop */
-                PushCPtr(errObj);
+                PushCPtr(exception);
                 return handler;
            }
         case STOP_FRAME:
@@ -2760,7 +2757,7 @@ static void* enterBCO_primop2 ( int primop2code,
                 break; 
             }
 
-        /* Most of these generate alignment warnings on gSparcs and similar architectures.
+        /* Most of these generate alignment warnings on Sparcs and similar architectures.
          * These are harmless and are caused by the cast to C* in BYTE_ARR_CTS.
          */
         case i_indexCharArray:   
@@ -2915,147 +2912,139 @@ static void* enterBCO_primop2 ( int primop2code,
                 break;
             }
 
-#ifdef PROVIDE_CONCURRENT
-        case i_fork:
-            {
-                StgClosure* c = PopCPtr();
-                StgTSO* t = createGenThread(RtsFlags.GcFlags.initialStkSize,c);
-                PushPtr(stgCast(StgPtr,t));
-
-                /* switch at the earliest opportunity */ 
-                context_switch = 1;
-                /* but don't automatically switch to GHC - or you'll waste your
-                 * time slice switching back.
-                 * 
-                 * Actually, there's more to it than that: the default
-                 * (ThreadEnterGHC) causes the thread to crash - don't 
-                 * understand why. - ADR
-                 */
-                t->whatNext = ThreadEnterHugs;
-                break;
-            }
-        case i_killThread:
-            {
-                StgTSO* tso = stgCast(StgTSO*,PopPtr());
-                deleteThread(tso);
-                if (tso == cap->rCurrentTSO) { /* suicide */
-                    *return2 = ThreadFinished;
-                    return (void*)(1+(NULL));
-                }
-                break;
-            }
-        case i_sameMVar:
-            { /* identical to i_sameRef */
-                StgPtr x = PopPtr();
-                StgPtr y = PopPtr();
-                PushTaggedBool(x==y);
-                break;
-            }
         case i_newMVar:
             {
                 StgMVar *mvar = stgCast(StgMVar*,allocate(sizeofW(StgMVar)));
                 SET_INFO(mvar,&EMPTY_MVAR_info);
-                mvar->head = mvar->tail = EndTSOQueue;
-                /* ToDo: this is a little strange */
+                mvar->head = mvar->tail = (StgTSO *)&END_TSO_QUEUE_closure;
                 mvar->value = stgCast(StgClosure*,&END_TSO_QUEUE_closure);
                 PushPtr(stgCast(StgPtr,mvar));
                 break;
             }
-#if 1
-#if 0
-ToDo: another way out of the problem might be to add an explicit
-continuation to primTakeMVar: takeMVar v = primTakeMVar v takeMVar.
-The problem with this plan is that now I dont know how much to chop
-off the stack.
-#endif
         case i_takeMVar:
             {
-                StgMVar *mvar = stgCast(StgMVar*,PopPtr());
-                /* If the MVar is empty, put ourselves
-                 * on its blocking queue, and wait
-                 * until we're woken up.  
-                 */
-                if (GET_INFO(mvar) != &FULL_MVAR_info) {
-                    if (mvar->head == EndTSOQueue) {
+                StgMVar *mvar = (StgMVar*)PopCPtr();
+                if (GET_INFO(mvar) == &EMPTY_MVAR_info) {
+
+                    /* The MVar is empty.  Attach ourselves to the TSO's 
+                       blocking queue.
+                    */
+                    if (mvar->head == (StgTSO *)&END_TSO_QUEUE_closure) {
                         mvar->head = cap->rCurrentTSO;
                     } else {
                         mvar->tail->link = cap->rCurrentTSO;
                     }
-                    cap->rCurrentTSO->link = EndTSOQueue;
+                    cap->rCurrentTSO->link = (StgTSO *)&END_TSO_QUEUE_closure;
+                    cap->rCurrentTSO->why_blocked = BlockedOnMVar;
+                    cap->rCurrentTSO->block_info.closure = (StgClosure *)mvar;
                     mvar->tail = cap->rCurrentTSO;
 
-                    /* Hack, hack, hack.
-                     * When we block, we push a restart closure
-                     * on the stack - but which closure?
-                     * We happen to know that the BCO we're
-                     * executing looks like this:
-                     *
-                     *  0:      STK_CHECK 4
-                     *  2:      HP_CHECK 3
-                     *  4:      TEST 0 29
-                     *  7:      UNPACK
-                     *  8:      VAR 3
-                     *  10:     VAR 1
-                     *  12:     primTakeMVar
-                     *  14:     ALLOC_CONSTR 0x8213a80
-                     *  16:     VAR 2
-                     *  18:     VAR 2
-                     *  20:     PACK 2
-                     *  22:     VAR 0
-                     *  24:     SLIDE 1 7
-                     *  27:     ENTER
-                     *  28:     PANIC
-                     *  29:     PANIC
-                     *
-                     * so we rearrange the stack to look the
-                     * way it did when we entered this BCO
-                                    * and push ths BCO.
-                     * What a disgusting hack!
-                     */
-
-                    PopPtr();
-                    PopPtr();
-                    PushCPtr(obj);
+                    /* At this point, the top-of-stack holds the MVar,
+                       and underneath is the world token ().  So the 
+                       stack is in the same state as when primTakeMVar
+                       was entered (primTakeMVar is handwritten bytecode).
+                       Push obj, which is this BCO, and return to the
+                       scheduler.  When the MVar is filled, the scheduler
+                       will re-enter primTakeMVar, with the args still on
+                       the top of the stack. 
+                    */
+                    PushCPtr((StgClosure*)(*bco));
                     *return2 = ThreadBlocked;
                     return (void*)(1+(NULL));
 
                 } else {
                     PushCPtr(mvar->value);
+                    mvar->value = (StgClosure *)&END_TSO_QUEUE_closure;
                     SET_INFO(mvar,&EMPTY_MVAR_info);
-                    /* ToDo: this is a little strange */
-                    mvar->value = (StgClosure*)&END_TSO_QUEUE_closure;
                 }
                 break;
             }
-#endif
         case i_putMVar:
             {
                 StgMVar*    mvar  = stgCast(StgMVar*,PopPtr());
                 StgClosure* value = PopCPtr();
                 if (GET_INFO(mvar) == &FULL_MVAR_info) {
-                    return (raisePrim("putMVar {full MVar}"));
+                    return (makeErrorCall("putMVar {full MVar}"));
                 } else {
                     /* wake up the first thread on the
                      * queue, it will continue with the
                      * takeMVar operation and mark the
                      * MVar empty again.  
                      */
-                    StgTSO* tso = mvar->head;
-                    SET_INFO(mvar,&FULL_MVAR_info);
                     mvar->value = value;
-                    if (tso != EndTSOQueue) {
-                        PUSH_ON_RUN_QUEUE(tso);
-                        mvar->head = tso->link;
-                        tso->link = EndTSOQueue;
-                        if (mvar->head == EndTSOQueue) {
-                            mvar->tail = EndTSOQueue;
-                        }
+
+                    if (mvar->head != (StgTSO *)&END_TSO_QUEUE_closure) {
+                       ASSERT(mvar->head->why_blocked == BlockedOnMVar);
+                       mvar->head = unblockOne(mvar->head);
+                       if (mvar->head == (StgTSO *)&END_TSO_QUEUE_closure) {
+                          mvar->tail = (StgTSO *)&END_TSO_QUEUE_closure;
+                       }
                     }
+
+                    /* unlocks the MVar in the SMP case */
+                    SET_INFO(mvar,&FULL_MVAR_info);
+
+                    /* yield for better communication performance */
+                    context_switch = 1;
                 }
-                /* yield for better communication performance */
+                break;
+            }
+        case i_sameMVar:
+            {   /* identical to i_sameRef */
+                StgMVar* x = (StgMVar*)PopPtr();
+                StgMVar* y = (StgMVar*)PopPtr();
+                PushTaggedBool(x==y);
+                break;
+            }
+        case i_getThreadId:
+            {
+                StgWord tid = cap->rCurrentTSO->id;
+                PushTaggedWord(tid);
+                break;
+            }
+        case i_cmpThreadIds:
+            {
+                StgWord tid1 = PopTaggedWord();
+                StgWord tid2 = PopTaggedWord();
+                if (tid1 < tid2) PushTaggedInt(-1);
+                else if (tid1 > tid2) PushTaggedInt(1);
+                else PushTaggedInt(0);
+                break;
+            }
+        case i_forkIO:
+            {
+                StgClosure* closure;
+                StgTSO*     tso;
+                StgWord     tid;
+                closure = PopCPtr();
+                tso     = createGenThread (RtsFlags.GcFlags.initialStkSize,closure);
+                tid     = tso->id;
+                scheduleThread(tso);
                 context_switch = 1;
+                PushTaggedWord(tid);
                 break;
             }
+
+#ifdef PROVIDE_CONCURRENT
+        case i_killThread:
+            {
+                StgTSO* tso = stgCast(StgTSO*,PopPtr());
+                deleteThread(tso);
+                if (tso == cap->rCurrentTSO) { /* suicide */
+                    *return2 = ThreadFinished;
+                    return (void*)(1+(NULL));
+                }
+                break;
+            }
+
+#if 1
+#if 0
+ToDo: another way out of the problem might be to add an explicit
+continuation to primTakeMVar: takeMVar v = primTakeMVar v takeMVar.
+The problem with this plan is that now I dont know how much to chop
+off the stack.
+#endif
+#endif
         case i_delay:
         case i_waitRead:
         case i_waitWrite:
@@ -3063,15 +3052,19 @@ off the stack.
                 ASSERT(0);
                 break;
 #endif /* PROVIDE_CONCURRENT */
+
         case i_ccall_ccall_Id:
         case i_ccall_ccall_IO:
         case i_ccall_stdcall_Id:
         case i_ccall_stdcall_IO:
             {
                 int r;
-                CFunDescriptor* descriptor = PopTaggedAddr();
-                void (*funPtr)(void)       = PopTaggedAddr();
-                char cc = (primop2code == i_ccall_stdcall_Id ||
+                CFunDescriptor* descriptor;
+                void (*funPtr)(void);
+                char cc;
+                descriptor = PopTaggedAddr();
+                funPtr     = PopTaggedAddr();
+                 cc = (primop2code == i_ccall_stdcall_Id ||
                            primop2code == i_ccall_stdcall_IO)
                           ? 's' : 'c';
                 r = ccall(descriptor,funPtr,bco,cc,cap);