Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
comparison VMS.c @ 8:9a1b7de19e39
Compiles -- with win thds
| author | Me |
|---|---|
| date | Tue, 01 Jun 2010 05:33:01 -0700 |
| parents | cf5007e51b96 |
| children | d801fe740275 |
comparison
equal
deleted
inserted
replaced
| 1:c3d3af1bdd18 | 2:e330519cdcd3 |
|---|---|
| 12 #include "Queue_impl/BlockingQueue.h" | 12 #include "Queue_impl/BlockingQueue.h" |
| 13 | 13 |
| 14 | 14 |
| 15 /*Setup has two phases: | 15 /*Setup has two phases: |
| 16 * 1) Semantic layer first calls init_VMS, which creates masterEnv, and puts | 16 * 1) Semantic layer first calls init_VMS, which creates masterEnv, and puts |
| 17 * the master work-unit into the work-queue | 17 * the master virt procr into the work-queue, ready for first "call" |
| 18 * 2) Semantic layer then does its own init, which creates the initial | 18 * 2) Semantic layer then does its own init, which creates the seed virt |
| 19 * work-units inside the semantic layer, ready to schedule them when | 19 * procr inside the semantic layer, ready to schedule it when |
| 20 * asked by the first run of the masterLoop. | 20 * asked by the first run of the masterLoop. |
| 21 * | 21 * |
| 22 *This part is bit weird because VMS really wants to be "always there", and | 22 *This part is bit weird because VMS really wants to be "always there", and |
| 23 * have applications attach and detach.. for now, this VMS is part of | 23 * have applications attach and detach.. for now, this VMS is part of |
| 24 * the app, so the VMS system starts up as part of running the app. | 24 * the app, so the VMS system starts up as part of running the app. |
| 25 * | 25 * |
| 26 *The semantic layer is fully isolated from the VMS internasl by | 26 *The semantic layer is isolated from the VMS internals by making the |
| 27 * making the semantic layer setup into a state that it's ready with its | 27 * semantic layer do setup to a state that it's ready with its |
| 28 * initial work-units, ready to schedule them to slaves when the masterLoop | 28 * initial virt procrs, ready to schedule them to slots when the masterLoop |
| 29 * asks. Without this pattern, the semantic layer's setup would | 29 * asks. Without this pattern, the semantic layer's setup would |
| 30 * have to modify slaves directly to assign the initial work-units, and put | 30 * have to modify slots directly to assign the initial virt-procrs, and put |
| 31 * them into the workQ itself, breaking the isolation completely. | 31 * them into the workQ itself, breaking the isolation completely. |
| 32 * | 32 * |
| 33 * | 33 * |
| 34 *The semantic layer creates the initial work-unit(s), and adds its | 34 *The semantic layer creates the initial virt procr(s), and adds its |
| 35 * own environment data to masterEnv, and fills in the pointers to | 35 * own environment to masterEnv, and fills in the pointers to |
| 36 * the requestHandler and slaveScheduler plug-in functions | 36 * the requestHandler and slaveScheduler plug-in functions |
| 37 * | 37 */ |
| 38 *This allocates VMS data structures, populates the master VMSProc, | 38 |
| 39 void | |
| 40 create_sched_slots( MasterEnv *masterEnv ); | |
| 41 | |
| 42 | |
| 43 /*This allocates VMS data structures, populates the master VMSProc, | |
| 39 * and master environment, and returns the master environment to the semantic | 44 * and master environment, and returns the master environment to the semantic |
| 40 * layer. | 45 * layer. |
| 41 */ | 46 */ |
| 42 //Global vars are all inside VMS.h | 47 void |
| 43 MasterEnv * | 48 VMS__init() |
| 44 VMS__init( ) | |
| 45 { MasterEnv *masterEnv; | 49 { MasterEnv *masterEnv; |
| 46 QueueStruc *workQ; | 50 QueueStruc *workQ; |
| 47 | 51 |
| 48 //Make the central work-queue | 52 //Make the central work-queue |
| 49 _VMSWorkQ = makeQ(); | 53 _VMSWorkQ = makeQ(); |
| 50 workQ = _VMSWorkQ; | 54 workQ = _VMSWorkQ; |
| 51 | 55 |
| 52 _VMSMasterEnv = malloc( sizeof(MasterEnv) ); | 56 _VMSMasterEnv = malloc( sizeof(MasterEnv) ); |
| 53 masterEnv = _VMSMasterEnv; | 57 masterEnv = _VMSMasterEnv; |
| 54 | 58 |
| 55 create_master( masterEnv ); | 59 //create the master virtual processor |
| 60 masterEnv->masterVirtPr = VMS__create_procr( &masterLoop, masterEnv ); | |
| 56 | 61 |
| 57 create_sched_slots( masterEnv ); | 62 create_sched_slots( masterEnv ); |
| 58 | 63 |
| 59 masterEnv->schedSlots[0]->needsProcrAssigned = FALSE; //never checked | 64 //Set slot 0 to be the master virt procr & set flags just in case |
| 60 masterEnv->schedSlots[0]->workIsDone = FALSE; //never checked | 65 masterEnv->schedSlots[0]->needsProcrAssigned = FALSE; //says don't touch |
| 66 masterEnv->schedSlots[0]->workIsDone = FALSE; //says don't touch | |
| 61 masterEnv->schedSlots[0]->procrAssignedToSlot = masterEnv->masterVirtPr; | 67 masterEnv->schedSlots[0]->procrAssignedToSlot = masterEnv->masterVirtPr; |
| 62 | 68 |
| 63 //First core loop to start up gets this, which will schedule seed Pr | 69 //First core loop to start up gets this, which will schedule seed Pr |
| 64 //TODO: debug: check address of masterVirtPr | 70 //TODO: debug: check address of masterVirtPr |
| 65 writeQ( &(masterEnv->masterVirtPr), workQ ); | 71 writeQ( masterEnv->masterVirtPr, workQ ); |
| 66 } | 72 } |
| 67 | 73 |
| 68 | |
| 69 | |
| 70 /*Fill up the master VirtProcr data structure, which is already alloc'd | |
| 71 * in the masterEnv. | |
| 72 * The coreLoop treats master virt pr same as the slave virt processors | |
| 73 * | |
| 74 *The first time it runs, will jump to the function ptr so have to, in here, | |
| 75 * create the stack, which will be used by the plug-in functions, and set | |
| 76 * up __cdecl just like do for the other virtual processors. | |
| 77 */ | |
| 78 void | |
| 79 create_master( MasterEnv *masterEnv ) | |
| 80 { VirtProcr masterPr; | |
| 81 char * stackLocs, stackPtr; | |
| 82 | |
| 83 //TODO: debug this to be sure got addr of struct in masterEnv correctly | |
| 84 masterPr = &(masterEnv->masterVirtPr); | |
| 85 masterPr->initialData = masterEnv; | |
| 86 | |
| 87 masterPr->nextInstrPt = &masterLoop; | |
| 88 | |
| 89 //alloc stack locations, make stackPtr be the last addr in the locs, | |
| 90 // minus room for the two parameters. Put initData at stackPtr, | |
| 91 // animatingPr just above | |
| 92 stackLocs = malloc( 0x100000 ); //1 meg stack -- default Win thread's size | |
| 93 stackPtr = ( (char *)stackLocs + 0x100000 - 0x8 ); | |
| 94 masterPr->stackPtr = stackPtr; | |
| 95 masterPr->framePtr = stackPtr; | |
| 96 asm volatile("movl %0, %%esp; | |
| 97 movl %1, (%%esp); | |
| 98 movl %2, $0x4(%%esp); | |
| 99 movl %%esp, %%ebp; " /*framePtr in ebp never used*/ | |
| 100 /* outputs */ : | |
| 101 /* inputs */ : "g" (stackPtr), "g" (initData), "g" (animPr) | |
| 102 /* clobber */ : | |
| 103 ); | |
| 104 } | |
| 105 | 74 |
| 106 void | 75 void |
| 107 create_sched_slots( MasterEnv *masterEnv ) | 76 create_sched_slots( MasterEnv *masterEnv ) |
| 108 { SchedSlot *slots; | 77 { SchedSlot **schedSlots, **filledSlots; |
| 109 int i; | 78 int i; |
| 110 | 79 |
| 111 slots = masterEnv->schedSlots; //TODO: make sure this is right | 80 schedSlots = malloc( NUM_SCHED_SLOTS * sizeof(SchedSlot *) ); |
| 81 filledSlots = malloc( NUM_SCHED_SLOTS * sizeof(SchedSlot *) ); | |
| 82 masterEnv->schedSlots = schedSlots; | |
| 83 masterEnv->filledSlots = filledSlots; | |
| 84 | |
| 112 for( i = 0; i < NUM_SCHED_SLOTS; i++ ) | 85 for( i = 0; i < NUM_SCHED_SLOTS; i++ ) |
| 113 { | 86 { |
| 87 schedSlots[i] = malloc( sizeof(SchedSlot) ); | |
| 88 | |
| 114 //Set state to mean "handling requests done, slot needs filling" | 89 //Set state to mean "handling requests done, slot needs filling" |
| 115 slots[i].workIsDone = FALSE; | 90 schedSlots[i]->workIsDone = FALSE; |
| 116 slots[i].needsProcrAssigned = TRUE; | 91 schedSlots[i]->needsProcrAssigned = TRUE; |
| 117 } | 92 } |
| 118 } | 93 } |
| 94 | |
| 119 | 95 |
| 120 /*Semantic layer calls this when it want the system to start running.. | 96 /*Semantic layer calls this when it want the system to start running.. |
| 121 * | 97 * |
| 122 *This creates the core loops, pins them to physical cores, gives them the | 98 *This creates the core loops, pins them to physical cores, gives them the |
| 123 * pointer to the workQ, and starts them running. | 99 * pointer to the workQ, and starts them running. |
| 124 */ | 100 */ |
| 125 void | 101 void |
| 126 VMS__start() | 102 VMS__start() |
| 127 { int retCode, coreIdx; | 103 { int retCode, coreIdx; |
| 128 | 104 |
| 129 //TODO: still just skeleton code -- figure out right way to do this | 105 //Create the win threads that animate the core loops |
| 130 | 106 for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) |
| 131 //Create the PThread loops that take from work-queue, and start them | |
| 132 for( coreIdx=0; coreIdx < NUM_WORKERS; coreIdx++ ) | |
| 133 { | 107 { |
| 134 thdParams[coreIdx] = (ThdParams *)malloc( sizeof(ThdParams) ); | 108 thdParams[coreIdx] = (ThdParams *)malloc( sizeof(ThdParams) ); |
| 135 thdParams[coreIdx]->workQ = _VMSWorkQ; | 109 thdParams[coreIdx]->coreNum = coreIdx; |
| 136 thdParams[coreIdx]->id = coreIdx; | 110 |
| 137 | 111 coreLoopThds[coreIdx] = |
| 138 //Now make and start thd.. the coreLoopThds entry | 112 CreateThread ( NULL, // Security attributes |
| 139 // has all the info needed to later stop the thread. | 113 0, // Stack size |
| 140 retCode = | 114 coreLoop, |
| 141 pthread_create( &(coreLoopThds[coreIdx]), thdAttrs, &coreLoop, | 115 thdParams[coreIdx], |
| 142 (void *)(thdParams[coreIdx]) ); | 116 CREATE_SUSPENDED, |
| 143 if( retCode != 0 ) | 117 &(thdIds[coreIdx]) |
| 144 { //error | 118 ); |
| 145 printf("ERROR creating coreLoop %d, code: %d\n", coreIdx, retCode); | 119 ResumeThread( coreLoopThds[coreIdx] ); //starts thread |
| 146 exit(-1); | |
| 147 } | |
| 148 | |
| 149 pinThdToCore( ); //figure out how to specify this.. | |
| 150 | |
| 151 startThd(); //look up PThread call to start the thread running, if it's | |
| 152 // not automatic | |
| 153 } | 120 } |
| 121 } | |
| 122 | |
| 123 | |
| 124 | |
| 125 /*Create stack, then create __cdecl structure on it and put initialData and | |
| 126 * pointer to the new structure instance into the parameter positions on | |
| 127 * the stack | |
| 128 *Then put function pointer into nextInstrPt -- the stack is setup in std | |
| 129 * call structure, so jumping to function ptr is same as a GCC generated | |
| 130 * function call | |
| 131 *No need to save registers on old stack frame, because there's no old | |
| 132 * animator state to return to -- | |
| 133 * | |
| 134 */ | |
| 135 VirtProcr * | |
| 136 VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData ) | |
| 137 { VirtProcr *newPr; | |
| 138 char *stackLocs, *stackPtr; | |
| 139 | |
| 140 newPr = malloc( sizeof(VirtProcr) ); | |
| 141 newPr->nextInstrPt = fnPtr; | |
| 142 newPr->initialData = initialData; | |
| 143 | |
| 144 //alloc stack locations, make stackPtr be the highest addr minus room | |
| 145 // for 2 params. Put initData at stackPtr, animatingPr just above | |
| 146 stackLocs = malloc( 0x100000 ); //1 meg stack -- default Win thread's size | |
| 147 stackPtr = ( (char *)stackLocs + 0x100000 - 0x8 ); | |
| 148 //setup __cdecl on stack -- coreloop will switch to stackPtr before jmp | |
| 149 *(stackPtr + 4) = newPr; //rightmost param | |
| 150 *stackPtr = initialData; //next param to left | |
| 151 newPr->stackPtr = stackPtr; //core loop will switch to this, then | |
| 152 newPr->framePtr = stackPtr; //suspend loop will save new stack & frame ptr | |
| 153 | |
| 154 return newPr; | |
| 155 } | |
| 156 | |
| 157 | |
| 158 /*This inserts the semantic-layer's data into the standard VMS carrier | |
| 159 */ | |
| 160 inline void | |
| 161 VMS__send_sem_request( void *semReqData, VirtProcr *callingPr ) | |
| 162 { SlaveReqst *req; | |
| 163 | |
| 164 req = malloc( sizeof(SlaveReqst) ); | |
| 165 req->slaveFrom = callingPr; | |
| 166 req->semReqData = semReqData; | |
| 167 req->nextRequest = callingPr->requests; | |
| 168 callingPr->requests = req; | |
| 154 } | 169 } |
| 155 | 170 |
| 156 /*there is a label inside this function -- save the addr of this label in | 171 /*there is a label inside this function -- save the addr of this label in |
| 157 * the callingPr struc, as the pick-up point from which to start the next | 172 * the callingPr struc, as the pick-up point from which to start the next |
| 158 * work-unit for that procr. If turns out have to save registers, then | 173 * work-unit for that procr. If turns out have to save registers, then |
| 160 * "done with work-unit" label. The procr struc is in the request in the | 175 * "done with work-unit" label. The procr struc is in the request in the |
| 161 * slave that animated the just-ended work-unit, so all the state is saved | 176 * slave that animated the just-ended work-unit, so all the state is saved |
| 162 * there, and will get passed along, inside the request handler, to the | 177 * there, and will get passed along, inside the request handler, to the |
| 163 * next work-unit for that procr. | 178 * next work-unit for that procr. |
| 164 */ | 179 */ |
| 180 void | |
| 165 VMS__suspend_processor( VirtProcr *callingPr ) | 181 VMS__suspend_processor( VirtProcr *callingPr ) |
| 166 { void *jmpPt; | 182 { void *jmpPt, *stackPtr, *framePtr; |
| 167 | 183 |
| 168 callingPr->nextInstrPt = &&ResumePt; | 184 callingPr->nextInstrPt = &&ResumePt; |
| 169 | 185 |
| 170 //return ownership of the virt procr and sched slot to Master virt pr | 186 //return ownership of the virt procr and sched slot to Master virt pr |
| 171 callingPr->schedSlot->workIsDone = TRUE; | 187 callingPr->schedSlot->workIsDone = TRUE; |
| 172 | 188 |
| 173 jmpPt = callingPr->coreLoopStartPt; | 189 jmpPt = callingPr->coreLoopStartPt; |
| 190 stackPtr = &(callingPr->stackPtr); | |
| 191 framePtr = &(callingPr->framePtr); | |
| 174 | 192 |
| 175 //put all regs in the clobber list to make sure GCC has saved all | 193 //put all regs in the clobber list to make sure GCC has saved all |
| 176 // so safe to jump to core loop, where they *will* get clobbered | 194 // so safe to jump to core loop, where they *will* get clobbered |
| 177 asm volatile("movl %%esp, %0; | 195 asm volatile("movl %%esp, %0; \ |
| 178 movl %%ebp, %1; | 196 movl %%ebp, %1; \ |
| 179 jmp %2 " | 197 jmp %2 " |
| 180 /* outputs */ : "=m" (currPr->stackPtr), "=m" (currPr->framePtr) | 198 /* outputs */ : "=g" (stackPtr), "=g" (framePtr) |
| 181 /* inputs */ : "g" (jmpPt) | 199 /* inputs */ : "g" (jmpPt) |
| 182 /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%edi","%esi" | 200 /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%edi","%esi" |
| 183 ); | 201 ); |
| 184 | 202 |
| 185 ResumePt: | 203 ResumePt: |
| 186 return; | 204 return; |
| 187 } | 205 } |
| 188 | 206 |
| 189 | 207 void |
| 190 /*Create stack, then create __cdecl structure on it and put initialData and | 208 VMS__dissipate_animating_processor( VirtProcr *animatingPr ) |
| 191 * pointer to the new structure instance into the parameter positions on | 209 { |
| 192 * the stack | 210 |
| 193 *Then put function pointer into nextInstrPt -- the stack is setup in std | 211 } |
| 194 * call structure, so jumping to function ptr is same as a GCC generated | 212 |
| 195 * function call | 213 /*This runs in main thread -- so can only signal to the core loop to shut |
| 196 *No need to save registers on old stack frame, because there's no old | 214 * itself down -- |
| 197 * animator state to return to -- | 215 * |
| 198 * | 216 *Want the master to decide when to shut down -- when semantic layer tells it |
| 199 */ | 217 * to -- say, when all the application-virtual processors have dissipated. |
| 200 VirtProcr * | 218 * |
| 201 VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData ) | 219 *Maybe return a special code from scheduling plug-in.. master checks and |
| 202 { VirtProcr newPr; | 220 * when sees, it shuts down the core loops -- does this by scheduling a |
| 203 | 221 * special virt processor whose next instr pt is the core-end label. |
| 204 newPr = malloc( sizeof(VirtProcr) ); | 222 */ |
| 205 newPr->nextInstrPt = fnPtr; | 223 void |
| 206 newPr->initialData = initialData; | 224 VMS__shutdown() |
| 207 newPr->stackPtr = createNewStack(); | 225 { int coreIdx; |
| 208 newPr->framePtr = newPr->stackPtr; | 226 |
| 209 put params onto stack and setup __cdecl call structure | 227 //Create the win threads that animate the core loops |
| 210 | 228 for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) |
| 211 return newPr; | 229 { |
| 212 } | 230 |
| 213 | 231 } |
| 214 | 232 } |
| 215 /*The semantic virt procr is available in the request sent from the slave | |
| 216 * | |
| 217 * The request handler has to add the work-unit created to the semantic | |
| 218 * virtual processor the work-unit is a section of its time-line -- does this when create the | |
| 219 * work-unit -- means the procr data struc is available in the request sent | |
| 220 * from the slave, from which the new work-unit is generated.. | |
| 221 */ | |
| 222 inline void | |
| 223 VMS__add_request_to_slave( SlaveReqst req, VirtProcr callingPr ) | |
| 224 { | |
| 225 req->nextRequest = callingPr->requests; | |
| 226 callingPr->requests = req; | |
| 227 } | |
| 228 | |
| 229 | |
| 230 |
