Me@0: /* Me@0: * Copyright 2010 OpenSourceCodeStewardshipFoundation Me@0: * Me@0: * Licensed under BSD Me@0: */ Me@0: Me@0: Me@0: Me@0: #include Me@0: #include Me@0: Me@0: #include "VMS.h" Me@0: Me@0: Me@0: Me@0: /*This code is animated by the virtual Master processor. Me@0: *Note, it is animated on a different level in virtual processor hierarchy Me@0: * than the CoreLoop -- this is the code pointed to in a work-unit that the Me@0: * coreLoop jumps to Me@0: * Me@0: *Polls each virtual slave exactly once, hands any requests made by the slave Me@0: * to the "request handler" plug-in function Me@0: * Me@0: *Any slaves that have no work-unit assigned are given to the "schedule" Me@0: * plug-in function, which tries to assign a work-unit to it. Me@0: * Me@0: *When all slaves that need work-units have been given to the schedule plug-in, Me@0: * half of the ones that were successfully scheduled are put into the work Me@0: * queue, then a continuation of this function is put in, then the rest of the Me@0: * slaves that were successfully scheduled. Me@0: * Me@0: *The first thing this function does is busy-wait until the previous work-unit Me@0: * running this function is done. This ensures it doesn't overlap with Me@0: * tail-end of previous -- IE, continuation may sneak through queue before Me@0: * previous done putting second half of scheduled slaves in. This is the only Me@0: * race condition. Me@0: * Me@0: */ Me@0: Me@0: void masterLoop( void *data ) Me@0: { bool8 success; Me@0: int slaveIdx, numScheduled, numInFirstHalf, schedSlaveIdx; Me@0: VMSProcr currSlave, *virtSlaves; Me@0: MasterEnv *masterEnv; Me@0: SlaveScheduler slaveScheduler; Me@0: RequestHandler requestHandler; Me@0: Me@0: Me@0: masterEnv = (MasterEnv *)data; Me@0: Me@0: requestHandler = masterEnv->requestHandler; Me@0: slaveScheduler = masterEnv->slaveScheduler; Me@0: virtSlaves = masterEnv->virtSlaves; Me@0: Me@0: //if another continuation of Master still running, busy-wait Me@0: while( masterEnv->stillRunning ) /*busy wait*/ ; Me@0: Me@0: //this is the only master running now, set flag again Me@0: masterEnv->stillRunning = 1; Me@0: Me@0: //prepare for scheduling Me@0: masterEnv->numScheduled = 0; Me@0: Me@0: //Poll each slave structure's Done flag Me@0: for( slaveIdx = 0; slaveIdx < NUM_SLAVES; slaveIdx++) Me@0: { Me@0: currSlave = virtSlaves[ slaveIdx ]; Me@0: Me@0: if( currSlave->workIsDone ) Me@0: { Me@0: currSlave->workIsDone = FALSE; Me@0: currSlave->needsWorkAssigned = TRUE; Me@0: Me@0: //process requests from slave to master Me@0: (*requestHandler)( currSlave ); Me@0: } Me@0: if( currSlave->needsWorkAssigned ) Me@0: { //give slave a new work-unit Me@0: success = Me@0: (*slaveScheduler)( currSlave, masterEnv ); Me@0: Me@0: if( success ) Me@0: { addToVect( currSlave, &(masterEnv->scheduledSlaves), Me@0: &(masterEnv->numScheduled) ); Me@0: currSlave->needsWorkAssigned = FALSE; Me@0: } Me@0: } Me@0: } Me@0: Me@0: //put half scheduled slaves in, then continuation, then other half Me@0: VMSProcr **scheduledSlaves; Me@0: numInFirstHalf = masterEnv->numScheduled / 2; Me@0: scheduledSlaves = masterEnv->scheduledSlaves; Me@0: for( schedSlaveIdx = 0; schedSlaveIdx < numInFirstHalf; schedSlaveIdx++) Me@0: { Me@0: writeQ( scheduledSlaves[ schedSlaveIdx ], workQ ); Me@0: } Me@0: Me@0: //enqueue continuation of this loop Me@0: // note that After this enqueue, continuation might sneak through Me@0: writeQ( masterEnv->masterWorkUnit, workQ ); Me@0: for( schedSlaveIdx = numInFirstHalf; Me@0: schedSlaveIdx < numScheduled; Me@0: schedSlaveIdx++) Me@0: { Me@0: writeQ( scheduledSlaves[ schedSlaveIdx ]->workUnitToDo, workQ ); Me@0: } Me@0: Me@0: //all done, so okay for continuation to proceed Me@0: masterEnv->stillRunning = 0; Me@0: } Me@0: Me@0: