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