VMS/VMS_Implementations/VMS_impls/VMS__MC_shared_impl

view PR__SS.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 7b6f8cf08b1f
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>
13 #include <pthread.h>
15 #include "PR.h"
18 #define thdAttrs NULL
21 /* MEANING OF WL PI SS int
22 * These indicate which places the function is safe to use. They stand for:
23 * WL: Wrapper Library
24 * PI: Plugin
25 * SS: Startup and Shutdown
26 * int: internal to the PR implementation
27 */
30 //===========================================================================
32 MallocProlog *
33 create_free_list();
35 void
36 endOSThreadFn( void *initData, SlaveVP *animatingSlv );
39 //===========================================================================
40 void
41 PR_SS__create_topEnv()
42 { TopEnv *masterEnv;
43 PRQueueStruc **readyToAnimateQs;
44 int32 coreIdx;
45 SlaveVP **masterVPs;
46 AnimSlot ***allAnimSlots; //ptr to array of ptrs
48 //Make the top env, which holds everything else
49 _PRTopEnv = malloc( sizeof(TopEnv) );
51 //Very first thing put into the top env is the free-list, seeded
52 // with a massive initial chunk of memory.
53 //After this, all other mallocs are PR__malloc.
54 _PRTopEnv->freeLists = PR_ext__create_free_list();
55 _PRTopEnv->amtOfOutstandingMem = 0;
57 //===================== Only PR__malloc after this =====================
58 //
60 //=================== Both single and multi lang vars ==================
61 //
62 //
63 _PRTopEnv->metaInfo = PR_int__malloc( sizeof(PRSysMetaInfo) );
64 memset( _PRTopEnv->metaInfo, 0, sizeof(PRSysMetaInfo) );
66 masterVPs = PR_int__malloc( NUM_CORES * sizeof(SlaveVP *) );
67 _PRTopEnv->masterVPs = masterVPs;
69 allAnimSlots = PR_int__malloc( NUM_CORES * sizeof(AnimSlot *) );
70 _PRTopEnv->allAnimSlots = allAnimSlots;
72 //Make the animation slots and similar per-core structs..
73 for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
74 {
75 // allAnimSlots[ coreIdx ] = PR_SS__create_anim_slots( coreIdx ); //makes for one core
76 }
78 //For each animation slot, there is an idle slave, and an initial
79 // slave assigned as the current-task-slave. Create them here.
80 int32 coreNum, slotNum;
81 SlaveVP *idleSlv, *slotTaskSlv;
83 for( coreNum = 0; coreNum < NUM_CORES; coreNum++ )
84 { //langEnv->coreIsDone[coreNum] = FALSE; //use during shutdown
85 //Still have multiple slots -- left over from prev incarnation
86 allAnimSlots[ coreNum ] = PR_SS__create_anim_slots( coreNum ); //makes for one core
88 slotNum = 0; //quick fix -- remove last vestiges of multiple slots per core
89 idleSlv = PR_int__create_slaveVP_helper( &idle_fn, NULL );
90 idleSlv->coreAnimatedBy = coreNum;
91 idleSlv->typeOfVP = IdleVP;
92 idleSlv->animSlotAssignedTo = allAnimSlots[coreNum][slotNum];
93 //start with all slots filled by the idle slaves
94 (allAnimSlots[coreNum][slotNum])->slaveAssignedToSlot = idleSlv;
95 _PRTopEnv->idleSlv[coreNum][slotNum] = idleSlv;
98 slotTaskSlv = PR_int__create_slot_slave( );
99 slotTaskSlv->coreAnimatedBy = coreNum;
100 slotTaskSlv->animSlotAssignedTo = allAnimSlots[coreNum][slotNum];
102 slotTaskSlv->typeOfVP = SlotTaskSlv;
103 _PRTopEnv->slotTaskSlvs[coreNum][slotNum] = slotTaskSlv;
105 }
107 _PRTopEnv->slaveRecycleQ = makePRQ();
109 _PRTopEnv->masterLock = UNLOCKED;
110 _PRTopEnv->seed1 = rand()%1000; // init random number generator
111 _PRTopEnv->seed2 = rand()%1000; // init random number generator
113 _PRTopEnv->measHistsInfo = NULL;
115 _PRTopEnv->numSlavesCreated = 0; //used by create slave to set slave ID
117 //TODO: remove this, and the vars from TopEnv
118 //=================== single lang only vars ==================
119 //
120 //
121 _PRTopEnv->numSlavesCreated = 0; //used to give unique ID to processor
122 _PRTopEnv->numTasksCreated = 0; //to give unique ID to a task
123 _PRTopEnv->numSlavesAlive = 0;
125 _PRTopEnv->shutdownInitiated = FALSE;
126 _PRTopEnv->coreIsDone = PR_int__malloc( NUM_CORES * sizeof( bool32 ) );
127 memset( _PRTopEnv->coreIsDone, 0, NUM_CORES * sizeof( bool32 ) );
129 //=================== multi lang only vars ==================
130 //
131 //
132 readyToAnimateQs = PR_int__malloc( NUM_CORES * sizeof(PRQueueStruc *) );
134 //BUG: have a fixed max num processes, but never check whether exceeded
135 _PRTopEnv->processes = PR_int__malloc( NUM_IN_COLLECTION * sizeof(PRProcess *) );
136 _PRTopEnv->numProcesses = 0;
137 _PRTopEnv->currProcessIdx = 0;
138 _PRTopEnv->firstProcessReady = FALSE; //use while starting up coreCtlr
140 //initialize flags for waiting for activity within PR to complete
141 pthread_mutex_init( &(_PRTopEnv->activityDoneLock), NULL );
142 pthread_cond_init( &(_PRTopEnv->activityDoneCond), NULL );
143 _PRTopEnv->allActivityIsDone = FALSE;
145 //============================= MEASUREMENT STUFF ========================
147 MEAS__Make_Meas_Hists_for_Susp_Meas;
148 MEAS__Make_Meas_Hists_for_Master_Meas;
149 MEAS__Make_Meas_Hists_for_Master_Lock_Meas;
150 MEAS__Make_Meas_Hists_for_Malloc_Meas;
151 MEAS__Make_Meas_Hists_for_Plugin_Meas;
152 MEAS__Make_Meas_Hists_for_Language;
154 PROBES__Create_Probe_Bookkeeping_Vars;
156 HOLISTIC__Setup_Perf_Counters;
158 //========================================================================
159 }
161 AnimSlot **
162 PR_SS__create_anim_slots( int32 coreSlotsAreOn )
163 { AnimSlot **animSlots;
164 int i;
166 animSlots = PR_int__malloc( NUM_ANIM_SLOTS * sizeof(AnimSlot *) );
168 for( i = 0; i < NUM_ANIM_SLOTS; i++ )
169 {
170 animSlots[i] = PR_int__malloc( sizeof(AnimSlot) );
172 //Set state to mean "handling requests done, slot needs filling"
173 animSlots[i]->workIsDone = FALSE;
174 animSlots[i]->needsWorkAssigned = TRUE;
175 animSlots[i]->slotIdx = i; //quick retrieval of slot pos
176 animSlots[i]->coreSlotIsOn = coreSlotsAreOn;
177 }
178 return animSlots;
179 }
181 void
182 PR_SS__freeAnimSlots( AnimSlot **animSlots )
183 { int i;
184 for( i = 0; i < NUM_ANIM_SLOTS; i++ )
185 {
186 PR_int__free( animSlots[i] );
187 }
188 PR_int__free( animSlots );
189 }
192 /*This is called during PR startup.. It simple creates the OS threads, with the
193 * core controller code as the top level function.
194 *However, there's nothing for these threads to do until a process is created,
195 * so, the core controller has a cond-var and flag in the top env they all
196 * "wait" on. The process creation call includes a singleton that releases
197 * all the core controller threads when the first process is created.
198 */
199 void
200 PR_SS__create_the_coreCtlr_OS_threads()
201 {
202 //========================================================================
203 // Create the Threads
204 int coreIdx, retCode;
206 //Need the threads to be created suspended, and wait for a signal
207 // before proceeding -- gives time after creating to initialize other
208 // stuff before the coreCtlrs set off.
209 _PRTopEnv->firstProcessReady = 0;
211 //initialize the cond used to make the new threads wait and sync up
212 //must do this before *creating* the threads..
213 pthread_mutex_init( &suspendLock, NULL );
214 pthread_cond_init( &suspendCond, NULL );
216 //Make the threads that animate the core controllers
217 for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ )
218 { coreCtlrThdParams[coreIdx] = PR_int__malloc( sizeof(ThdParams) );
219 coreCtlrThdParams[coreIdx]->coreNum = coreIdx;
221 retCode =
222 pthread_create( &(coreCtlrThdHandles[coreIdx]),
223 thdAttrs,
224 &coreController,
225 (void *)(coreCtlrThdParams[coreIdx]) );
226 if(retCode){printf("ERROR creating thread: %d\n", retCode); exit(1);}
227 }
228 }
231 //======================
232 //===
233 //=
234 //inline
235 void *
236 PR_SS__create_lang_env( int32 size, SlaveVP *slave, int32 magicNum )
237 {
238 return PR_int__create_lang_env_in_process( size, slave->processSlaveIsIn, magicNum );
239 }
242 /*These store the pointer to handler into the language env -- language env
243 * found by using magic num to look it up in the process that the seedVP
244 * is inside of.
245 */
246 void
247 PR_SS__register_assigner( SlaveAssigner assigner, SlaveVP *seedVP, int32 magicNum )
248 { PRLangEnv *protoLangEnv;
250 protoLangEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum );
251 protoLangEnv->workAssigner = assigner;
252 }
253 void
254 PR_SS__register_lang_shutdown_handler( LangShutdownHdlr shutdownHdlr, SlaveVP *seedVP,
255 int32 magicNum )
256 { PRLangEnv *protoLangEnv;
258 protoLangEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum );
259 protoLangEnv->shutdownHdlr = shutdownHdlr;
260 }
261 void
262 PR_SS__register_lang_data_creator( LangDataCreator langDataCreator,
263 SlaveVP *seedVP, int32 magicNum )
264 { PRLangEnv *protoLangEnv;
266 protoLangEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum );
267 protoLangEnv->langDataCreator = langDataCreator;
268 }
269 void
270 PR_SS__register_lang_meta_task_creator( LangMetaTaskCreator langMetaTaskCreator,
271 SlaveVP *seedVP, int32 magicNum )
272 { PRLangEnv *protoLangEnv;
274 protoLangEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum );
275 protoLangEnv->langMetaTaskCreator = langMetaTaskCreator;
276 }
277 void
278 PR_SS__register_make_slave_ready_fn( MakeSlaveReadyFn fn, SlaveVP *seedVP,
279 int32 magicNum )
280 { PRLangEnv *protoLangEnv;
282 protoLangEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum );
283 protoLangEnv->makeSlaveReadyFn = fn;
284 }
285 void
286 PR_SS__register_make_task_ready_fn( MakeTaskReadyFn fn, SlaveVP *seedVP,
287 int32 magicNum )
288 { PRLangEnv *protoLangEnv;
290 protoLangEnv = PR_SS__give_proto_lang_env_for_slave( seedVP, magicNum );
291 protoLangEnv->makeTaskReadyFn = fn;
292 }
294 //========
297 /*are in Master when call this.. due to detecting end-of-work, from inside
298 * end-task or dissipate.. or, call this when app calls "end process"
299 */
300 void
301 PR_SS__end_process_normally( PRProcess *process )
302 { int32 i, processIdx;
303 PRProcess **processes;
305 //remove process from PR's list of processes..
306 processes = _PRTopEnv->processes;
307 //find the process within the list
308 for( i = 0; i < _PRTopEnv->numProcesses; i++ )
309 { if( processes[i] == process )
310 { processIdx = i;
311 break;
312 }
313 }
314 //move all the higher processes down, overwriting the target
315 for( i = processIdx +1; i < _PRTopEnv->numProcesses; i++ )
316 { processes[i-1] = processes[i];
317 }
318 _PRTopEnv->numProcesses -= 1;
320 //remove process from the process-to-slot chooser
321 _PRTopEnv->currProcessIdx = 0; //start choosing starting at process 0
323 //call shutdown on each langlet started in process (which frees any
324 // langlet-allocd data in langEnv);
325 //Then free the lang env
326 PRLangEnv *protoLangEnv;
327 for( i = 0; i < process->numLangEnvs; i++ )
328 { protoLangEnv = process->protoLangEnvsList[i];
329 //The lang shutdowns should free any slaves or tasks in the langEnv
330 (*protoLangEnv->shutdownHdlr)(&(protoLangEnv[1]));
331 PR_int__free( protoLangEnv ); //don't need to remove from process!
332 }
333 PR_int__free( process->protoLangEnvsList ); //array of Envs empty so free it
334 PR_int__free( &(((int32 *)process->langEnvs)[-1]) ); //the collection array
336 //any slaves from this process still in slots will finish executing, but
337 // have no lang env for the request handlers to use!
338 //So, have to mark each slave, so the request handling isn't done
339 AnimSlot *slot, **animSlots;
340 int32 core;
341 for( core = 0; core < NUM_CORES; core++ )
342 { animSlots = _PRTopEnv->allAnimSlots[core];
343 for( i = 0; i < NUM_ANIM_SLOTS; i++ )
344 { slot = animSlots[i];
345 if( slot->slaveAssignedToSlot->processSlaveIsIn == process )
346 { //turn off req handling by disallowing slave from chging slot flag
347 slot->slaveAssignedToSlot->animSlotAssignedTo = NULL;
348 slot->workIsDone = FALSE; //just in case, make sure req hdling off
349 slot->needsWorkAssigned = TRUE; //make new slave be assigned
350 }
351 }
352 }
354 //cause resume of "PR__wait_for_process_to_end()" call
355 if( process->hasWaitingToEnd )
356 {
357 #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
358 process->executionIsComplete = TRUE;
359 PR_int__free(process);
360 //The "wait for process to end" call started the PR activity that
361 // happens inside that process. That leads to here, running inside the
362 // master.. so just return, and let the core ctlr detect no work and
363 // return.
364 return;
365 #else
366 //Here, must use OS thread constructs.. the main thread is waiting for
367 // PR process to complete. So, at this point, cause main to resume.
369 pthread_mutex_lock( &(process->doneLock) );
370 process->executionIsComplete = TRUE;
371 pthread_cond_broadcast( &(process->doneCond) );
372 pthread_mutex_unlock( &(process->doneLock) );
373 //now wait for woken waiter to Ack, then free the process struct
374 pthread_mutex_lock( &(process->doneAckLock) ); //BUG:? may be a race
375 pthread_mutex_unlock( &(process->doneAckLock) );
376 PR_int__free(process);
377 #endif
378 }
379 //if no more processes, cause resume of "PR__wait_for_all_activity_to_end"
380 if( _PRTopEnv->numProcesses == 0)
381 {
382 pthread_mutex_lock( &(_PRTopEnv->activityDoneLock) );
383 _PRTopEnv->allActivityIsDone = TRUE;
384 pthread_cond_broadcast( &(_PRTopEnv->activityDoneCond) );
385 pthread_mutex_unlock( &(_PRTopEnv->activityDoneLock) );
386 }
387 }
390 /*Calling this causes the core controller OS threads to exit,
391 *
392 *The _PRTopEnv is used inside this shut down function, so it wait until
393 * the OS thread shutdown is done before freeing it.
394 *
395 *In here,create one core-loop shut-down slave for each core controller
396 * and put them all directly into the animation slots.
397 *
398 *Note, this function should ONLY be called after all processes have ended,
399 * because it doesn't pay attention to whether unfinished work exists..
400 */
401 void
402 PR_SS__shutdown_OS_threads()
403 { int32 coreIdx;
404 SlaveVP *shutDownSlv;
405 AnimSlot **animSlots;
406 //create the shutdown processors, one for each core controller -- put them
407 // directly into the slots
408 PR_int__get_wrapper_lock();
409 for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
410 { //Note, this is running in the master
411 shutDownSlv = PR_SS__create_shutdown_slave();
412 //last slave has dissipated, so no more in slots, so write
413 // shut down slave into first animulng slot.
414 animSlots = _PRTopEnv->allAnimSlots[ coreIdx ];
415 animSlots[0]->slaveAssignedToSlot = shutDownSlv;
416 animSlots[0]->workIsDone = TRUE;
417 animSlots[0]->needsWorkAssigned = FALSE;
418 shutDownSlv->coreAnimatedBy = coreIdx;
419 shutDownSlv->animSlotAssignedTo = animSlots[ 0 ];
420 }
421 PR_int__release_master_lock();
422 }
425 SlaveVP* PR_SS__create_shutdown_slave(int32 coreNum)
426 {
427 SlaveVP* shutdownVP;
429 shutdownVP = PR_int__create_slaveVP_helper( &idle_fn, NULL );
430 shutdownVP->typeOfVP = ShutdownVP;
432 return shutdownVP;
433 }
436 /*This is run in the main thread, as part of the PR__shutdown() call
437 * It frees any memory allocated from the OS
438 */
439 void
440 PR_SS__cleanup_at_end_of_shutdown()
441 {
442 //All the environment data has been allocated with PR__malloc, so just
443 // free the memory obtained by PR__malloc, then free the top env.
444 //These are the only two that use system free
445 PR_ext__free_free_list( _PRTopEnv->freeLists );
446 free( (void *)_PRTopEnv );
447 }
451 void
452 PR_SS__print_out_measurements()
453 {
454 if( _PRTopEnv->measHistsInfo != NULL )
455 { forAllInDynArrayDo( _PRTopEnv->measHistsInfo, (DynArrayFnPtr)&printHist );
456 forAllInDynArrayDo( _PRTopEnv->measHistsInfo, (DynArrayFnPtr)&saveHistToFile);
457 forAllInDynArrayDo( _PRTopEnv->measHistsInfo, (DynArrayFnPtr)&freeHist );
458 }
460 MEAS__Print_Hists_for_Susp_Meas;
461 MEAS__Print_Hists_for_Master_Meas;
462 MEAS__Print_Hists_for_Master_Lock_Meas;
463 MEAS__Print_Hists_for_Malloc_Meas;
464 MEAS__Print_Hists_for_Plugin_Meas;
465 }
467 /*This waits for the OS threads in the PR system to end. Causing them to end
468 * has to be done separately (haven't worked out details as of this comment)
469 */
470 void
471 PR_SS__wait_for_PR_to_shutdown()
472 {
473 //wait for all to complete
474 int coreIdx;
475 for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ )
476 {
477 pthread_join( coreCtlrThdHandles[coreIdx], NULL );
478 }
479 }
482 //============================
484 /*Am trying to be cute, avoiding IF statement in coreCtlr that checks for
485 * a special shutdown slaveVP. Ended up with extra-complex shutdown sequence.
486 *This function has the sole purpose of setting the stack and framePtr
487 * to the coreCtlr's stack and framePtr.. it does that then jumps to the
488 * core ctlr's shutdown point -- might be able to just call Pthread_exit
489 * from here, but am going back to the pthread's stack and setting everything
490 * up just as if it never jumped out, before calling pthread_exit.
491 *The end-point of core ctlr will free the stack and so forth of the
492 * processor that animates this function, (this fn is transfering the
493 * animator of the AppSlv that is in turn animating this function over
494 * to core controller function -- note that this slices out a level of virtual
495 * processors).
496 */
497 void
498 endOSThreadFn( void *initData, SlaveVP *animatingSlv )
499 {
500 #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
501 asmTerminateCoreCtlrSeq(animatingSlv);
502 #else
503 return;
504 asmTerminateCoreCtlr(animatingSlv);
505 #endif
506 }
508 //================================