annotate VMS.c @ 1:cf5007e51b96

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