diff VMS.c @ 8:9a1b7de19e39

Compiles -- with win thds
author Me
date Tue, 01 Jun 2010 05:33:01 -0700
parents cf5007e51b96
children d801fe740275
line diff
     1.1 --- a/VMS.c	Tue Jun 01 05:32:41 2010 -0700
     1.2 +++ b/VMS.c	Tue Jun 01 05:33:01 2010 -0700
     1.3 @@ -14,34 +14,38 @@
     1.4  
     1.5  /*Setup has two phases:
     1.6   * 1) Semantic layer first calls init_VMS, which creates masterEnv, and puts
     1.7 - *    the master work-unit into the work-queue
     1.8 - * 2) Semantic layer then does its own init, which creates the initial
     1.9 - *    work-units inside the semantic layer, ready to schedule them when
    1.10 + *    the master virt procr into the work-queue, ready for first "call"
    1.11 + * 2) Semantic layer then does its own init, which creates the seed virt
    1.12 + *    procr inside the semantic layer, ready to schedule it when
    1.13   *    asked by the first run of the masterLoop.
    1.14   *
    1.15   *This part is bit weird because VMS really wants to be "always there", and
    1.16   * have applications attach and detach..  for now, this VMS is part of
    1.17   * the app, so the VMS system starts up as part of running the app.
    1.18   *
    1.19 - *The semantic layer is fully isolated from the VMS internasl by
    1.20 - * making the semantic layer setup into a state that it's ready with its
    1.21 - * initial work-units, ready to schedule them to slaves when the masterLoop
    1.22 + *The semantic layer is isolated from the VMS internals by making the
    1.23 + * semantic layer do setup to a state that it's ready with its
    1.24 + * initial virt procrs, ready to schedule them to slots when the masterLoop
    1.25   * asks.  Without this pattern, the semantic layer's setup would
    1.26 - * have to modify slaves directly to assign the initial work-units, and put
    1.27 + * have to modify slots directly to assign the initial virt-procrs, and put
    1.28   * them into the workQ itself, breaking the isolation completely.
    1.29   *
    1.30   * 
    1.31 - *The semantic layer creates the initial work-unit(s), and adds its
    1.32 - * own environment data to masterEnv, and fills in the pointers to
    1.33 + *The semantic layer creates the initial virt procr(s), and adds its
    1.34 + * own environment to masterEnv, and fills in the pointers to
    1.35   * the requestHandler and slaveScheduler plug-in functions
    1.36 - *
    1.37 - *This allocates VMS data structures, populates the master VMSProc,
    1.38 + */
    1.39 +
    1.40 +void
    1.41 +create_sched_slots( MasterEnv *masterEnv );
    1.42 +
    1.43 +
    1.44 +/*This allocates VMS data structures, populates the master VMSProc,
    1.45   * and master environment, and returns the master environment to the semantic
    1.46   * layer.
    1.47   */
    1.48 -   //Global vars are all inside VMS.h
    1.49 -MasterEnv *
    1.50 -VMS__init(  )
    1.51 +void
    1.52 +VMS__init()
    1.53   { MasterEnv  *masterEnv;
    1.54     QueueStruc *workQ;
    1.55  
    1.56 @@ -52,71 +56,43 @@
    1.57     _VMSMasterEnv = malloc( sizeof(MasterEnv) );
    1.58     masterEnv     = _VMSMasterEnv;
    1.59  
    1.60 -   create_master( masterEnv );
    1.61 +      //create the master virtual processor
    1.62 +   masterEnv->masterVirtPr = VMS__create_procr( &masterLoop, masterEnv );
    1.63  
    1.64     create_sched_slots( masterEnv );
    1.65  
    1.66 -   masterEnv->schedSlots[0]->needsProcrAssigned  = FALSE;  //never checked
    1.67 -   masterEnv->schedSlots[0]->workIsDone          = FALSE;  //never checked
    1.68 +     //Set slot 0 to be the master virt procr & set flags just in case
    1.69 +   masterEnv->schedSlots[0]->needsProcrAssigned  = FALSE;  //says don't touch
    1.70 +   masterEnv->schedSlots[0]->workIsDone          = FALSE;  //says don't touch
    1.71     masterEnv->schedSlots[0]->procrAssignedToSlot = masterEnv->masterVirtPr;
    1.72  
    1.73        //First core loop to start up gets this, which will schedule seed Pr
    1.74        //TODO: debug: check address of masterVirtPr
    1.75 -   writeQ( &(masterEnv->masterVirtPr), workQ );
    1.76 +   writeQ( masterEnv->masterVirtPr, workQ );
    1.77   }
    1.78  
    1.79  
    1.80 -
    1.81 -/*Fill up the master VirtProcr data structure, which is already alloc'd
    1.82 - * in the masterEnv.
    1.83 - * The coreLoop treats master virt pr same as the slave virt processors
    1.84 - * 
    1.85 - *The first time it runs, will jump to the function ptr so have to, in here,
    1.86 - * create the stack, which will be used by the plug-in functions, and set
    1.87 - * up __cdecl just like do for the other virtual processors.
    1.88 - */
    1.89 -void
    1.90 -create_master( MasterEnv *masterEnv )
    1.91 - { VirtProcr masterPr;
    1.92 -   char * stackLocs, stackPtr;
    1.93 -
    1.94 -      //TODO: debug this to be sure got addr of struct in masterEnv correctly
    1.95 -   masterPr                = &(masterEnv->masterVirtPr);
    1.96 -   masterPr->initialData   = masterEnv;
    1.97 -
    1.98 -   masterPr->nextInstrPt   = &masterLoop;
    1.99 -
   1.100 -      //alloc stack locations, make stackPtr be the last addr in the locs,
   1.101 -      // minus room for the two parameters.  Put initData at stackPtr,
   1.102 -      // animatingPr just above
   1.103 -   stackLocs = malloc( 0x100000 ); //1 meg stack -- default Win thread's size
   1.104 -   stackPtr = ( (char *)stackLocs + 0x100000 - 0x8 );
   1.105 -   masterPr->stackPtr = stackPtr;
   1.106 -   masterPr->framePtr = stackPtr;
   1.107 -   asm volatile("movl %0, %%esp;
   1.108 -                 movl %1, (%%esp);
   1.109 -                 movl %2, $0x4(%%esp);
   1.110 -                 movl %%esp, %%ebp;   " /*framePtr in ebp never used*/
   1.111 -   /* outputs */ : 
   1.112 -   /* inputs  */ : "g" (stackPtr), "g" (initData),  "g" (animPr)
   1.113 -   /* clobber */ : 
   1.114 -                );
   1.115 - }
   1.116 -
   1.117  void
   1.118  create_sched_slots( MasterEnv *masterEnv )
   1.119 - { SchedSlot  *slots;
   1.120 + { SchedSlot  **schedSlots, **filledSlots;
   1.121     int i;
   1.122  
   1.123 -   slots = masterEnv->schedSlots;  //TODO: make sure this is right
   1.124 +   schedSlots  = malloc( NUM_SCHED_SLOTS * sizeof(SchedSlot *) );
   1.125 +   filledSlots = malloc( NUM_SCHED_SLOTS * sizeof(SchedSlot *) );
   1.126 +   masterEnv->schedSlots  = schedSlots;
   1.127 +   masterEnv->filledSlots = filledSlots;
   1.128 +
   1.129     for( i = 0; i < NUM_SCHED_SLOTS; i++ )
   1.130      {
   1.131 +      schedSlots[i] = malloc( sizeof(SchedSlot) );
   1.132 +
   1.133           //Set state to mean "handling requests done, slot needs filling"
   1.134 -      slots[i].workIsDone         = FALSE;
   1.135 -      slots[i].needsProcrAssigned = TRUE;
   1.136 +      schedSlots[i]->workIsDone         = FALSE;
   1.137 +      schedSlots[i]->needsProcrAssigned = TRUE;
   1.138      }
   1.139   }
   1.140  
   1.141 +
   1.142  /*Semantic layer calls this when it want the system to start running..
   1.143   *
   1.144   *This creates the core loops, pins them to physical cores, gives them the
   1.145 @@ -126,31 +102,70 @@
   1.146  VMS__start()
   1.147   { int retCode, coreIdx;
   1.148  
   1.149 -//TODO: still just skeleton code -- figure out right way to do this
   1.150 +   //Create the win threads that animate the core loops
   1.151 +   for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ )
   1.152 +    {
   1.153 +      thdParams[coreIdx]          = (ThdParams *)malloc( sizeof(ThdParams) );
   1.154 +      thdParams[coreIdx]->coreNum = coreIdx;
   1.155  
   1.156 -      //Create the PThread loops that take from work-queue, and start them
   1.157 -   for( coreIdx=0; coreIdx < NUM_WORKERS; coreIdx++ )
   1.158 -    {
   1.159 -      thdParams[coreIdx]        = (ThdParams *)malloc( sizeof(ThdParams) );
   1.160 -      thdParams[coreIdx]->workQ = _VMSWorkQ;
   1.161 -      thdParams[coreIdx]->id    = coreIdx;
   1.162 +      coreLoopThds[coreIdx] =
   1.163 +          CreateThread (   NULL, // Security attributes
   1.164 +                           0, // Stack size
   1.165 +                           coreLoop,
   1.166 +                           thdParams[coreIdx],
   1.167 +                           CREATE_SUSPENDED,
   1.168 +                           &(thdIds[coreIdx])
   1.169 +                          );
   1.170 +      ResumeThread( coreLoopThds[coreIdx] ); //starts thread
   1.171 +    }
   1.172 + }
   1.173  
   1.174 -         //Now make and start thd..  the coreLoopThds entry
   1.175 -         // has all the info needed to later stop the thread.
   1.176 -      retCode =
   1.177 -       pthread_create( &(coreLoopThds[coreIdx]), thdAttrs, &coreLoop,
   1.178 -                       (void *)(thdParams[coreIdx]) );
   1.179 -      if( retCode != 0 )
   1.180 -       { //error
   1.181 -         printf("ERROR creating coreLoop %d, code: %d\n", coreIdx, retCode);
   1.182 -         exit(-1);
   1.183 -       }
   1.184  
   1.185 -      pinThdToCore( );  //figure out how to specify this..
   1.186  
   1.187 -      startThd(); //look up PThread call to start the thread running, if it's
   1.188 -                  // not automatic
   1.189 -    }
   1.190 +/*Create stack, then create __cdecl structure on it and put initialData and
   1.191 + * pointer to the new structure instance into the parameter positions on
   1.192 + * the stack
   1.193 + *Then put function pointer into nextInstrPt -- the stack is setup in std
   1.194 + * call structure, so jumping to function ptr is same as a GCC generated
   1.195 + * function call
   1.196 + *No need to save registers on old stack frame, because there's no old
   1.197 + * animator state to return to --
   1.198 + *
   1.199 + */
   1.200 +VirtProcr *
   1.201 +VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData )
   1.202 + { VirtProcr *newPr;
   1.203 +   char      *stackLocs, *stackPtr;
   1.204 +
   1.205 +   newPr              = malloc( sizeof(VirtProcr) );
   1.206 +   newPr->nextInstrPt = fnPtr;
   1.207 +   newPr->initialData = initialData;
   1.208 +
   1.209 +      //alloc stack locations, make stackPtr be the highest addr minus room
   1.210 +      // for 2 params.  Put initData at stackPtr, animatingPr just above
   1.211 +   stackLocs = malloc( 0x100000 ); //1 meg stack -- default Win thread's size
   1.212 +   stackPtr = ( (char *)stackLocs + 0x100000 - 0x8 );
   1.213 +      //setup __cdecl on stack -- coreloop will switch to stackPtr before jmp
   1.214 +   *(stackPtr + 4) = newPr;  //rightmost param
   1.215 +   *stackPtr = initialData;  //next  param to left
   1.216 +   newPr->stackPtr = stackPtr; //core loop will switch to this, then
   1.217 +   newPr->framePtr = stackPtr; //suspend loop will save new stack & frame ptr
   1.218 +
   1.219 +   return newPr;
   1.220 + }
   1.221 +
   1.222 +
   1.223 +/*This inserts the semantic-layer's data into the standard VMS carrier
   1.224 + */
   1.225 +inline void
   1.226 +VMS__send_sem_request( void *semReqData, VirtProcr *callingPr )
   1.227 + { SlaveReqst *req;
   1.228 +
   1.229 +   req = malloc( sizeof(SlaveReqst) );
   1.230 +   req->slaveFrom      = callingPr;
   1.231 +   req->semReqData     = semReqData;
   1.232 +   req->nextRequest    = callingPr->requests;
   1.233 +   callingPr->requests = req;
   1.234   }
   1.235  
   1.236   /*there is a label inside this function -- save the addr of this label in
   1.237 @@ -162,8 +177,9 @@
   1.238   * there, and will get passed along, inside the request handler, to the
   1.239   * next work-unit for that procr.
   1.240   */
   1.241 +void
   1.242  VMS__suspend_processor( VirtProcr *callingPr )
   1.243 - { void *jmpPt;
   1.244 + { void *jmpPt, *stackPtr, *framePtr;
   1.245  
   1.246     callingPr->nextInstrPt = &&ResumePt;
   1.247  
   1.248 @@ -171,13 +187,15 @@
   1.249     callingPr->schedSlot->workIsDone = TRUE;
   1.250  
   1.251     jmpPt    = callingPr->coreLoopStartPt;
   1.252 +   stackPtr = &(callingPr->stackPtr);
   1.253 +   framePtr = &(callingPr->framePtr);
   1.254  
   1.255        //put all regs in the clobber list to make sure GCC has saved all
   1.256        // so safe to jump to core loop, where they *will* get clobbered
   1.257 -   asm volatile("movl %%esp, %0;
   1.258 -                 movl %%ebp, %1;
   1.259 -                 jmp  %2        "
   1.260 -   /* outputs */ : "=m" (currPr->stackPtr), "=m" (currPr->framePtr)
   1.261 +   asm volatile("movl %%esp, %0; \
   1.262 +                 movl %%ebp, %1; \
   1.263 +                 jmp  %2         "
   1.264 +   /* outputs */ : "=g" (stackPtr), "=g" (framePtr)
   1.265     /* inputs  */ : "g" (jmpPt)
   1.266     /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%edi","%esi"
   1.267                  );
   1.268 @@ -186,45 +204,29 @@
   1.269     return;
   1.270   }
   1.271  
   1.272 +void
   1.273 +VMS__dissipate_animating_processor( VirtProcr *animatingPr )
   1.274 + {
   1.275  
   1.276 -/*Create stack, then create __cdecl structure on it and put initialData and
   1.277 - * pointer to the new structure instance into the parameter positions on
   1.278 - * the stack
   1.279 - *Then put function pointer into nextInstrPt -- the stack is setup in std
   1.280 - * call structure, so jumping to function ptr is same as a GCC generated
   1.281 - * function call
   1.282 - *No need to save registers on old stack frame, because there's no old
   1.283 - * animator state to return to -- 
   1.284 - *
   1.285 - */
   1.286 -VirtProcr *
   1.287 -VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData )
   1.288 - { VirtProcr   newPr;
   1.289 -
   1.290 -   newPr              = malloc( sizeof(VirtProcr) );
   1.291 -   newPr->nextInstrPt = fnPtr;
   1.292 -   newPr->initialData = initialData;
   1.293 -   newPr->stackPtr    = createNewStack();
   1.294 -   newPr->framePtr    = newPr->stackPtr;
   1.295 -   put params onto stack and setup __cdecl call structure
   1.296 -
   1.297 -   return newPr;
   1.298   }
   1.299  
   1.300 +/*This runs in main thread -- so can only signal to the core loop to shut
   1.301 + * itself down --
   1.302 + *
   1.303 + *Want the master to decide when to shut down -- when semantic layer tells it
   1.304 + * to -- say, when all the application-virtual processors have dissipated.
   1.305 + *
   1.306 + *Maybe return a special code from scheduling plug-in..  master checks and
   1.307 + * when sees, it shuts down the core loops -- does this by scheduling a
   1.308 + * special virt processor whose next instr pt is the core-end label.
   1.309 + */
   1.310 +void
   1.311 +VMS__shutdown()
   1.312 + { int coreIdx;
   1.313 + 
   1.314 +   //Create the win threads that animate the core loops
   1.315 +   for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ )
   1.316 +    {
   1.317  
   1.318 -/*The semantic virt procr is available in the request sent from the slave
   1.319 - * 
   1.320 - * The request handler has to add the work-unit created to the semantic
   1.321 - * virtual processor the work-unit is a section of its time-line -- does this when create the
   1.322 - * work-unit -- means the procr data struc is available in the request sent
   1.323 - * from the slave, from which the new work-unit is generated..
   1.324 - */
   1.325 -inline void
   1.326 -VMS__add_request_to_slave( SlaveReqst req, VirtProcr callingPr )
   1.327 - { 
   1.328 -   req->nextRequest =  callingPr->requests;
   1.329 -   callingPr->requests = req;
   1.330 - }
   1.331 -
   1.332 -
   1.333 -
   1.334 +    }
   1.335 + }
   1.336 \ No newline at end of file