# HG changeset patch # User Me # Date 1275395581 25200 # Node ID 9a1b7de19e399fe574046c970016dcb57426f81a # Parent f96e4b3b35c7da6573b6cffb6f5739ffb0d1341e Compiles -- with win thds diff -r f96e4b3b35c7 -r 9a1b7de19e39 VMS.c --- a/VMS.c Tue Jun 01 05:32:41 2010 -0700 +++ b/VMS.c Tue Jun 01 05:33:01 2010 -0700 @@ -14,34 +14,38 @@ /*Setup has two phases: * 1) Semantic layer first calls init_VMS, which creates masterEnv, and puts - * the master work-unit into the work-queue - * 2) Semantic layer then does its own init, which creates the initial - * work-units inside the semantic layer, ready to schedule them when + * the master virt procr into the work-queue, ready for first "call" + * 2) Semantic layer then does its own init, which creates the seed virt + * procr inside the semantic layer, ready to schedule it when * asked by the first run of the masterLoop. * *This part is bit weird because VMS really wants to be "always there", and * have applications attach and detach.. for now, this VMS is part of * the app, so the VMS system starts up as part of running the app. * - *The semantic layer is fully isolated from the VMS internasl by - * making the semantic layer setup into a state that it's ready with its - * initial work-units, ready to schedule them to slaves when the masterLoop + *The semantic layer is isolated from the VMS internals by making the + * semantic layer do setup to a state that it's ready with its + * initial virt procrs, ready to schedule them to slots when the masterLoop * asks. Without this pattern, the semantic layer's setup would - * have to modify slaves directly to assign the initial work-units, and put + * have to modify slots directly to assign the initial virt-procrs, and put * them into the workQ itself, breaking the isolation completely. * * - *The semantic layer creates the initial work-unit(s), and adds its - * own environment data to masterEnv, and fills in the pointers to + *The semantic layer creates the initial virt procr(s), and adds its + * own environment to masterEnv, and fills in the pointers to * the requestHandler and slaveScheduler plug-in functions - * - *This allocates VMS data structures, populates the master VMSProc, + */ + +void +create_sched_slots( MasterEnv *masterEnv ); + + +/*This allocates VMS data structures, populates the master VMSProc, * and master environment, and returns the master environment to the semantic * layer. */ - //Global vars are all inside VMS.h -MasterEnv * -VMS__init( ) +void +VMS__init() { MasterEnv *masterEnv; QueueStruc *workQ; @@ -52,71 +56,43 @@ _VMSMasterEnv = malloc( sizeof(MasterEnv) ); masterEnv = _VMSMasterEnv; - create_master( masterEnv ); + //create the master virtual processor + masterEnv->masterVirtPr = VMS__create_procr( &masterLoop, masterEnv ); create_sched_slots( masterEnv ); - masterEnv->schedSlots[0]->needsProcrAssigned = FALSE; //never checked - masterEnv->schedSlots[0]->workIsDone = FALSE; //never checked + //Set slot 0 to be the master virt procr & set flags just in case + masterEnv->schedSlots[0]->needsProcrAssigned = FALSE; //says don't touch + masterEnv->schedSlots[0]->workIsDone = FALSE; //says don't touch masterEnv->schedSlots[0]->procrAssignedToSlot = masterEnv->masterVirtPr; //First core loop to start up gets this, which will schedule seed Pr //TODO: debug: check address of masterVirtPr - writeQ( &(masterEnv->masterVirtPr), workQ ); + writeQ( masterEnv->masterVirtPr, workQ ); } - -/*Fill up the master VirtProcr data structure, which is already alloc'd - * in the masterEnv. - * The coreLoop treats master virt pr same as the slave virt processors - * - *The first time it runs, will jump to the function ptr so have to, in here, - * create the stack, which will be used by the plug-in functions, and set - * up __cdecl just like do for the other virtual processors. - */ -void -create_master( MasterEnv *masterEnv ) - { VirtProcr masterPr; - char * stackLocs, stackPtr; - - //TODO: debug this to be sure got addr of struct in masterEnv correctly - masterPr = &(masterEnv->masterVirtPr); - masterPr->initialData = masterEnv; - - masterPr->nextInstrPt = &masterLoop; - - //alloc stack locations, make stackPtr be the last addr in the locs, - // minus room for the two parameters. Put initData at stackPtr, - // animatingPr just above - stackLocs = malloc( 0x100000 ); //1 meg stack -- default Win thread's size - stackPtr = ( (char *)stackLocs + 0x100000 - 0x8 ); - masterPr->stackPtr = stackPtr; - masterPr->framePtr = stackPtr; - asm volatile("movl %0, %%esp; - movl %1, (%%esp); - movl %2, $0x4(%%esp); - movl %%esp, %%ebp; " /*framePtr in ebp never used*/ - /* outputs */ : - /* inputs */ : "g" (stackPtr), "g" (initData), "g" (animPr) - /* clobber */ : - ); - } - void create_sched_slots( MasterEnv *masterEnv ) - { SchedSlot *slots; + { SchedSlot **schedSlots, **filledSlots; int i; - slots = masterEnv->schedSlots; //TODO: make sure this is right + schedSlots = malloc( NUM_SCHED_SLOTS * sizeof(SchedSlot *) ); + filledSlots = malloc( NUM_SCHED_SLOTS * sizeof(SchedSlot *) ); + masterEnv->schedSlots = schedSlots; + masterEnv->filledSlots = filledSlots; + for( i = 0; i < NUM_SCHED_SLOTS; i++ ) { + schedSlots[i] = malloc( sizeof(SchedSlot) ); + //Set state to mean "handling requests done, slot needs filling" - slots[i].workIsDone = FALSE; - slots[i].needsProcrAssigned = TRUE; + schedSlots[i]->workIsDone = FALSE; + schedSlots[i]->needsProcrAssigned = TRUE; } } + /*Semantic layer calls this when it want the system to start running.. * *This creates the core loops, pins them to physical cores, gives them the @@ -126,31 +102,70 @@ VMS__start() { int retCode, coreIdx; -//TODO: still just skeleton code -- figure out right way to do this + //Create the win threads that animate the core loops + for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) + { + thdParams[coreIdx] = (ThdParams *)malloc( sizeof(ThdParams) ); + thdParams[coreIdx]->coreNum = coreIdx; - //Create the PThread loops that take from work-queue, and start them - for( coreIdx=0; coreIdx < NUM_WORKERS; coreIdx++ ) - { - thdParams[coreIdx] = (ThdParams *)malloc( sizeof(ThdParams) ); - thdParams[coreIdx]->workQ = _VMSWorkQ; - thdParams[coreIdx]->id = coreIdx; + coreLoopThds[coreIdx] = + CreateThread ( NULL, // Security attributes + 0, // Stack size + coreLoop, + thdParams[coreIdx], + CREATE_SUSPENDED, + &(thdIds[coreIdx]) + ); + ResumeThread( coreLoopThds[coreIdx] ); //starts thread + } + } - //Now make and start thd.. the coreLoopThds entry - // has all the info needed to later stop the thread. - retCode = - pthread_create( &(coreLoopThds[coreIdx]), thdAttrs, &coreLoop, - (void *)(thdParams[coreIdx]) ); - if( retCode != 0 ) - { //error - printf("ERROR creating coreLoop %d, code: %d\n", coreIdx, retCode); - exit(-1); - } - pinThdToCore( ); //figure out how to specify this.. - startThd(); //look up PThread call to start the thread running, if it's - // not automatic - } +/*Create stack, then create __cdecl structure on it and put initialData and + * pointer to the new structure instance into the parameter positions on + * the stack + *Then put function pointer into nextInstrPt -- the stack is setup in std + * call structure, so jumping to function ptr is same as a GCC generated + * function call + *No need to save registers on old stack frame, because there's no old + * animator state to return to -- + * + */ +VirtProcr * +VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData ) + { VirtProcr *newPr; + char *stackLocs, *stackPtr; + + newPr = malloc( sizeof(VirtProcr) ); + newPr->nextInstrPt = fnPtr; + newPr->initialData = initialData; + + //alloc stack locations, make stackPtr be the highest addr minus room + // for 2 params. Put initData at stackPtr, animatingPr just above + stackLocs = malloc( 0x100000 ); //1 meg stack -- default Win thread's size + stackPtr = ( (char *)stackLocs + 0x100000 - 0x8 ); + //setup __cdecl on stack -- coreloop will switch to stackPtr before jmp + *(stackPtr + 4) = newPr; //rightmost param + *stackPtr = initialData; //next param to left + newPr->stackPtr = stackPtr; //core loop will switch to this, then + newPr->framePtr = stackPtr; //suspend loop will save new stack & frame ptr + + return newPr; + } + + +/*This inserts the semantic-layer's data into the standard VMS carrier + */ +inline void +VMS__send_sem_request( void *semReqData, VirtProcr *callingPr ) + { SlaveReqst *req; + + req = malloc( sizeof(SlaveReqst) ); + req->slaveFrom = callingPr; + req->semReqData = semReqData; + req->nextRequest = callingPr->requests; + callingPr->requests = req; } /*there is a label inside this function -- save the addr of this label in @@ -162,8 +177,9 @@ * there, and will get passed along, inside the request handler, to the * next work-unit for that procr. */ +void VMS__suspend_processor( VirtProcr *callingPr ) - { void *jmpPt; + { void *jmpPt, *stackPtr, *framePtr; callingPr->nextInstrPt = &&ResumePt; @@ -171,13 +187,15 @@ callingPr->schedSlot->workIsDone = TRUE; jmpPt = callingPr->coreLoopStartPt; + stackPtr = &(callingPr->stackPtr); + framePtr = &(callingPr->framePtr); //put all regs in the clobber list to make sure GCC has saved all // so safe to jump to core loop, where they *will* get clobbered - asm volatile("movl %%esp, %0; - movl %%ebp, %1; - jmp %2 " - /* outputs */ : "=m" (currPr->stackPtr), "=m" (currPr->framePtr) + asm volatile("movl %%esp, %0; \ + movl %%ebp, %1; \ + jmp %2 " + /* outputs */ : "=g" (stackPtr), "=g" (framePtr) /* inputs */ : "g" (jmpPt) /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%edi","%esi" ); @@ -186,45 +204,29 @@ return; } +void +VMS__dissipate_animating_processor( VirtProcr *animatingPr ) + { -/*Create stack, then create __cdecl structure on it and put initialData and - * pointer to the new structure instance into the parameter positions on - * the stack - *Then put function pointer into nextInstrPt -- the stack is setup in std - * call structure, so jumping to function ptr is same as a GCC generated - * function call - *No need to save registers on old stack frame, because there's no old - * animator state to return to -- - * - */ -VirtProcr * -VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData ) - { VirtProcr newPr; - - newPr = malloc( sizeof(VirtProcr) ); - newPr->nextInstrPt = fnPtr; - newPr->initialData = initialData; - newPr->stackPtr = createNewStack(); - newPr->framePtr = newPr->stackPtr; - put params onto stack and setup __cdecl call structure - - return newPr; } +/*This runs in main thread -- so can only signal to the core loop to shut + * itself down -- + * + *Want the master to decide when to shut down -- when semantic layer tells it + * to -- say, when all the application-virtual processors have dissipated. + * + *Maybe return a special code from scheduling plug-in.. master checks and + * when sees, it shuts down the core loops -- does this by scheduling a + * special virt processor whose next instr pt is the core-end label. + */ +void +VMS__shutdown() + { int coreIdx; + + //Create the win threads that animate the core loops + for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) + { -/*The semantic virt procr is available in the request sent from the slave - * - * The request handler has to add the work-unit created to the semantic - * virtual processor the work-unit is a section of its time-line -- does this when create the - * work-unit -- means the procr data struc is available in the request sent - * from the slave, from which the new work-unit is generated.. - */ -inline void -VMS__add_request_to_slave( SlaveReqst req, VirtProcr callingPr ) - { - req->nextRequest = callingPr->requests; - callingPr->requests = req; - } - - - + } + } \ No newline at end of file