Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VSs_impls > VSs__MC_shared_impl
view VSs.c @ 27:3b30da4643d1
Update2.. in middle of changes.. made request handler ptr be sent w/req struct
| author | Sean Halle <seanhalle@yahoo.com> |
|---|---|
| date | Sat, 12 Jan 2013 11:31:51 -0800 |
| parents | a60399b62614 |
| children | 91caa8a9d591 |
line source
1 /*
2 * Copyright 2010 OpenSourceCodeStewardshipFoundation
3 *
4 * Licensed under BSD
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <malloc.h>
11 #include "Queue_impl/PrivateQueue.h"
12 #include "Hash_impl/PrivateHash.h"
14 #include "VSs.h"
15 #include "Measurement/VSs_Counter_Recording.h"
17 //==========================================================================
18 void
19 VSs__init_Helper();
21 SlaveVP *
22 VSs__create_thread_w_ID_and_affinity( TopLevelFnPtr fnPtr, void *initData,
23 int32 *thdID, int32 coreToAssignOnto, SlaveVP *creatingThd );
25 //==========================================================================
29 //===========================================================================
32 /*These are the library functions *called in the application*
33 *
34 *There's a pattern for the outside sequential code to interact with the
35 * PR_HW code.
36 *The PR_HW system is inside a boundary.. every VSs system is in its
37 * own directory that contains the functions for each of the processor types.
38 * One of the processor types is the "seed" processor that starts the
39 * cascade of creating all the processors that do the work.
40 *So, in the directory is a file called "EntryPoint.c" that contains the
41 * function, named appropriately to the work performed, that the outside
42 * sequential code calls. This function follows a pattern:
43 *1) it calls VSs__init()
44 *2) it creates the initial data for the seed processor, which is passed
45 * in to the function
46 *3) it creates the seed VSs processor, with the data to start it with.
47 *4) it calls startVSsThenWaitUntilWorkDone
48 *5) it gets the returnValue from the transfer struc and returns that
49 * from the function
50 *
51 *For now, a new VSs system has to be created via VSs__init every
52 * time an entry point function is called -- later, might add letting the
53 * VSs system be created once, and let all the entry points just reuse
54 * it -- want to be as simple as possible now, and see by using what makes
55 * sense for later..
56 */
60 //===========================================================================
62 int32
63 VSs__giveMinWorkUnitCycles( float32 percentOverhead )
64 {
65 return MIN_WORK_UNIT_CYCLES;
66 }
68 int32
69 VSs__giveIdealNumWorkUnits()
70 {
71 return NUM_ANIM_SLOTS * NUM_CORES;
72 }
74 int32
75 VSs__give_number_of_cores_to_schedule_onto()
76 {
77 return NUM_CORES;
78 }
80 /*For now, use TSC -- later, make these two macros with assembly that first
81 * saves jump point, and second jumps back several times to get reliable time
82 */
83 void
84 VSs__begin_primitive( SlaveVP *animSlv )
85 { VSsLangData *langData;
87 langData = (VSsLangData *)PR_WL__give_lang_data( animSlv, VSs_MAGIC_NUMBER);
89 saveLowTimeStampCountInto( langData->primitiveStartTime );
90 }
92 /*Just quick and dirty for now -- make reliable later
93 * will want this to jump back several times -- to be sure cache is warm
94 * because don't want comm time included in calc-time measurement -- and
95 * also to throw out any "weird" values due to OS interrupt or TSC rollover
96 */
97 int32
98 VSs__end_primitive_and_give_cycles( SlaveVP *animSlv )
99 { int32 endTime, startTime;
100 VSsLangData *langData;
102 //TODO: fix by repeating time-measurement
103 saveLowTimeStampCountInto( endTime );
104 langData = (VSsLangData *)PR_WL__give_lang_data( animSlv, VSs_MAGIC_NUMBER);
105 startTime = langData->primitiveStartTime;
106 return (endTime - startTime);
107 }
111 //===========================================================================
113 SlaveVP *
114 VSs__create_thread( TopLevelFnPtr fnPtr, void *initData,
115 SlaveVP *creatingThd )
116 {
117 return VSs__create_thread_w_ID_and_affinity( fnPtr, initData, NO_ID,
118 ANY_CORE, creatingThd );
119 }
121 SlaveVP *
122 VSs__create_thread_w_ID( TopLevelFnPtr fnPtr, void *initData, int32 *thdID,
123 SlaveVP *creatingThd )
124 {
125 return VSs__create_thread_w_ID_and_affinity( fnPtr, initData, thdID,
126 ANY_CORE, creatingThd );
127 }
129 /* old version -- looks safe to delete
130 SlaveVP *
131 VSs__create_slave_with_affinity( TopLevelFnPtr fnPtr, void *initData,
132 SlaveVP *creatingSlv, int32 coreToAssignOnto )
133 { VSsLangReq reqData;
135 //the lang request data is on the stack and disappears when this
136 // call returns -- it's guaranteed to remain in the VP's stack for as
137 // long as the VP is suspended.
138 reqData.reqType = create_slave_w_aff; //not used, May 2012
139 reqData.coreToAssignOnto = coreToAssignOnto;
140 reqData.fnPtr = fnPtr;
141 reqData.initData = initData;
142 reqData.callingSlv = creatingSlv;
144 PR_WL__send_create_slaveVP_req( &reqData, creatingSlv, VSs_MAGIC_NUMBER );
146 return creatingSlv->dataRetFromReq;
147 }
148 */
151 SlaveVP *
152 VSs__create_thread_w_ID_and_affinity( TopLevelFnPtr fnPtr, void *initData,
153 int32 *thdID, int32 coreToAssignOnto, SlaveVP *creatingThd )
154 { VSsLangReq reqData;
156 //the lang request data is on the stack and disappears when this
157 // call returns -- it's guaranteed to remain in the VP's stack for as
158 // long as the VP is suspended.
159 reqData.reqType = create_slave; //know type because in a PR create req
160 reqData.coreToAssignOnto = coreToAssignOnto;
161 reqData.fnPtr = fnPtr;
162 reqData.initData = initData;
164 PR_WL__send_create_slaveVP_req( &reqData, thdID, &handleCreateThd,
165 creatingThd, VSs_MAGIC_NUMBER );
166 return (SlaveVP *)creatingThd->dataRetFromReq;
167 }
169 /*This is always the last thing done in the code animated by a thread VP.
170 * Normally, this would be the last line of the thread's top level function.
171 * But, if the thread exits from any point, it has to do so by calling
172 * this.
173 *
174 *It simply sends a dissipate request, which handles all the state cleanup.
175 */
176 void
177 VSs__end_thread( SlaveVP *thdToEnd )
178 {
179 //the lang request is null for VSs version of end slave
180 PR_WL__send_end_slave_req( NULL, &handleDissipate, thdToEnd, VSs_MAGIC_NUMBER );
181 }
185 //===========================================================================
188 //======================= task submit and end ==============================
189 /*
190 */
191 void
192 VSs__submit_task( VSsTaskType *taskType, void *args, SlaveVP *animSlv)
193 { VSsLangReq reqData;
195 reqData.reqType = submit_task;
197 reqData.taskType = taskType;
198 reqData.args = args;
199 reqData.callingSlv = animSlv;
201 //Create task is a special form, so have to pass as parameters, the
202 // top-level-fn of task and the data for that fn, plus lang's req,
203 // animating slave, and lang's magic number
204 PR_WL__send_create_task_req( taskType->fn, args, &reqData, NO_ID,
205 &handleSubmitTask, animSlv, VSs_MAGIC_NUMBER );
206 }
208 void
209 VSs__submit_task_with_ID( VSsTaskType *taskType, void *args, int32 *taskID,
210 SlaveVP *animSlv )
211 { VSsLangReq reqData;
213 reqData.reqType = submit_task;
215 reqData.taskType = taskType;
216 reqData.args = args;
217 reqData.callingSlv = animSlv;
219 PR_WL__send_create_task_req( taskType->fn, args, &reqData, taskID,
220 &handleSubmitTask, animSlv, VSs_MAGIC_NUMBER );
221 }
224 /*This call is the last to happen in every task. It causes the slave to
225 * suspend and get the next task out of the task-queue. Notice there is no
226 * assigner here.. only one slave, no slave ReadyQ, and so on..
227 *Can either make the assigner take the next task out of the taskQ, or can
228 * leave all as it is, and make task-end take the next task.
229 *Note: this fits the case in the new PR for no-context tasks, so will use
230 * the built-in taskQ of new PR, and should be local and much faster.
231 *
232 *The task-stub is saved in the animSlv, so the request handler will get it
233 * from there, along with the task-type which has arg types, and so on..
234 *
235 * NOTE: if want, don't need to send the animating SlaveVP around..
236 * instead, can make a single slave per core, and coreCtrlr looks up the
237 * slave from having the core number.
238 *
239 *But, to stay compatible with all the other PR languages, leave it in..
240 */
241 void
242 VSs__end_task( SlaveVP *animSlv )
243 { VSsLangReq reqData;
245 //VSs has nothing extra to communicate to end task handler, so lang req is NULL
246 PR_WL__send_end_task_request( NULL, &handleEndTask, animSlv, VSs_MAGIC_NUMBER );
247 }
250 /*Waits for all tasks that are direct children to end, then resumes calling
251 * task or thread
252 */
253 void
254 VSs__taskwait(SlaveVP *animSlv)
255 {
256 VSsLangReq reqData;
258 reqData.reqType = taskwait;
259 reqData.callingSlv = animSlv;
261 PR_WL__send_lang_request( &reqData, &handleTaskwait, animSlv, VSs_MAGIC_NUMBER );
262 }
266 //========================== send and receive ============================
267 //
269 inline int32 *
270 VSs__give_self_taskID( SlaveVP *animSlv )
271 {
272 return PR__give_ID_from_slave( animSlv, VSs_MAGIC_NUMBER );
273 }
275 //================================ send ===================================
277 void
278 VSs__send_of_type_to( void *msg, const int32 type, int32 *receiverID,
279 SlaveVP *senderSlv )
280 { VSsLangReq reqData;
282 reqData.reqType = send_type_to;
284 reqData.msg = msg;
285 reqData.msgType = type;
286 reqData.receiverID = receiverID;
287 reqData.senderSlv = senderSlv;
289 reqData.nextReqInHashEntry = NULL;
291 PR_WL__send_lang_request( &reqData, &handleSendTypeTo, senderSlv, VSs_MAGIC_NUMBER );
293 //When come back from suspend, no longer own data reachable from msg
294 }
296 void
297 VSs__send_from_to( void *msg, int32 *senderID, int32 *receiverID, SlaveVP *senderSlv )
298 { VSsLangReq reqData;
300 reqData.reqType = send_from_to;
302 reqData.msg = msg;
303 reqData.senderID = senderID;
304 reqData.receiverID = receiverID;
305 reqData.senderSlv = senderSlv;
307 reqData.nextReqInHashEntry = NULL;
309 PR_WL__send_lang_request( &reqData, &handleSendFromTo, senderSlv, VSs_MAGIC_NUMBER );
310 }
313 //================================ receive ================================
315 /*The "type" version of send and receive creates a many-to-one relationship.
316 * The sender is anonymous, and many sends can stack up, waiting to be
317 * received. The same receiver can also have send from-to's
318 * waiting for it, and those will be kept separate from the "type"
319 * messages.
320 */
321 void *
322 VSs__receive_type_to( const int32 type, int32* receiverID, SlaveVP *receiverSlv )
323 { DEBUG__printf1(dbgRqstHdlr,"WL: receive type to %d",receiverID[1] );
324 VSsLangReq reqData;
326 reqData.reqType = receive_type_to;
328 reqData.msgType = type;
329 reqData.receiverID = receiverID;
330 reqData.receiverSlv = receiverSlv;
332 reqData.nextReqInHashEntry = NULL;
334 PR_WL__send_lang_request( &reqData, &handleReceiveTypeTo, receiverSlv, VSs_MAGIC_NUMBER );
336 return receiverSlv->dataRetFromReq;
337 }
341 /*Call this at the point a receiving task wants in-coming data.
342 * Use this from-to form when know senderID -- it makes a direct channel
343 * between sender and receiver.
344 */
345 void *
346 VSs__receive_from_to( int32 *senderID, int32 *receiverID, SlaveVP *receiverSlv )
347 {
348 VSsLangReq reqData;
350 reqData.reqType = receive_from_to;
352 reqData.senderID = senderID;
353 reqData.receiverID = receiverID;
354 reqData.receiverSlv = receiverSlv;
356 reqData.nextReqInHashEntry = NULL;
357 DEBUG__printf2(dbgRqstHdlr,"WL: receive from %d to: %d", reqData.senderID[1], reqData.receiverID[1]);
359 PR_WL__send_lang_request( &reqData, &handleReceiveFromTo, receiverSlv, VSs_MAGIC_NUMBER );
361 return receiverSlv->dataRetFromReq;
362 }
367 //==========================================================================
368 //
369 /*A function singleton is a function whose body executes exactly once, on a
370 * single core, no matter how many times the fuction is called and no
371 * matter how many cores or the timing of cores calling it.
372 *
373 *A data singleton is a ticket attached to data. That ticket can be used
374 * to get the data through the function exactly once, no matter how many
375 * times the data is given to the function, and no matter the timing of
376 * trying to get the data through from different cores.
377 */
379 /*asm function declarations*/
380 void asm_save_ret_to_singleton(VSsSingleton *singletonPtrAddr);
381 void asm_write_ret_from_singleton(VSsSingleton *singletonPtrAddr);
383 /*Fn singleton uses ID as index into array of singleton structs held in the
384 * language environment.
385 */
386 void
387 VSs__start_fn_singleton( int32 singletonID, SlaveVP *animSlv )
388 {
389 VSsLangReq reqData;
391 //
392 reqData.reqType = singleton_fn_start;
393 reqData.singletonID = singletonID;
395 PR_WL__send_lang_request( &reqData, &handleStartFnSingleton, animSlv, VSs_MAGIC_NUMBER );
396 if( animSlv->dataRetFromReq ) //will be 0 or addr of label in end singleton
397 {
398 VSsLangEnv *langEnv =
399 PR_int__give_lang_env_for_slave__ML( animSlv, VSs_MAGIC_NUMBER );
400 asm_write_ret_from_singleton(&(langEnv->fnSingletons[ singletonID]));
401 }
402 }
404 /*Data singleton hands addr of loc holding a pointer to a singleton struct.
405 * The start_data_singleton makes the structure and puts its addr into the
406 * location.
407 */
408 void
409 VSs__start_data_singleton( VSsSingleton **singletonAddr, SlaveVP *animSlv )
410 {
411 VSsLangReq reqData;
413 if( *singletonAddr && (*singletonAddr)->hasFinished )
414 goto JmpToEndSingleton;
416 reqData.reqType = singleton_data_start;
417 reqData.singletonPtrAddr = singletonAddr;
419 PR_WL__send_lang_request( &reqData, &handleStartDataSingleton, animSlv, VSs_MAGIC_NUMBER );
420 if( animSlv->dataRetFromReq ) //either 0 or end singleton's return addr
421 { //Assembly code changes the return addr on the stack to the one
422 // saved into the singleton by the end-singleton-fn
423 //The return addr is at 0x4(%%ebp)
424 JmpToEndSingleton:
425 asm_write_ret_from_singleton(*singletonAddr);
426 }
427 //now, simply return
428 //will exit either from the start singleton call or the end-singleton call
429 }
431 /*Uses ID as index into array of flags. If flag already set, resumes from
432 * end-label. Else, sets flag and resumes normally.
433 *
434 *Note, this call cannot be inlined because the instr addr at the label
435 * inside is shared by all invocations of a given singleton ID.
436 */
437 void
438 VSs__end_fn_singleton( int32 singletonID, SlaveVP *animSlv )
439 {
440 VSsLangReq reqData;
442 //don't need this addr until after at least one singleton has reached
443 // this function
444 VSsLangEnv *
445 langEnv = PR_int__give_lang_env_for_slave__ML( animSlv, VSs_MAGIC_NUMBER );
447 asm_write_ret_from_singleton(&(langEnv->fnSingletons[ singletonID]));
449 reqData.reqType = singleton_fn_end;
450 reqData.singletonID = singletonID;
452 PR_WL__send_lang_request( &reqData, &handleEndFnSingleton, animSlv, VSs_MAGIC_NUMBER );
454 EndSingletonInstrAddr:
455 return;
456 }
458 void
459 VSs__end_data_singleton( VSsSingleton **singletonPtrAddr, SlaveVP *animSlv )
460 {
461 VSsLangReq reqData;
463 //don't need this addr until after singleton struct has reached
464 // this function for first time
465 //do assembly that saves the return addr of this fn call into the
466 // data singleton -- that data-singleton can only be given to exactly
467 // one instance in the code of this function. However, can use this
468 // function in different places for different data-singletons.
469 asm_save_ret_to_singleton(*singletonPtrAddr);
471 reqData.reqType = singleton_data_end;
472 reqData.singletonPtrAddr = singletonPtrAddr;
474 PR_WL__send_lang_request( &reqData, &handleEndDataSingleton, animSlv, VSs_MAGIC_NUMBER );
475 }
477 /*This executes the function in the masterVP, so it executes in isolation
478 * from any other copies -- only one copy of the function can ever execute
479 * at a time.
480 *
481 *It suspends to the master, and the request handler takes the function
482 * pointer out of the request and calls it, then resumes the VP.
483 *Only very short functions should be called this way -- for longer-running
484 * isolation, use transaction-start and transaction-end, which run the code
485 * between as work-code.
486 */
487 void
488 VSs__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster,
489 void *data, SlaveVP *animSlv )
490 {
491 VSsLangReq reqData;
493 //
494 reqData.reqType = atomic;
495 reqData.fnToExecInMaster = ptrToFnToExecInMaster;
496 reqData.dataForFn = data;
498 PR_WL__send_lang_request( &reqData, &handleAtomic, animSlv, VSs_MAGIC_NUMBER );
499 }
502 /*This suspends to the master.
503 *First, it looks at the VP's data, to see the highest transactionID that VP
504 * already has entered. If the current ID is not larger, it throws an
505 * exception stating a bug in the code. Otherwise it puts the current ID
506 * there, and adds the ID to a linked list of IDs entered -- the list is
507 * used to check that exits are properly ordered.
508 *Next it is uses transactionID as index into an array of transaction
509 * structures.
510 *If the "VP_currently_executing" field is non-null, then put requesting VP
511 * into queue in the struct. (At some point a holder will request
512 * end-transaction, which will take this VP from the queue and resume it.)
513 *If NULL, then write requesting into the field and resume.
514 */
515 void
516 VSs__start_transaction( int32 transactionID, SlaveVP *animSlv )
517 {
518 VSsLangReq reqData;
520 //
521 reqData.callingSlv = animSlv;
522 reqData.reqType = trans_start;
523 reqData.transID = transactionID;
525 PR_WL__send_lang_request( &reqData, &handleTransStart, animSlv, VSs_MAGIC_NUMBER );
526 }
528 /*This suspends to the master, then uses transactionID as index into an
529 * array of transaction structures.
530 *It looks at VP_currently_executing to be sure it's same as requesting VP.
531 * If different, throws an exception, stating there's a bug in the code.
532 *Next it looks at the queue in the structure.
533 *If it's empty, it sets VP_currently_executing field to NULL and resumes.
534 *If something in, gets it, sets VP_currently_executing to that VP, then
535 * resumes both.
536 */
537 void
538 VSs__end_transaction( int32 transactionID, SlaveVP *animSlv )
539 {
540 VSsLangReq reqData;
542 //
543 reqData.callingSlv = animSlv;
544 reqData.reqType = trans_end;
545 reqData.transID = transactionID;
547 PR_WL__send_lang_request( &reqData, &handleTransEnd, animSlv, VSs_MAGIC_NUMBER );
548 }
550 //======================== Internal ==================================
