annotate MasterLoop.c @ 26:668278fa7a63

Sequential -- just starting to add sequential version
author Me
date Mon, 26 Jul 2010 15:25:53 -0700
parents a0af8d4fca35
children 5a2068cbc28b
rev   line source
Me@0 1 /*
Me@0 2 * Copyright 2010 OpenSourceCodeStewardshipFoundation
Me@0 3 *
Me@0 4 * Licensed under BSD
Me@0 5 */
Me@0 6
Me@0 7
Me@0 8
Me@0 9 #include <stdio.h>
Me@0 10 #include <malloc.h>
Me@9 11 #include <stddef.h>
Me@0 12
Me@0 13 #include "VMS.h"
Me@0 14
Me@0 15
Me@0 16
Me@0 17 /*This code is animated by the virtual Master processor.
Me@0 18 *
Me@11 19 *Polls each sched slot exactly once, hands any requests made by a newly
Me@11 20 * done slave to the "request handler" plug-in function
Me@0 21 *
Me@11 22 *Any slots that need a virt procr assigned are given to the "schedule"
Me@11 23 * plug-in function, which tries to assign a virt procr (slave) to it.
Me@0 24 *
Me@11 25 *When all slots needing a processor have been given to the schedule plug-in,
Me@11 26 * a fraction of the procrs successfully scheduled are put into the
Me@11 27 * work queue, then a continuation of this function is put in, then the rest
Me@11 28 * of the virt procrs that were successfully scheduled.
Me@0 29 *
Me@11 30 *The first thing the continuation does is busy-wait until the previous
Me@11 31 * animation completes. This is because an (unlikely) continuation may
Me@11 32 * sneak through queue before previous continuation is done putting second
Me@11 33 * part of scheduled slaves in, which is the only race condition.
Me@0 34 *
Me@0 35 */
Me@0 36
Me@4 37 /*May 29, 2010 -- birth a Master during init so that first core loop to
Me@11 38 * start running gets it and does all the stuff for a newly born --
Me@11 39 * from then on, will be doing continuation, but do suspension self
Me@4 40 * directly at end of master loop
Me@4 41 *So VMS__init just births the master virtual processor same way it births
Me@4 42 * all the others -- then does any extra setup needed and puts it into the
Me@4 43 * work queue.
Me@4 44 *However means have to make masterEnv a global static volatile the same way
Me@4 45 * did with workQ in core loop. -- for performance, put the
Me@11 46 * jump to the core loop directly in here, and have it directly jump back.
Me@4 47 */
Me@4 48 void masterLoop( void *initData, VirtProcr *masterPr )
Me@21 49 {
Me@26 50 int slotIdx, numFilled, filledSlotIdx, masterHasBeenQueued;
Me@21 51 VirtProcr *schedVirtPr;
Me@4 52 SchedSlot *currSlot, **schedSlots, **filledSlots;
Me@0 53 MasterEnv *masterEnv;
Me@26 54 VMSQueueStruc *workQ;
Me@21 55 void *jmpPt, *stackPtrAddr, *framePtrAddr, *stillRunningAddr;
Me@21 56 void *coreLoopFramePtr, *coreLoopStackPtr, *semanticEnv;
Me@4 57
Me@0 58 SlaveScheduler slaveScheduler;
Me@0 59 RequestHandler requestHandler;
Me@0 60
Me@4 61 //this will run as the first virt processor in workQ, and will be a
Me@4 62 // new born -- so will do all the GCC-generated allocating space on
Me@4 63 // the stack owned by master virt procr -- and will run this last bit
Me@4 64 // of setup code..
Me@4 65 masterPr->nextInstrPt = &&masterLoopStartPt;
Me@0 66
Me@26 67 //The second time MasterVP comes out of queue, the first animation of
Me@26 68 // it hasn't written the stackPtr and framePtr yet -- but the second
Me@26 69 // animation has already had its stackPtr and framePtr set to the old
Me@26 70 // value by the coreLoop. Fix this by writing the correct stack and
Me@26 71 // frame pointers here, at which point they're correct in the first
Me@26 72 // animation of MasterVP.
Me@26 73 //TODO: remove writing stackPtr and framePtr at the bottom, for eff
Me@26 74 stackPtrAddr = &(masterPr->stackPtr);
Me@26 75 framePtrAddr = &(masterPr->framePtr);
Me@26 76
Me@26 77 asm volatile("movl %0, %%eax; \
Me@26 78 movl %%esp, (%%eax); \
Me@26 79 movl %1, %%eax; \
Me@26 80 movl %%ebp, (%%eax); "
Me@26 81 /* outputs */ : "=g" (stackPtrAddr), "=g" (framePtrAddr) \
Me@26 82 /* inputs */ : \
Me@26 83 /* clobber */ : "memory", "%eax", "%ebx" \
Me@26 84 );
Me@26 85
Me@26 86
Me@4 87 masterLoopStartPt:
Me@0 88
Me@4 89 //if another reference to same Master VirtProcr still going, busy-wait
Me@4 90 //Could put this lower, but don't want to think about shared stack..
Me@21 91 while( _VMSMasterEnv->stillRunning ) /*busy wait*/ ;
Me@4 92 //TODO: want to do busy-wait as assembly, to be sure stack not touched?
Me@4 93
Me@4 94 //this is the only master running now, set flag again
Me@21 95 _VMSMasterEnv->stillRunning = TRUE;
Me@21 96 masterEnv = _VMSMasterEnv;
Me@4 97
Me@4 98 //TODO: gdb -- check that a volatile _VMSMasterEnv and _VMSWorkQ means
Me@4 99 // all these will be re-filled every time jump here..
Me@4 100 workQ = _VMSWorkQ;
Me@0 101 requestHandler = masterEnv->requestHandler;
Me@0 102 slaveScheduler = masterEnv->slaveScheduler;
Me@4 103 schedSlots = masterEnv->schedSlots;
Me@4 104 filledSlots = masterEnv->filledSlots;
Me@11 105 masterPr = masterEnv->masterVirtPr; //post-jmp clobbered, re-load
Me@21 106 semanticEnv = masterEnv->semanticEnv;
Me@0 107
Me@0 108 //prepare for scheduling
Me@26 109 numFilled = 0;
Me@26 110 masterHasBeenQueued = FALSE;
Me@0 111
Me@21 112 //Poll each slot's Done flag -- slot 0 reserved for master, start at 1
Me@26 113 for( slotIdx = 0; slotIdx < NUM_SCHED_SLOTS; slotIdx++)
Me@0 114 {
Me@4 115 currSlot = schedSlots[ slotIdx ];
Me@0 116
Me@4 117 if( currSlot->workIsDone )
Me@0 118 {
Me@4 119 currSlot->workIsDone = FALSE;
Me@4 120 currSlot->needsProcrAssigned = TRUE;
Me@0 121
Me@0 122 //process requests from slave to master
Me@21 123 (*requestHandler)( currSlot->procrAssignedToSlot, semanticEnv );
Me@0 124 }
Me@4 125 if( currSlot->needsProcrAssigned )
Me@4 126 { //give slot a new virt procr
Me@21 127 schedVirtPr =
Me@21 128 (*slaveScheduler)( semanticEnv );
Me@0 129
Me@21 130 if( schedVirtPr != NULL )
Me@21 131 { currSlot->procrAssignedToSlot = schedVirtPr;
Me@26 132 schedVirtPr->schedSlot = currSlot;
Me@26 133 currSlot->needsProcrAssigned = FALSE;
Me@4 134
Me@26 135 filledSlots[ numFilled ] = currSlot;
Me@26 136 numFilled += 1;
Me@4 137
Me@26 138 writeVMSQ( schedVirtPr, workQ );
Me@26 139 if( numFilled == masterEnv->numToPrecede )
Me@26 140 {
Me@26 141 writeVMSQ( masterEnv->masterVirtPr, workQ );
Me@26 142 masterHasBeenQueued = TRUE;
Me@26 143 }
Me@26 144
Me@0 145 }
Me@0 146 }
Me@0 147 }
Me@0 148
Me@26 149 if( !masterHasBeenQueued )
Me@26 150 {
Me@26 151 writeVMSQ( masterEnv->masterVirtPr, workQ );
Me@26 152 }
Me@26 153
Me@26 154 //Adjust the number to precede, for next round -- assume rate of
Me@26 155 // finishing work is stable -- which is a bad assumption! But, just
Me@26 156 // want something working for the moment, look at dynamic behavior
Me@26 157 // later
Me@26 158 //TODO: look at dynamic behavior -- time-average numToPrecede or something
Me@26 159 if( numFilled < NUM_CORES - 1 )
Me@26 160 {
Me@26 161 masterEnv->numToPrecede = 0;
Me@26 162 }
Me@26 163 else
Me@26 164 { masterEnv->numToPrecede = numFilled - NUM_CORES + 1;
Me@26 165 }
Me@26 166 /*
Me@21 167 //put some scheduled slaves in, then Master continuation, then rest
Me@21 168 //Adjust position of master such that it maintains close to a fixed
Me@21 169 // ratio --> make NUM_CORES - 1 slots or fewer come after the master
Me@26 170
Me@21 171 for( filledSlotIdx = 0; filledSlotIdx < numPrecede; filledSlotIdx++)
Me@0 172 {
Me@26 173 writeVMSQ( filledSlots[ filledSlotIdx ]->procrAssignedToSlot, workQ );
Me@0 174 }
Me@0 175
Me@0 176 //enqueue continuation of this loop
Me@0 177 // note that After this enqueue, continuation might sneak through
Me@26 178 writeVMSQ( masterEnv->masterVirtPr, workQ );
Me@21 179
Me@21 180 for( filledSlotIdx = numPrecede;
Me@21 181 filledSlotIdx < numFilled;
Me@4 182 filledSlotIdx++)
Me@0 183 {
Me@26 184 writeVMSQ( filledSlots[ filledSlotIdx ]->procrAssignedToSlot, workQ );
Me@0 185 }
Me@0 186
Me@4 187 masterEnv->numFilled = 0;
Me@26 188 */
Me@4 189
Me@4 190 //Save stack ptr and frame -- don't need to, take out later, but safe
Me@4 191 // Also, wait to set stillRunning to FALSE until just before jump, to
Me@21 192 // be safe -- although the two simulatneously animated MasterLoops
Me@21 193 // are on different cores, so have different stacks, so no worries
Me@21 194 // there.
Me@21 195 //Restore CoreLoop's stack frame (and stack pointer, to be safe)
Me@21 196 //TODO: cafefully verify don't need to force saving anything to stack
Me@21 197 // before jumping back to core loop.
Me@21 198 stackPtrAddr = &(masterPr->stackPtr);
Me@21 199 framePtrAddr = &(masterPr->framePtr);
Me@21 200 stillRunningAddr = &(_VMSMasterEnv->stillRunning); //when race condition
Me@21 201 //arises, stillRunning is shared between the two cores both animating
Me@21 202 // MasterLoop -- but those two cores have different esp & ebp, so safe
Me@21 203 // to change stack and frame pointer here, without one messing up other
Me@21 204 // one
Me@21 205
Me@21 206 jmpPt = masterPr->coreLoopStartPt;
Me@21 207 coreLoopFramePtr = masterPr->coreLoopFramePtr;//need this only
Me@21 208 coreLoopStackPtr = masterPr->coreLoopStackPtr;//shouldn't need -- safety
Me@21 209
Me@21 210 asm volatile("movl %0, %%eax; \
Me@21 211 movl %%esp, (%%eax); \
Me@21 212 movl %1, %%eax; \
Me@21 213 movl %%ebp, (%%eax); \
Me@21 214 movl %2, %%ebx; \
Me@21 215 movl %3, %%eax; \
Me@21 216 movl %4, %%esp; \
Me@21 217 movl %5, %%ebp; \
Me@21 218 movl $0x0, (%%ebx); \
Me@21 219 jmp %%eax " \
Me@21 220 /* outputs */ : "=g" (stackPtrAddr), "=g" (framePtrAddr), \
Me@21 221 "=g"(stillRunningAddr) \
Me@21 222 /* inputs */ : "g" (jmpPt), "g"(coreLoopStackPtr), "g"(coreLoopFramePtr)\
Me@21 223 /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi" \
Me@21 224 );//can probably make clobber list empty -- but safe for now
Me@0 225 }
Me@0 226
Me@0 227