annotate MasterLoop.c @ 6:21842fec64db

Added win thds and End Thd point
author Me
date Tue, 01 Jun 2010 05:31:40 -0700
parents a5fe730dfc2e
children a87d02855dee
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@0 11
Me@0 12 #include "VMS.h"
Me@0 13
Me@0 14
Me@0 15
Me@0 16 /*This code is animated by the virtual Master processor.
Me@0 17 *Note, it is animated on a different level in virtual processor hierarchy
Me@0 18 * than the CoreLoop -- this is the code pointed to in a work-unit that the
Me@0 19 * coreLoop jumps to
Me@0 20 *
Me@0 21 *Polls each virtual slave exactly once, hands any requests made by the slave
Me@0 22 * to the "request handler" plug-in function
Me@0 23 *
Me@0 24 *Any slaves that have no work-unit assigned are given to the "schedule"
Me@0 25 * plug-in function, which tries to assign a work-unit to it.
Me@0 26 *
Me@0 27 *When all slaves that need work-units have been given to the schedule plug-in,
Me@0 28 * half of the ones that were successfully scheduled are put into the work
Me@0 29 * queue, then a continuation of this function is put in, then the rest of the
Me@0 30 * slaves that were successfully scheduled.
Me@0 31 *
Me@0 32 *The first thing this function does is busy-wait until the previous work-unit
Me@0 33 * running this function is done. This ensures it doesn't overlap with
Me@0 34 * tail-end of previous -- IE, continuation may sneak through queue before
Me@0 35 * previous done putting second half of scheduled slaves in. This is the only
Me@0 36 * race condition.
Me@0 37 *
Me@0 38 */
Me@0 39
Me@4 40 /*May 29, 2010 -- birth a Master during init so that first core loop to
Me@4 41 * start running gets it and does all the stuff for a newly born
Me@4 42 * from then on, will be doing continuation -- but do suspension self
Me@4 43 * directly at end of master loop
Me@4 44 *So VMS__init just births the master virtual processor same way it births
Me@4 45 * all the others -- then does any extra setup needed and puts it into the
Me@4 46 * work queue.
Me@4 47 *However means have to make masterEnv a global static volatile the same way
Me@4 48 * did with workQ in core loop. -- for performance, put the
Me@4 49 * jump to core loop directly in here, and have it directly jump back.
Me@4 50 */
Me@4 51 void masterLoop( void *initData, VirtProcr *masterPr )
Me@0 52 { bool8 success;
Me@4 53 int slotIdx, numScheduled, numInFirstChunk, filledSlotIdx;
Me@4 54 SchedSlot *currSlot, **schedSlots, **filledSlots;
Me@0 55 MasterEnv *masterEnv;
Me@4 56 QueueStruc *workQ;
Me@4 57 // VirtProcr *masterPr;
Me@4 58 void *jmpPt;
Me@4 59
Me@0 60 SlaveScheduler slaveScheduler;
Me@0 61 RequestHandler requestHandler;
Me@0 62
Me@4 63 //this will run as the first virt processor in workQ, and will be a
Me@4 64 // new born -- so will do all the GCC-generated allocating space on
Me@4 65 // the stack owned by master virt procr -- and will run this last bit
Me@4 66 // of setup code..
Me@4 67 masterPr->nextInstrPt = &&masterLoopStartPt;
Me@0 68
Me@4 69
Me@4 70 masterLoopStartPt:
Me@0 71
Me@4 72 //if another reference to same Master VirtProcr still going, busy-wait
Me@4 73 //Could put this lower, but don't want to think about shared stack..
Me@4 74 while( masterEnv->stillRunning ) /*busy wait*/ ;
Me@4 75 //TODO: want to do busy-wait as assembly, to be sure stack not touched?
Me@4 76
Me@4 77 //this is the only master running now, set flag again
Me@4 78 masterEnv->stillRunning = TRUE;
Me@4 79
Me@4 80 //TODO: gdb -- check that a volatile _VMSMasterEnv and _VMSWorkQ means
Me@4 81 // all these will be re-filled every time jump here..
Me@4 82 workQ = _VMSWorkQ;
Me@4 83 masterEnv = _VMSMasterEnv;
Me@0 84 requestHandler = masterEnv->requestHandler;
Me@0 85 slaveScheduler = masterEnv->slaveScheduler;
Me@4 86 schedSlots = masterEnv->schedSlots;
Me@4 87 filledSlots = masterEnv->filledSlots;
Me@4 88 masterPr = masterEnv->masterVirtPr;
Me@0 89
Me@0 90
Me@0 91 //prepare for scheduling
Me@4 92 masterEnv->numFilled = 0;
Me@0 93
Me@4 94 //Poll each slot's Done flag -- slot 0 reseved for master, start at 1
Me@4 95 for( slotIdx = 1; slotIdx < NUM_SCHED_SLOTS; slotIdx++)
Me@0 96 {
Me@4 97 currSlot = schedSlots[ slotIdx ];
Me@0 98
Me@4 99 if( currSlot->workIsDone )
Me@0 100 {
Me@4 101 currSlot->workIsDone = FALSE;
Me@4 102 currSlot->needsProcrAssigned = TRUE;
Me@0 103
Me@0 104 //process requests from slave to master
Me@4 105 (*requestHandler)( currSlot->procrAssignedToSlot->requests );
Me@0 106 }
Me@4 107 if( currSlot->needsProcrAssigned )
Me@4 108 { //give slot a new virt procr
Me@0 109 success =
Me@4 110 (*slaveScheduler)( currSlot, masterEnv->semanticEnv );
Me@0 111
Me@0 112 if( success )
Me@4 113 { int numFilled = masterEnv->numFilled;
Me@4 114
Me@4 115 filledSlots[numFilled] = currSlot;
Me@4 116 masterEnv->numFilled += 1;
Me@4 117
Me@4 118 currSlot->needsProcrAssigned = FALSE;
Me@0 119 }
Me@0 120 }
Me@0 121 }
Me@0 122
Me@4 123 //put some scheduled slaves in, then continuation, then rest
Me@4 124 numInFirstChunk = masterEnv->numFilled / 2; //tweak this from experiments
Me@4 125 for( filledSlotIdx = 0; filledSlotIdx < numInFirstChunk; filledSlotIdx++)
Me@0 126 {
Me@4 127 writeQ( filledSlots[ filledSlotIdx ]->procrAssignedToSlot, workQ );
Me@0 128 }
Me@0 129
Me@0 130 //enqueue continuation of this loop
Me@0 131 // note that After this enqueue, continuation might sneak through
Me@4 132 writeQ( schedSlots[0]->procrAssignedToSlot, workQ );//master always slot 0
Me@4 133 for( filledSlotIdx = numInFirstChunk;
Me@4 134 filledSlotIdx < numScheduled;
Me@4 135 filledSlotIdx++)
Me@0 136 {
Me@4 137 writeQ( filledSlots[ filledSlotIdx ]->procrAssignedToSlot, workQ );
Me@0 138 }
Me@0 139
Me@4 140 masterEnv->numFilled = 0;
Me@4 141
Me@4 142 //Don't want code above to try to look at requests in masterVirtPr,
Me@4 143 // so leave workDone at FALSE, but do want it to schedule into
Me@4 144 // the slot, so set needs procr assigned to TRUE.
Me@4 145 masterPr->schedSlot->needsProcrAssigned = TRUE;
Me@4 146
Me@4 147 //Save stack ptr and frame -- don't need to, take out later, but safe
Me@4 148 // Also, wait to set stillRunning to FALSE until just before jump, to
Me@4 149 // protect stack might need to jmp directly to asm busy-wait to be
Me@4 150 // sure stack not touched
Me@4 151 //TODO: gdb check that busy-wait doesn't touch stack, so this is safe
Me@4 152 //don't need any regs to be valid when come back, so clobber list empty
Me@4 153 //TODO: gdb the jmp -- make sure it jumps through register or mem
Me@4 154 asm volatile("movl %%esp, %0; \
Me@4 155 movl %%ebp, %1; \
Me@4 156 movl $0x0, %2; \
Me@4 157 jmp %3 "
Me@4 158 /* outputs */ : "=m" (masterPr->stackPtr), "=m" (masterPr->framePtr),
Me@4 159 "=m" (masterEnv->stillRunning)
Me@4 160 /* inputs */ : "r" (masterPr->coreLoopStartPt)
Me@4 161 /* clobber */
Me@4 162 );
Me@0 163 }
Me@0 164
Me@0 165