VMS/VMS_Implementations/VMS_impls/VMS__MC_shared_impl

view PR__int.c @ 286:b02b34681414

VReo V2 -- saves checker and doer fn with the port, where triggered
author Sean Halle <seanhalle@yahoo.com>
date Wed, 10 Jul 2013 14:49:04 -0700
parents 72ffdb11ad8e
children 744b5ff9851e
line source
1 /*
2 * Copyright 2010 OpenSourceResearchInstitute
3 *
4 * Licensed under BSD
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <malloc.h>
11 #include <inttypes.h>
12 #include <sys/time.h>
14 #include "PR.h"
17 /* MEANING OF WL PI SS int
18 * These indicate which places the function is safe to use. They stand for:
19 * WL: Wrapper Library
20 * PI: Plugin
21 * SS: Startup and Shutdown
22 * int: internal to the PR implementation
23 */
25 //===========================================================================
26 //
27 //===========================================================================
28 /*This does the basic work of creating the SlaveVP structure.. but doesn't
29 * know which process it goes in, nor what type of VP it is, etc..
30 */
31 inline
32 SlaveVP *
33 PR_int__create_slaveVP_helper( BirthFnPtr fnPtr, void *dataParam )
34 { SlaveVP *newSlv;
35 void *stackLocs;
37 newSlv = PR_int__malloc( sizeof(SlaveVP) );
38 stackLocs = PR_int__malloc( VIRT_PROCR_STACK_SIZE );
39 if( stackLocs == 0 )
40 { perror("PR_int__malloc stack"); exit(1); }
42 newSlv->startOfStack = stackLocs;
43 newSlv->slaveNum = _PRTopEnv->numSlavesCreated++;
44 newSlv->request = NULL;
45 newSlv->animSlotAssignedTo = NULL;
47 newSlv->numTimesAssignedToASlot = 0;
50 newSlv->langDatas =
51 (PRLangData **)PR_int__make_collection_of_size( NUM_IN_COLLECTION );
53 newSlv->metaTasks =
54 (PRMetaTask **) PR_int__make_collection_of_size( NUM_IN_COLLECTION );
56 PR_int__reset_slaveVP_to_BirthFn( newSlv, fnPtr, dataParam );
58 //============================= MEASUREMENT STUFF ========================
59 #ifdef PROBES__TURN_ON_STATS_PROBES
60 //TODO: make this TSCHiLow or generic equivalent
61 //struct timeval timeStamp;
62 //gettimeofday( &(timeStamp), NULL);
63 //newSlv->createPtInSecs = timeStamp.tv_sec +(timeStamp.tv_usec/1000000.0) -
64 // _PRTopEnv->createPtInSecs;
65 #endif
66 //========================================================================
68 newSlv->typeOfVP = GenericSlave; //may be changed later!
70 return newSlv;
71 }
73 inline
74 SlaveVP *
75 PR_int__create_slaveVP( BirthFnPtr fnPtr, void *dataParam, PRProcess *process )
76 { SlaveVP *newSlv;
78 newSlv = PR_int__create_slaveVP_helper( fnPtr, dataParam );
80 process->numLiveGenericSlvs += 1;
82 return newSlv;
83 }
86 /*A slot slave doesn't use array for lang data nor meta tasks, but it's in
87 * there anyway.. have to copy what create slave does, so can just change
88 * the type when a slot slave is converted..
89 */
90 SlaveVP *
91 PR_int__create_slot_slave( )
92 { SlaveVP *retSlv;
94 retSlv = PR_int__create_slaveVP_helper( &idle_fn, NULL );
95 retSlv->typeOfVP = SlotTaskSlv;
98 retSlv->langDatas =
99 (PRLangData **) PR_int__make_collection_of_size( NUM_IN_COLLECTION );
101 retSlv->metaTasks =
102 (PRMetaTask **) PR_int__make_collection_of_size( NUM_IN_COLLECTION );
104 return retSlv;
105 }
109 /*Called when a new slot slave is needed.. takes from recycle pool, and
110 * sets the slave up to be a slot slave -- no lang data array, no meta task
111 * array.
112 */
113 SlaveVP *
114 PR_int__get_recycled_slot_slave( )
115 { SlaveVP *retSlv;
117 //take slave from recycle Q
118 retSlv = readPrivQ( _PRTopEnv->slaveRecycleQ );
120 if( retSlv != NULL )
121 {
122 //set slave up with slot-slave's initial values.
123 retSlv->typeOfVP = SlotTaskSlv;
124 retSlv->slaveNum = _PRTopEnv->numSlavesCreated++;
125 retSlv->numTimesAssignedToASlot = 0;
126 retSlv->request = NULL;
127 }
128 else //if none to recycle, create a new one
129 { retSlv = PR_int__create_slot_slave();
130 }
132 return retSlv;
133 }
135 //==========================================================================
136 /*When a task in a slot slave suspends, the slot slave has to be changed to
137 * a free task slave, then the slot slave replaced. The replacement can be
138 * either a recycled free task slave that finished it's task and has been
139 * idle in the recycle queue, or else create a new slave to be the slot slave.
140 *The master only calls this with a slot slave that needs to be replaced.
141 *
142 *The master continues after this call, handing the converted Free task slave
143 * to a request handler, which places the converted slave into the langlet's
144 * env, so it will eventually resume
145 */
146 inline
147 void
148 PR_int__replace_with_new_slot_slv( SlaveVP *oldSlotSlv )
149 { SlaveVP *newSlotSlv;
151 //get a new slave to be the slot slave
152 newSlotSlv = PR_int__get_recycled_slot_slave();
154 //a slot slave is pinned to a particular slot on a particular core
155 //Note, this happens before the request is seen by handler, so nothing
156 // has had a chance to change the coreAnimatedBy or anything else..
157 newSlotSlv->animSlotAssignedTo = oldSlotSlv->animSlotAssignedTo;
158 newSlotSlv->coreAnimatedBy = oldSlotSlv->coreAnimatedBy;
160 //put it into the slot slave matrix
161 int32 slotNum = oldSlotSlv->animSlotAssignedTo->slotIdx;
162 int32 coreNum = oldSlotSlv->coreAnimatedBy;
163 _PRTopEnv->slotTaskSlvs[coreNum][slotNum] = newSlotSlv;
165 //Fix up requester, to be an extra slave now (but not an ended one)
166 // because it's active, doesn't go into freeTaskSlvRecycleQ
167 //Note that process was set when task was assigned to the slot slave..
168 oldSlotSlv->typeOfVP = FreeTaskSlv;
169 }
171 void idle_fn(void* data, SlaveVP *animatingSlv)
172 {
173 while(1)
174 { PR_WL__suspend_slaveVP_and_send_req( animatingSlv );
175 }
176 }
180 //===========================================================================
181 /*there is a label inside this function -- save the addr of this label in
182 * the callingSlv struc, as the pick-up point from which to start the next
183 * work-unit for that slave. If turns out have to save registers, then
184 * save them in the slave struc too. Then do assembly jump to the CoreCtlr's
185 * "done with work-unit" label. The slave struc is in the request in the
186 * slave that animated the just-ended work-unit, so all the state is saved
187 * there, and will get passed along, inside the request handler, to the
188 * next work-unit for that slave.
189 */
190 void
191 PR_WL__suspend_slaveVP_and_send_req( SlaveVP *animatingSlv )
192 {
194 //This suspended Slv will get assigned by Master again at some
195 // future point
197 //return ownership of the Slv and anim slot to Master virt pr
198 animatingSlv->animSlotAssignedTo->workIsDone = TRUE;
200 HOLISTIC__Record_HwResponderInvocation_start;
201 MEAS__Capture_Pre_Susp_Point;
202 //This assembly function is a PR primitive that first saves the
203 // stack and frame pointer, plus an addr inside this assembly code.
204 //When core ctlr later gets this slave out of a sched slot, it
205 // restores the stack and frame and then jumps to the addr.. that
206 // jmp causes return from this function.
207 //So, in effect, this function takes a variable amount of wall-clock
208 // time to complete -- the amount of time is determined by the
209 // Master, which makes sure the memory is in a consistent state first.
210 switchToCoreCtlr(animatingSlv);
211 flushRegisters();
212 MEAS__Capture_Post_Susp_Point;
214 return;
215 }
219 /*In multi-lang mode, there are multiple langData in the slave..
220 *
221 *At some point want to recycle rather than free..
222 *
223 *For now, iterate through langData, call registered free-er on each, then
224 * free the basic slave
225 *
226 *DOES NOT DECREMENT NUMBER OF LIVE SLAVES IN PROCESS
227 */
228 void
229 PR_int__free_slaveVP( SlaveVP *slave )
230 {
231 PR_int__apply_Fn_to_all_in_collection( &freeLangDataAsElem,
232 (PRCollElem**) slave->langDatas );
233 PR_int__apply_Fn_to_all_in_collection( &freeMetaTaskAsElem,
234 (PRCollElem**) slave->metaTasks );
236 PR_int__free( &(((int32*)(slave->langDatas))[-1]) );
237 PR_int__free( &(((int32*)(slave->metaTasks))[-1]) );
238 PR_int__free( slave->startOfStack );
239 PR_int__free( slave );
240 }
242 /*This calls the freer registered for each langlet's lang data and meta
243 * task. Then it makes the collections empty. It also recycles the slave
244 * struct.
245 *Note: it does not clear "next in coll" pointers in the coll elements!
246 *
247 *DOES NOT DECREMENT NUMBER OF LIVE SLAVES IN PROCESS
248 *
249 *Note, the fn applied to all elements of collections checks the "don't delete"
250 * flag in the lang data and the meta task.. so, if an alternative way of
251 * freeing the slaveVP struct is created, it should handle the "don't delete"
252 * flag. (although, an "abort" cleanup should ignore the don't delete flag)
253 */
254 void
255 PR_int__recycle_slaveVP( SlaveVP *slave )
256 {
257 PR_int__apply_Fn_to_all_in_collection( &freeLangDataAsElem,
258 (PRCollElem**) slave->langDatas );
259 PR_int__apply_Fn_to_all_in_collection( &freeMetaTaskAsElem,
260 (PRCollElem**) slave->metaTasks );
261 //now, set the collections to "empty"
262 PR_int__set_collection_to_empty((PRCollElem**) slave->langDatas);
263 PR_int__set_collection_to_empty((PRCollElem**) slave->metaTasks);
265 writePrivQ( slave, _PRTopEnv->slaveRecycleQ );
266 }
268 /*Receives a protoLangData, but in the form of a void, so have to cast
269 *First checks the "no delete" flag..
270 */
271 void
272 freeLangDataAsElem( void *elem )
273 { PRLangData *protoLangData;
275 protoLangData = (PRLangData *)elem; //recycler actually receives the prolog.
276 if( protoLangData->goAheadAndFree == FALSE )
277 return;
279 //apply the free fn that's stored in the lang data prolog
280 //Note: freeing whole slave, so no need to remove from collection
281 //Note: langlet's freer only frees what langlet has malloc'd
282 if(protoLangData->freer != NULL)
283 { (*(protoLangData->freer))( PR_int__give_lang_data_of_prolog(protoLangData) );
284 }
285 PR_int__free( protoLangData );
286 }
288 /*Receives a protoMetaTask, but in form of a void, so have to cast
289 */
290 void
291 freeMetaTaskAsElem( void *elem )
292 { PRMetaTask *protoMetaTask;
294 protoMetaTask = (PRMetaTask *)elem; //recycler receives the prolog, and must call
295 //a PR Fn to convert prolog to lang-specific version.
297 if( protoMetaTask->goAheadAndFree == FALSE )
298 return;
300 //apply the free fn that's stored in the meta task prolog
301 (*(protoMetaTask->freer))( PR_int__give_lang_meta_task_of_prolog(protoMetaTask) );
302 }
306 //======================================
307 inline
308 void *
309 PR_int__give_lang_env( PRLangEnv *protoLangEnv )
310 {
311 return (void *) &(protoLangEnv[1]);
312 }
313 inline
314 PRLangEnv *
315 PR_int__give_proto_lang_env( void *langEnv )
316 {
317 return (PRLangEnv *) &(((PRLangEnv *)langEnv)[-1]);
318 }
320 //inline
321 void *
322 PR_int__create_lang_env_in_process( int32 numBytes, PRProcess *process, int32 magicNum )
323 { PRLangEnv *retEnv;
324 PRCollElem **langEnvs;
326 //make the new lang env, with room for the prolog
327 retEnv = PR_int__malloc( sizeof(PRLangEnv) + numBytes );
328 retEnv->chainedLangEnv = NULL; //used while inserting into langEnvs
329 retEnv->langMagicNumber = magicNum; //used while inserting into langEnvs
330 retEnv->processEnvIsIn = process;
331 retEnv->numLiveWork = 0;
332 retEnv->waitingForWorkToEndQ = makePrivQ();
334 //process has a PR Collection of lang envs -- get it and insert into it
335 langEnvs = (PRCollElem **)process->langEnvs;
336 PR_int__insert_elem_into_collection( (PRCollElem *)retEnv, langEnvs, magicNum);
337 int32 idxInProcess = process->numLangEnvs; //index starts at 0 for first lang
338 process->protoLangEnvsList[idxInProcess] = retEnv;
339 retEnv->idxInProcess = idxInProcess;
340 process->numLangEnvs += 1;
342 return (void *)&(retEnv[1]); //skip over prolog
343 }
345 inline
346 void *
347 PR_int__remove_lang_env_from_process_and_free( void *langEnv )
348 { PRLangEnv *protoLangEnv = PR_int__give_proto_lang_env( langEnv );
349 PRCollElem **langEnvs;
350 PRLangEnv **langEnvsList;
352 //process has a PR Collection of lang envs -- get it and remove env
353 PRProcess *process = protoLangEnv->processEnvIsIn;
354 langEnvs = (PRCollElem **)process->langEnvs;
355 PR_int__remove_elem_from_collection( protoLangEnv->langMagicNumber, langEnvs );
356 int32 count, idx;
357 idx = protoLangEnv->idxInProcess;
358 count = (process->numLangEnvs - idx) * sizeof(PRLangEnv *);//idx starts at 0
359 memmove( &(langEnvsList[idx]), &(langEnvsList[idx+1]), count);
360 process->numLangEnvs -= 1;
362 PR_int__free( protoLangEnv );
363 }
365 inline
366 void *
367 PR_int__give_lang_env_of_req( PRReqst *req, SlaveVP *requestingSlv )
368 {
369 return PR_int__give_lang_env_from_process( requestingSlv->processSlaveIsIn,
370 req->langMagicNumber );
371 }
373 inline
374 void *
375 PR_int__give_lang_env_for_slave( SlaveVP *slave, int32 magicNum )
376 {
377 return PR_int__give_lang_env_from_process( slave->processSlaveIsIn, magicNum );
378 }
379 inline
380 PRLangEnv *
381 PR_int__give_proto_lang_env_for_slave( SlaveVP *slave, int32 magicNum )
382 {
383 return PR_int__give_proto_lang_env_from_process( slave->processSlaveIsIn, magicNum );
384 }
386 inline
387 void *
388 PR_int__give_lang_env_from_process( PRProcess *process, int32 magicNum )
389 { PRLangEnv *retLangEnv;
390 PRCollElem **langEnvs;
392 langEnvs = (PRCollElem **)process->langEnvs;
393 retLangEnv = PR_int__lookup_elem_in_collection( magicNum, langEnvs );
394 if( retLangEnv != NULL )
395 return &(retLangEnv[1]); //skip over prolog
396 else
397 return NULL;
398 }
399 inline
400 PRLangEnv *
401 PR_int__give_proto_lang_env_from_process( PRProcess *process, int32 magicNum )
402 { PRLangEnv *retLangEnv;
403 PRCollElem **langEnvs;
405 langEnvs = (PRCollElem **)process->langEnvs;
406 retLangEnv = PR_int__lookup_elem_in_collection( magicNum, langEnvs );
407 return retLangEnv; //return prolog
408 }
410 /*
411 inline
412 void
413 PR_int__set_work_in_lang_env( void *_langEnv )
414 { PRLangEnv *protoLangEnv = &(((PRLangEnv *)_langEnv)[-1]); //go to the prolog
415 if( protoLangEnv->hasWork != TRUE )
416 { protoLangEnv->hasWork = TRUE;
417 protoLangEnv->processEnvIsIn->numEnvsWithWork += 1;
418 }
419 }
420 inline
421 void
422 PR_int__clear_work_in_lang_env( void *_langEnv )
423 { PRLangEnv *prototLangEnv = &(((PRLangEnv *)_langEnv)[-1]); //back up addr to the prolog
425 if( prototLangEnv->hasWork != FALSE )
426 { prototLangEnv->hasWork = FALSE;
427 prototLangEnv->processEnvIsIn->numEnvsWithWork -= 1;
428 }
429 }
430 */
432 /*This is to be called by langlet's assigner.
433 */
434 inline
435 void
436 PR_int__put_slave_into_slot( SlaveVP *slave, AnimSlot *slot )
437 {
438 slave->coreAnimatedBy = slot->coreSlotIsOn;
439 //if work found, put into slot, and adjust flags and state
440 slot->slaveAssignedToSlot = slave;
441 slave->animSlotAssignedTo = slot;
442 slot->needsWorkAssigned = FALSE;
444 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
445 //have a slave to be assigned to the slot
446 //assignSlv->numTimesAssigned++;
447 //get previous occupant of the slot
448 PRProcess *process = slave->processSlaveIsIn;
449 int32 coreNum = slot->coreSlotIsOn;
450 int32 slotNum = slot->slotIdx;
451 Unit prev_in_slot =
452 process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum];
453 if(prev_in_slot.vp != 0) //if not first slave in slot, make dependency
454 { Dependency newD; // is a hardware dependency
455 newD.from_vp = prev_in_slot.vp;
456 newD.from_task = prev_in_slot.task;
457 newD.to_vp = slave->slaveNum;
458 newD.to_task = slave->numTimesAssignedToASlot;
459 addToListOfArrays(Dependency,newD,process->hwArcs);
460 }
461 prev_in_slot.vp = slave->slaveNum; //make new slave the new previous
462 prev_in_slot.task = slave->numTimesAssignedToASlot;
463 process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] =
464 prev_in_slot;
466 #endif
467 }
470 /*This is to be called by langlet's assigner
471 */
472 inline
473 void
474 PR_int__put_task_into_slot( void *langMetaTask, AnimSlot *slot )
475 { int32 slotNum, coreNum;
476 SlaveVP *slotSlv;
477 PRMetaTask *protoMetaTask;
479 protoMetaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask );
481 //get the slot slave to assign the task to..
482 slotNum = slot->slotIdx;
483 coreNum = slot->coreSlotIsOn;
484 slotSlv = _PRTopEnv->slotTaskSlvs[coreNum][slotNum];
486 //point slave to task's function
487 PR_int__reset_slaveVP_to_BirthFn( slotSlv, protoMetaTask->topLevelFn, protoMetaTask->initData );
488 PR_int__insert_meta_task_into_slave( protoMetaTask, slotSlv );
489 slotSlv->processSlaveIsIn = protoMetaTask->processTaskIsIn;
490 PR_int__put_slave_into_slot( slotSlv, slot );
491 }
493 //==========================
494 inline
495 PRMetaTask *
496 PR_int__give_prolog_of_lang_meta_task( void *task )
497 {
498 return (PRMetaTask *) &(((PRMetaTask *)task)[-1]);
499 }
501 inline
502 void *
503 PR_int__give_lang_meta_task_of_prolog( PRMetaTask *metaTask)
504 {
505 return (void *)&(metaTask[1]);
506 }
509 inline
510 PRMetaTask *
511 PR_int__create_proto_meta_task( int32 size, LangMetaTaskFreer freer, int32 magicNum )
512 { PRMetaTask *retMetaTask;
514 //make the new meta task
515 retMetaTask = PR_int__malloc( sizeof(PRMetaTask) + size );
516 retMetaTask->chainedMetaTask = NULL;
517 retMetaTask->langMagicNumber = magicNum;
518 retMetaTask->slaveAssignedTo = NULL;
519 retMetaTask->taskType = SlotTask; //just common default
520 retMetaTask->ID = NULL;
521 retMetaTask->freer = freer;
522 retMetaTask->goAheadAndFree = TRUE;
524 return retMetaTask; //skip over prolog
525 }
527 /*Calls the lang's freer, which is pointed to, and also removes from collection
528 */
529 void
530 PR_int__free_lang_meta_task_and_remove_from_coll( void *langMetaTask)
531 { PRMetaTask *protoMetaTask;
533 protoMetaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask );
534 PR_int__remove_elem_from_collection( protoMetaTask->langMagicNumber,
535 (PRCollElem **) protoMetaTask->slaveAssignedTo->metaTasks );
537 (*protoMetaTask->freer)(langMetaTask);
538 PR_int__free( protoMetaTask );
539 }
541 /*Just calls the lang's freer, and frees the malloc'd meta-task chunk. Should
542 * already have been removed from slave's collection and all queues holding it
543 */
544 void
545 PR_int__free_lang_meta_task( void *langMetaTask)
546 { PRMetaTask *protoMetaTask;
548 protoMetaTask = PR_int__give_prolog_of_lang_meta_task( langMetaTask );
550 (*protoMetaTask->freer)(langMetaTask);
551 PR_int__free( protoMetaTask );
552 }
554 inline
555 void *
556 PR_int__create_lang_meta_task( int32 size, LangMetaTaskFreer freer, int32 magicNum )
557 { PRMetaTask *retMetaTask;
559 //make the new meta task
561 retMetaTask = PR_int__create_proto_meta_task( size, freer, magicNum );
563 return &(retMetaTask[1]); //skip over prolog
564 }
566 inline
567 void
568 PR_int__insert_meta_task_into_slave( PRMetaTask *task, SlaveVP *slave )
569 {
570 task->slaveAssignedTo = slave;
571 PR_int__insert_elem_into_collection( (PRCollElem *)task,
572 (PRCollElem **)slave->metaTasks, task->langMagicNumber );
573 }
574 inline
575 void
576 PR_int__insert_lang_meta_task_into_slave( void *langMetaTask, SlaveVP *slave )
577 { PRMetaTask *metaTask = &(((PRMetaTask*)langMetaTask)[-1]);
578 metaTask->slaveAssignedTo = slave;
579 PR_int__insert_elem_into_collection( (PRCollElem *)metaTask,
580 (PRCollElem **)slave->metaTasks, metaTask->langMagicNumber );
581 }
583 /*allocates space for a new lang-meta-task, and inserts it into the slave,
584 * under the given magic number.
585 */
586 inline
587 void *
588 PR_int__create_lang_meta_task_in_slave( int32 size, LangMetaTaskFreer freer, SlaveVP *slave, int32 magicNum )
589 { PRMetaTask *retMetaTask;
590 PRCollElem **metaTasks;
592 //make the new meta task
593 retMetaTask = PR_int__create_proto_meta_task( size, freer, magicNum );
594 retMetaTask->slaveAssignedTo = slave;
595 retMetaTask->taskType = GenericSlave;
597 //have a "collection" of meta tasks inside the slave
598 metaTasks = (PRCollElem **)slave->metaTasks;
599 PR_int__insert_elem_into_collection( (PRCollElem *)retMetaTask,
600 metaTasks, magicNum );
602 return &(retMetaTask[1]); //skip over prolog
603 }
607 inline
608 void *
609 PR_int__give_lang_meta_task_from_slave( SlaveVP *slave, int32 magicNum )
610 { PRMetaTask *retMetaTask;
611 PRCollElem **metaTasks;
612 PRLangEnv *protoLangEnv;
614 metaTasks = (PRCollElem **)slave->metaTasks;
615 retMetaTask = PR_int__lookup_elem_in_collection( magicNum, metaTasks );
616 if( retMetaTask != NULL )
617 return PR_int__give_lang_meta_task_of_prolog(retMetaTask); //skip over prolog
618 else
619 { protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, magicNum );
620 if(protoLangEnv->langMetaTaskCreator == NULL)
621 PR_int__error("register a meta task creator");
622 //This will call
623 return (*protoLangEnv->langMetaTaskCreator)( slave );
624 }
625 }
628 //================== langData =============================
629 inline
630 PRLangData *
631 PR_int__give_prolog_of_lang_data( void *langData )
632 {
633 return (PRLangData *) &(((PRLangData *)langData)[-1]);
634 }
636 inline
637 void *
638 PR_int__give_lang_data_of_prolog( PRLangData *langData)
639 {
640 return (void *)&(langData[1]);
641 }
643 /*Allocates space for a new lang-data, and inserts it into the slave,
644 * under the given magic number. Also returns it.
645 *
646 *Langlet is responsible for using this to create lang data inside its
647 * create-slave handler
648 */
649 inline
650 void *
651 PR_PI__create_lang_data_in_slave( int32 size, LangDataFreer freer,
652 SlaveVP *slave, int32 magicNum )
653 { PRLangData *retLangData;
654 PRCollElem **langDatas;
656 //make the new lang Data
657 retLangData = PR_int__malloc( sizeof(PRLangData) + size );
658 retLangData->chainedLangData = NULL;
659 retLangData->langMagicNumber = magicNum;
660 retLangData->freer = freer;
661 retLangData->goAheadAndFree = TRUE;
662 retLangData->slaveAssignedTo = slave;
664 //multilang has a "collection" of lang datas inside the slave
665 langDatas = (PRCollElem **)slave->langDatas;
666 PR_int__insert_elem_into_collection( (PRCollElem *)retLangData, langDatas, magicNum );
668 return &(retLangData[1]); //skip over prolog
669 }
670 void
671 PR_int__free_lang_data( void *langData)
672 { PRLangData *protoLangData;
674 protoLangData = PR_int__give_prolog_of_lang_data( langData );
675 PR_int__remove_elem_from_collection( protoLangData->langMagicNumber,
676 (PRCollElem **) protoLangData->slaveAssignedTo->langDatas );
678 (*protoLangData->freer)(langData);
679 PR_int__free( protoLangData );
680 }
682 inline
683 void *
684 PR_int__give_lang_data_from_slave( SlaveVP *slave, int32 magicNum )
685 { PRLangData *retLangData;
686 PRCollElem **langDatas;
687 PRLangEnv *protoLangEnv;
689 langDatas = (PRCollElem **)slave->langDatas;
690 retLangData = PR_int__lookup_elem_in_collection( magicNum, langDatas );
691 if( retLangData != NULL )
692 return &( retLangData[1] ); //skip over prolog
693 else
694 { protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, magicNum );
695 if(protoLangEnv->langDataCreator == NULL)
696 PR_int__error("register a lang data creator");
697 //This will call PR_PI__create_lang_data_in_slave -- puts it into slave
698 return (*protoLangEnv->langDataCreator)( slave );
699 }
700 }
703 //===============================================
704 PRCollElem ** //return an array of pointers
705 PR_int__make_collection_of_size( int32 numInColl )
706 { int32 *prolog;
707 PRCollElem **coll;
708 //Note using size of a pointer to a coll element
709 int32 numBytes = sizeof(int32) + numInColl * sizeof(PRCollElem *);
710 prolog = PR_int__malloc( numBytes );
712 //operation of collection relies upon initial entries being NULL
713 memset(prolog, ZERO, numBytes>>2); //BUG: if size not multiple of 4
715 prolog[0] = numInColl;
716 coll = (PRCollElem **)&(prolog[1]);
717 return coll;
718 }
720 inline
721 void
722 PR_int__insert_elem_into_collection( PRCollElem *elem, PRCollElem **coll, int32 hash )
723 { int32 idx, numIdxsInColl;
724 PRCollElem *test;
726 numIdxsInColl = ((int32 *)coll)[-1]; //prolog holds number of idexes in array
728 //figure out where to link in
729 idx = hash & (numIdxsInColl - 1); //mask off, leaving lowest bits
730 test = coll[idx];
731 elem->chained = NULL; //elem goes at end of any chain, so just being sure here
732 if( test == NULL ) //spot empty, so add there
733 { //add to the array
734 coll[idx] = elem;
735 }
736 else //collision -- look for last in chain, then add there
737 { while( test->chained != NULL )
738 { test = test->chained;
739 }
740 //add new to the end of chain
741 test->chained = elem;
742 }
743 }
745 inline
746 void *
747 PR_int__lookup_elem_in_collection( int32 hash, PRCollElem **coll )
748 { int32 idx, numIdxsInColl;
749 PRCollElem *test;
751 numIdxsInColl = ((int32 *)coll)[-1]; //prolog holds number of indexes in array
753 idx = hash & (numIdxsInColl - 1); //mask off, leaving lowest bits
754 test = coll[idx];
755 if( test == NULL ) goto NotFound;
756 while( test->hash != hash )
757 { test = test->chained;
758 if( test == NULL ) goto NotFound;
759 }
760 return test;
762 NotFound:
763 return NULL;
764 }
766 inline
767 void
768 PR_int__remove_elem_from_collection( int32 hash, PRCollElem **coll )
769 { int32 idx, numIdxsInColl;
770 PRCollElem *test, *prev;
772 numIdxsInColl = ((int32 *)coll)[-1]; //num indexes in prolog -- power of 2
774 idx = hash & (numIdxsInColl - 1); //mask off, leaving lowest bits (power of 2)
775 test = coll[idx];
776 if( test == NULL ) return; //not found, nothing to remove
777 prev = NULL;
778 while( test->hash != hash )
779 { prev = test;
780 test = test->chained;
781 if( test == NULL ) return; //not found, nothing to remove
782 }
783 if( prev == NULL) //is first elem in chain, so modify ptr in array
784 { coll[idx] = coll[idx]->chained;
785 return;
786 }
787 else //remove link from chain
788 { prev->chained = test->chained;
789 return;
790 }
791 }
794 /*The function is allowed to modify its OWN chaining.. this takes the next
795 * in chain before calling the function (useful when the function conditionally
796 * frees)
797 */
798 inline
799 void
800 PR_int__apply_Fn_to_all_in_collection( void (*Fn)(void *), PRCollElem **coll )
801 { int32 idx, numIdxsInColl;
802 PRCollElem *test, *chainedTest;
804 numIdxsInColl = ((int32 *)coll)[-1]; //prolog is num idxs
805 //march down array of elements, for each, march down linked chain of elems
806 for( idx = 0; idx < numIdxsInColl; idx++ )
807 { test = coll[idx];
808 while( test != NULL )
809 { chainedTest = test->chained; //Fn may destroy test or change test->chained
810 (*Fn)((void *)test);
811 test = chainedTest;
812 }
813 }
814 }
816 /*Just sets all entries to NULL -- doesn't modify chaining of any elements
817 * that may be left in the collection..
818 */
819 inline
820 void
821 PR_int__set_collection_to_empty( PRCollElem **coll )
822 { int32 numIdxsInColl = ((int32 *)coll)[-1]; //prolog is num idxs
823 memset( coll, 0, numIdxsInColl * sizeof(PRCollElem *) );
824 }
825 //==========================================
828 //==========================================
830 /*Later, improve this -- for now, just exits the application after printing
831 * the error message.
832 */
833 void
834 PR_int__throw_exception( char *msgStr, SlaveVP *reqstSlv, PRExcp *excpData )
835 {
836 printf("%s",msgStr);
837 fflush(stdin);
838 exit(1);
839 }
841 void
842 PR_int__error( char *msgStr )
843 {
844 printf("%s",msgStr);
845 fflush(stdin);
846 exit(1);
847 }
850 char *
851 PR_int__strDup( char *str )
852 { char *retStr;
854 if( str == NULL ) return NULL;
855 retStr = (char *)PR_int__malloc( strlen(str) + 1 );
856 strcpy( retStr, str );
858 return (char *)retStr;
859 }
862 inline void
863 PR_int__backoff_for_TooLongToGetLock( int32 numTriesToGetLock );
865 inline void
866 PR_int__get_wrapper_lock()
867 { int32 *addrOfWrapperLock;
869 #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
870 return;
871 #endif
873 addrOfWrapperLock = &(_PRTopEnv->wrapperLock);
875 int numTriesToGetLock = 0;
876 int gotLock = 0;
878 // MEAS__Capture_Pre_Master_Lock_Point;
879 while( !gotLock ) //keep going until get master lock
880 {
881 numTriesToGetLock++; //if too many, means too much contention
882 if( numTriesToGetLock > NUM_TRIES_BEFORE_DO_BACKOFF )
883 { PR_int__backoff_for_TooLongToGetLock( numTriesToGetLock );
884 }
885 if( numTriesToGetLock > MASTERLOCK_RETRIES_BEFORE_YIELD )
886 { numTriesToGetLock = 0;
887 pthread_yield();
888 }
890 //try to get the lock
891 gotLock = __sync_bool_compare_and_swap( addrOfWrapperLock,
892 UNLOCKED, LOCKED );
893 }
894 // MEAS__Capture_Post_Master_Lock_Point;
895 }
897 inline void
898 PR_int__get_malloc_lock()
899 { int32 *addrOfMallocLock;
901 #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
902 return;
903 #endif
905 addrOfMallocLock = &(_PRTopEnv->mallocLock);
907 int numTriesToGetLock = 0;
908 int gotLock = 0;
910 MEAS__Capture_Pre_Master_Lock_Point;
911 while( !gotLock ) //keep going until get master lock
912 {
913 numTriesToGetLock++; //if too many, means too much contention
914 if( numTriesToGetLock > NUM_TRIES_BEFORE_DO_BACKOFF )
915 { PR_int__backoff_for_TooLongToGetLock( numTriesToGetLock );
916 }
917 if( numTriesToGetLock > MASTERLOCK_RETRIES_BEFORE_YIELD )
918 { numTriesToGetLock = 0;
919 pthread_yield();
920 }
922 //try to get the lock
923 gotLock = __sync_bool_compare_and_swap( addrOfMallocLock,
924 UNLOCKED, LOCKED );
925 }
926 MEAS__Capture_Post_Master_Lock_Point;
927 }
929 /*Used by the backoff to pick a random amount of busy-wait. Can't use the
930 * system rand because it takes much too long.
931 *Note, are passing pointers to the seeds, which are then modified
932 */
933 inline uint32_t
934 PR_int__randomNumber()
935 {
936 _PRTopEnv->seed1 = 36969 * (_PRTopEnv->seed1 & 65535) +
937 (_PRTopEnv->seed1 >> 16);
938 _PRTopEnv->seed2 = 18000 * (_PRTopEnv->seed2 & 65535) +
939 (_PRTopEnv->seed2 >> 16);
940 return (_PRTopEnv->seed1 << 16) + _PRTopEnv->seed2;
941 }
944 /*Busy-waits for a random number of cycles -- chooses number of cycles
945 * differently than for the no-work backoff
946 */
947 inline void
948 PR_int__backoff_for_TooLongToGetLock( int32 numTriesToGetLock )
949 { int32 i, waitIterations;
950 volatile double fakeWorkVar; //busy-wait fake work
952 waitIterations =
953 PR_int__randomNumber()% (numTriesToGetLock * GET_LOCK_BACKOFF_WEIGHT);
954 //addToHist( wait_iterations, coreLoopThdParams->wait_iterations_hist );
955 for( i = 0; i < waitIterations; i++ )
956 { fakeWorkVar += (fakeWorkVar + 32.0) / 2.0; //busy-wait
957 }
958 }