[project @ 2000-04-27 16:35:29 by sewardj]
[ghc-hetmet.git] / ghc / rts / Evaluator.c
index 825d38f..e0a6558 100644 (file)
@@ -5,8 +5,8 @@
  * Copyright (c) 1994-1998.
  *
  * $RCSfile: Evaluator.c,v $
- * $Revision: 1.40 $
- * $Date: 2000/03/14 14:34:47 $
+ * $Revision: 1.50 $
+ * $Date: 2000/04/27 16:35:30 $
  * ---------------------------------------------------------------------------*/
 
 #include "Rts.h"
@@ -24,6 +24,7 @@
 #include "ForeignCall.h"
 #include "PrimOps.h"   /* for __{encode,decode}{Float,Double} */
 #include "Prelude.h"
+#include "Itimer.h"
 #include "Evaluator.h"
 #include "sainteger.h"
 
@@ -42,6 +43,9 @@
 #endif
 
 
+/* Allegedly useful macro, taken from ClosureMacros.h */
+#define payloadWord( c, i )   (*stgCast(StgWord*,      ((c)->payload+(i))))
+#define payloadPtr( c, i )    (*stgCast(StgPtr*,       ((c)->payload+(i))))
 
 /* An incredibly useful abbreviation.
  * Interestingly, there are some uses of END_TSO_QUEUE_closure that
@@ -67,8 +71,8 @@
 /* Make it possible for the evaluator to get hold of bytecode
    for a given function by name.  Useful but a hack.  Sigh.
  */
-extern void* getHugs_AsmObject_for ( char* s );
-extern int /*Bool*/ combined;
+extern void* /* StgClosure* */ getHugs_BCO_cptr_for ( char* s );
+extern int   /* Bool */ combined;
 
 /* --------------------------------------------------------------------------
  * Crude profiling stuff (mainly to assess effect of optimiser)
@@ -103,6 +107,7 @@ void cp_init ( void )
 }
 
 
+
 void cp_enter ( StgBCO* b )
 {
    int is_ret_cont;
@@ -254,6 +259,12 @@ void setRtsFlags( int x )
 }
 
 
+typedef struct { 
+  StgTSOBlockReason reason;
+  unsigned int delay;
+} HugsBlock;
+
+
 /* --------------------------------------------------------------------------
  * Entering-objects and bytecode interpreter part of evaluator
  * ------------------------------------------------------------------------*/
@@ -283,7 +294,7 @@ void setRtsFlags( int x )
 /* Forward decls ... */
 static        void* enterBCO_primop1 ( int );
 static        void* enterBCO_primop2 ( int , int* /*StgThreadReturnCode* */, 
-                                       StgBCO**, Capability* );
+                                       StgBCO**, Capability*, HugsBlock * );
 static inline void PopUpdateFrame ( StgClosure* obj );
 static inline void PopCatchFrame  ( void );
 static inline void PopSeqFrame    ( void );
@@ -452,6 +463,10 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
     register StgClosure*      obj;    /* object currently under evaluation */
              char             eCount; /* enter counter, for context switching */
 
+
+   HugsBlock hugsBlock = { NotBlocked, 0 };
+
+
 #ifdef DEBUG
     StgPtr tSp; StgUpdateFrame* tSu; StgPtr tSpLim;
 #endif
@@ -476,6 +491,8 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
 
     enterLoop:
 
+    numEnters++;
+
 #ifdef DEBUG
     assert(gSp == tSp);
     assert(gSu == tSu);
@@ -503,8 +520,35 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
 #endif
        ) {
        if (context_switch) {
-          xPushCPtr(obj); /* code to restart with */
-          RETURN(ThreadYielding);
+        switch(hugsBlock.reason) {
+        case NotBlocked: {
+          xPushCPtr(obj); /* code to restart with */
+          RETURN(ThreadYielding);
+        }
+        case BlockedOnDelay: /* fall through */
+        case BlockedOnRead:  /* fall through */
+        case BlockedOnWrite: {
+          ASSERT(cap->rCurrentTSO->why_blocked == NotBlocked);
+          cap->rCurrentTSO->why_blocked = BlockedOnDelay;
+          ACQUIRE_LOCK(&sched_mutex);
+          
+#if defined(HAVE_SETITIMER) || defined(mingw32_TARGET_OS)
+          cap->rCurrentTSO->block_info.delay 
+            = hugsBlock.delay + ticks_since_select;
+#else
+          cap->rCurrentTSO->block_info.target
+            = hugsBlock.delay + getourtimeofday();
+#endif
+          APPEND_TO_BLOCKED_QUEUE(cap->rCurrentTSO);
+          
+          RELEASE_LOCK(&sched_mutex);
+          
+          xPushCPtr(obj); /* code to restart with */
+          RETURN(ThreadBlocked);
+        }
+        default:
+          barf("Unknown context switch reasoning");
+        }
        }
     }
 
@@ -646,8 +690,12 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
                                      xPopUpdateFrame(obj);
                                      break;
                                 case STOP_FRAME:
+                                     barf("STOP frame during pap update");
+#if 0
+                                    cap->rCurrentTSO->what_next = ThreadComplete;
                                      SSS; PopStopFrame(obj); LLL;
                                      RETURN(ThreadFinished);
+#endif
                                 case SEQ_FRAME:
                                      SSS; PopSeqFrame(); LLL;
                                      ASSERT(xSp != (P_)xSu);
@@ -772,7 +820,7 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
                     nat np = info->layout.payload.nptrs; 
                     nat i;
                     for(i=0; i < p; ++i) {
-                        payloadCPtr(o,i) = xPopCPtr();
+                        o->payload[i] = xPopCPtr();
                     }
                     for(i=0; i < np; ++i) {
                         payloadWord(o,p+i) = 0xdeadbeef;
@@ -794,7 +842,7 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
                     nat np = info->layout.payload.nptrs; 
                     nat i;
                     for(i=0; i < p; ++i) {
-                        payloadCPtr(o,i) = xPopCPtr();
+                        o->payload[i] = xPopCPtr();
                     }
                     for(i=0; i < np; ++i) {
                         payloadWord(o,p+i) = 0xdeadbeef;
@@ -867,7 +915,7 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
                           || itbl->type == CONSTR_0_2
                           );
                     while (--i>=0) {
-                        xPushCPtr(payloadCPtr(o,i));
+                        xPushCPtr(o->payload[i]);
                     }
                     Continue;
                 }
@@ -1185,7 +1233,8 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
                     pc_saved = PC; 
                     bco_tmp  = bco;
                     SSS;
-                    p        = enterBCO_primop2 ( i, &trc, &bco_tmp, cap ); 
+                    p        = enterBCO_primop2 ( i, &trc, &bco_tmp, cap, 
+                                                 &hugsBlock ); 
                     LLL;
                     bco      = bco_tmp;
                     bciPtr   = &(bcoInstr(bco,pc_saved));
@@ -1194,8 +1243,9 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
                           /* we want to enter p */
                           obj = p; goto enterLoop;
                        } else {
-                          /* trc is the the StgThreadReturnCode for this thread */
-                          RETURN((StgThreadReturnCode)trc);
+                          /* trc is the the StgThreadReturnCode for 
+                          * this thread */
+                        RETURN((StgThreadReturnCode)trc);
                        };
                     }
                     Continue;
@@ -1312,22 +1362,19 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
                 xPushCPtr(obj); /* code to restart with */
                 RETURN(StackOverflow);
             }
-            /* ToDo: look for xSp==xSu && stackInt(0) == UPD_FRAME 
-               and insert an indirection immediately */
             SSS; bh = (StgBlockingQueue*)grabHpUpd(BLACKHOLE_sizeW()); LLL;
             SET_INFO(bh,&CAF_BLACKHOLE_info);
             bh->blocking_queue = EndTSOQueue;
             IF_DEBUG(gccafs,
-                     fprintf(stderr,"Created CAF_BLACKHOLE %p for CAF %p in evaluator\n",bh,caf));
+                     fprintf(stderr,"Created CAF_BLACKHOLE %p for CAF %p"
+                                    " in evaluator\n",bh,caf));
             SET_INFO(caf,&CAF_ENTERED_info);
             caf->value = (StgClosure*)bh;
-            if (caf->mut_link == NULL) { 
-               SSS; recordOldToNewPtrs((StgMutClosure*)caf); LLL; 
-            }
+
+            SSS; newCAF_made_by_Hugs(caf); LLL;
+
             xPushUpdateFrame(bh,0);
             xSp -= sizeofW(StgUpdateFrame);
-            caf->link = enteredCAFs;
-            enteredCAFs = caf;
             obj = caf->body;
             goto enterLoop;
         }
@@ -1343,7 +1390,7 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
     case SE_CAF_BLACKHOLE:
         {
             /* Let the scheduler figure out what to do :-) */
-            cap->rCurrentTSO->whatNext = ThreadEnterGHC;
+            cap->rCurrentTSO->what_next = ThreadEnterGHC;
             xPushCPtr(obj);
             RETURN(ThreadYielding);
         }
@@ -1435,7 +1482,9 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
                                                 + cap->rCurrentTSO->stack_size,xSu);
                                  LLL;
                                  );
+                        cap->rCurrentTSO->what_next = ThreadComplete;
                         SSS; PopStopFrame(obj); LLL;
+                        xPushPtr((P_)obj);
                         RETURN(ThreadFinished);
                     }
                 case RET_BCO:
@@ -1454,7 +1503,7 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
                 case RET_VEC_SMALL:
                 case RET_BIG:
                 case RET_VEC_BIG:
-                        cap->rCurrentTSO->whatNext = ThreadEnterGHC;
+                        cap->rCurrentTSO->what_next = ThreadEnterGHC;
                         xPushCPtr(obj);
                         RETURN(ThreadYielding);
                 default:
@@ -1475,7 +1524,7 @@ StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
             //fprintf(stderr, "entering unknown closure -- yielding to sched\n"); 
             //printObj(obj);
             //LLL;
-            cap->rCurrentTSO->whatNext = ThreadEnterGHC;
+            cap->rCurrentTSO->what_next = ThreadEnterGHC;
             xPushCPtr(obj); /* code to restart with */
             RETURN(ThreadYielding);
         }
@@ -1744,7 +1793,7 @@ static inline StgClosure* raiseAnError ( StgClosure* exception )
      * thunks which are currently under evaluation.
      */
     HaskellObj primRaiseClosure
-       = asmClosureOfObject(getHugs_AsmObject_for("primRaise"));
+       = getHugs_BCO_cptr_for("primRaise");
     HaskellObj reraiseClosure
        = rts_apply ( primRaiseClosure, exception );
    
@@ -1785,9 +1834,9 @@ static StgClosure* makeErrorCall ( const char* msg )
       (thinks: probably not so, but anyway ...)
    */
    HaskellObj error 
-      = asmClosureOfObject(getHugs_AsmObject_for("error"));
+      = getHugs_BCO_cptr_for("error");
    HaskellObj unpack
-      = asmClosureOfObject(getHugs_AsmObject_for("hugsprimUnpackString"));
+      = getHugs_BCO_cptr_for("hugsprimUnpackString");
    HaskellObj thunk
       = rts_apply ( unpack, rts_mkAddr ( (void*)msg ) );
    thunk
@@ -2644,11 +2693,14 @@ static void* enterBCO_primop1 ( int primop1code )
       return the address of it and leave *return2 unchanged.
    To return a StgThreadReturnCode to the scheduler,
       set *return2 to it and return a non-NULL value.
+   To cause a context switch, set context_switch (its a global),
+   and optionally set hugsBlock to your rational.
 */
 static void* enterBCO_primop2 ( int primop2code, 
                                 int* /*StgThreadReturnCode* */ return2,
                                 StgBCO** bco,
-                                Capability* cap )
+                                Capability* cap,
+                               HugsBlock *hugsBlock )
 {
         if (combined) {
           /* A small concession: we need to allow ccalls, 
@@ -2845,7 +2897,7 @@ static void* enterBCO_primop2 ( int primop2code,
 #endif
 #ifdef PROVIDE_FOREIGN
                 /* ForeignObj# operations */
-        case i_makeForeignObj:
+        case i_mkForeignObj:
             {
                 StgForeignObj *result 
                     = stgCast(StgForeignObj*,allocate(sizeofW(StgForeignObj)));
@@ -3015,21 +3067,7 @@ static void* enterBCO_primop2 ( int primop2code,
                 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;
-            }
+#ifdef PROVIDE_CONCURRENT
         case i_forkIO:
             {
                 StgClosure* closure;
@@ -3040,14 +3078,31 @@ static void* enterBCO_primop2 ( int primop2code,
                 tid     = tso->id;
                 scheduleThread(tso);
                 context_switch = 1;
+               /* Later: Change to use tso as the ThreadId */
                 PushTaggedWord(tid);
                 break;
             }
 
-#ifdef PROVIDE_CONCURRENT
         case i_killThread:
             {
-                StgTSO* tso = stgCast(StgTSO*,PopPtr());
+                StgWord n = PopTaggedWord();
+               StgTSO* tso = 0;
+               StgTSO *t;
+
+               // Map from ThreadId to Thread Structure */
+               for (t = all_threads; t != END_TSO_QUEUE; t = t->global_link) {
+                 if (n == t->id)
+                   tso = t;
+               }
+               if (tso == 0) {
+                 // Already dead
+                 break;
+               }
+
+               while (tso->what_next == ThreadRelocated) {
+                 tso = tso->link;
+               }
+
                 deleteThread(tso);
                 if (tso == cap->rCurrentTSO) { /* suicide */
                     *return2 = ThreadFinished;
@@ -3055,13 +3110,55 @@ static void* enterBCO_primop2 ( int primop2code,
                 }
                 break;
             }
-
+        case i_raiseInThread:
+         ASSERT(0); /* not (yet) supported */
         case i_delay:
+         {
+           StgInt  n = PopTaggedInt();
+           context_switch = 1;
+           hugsBlock->reason = BlockedOnDelay;
+           hugsBlock->delay = n;
+           break;
+         }
         case i_waitRead:
+         {
+           StgInt  n = PopTaggedInt();
+           context_switch = 1;
+           hugsBlock->reason = BlockedOnRead;
+           hugsBlock->delay = n;
+           break;
+         }
         case i_waitWrite:
-                /* As PrimOps.h says: Hmm, I'll think about these later. */
-                ASSERT(0);
+         {
+           StgInt  n = PopTaggedInt();
+           context_switch = 1;
+           hugsBlock->reason = BlockedOnWrite;
+           hugsBlock->delay = n;
+           break;
+         }
+       case i_yield:
+         {
+           /* The definition of yield include an enter right after
+            * the primYield, at which time context_switch is tested.
+            */
+           context_switch = 1;
+           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;
+            }
 #endif /* PROVIDE_CONCURRENT */
 
         case i_ccall_ccall_Id:
@@ -3429,5 +3526,4 @@ void B__decodeFloat (B* man, I_* exp, StgFloat flt)
 }
 
 #endif /* FLOATS_AS_DOUBLES */
-
 #endif /* INTERPRETER */