annotate AnimationMaster.c @ 285:7b6f8cf08b1f

Minor -- gave malloc its own lock and renamed TopLevelFn to BirthFn
author Sean Halle <seanhalle@yahoo.com>
date Wed, 12 Jun 2013 14:12:06 -0700
parents 72ffdb11ad8e
children 744b5ff9851e
rev   line source
seanhalle@230 1 /*
seanhalle@270 2 * Copyright 2012 OpenSourceResearchInstitute.org
seanhalle@230 3 *
seanhalle@230 4 * Licensed under BSD
seanhalle@230 5 */
seanhalle@230 6
seanhalle@230 7
seanhalle@230 8
seanhalle@230 9 #include <stdio.h>
seanhalle@230 10 #include <stddef.h>
seanhalle@230 11
seanhalle@260 12 #include "PR.h"
seanhalle@230 13
seanhalle@273 14 //========================= Local Declarations ========================
seanhalle@273 15 inline PRProcess *
seanhalle@273 16 pickAProcess( AnimSlot *slot );
seanhalle@273 17 inline bool32
seanhalle@273 18 assignWork( PRProcess *process, AnimSlot *slot );
seanhalle@230 19
seanhalle@273 20 inline void
seanhalle@273 21 PRHandle__CreateTask( PRReqst *req, SlaveVP *slave );
seanhalle@273 22 inline void
seanhalle@273 23 PRHandle__EndTask( PRReqst *req, SlaveVP *slave );
seanhalle@273 24 inline void
seanhalle@273 25 PRHandle__CreateSlave(PRReqst *req, SlaveVP *slave );
seanhalle@273 26 inline void
seanhalle@273 27 PRHandle__EndSlave( PRReqst *req, SlaveVP *slave );
seanhalle@268 28
seanhalle@273 29 inline void
seanhalle@273 30 PRHandle__LangShutdown( PRReqst *req, SlaveVP *requestingSlv );
seanhalle@268 31
seanhalle@273 32 inline void
seanhalle@273 33 handleMakeProbe( PRServiceReq *langReq, PRLangEnv *protoLangEnv );
seanhalle@273 34 inline void
seanhalle@273 35 handleThrowException( PRServiceReq *langReq, PRLangEnv *protoLangEnv );
seanhalle@230 36
seanhalle@285 37 void
seanhalle@285 38 debug_print_req(AnimSlot *slot, PRReqst *req);
seanhalle@285 39
seanhalle@273 40 //===========================================================================
seanhalle@272 41
seanhalle@272 42 /*Note: there used to be a coreController that was another animation
seanhalle@272 43 * layer below both the masterVP and the slaveVPs.. in that case, the
seanhalle@272 44 * masterVP was a virtual processor whose processor-state was the same
seanhalle@272 45 * as a slaveVP's processor sate, both implemented as a SlaveVP struct.
seanhalle@272 46 * Have removed that, and
seanhalle@272 47 * changed the masterVP implementation. Instead of being a special version
seanhalle@272 48 * of a proto-runtime virtual processor, using the slaveVP stuct, the
seanhalle@272 49 * Master "virtual processor" is now implemented as a pthread pinned to
seanhalle@272 50 * a physical core.
seanhalle@260 51 */
seanhalle@260 52
seanhalle@272 53 /*This is the behavior of the Master. The physical processor switches
seanhalle@272 54 * between animating the master, and animating a slave. When a slave
seanhalle@272 55 * suspends, the PR "suspend" primitive switches the physical core over
seanhalle@272 56 * to animating the masterVP, which is implemented as a pinned pthread.
seanhalle@272 57 * This function is the behavior of that masterVP.
seanhalle@272 58 *This function's job is to manage processing
seanhalle@272 59 * requests and to trigger assignment of new work to the physical core,
seanhalle@272 60 * and to manage sharing the core among processes.
seanhalle@272 61 */
seanhalle@261 62 inline
seanhalle@270 63 bool32
seanhalle@269 64 masterFunction( AnimSlot *slot )
seanhalle@261 65 { //Scan the animation slots
seanhalle@261 66 int32 magicNumber;
seanhalle@261 67 SlaveVP *slave;
seanhalle@268 68 PRLangEnv *langEnv;
seanhalle@261 69 PRReqst *req;
seanhalle@268 70 PRProcess *process;
seanhalle@273 71 bool32 didAssignWork;
seanhalle@260 72
seanhalle@268 73 //Check if newly-done slave in slot, which will need request handled
seanhalle@272 74 //NOTE: left over from when had a coreController & MasterVP managed
seanhalle@272 75 // several slots
seanhalle@268 76 if( slot->workIsDone )
seanhalle@268 77 { slot->workIsDone = FALSE;
seanhalle@268 78 slot->needsWorkAssigned = TRUE;
seanhalle@273 79
seanhalle@273 80 //An Idle VP has no request to handle, so skip to assign..
seanhalle@278 81 if( slot->slaveAssignedToSlot->typeOfVP != IdleVP &&
seanhalle@278 82 slot->slaveAssignedToSlot->typeOfVP != ShutdownVP)
seanhalle@273 83 {
seanhalle@273 84 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
seanhalle@273 85 MEAS__startReqHdlr;
seanhalle@261 86
seanhalle@261 87
seanhalle@273 88 //process the request made by the slave (held inside slave struc)
seanhalle@273 89 slave = slot->slaveAssignedToSlot;
seanhalle@273 90 req = slave->request;
seanhalle@285 91 debug_print_req(slot, req);
seanhalle@268 92
seanhalle@273 93 //If the requesting slave is a slot slave, and request is not
seanhalle@273 94 // task-end, then turn it into a free task slave & continue
seanhalle@273 95 if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd )
seanhalle@273 96 PR_int__replace_with_new_slot_slv( slave );
seanhalle@268 97
seanhalle@273 98 //Handle task create and end first -- they're special cases..
seanhalle@273 99 switch( req->reqType )
seanhalle@278 100 {
seanhalle@278 101 case TaskEnd:
seanhalle@273 102 { //do PR handler, which calls lang's hdlr and does recycle of
seanhalle@273 103 // free task slave if needed -- PR handler checks for free task Slv
seanhalle@273 104 PRHandle__EndTask( req, slave ); break;
seanhalle@273 105 }
seanhalle@273 106 case TaskCreate:
seanhalle@273 107 { //Do PR's create-task handler, which calls the lang's hdlr
seanhalle@273 108 // PR handler checks for free task Slv
seanhalle@273 109 PRHandle__CreateTask( req, slave ); break;
seanhalle@273 110 }
seanhalle@273 111 case SlvCreate: PRHandle__CreateSlave( req, slave ); break;
seanhalle@273 112 case SlvDissipate: PRHandle__EndSlave( req, slave ); break;
seanhalle@273 113 case Service: PRHandle__ServiceReq( slave ); break; //resumes into Service lang env
seanhalle@273 114 case Hardware: //for future expansion
seanhalle@273 115 case IO: //for future expansion
seanhalle@273 116 case OSCall: //for future expansion
seanhalle@273 117 PR_int__throw_exception("Not implemented", slave, NULL); break;
seanhalle@273 118 case LangShutdown: PRHandle__LangShutdown( req, slave ); break;
seanhalle@273 119 case Language: //normal lang request
seanhalle@273 120 { magicNumber = req->langMagicNumber;
seanhalle@273 121 langEnv = PR_PI__give_lang_env_for_slave( slave, magicNumber );
seanhalle@273 122 (*req->handler)( req->langReq, slave, langEnv );
seanhalle@273 123 }
seanhalle@267 124 }
seanhalle@273 125
seanhalle@268 126 MEAS__endReqHdlr;
seanhalle@267 127 HOLISTIC__Record_AppResponder_end;
seanhalle@273 128 }//if not idleVP
seanhalle@278 129 else if( slot->slaveAssignedToSlot->typeOfVP == ShutdownVP )
seanhalle@278 130 { //ShutdownVP used, essentially, as a flag, to cause terminate here
seanhalle@278 131 PR_int__release_master_lock();
seanhalle@278 132 terminateCoreCtlr( slot->slaveAssignedToSlot );
seanhalle@278 133 }
seanhalle@268 134 } //if have request to be handled
seanhalle@268 135
seanhalle@272 136 //NOTE: IF statement is leftover from when master managed many slots
seanhalle@273 137 didAssignWork = FALSE;
seanhalle@273 138 if( slot->needsWorkAssigned ) //can probably remove IF, now that only one slot
seanhalle@268 139 {
seanhalle@268 140 HOLISTIC__Record_Assigner_start;
seanhalle@272 141
seanhalle@268 142 //Pick a process to get this slot
seanhalle@268 143 process = pickAProcess( slot );
seanhalle@268 144
seanhalle@268 145 //Scan lang environs, looking for langEnv with ready work.
seanhalle@268 146 // call the Assigner for that lang Env, to get a slave for the slot
seanhalle@273 147 if( process != NULL )
seanhalle@273 148 { didAssignWork =
seanhalle@273 149 assignWork( process, slot );
seanhalle@273 150 }
seanhalle@268 151 HOLISTIC__Record_Assigner_end;
seanhalle@272 152
seanhalle@273 153 if( !didAssignWork ) //if no work assigned, be sure idle slave is in slot
seanhalle@273 154 { slot->slaveAssignedToSlot = _PRTopEnv->idleSlv[slot->coreSlotIsOn][0];
seanhalle@273 155 }
seanhalle@273 156 // fixme; //make into a loop that tries more processes if fails to assign
seanhalle@268 157 }//if slot needs slave assigned
seanhalle@270 158
seanhalle@273 159 return didAssignWork;
seanhalle@261 160 }
seanhalle@260 161
seanhalle@268 162 /*When several processes exist, use some pattern for picking one to give
seanhalle@268 163 * the animation slot to.
seanhalle@268 164 *First, it has to be a process that has work available.
seanhalle@268 165 *For now, just do a round-robin
seanhalle@261 166 */
seanhalle@268 167 inline
seanhalle@268 168 PRProcess *
seanhalle@268 169 pickAProcess( AnimSlot *slot )
seanhalle@268 170 { int32 idx;
seanhalle@268 171 PRProcess *process;
seanhalle@268 172
seanhalle@268 173 for( idx = _PRTopEnv->currProcessIdx; idx < _PRTopEnv->numProcesses; idx++)
seanhalle@268 174 {
seanhalle@268 175 process = _PRTopEnv->processes[ idx ];
seanhalle@268 176 if( process->numEnvsWithWork != 0 )
seanhalle@268 177 { _PRTopEnv->currProcessIdx = idx;
seanhalle@268 178 return process;
seanhalle@268 179 }
seanhalle@261 180 }
seanhalle@268 181 for( idx = 0; idx < _PRTopEnv->currProcessIdx; idx++)
seanhalle@268 182 {
seanhalle@268 183 process = _PRTopEnv->processes[ idx ];
seanhalle@268 184 if( process->numEnvsWithWork != 0 )
seanhalle@268 185 { _PRTopEnv->currProcessIdx = idx;
seanhalle@268 186 return process;
seanhalle@268 187 }
seanhalle@268 188 }
seanhalle@268 189 //none found
seanhalle@268 190 return NULL;
seanhalle@260 191 }
seanhalle@260 192
seanhalle@261 193 /*This does:
seanhalle@268 194 * 1) searches the language environments for one with work ready
seanhalle@261 195 * if finds one, asks its assigner to return work
seanhalle@261 196 * 2) checks what kind of work: new task, resuming task, resuming slave
seanhalle@261 197 * if new task, gets the slot slave and assigns task to it and returns slave
seanhalle@261 198 * else, gets the slave attached to the metaTask and returns that.
seanhalle@261 199 * 3) if no work found, then prune former task slaves waiting to be recycled.
seanhalle@261 200 * If no work and no slaves to prune, check for shutdown conditions.
seanhalle@261 201 *
seanhalle@268 202 * language env keeps its own work in its own structures, and has its own
seanhalle@261 203 * assigner. It chooses
seanhalle@261 204 * However, include a switch that switches-in an override assigner, which
seanhalle@268 205 * sees all the work in all the language env's. This is most likely
seanhalle@261 206 * generated by static tools and included in the executable. That means it
seanhalle@261 207 * has to be called via a registered pointer from here. The idea is that
seanhalle@261 208 * the static tools know which languages are grouped together.. and the
seanhalle@261 209 * override enables them to generate a custom assigner that uses info from
seanhalle@261 210 * all the languages in a unified way.. Don't really expect this to happen,
seanhalle@261 211 * but am making it possible.
seanhalle@260 212 */
seanhalle@268 213 inline
seanhalle@270 214 bool32
seanhalle@261 215 assignWork( PRProcess *process, AnimSlot *slot )
seanhalle@272 216 { int32 coreNum;
seanhalle@260 217
seanhalle@261 218 coreNum = slot->coreSlotIsOn;
seanhalle@260 219
seanhalle@267 220 if( process->overrideAssigner != NULL )
seanhalle@268 221 { if( process->numEnvsWithWork != 0 )
seanhalle@268 222 { (*process->overrideAssigner)( process, slot ); //calls PR fn that inserts work into slot
seanhalle@268 223 goto ReturnAfterAssigningWork; //quit for-loop, cause found work
seanhalle@261 224 }
seanhalle@268 225 else
seanhalle@261 226 goto NoWork;
seanhalle@261 227 }
seanhalle@261 228
seanhalle@268 229 //If here, then no override assigner, so search language envs for work
seanhalle@273 230 int32 envIdx, numEnvs; PRLangEnv **protoLangEnvsList, *protoLangEnv;
seanhalle@273 231 protoLangEnvsList = process->protoLangEnvsList;
seanhalle@268 232 numEnvs = process->numLangEnvs;
seanhalle@268 233 for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep langEnvs in hash & array
seanhalle@273 234 { protoLangEnv = protoLangEnvsList[envIdx];
seanhalle@273 235 if( protoLangEnv->numReadyWork > 0 )
seanhalle@272 236 { bool32
seanhalle@272 237 didAssignWork =
seanhalle@273 238 (*protoLangEnv->workAssigner)( PR_int__give_lang_env(protoLangEnv), slot ); //assigner calls PR to put slave/task into slot
seanhalle@272 239
seanhalle@272 240 if(didAssignWork)
seanhalle@273 241 { protoLangEnv->numReadyWork -= 1;
seanhalle@273 242 if( protoLangEnv->numReadyWork == 0 )
seanhalle@272 243 { process->numEnvsWithWork -= 1;
seanhalle@272 244 }
seanhalle@272 245 goto ReturnAfterAssigningWork; //quit for-loop, 'cause found work
seanhalle@272 246 }
seanhalle@272 247 else
seanhalle@272 248 goto NoWork; //quit for-loop, cause found work
seanhalle@272 249
seanhalle@268 250 //NOTE: bad search alg -- should start where left off, then wrap around
seanhalle@260 251 }
seanhalle@260 252 }
seanhalle@268 253 //If reach here, then have searched all langEnv's & none have work..
seanhalle@260 254
seanhalle@268 255 NoWork: //No work, if end up here..
seanhalle@260 256 {
seanhalle@260 257 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
seanhalle@272 258 returnSlv = process->idleSlv[coreNum][0]; //only one slot now, so [0]
seanhalle@260 259
seanhalle@260 260 //things that would normally happen in resume(), but idle VPs
seanhalle@260 261 // never go there
seanhalle@261 262 returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID
seanhalle@260 263 Unit newU;
seanhalle@268 264 newU.vp = returnSlv->slaveNum;
seanhalle@261 265 newU.task = returnSlv->numTimesAssignedToASlot;
seanhalle@261 266 addToListOfArrays(Unit,newU,process->unitList);
seanhalle@260 267
seanhalle@261 268 if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit
seanhalle@260 269 { Dependency newD; // to this one
seanhalle@268 270 newD.from_vp = returnSlv->slaveNum;
seanhalle@261 271 newD.from_task = returnSlv->numTimesAssignedToASlot - 1;
seanhalle@268 272 newD.to_vp = returnSlv->slaveNum;
seanhalle@261 273 newD.to_task = returnSlv->numTimesAssignedToASlot;
seanhalle@261 274 addToListOfArrays(Dependency, newD ,process->ctlDependenciesList);
seanhalle@260 275 }
seanhalle@268 276 #endif
seanhalle@268 277 HOLISTIC__Record_Assigner_end;
seanhalle@269 278 return FALSE;
seanhalle@260 279 }
seanhalle@268 280
seanhalle@268 281 ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic..
seanhalle@268 282 {
seanhalle@268 283 HOLISTIC__Record_Assigner_end;
seanhalle@269 284 return TRUE;
seanhalle@260 285 }
seanhalle@260 286 }
seanhalle@260 287
seanhalle@260 288
seanhalle@273 289 //=================================
seanhalle@273 290 //===
seanhalle@273 291 //=
seanhalle@273 292 /*Create task is a special form, that has PR behavior in addition to plugin
seanhalle@273 293 * behavior. Master calls this first, and it then calls the plugin's
seanhalle@273 294 * create task handler.
seanhalle@273 295 *
seanhalle@273 296 *Note: the requesting slave must be either generic slave or free task slave
seanhalle@273 297 */
seanhalle@273 298 inline
seanhalle@273 299 void
seanhalle@273 300 PRHandle__CreateTask( PRReqst *req, SlaveVP *slave )
seanhalle@273 301 { PRMetaTask *protoMetaTask;
seanhalle@273 302 PRProcess *process;
seanhalle@273 303 PRLangEnv *protoLangEnv;
seanhalle@273 304 void *task;
seanhalle@273 305
seanhalle@273 306 process = slave->processSlaveIsIn;
seanhalle@273 307
seanhalle@273 308 protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave,
seanhalle@273 309 req->langMagicNumber );
seanhalle@273 310
seanhalle@273 311 //Do the langlet's create-task handler, which keeps the task
seanhalle@273 312 // inside the langlet's lang env, but returns the langMetaTask
seanhalle@273 313 // so that PR can then put stuff into the prolog
seanhalle@273 314 //typedef void * (*CreateHandler)( void *, SlaveVP *, void * ); //req, slv, langEnv
seanhalle@273 315 //
seanhalle@273 316 task =
seanhalle@273 317 (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv) );
seanhalle@273 318 protoMetaTask = PR_int__give_prolog_of_lang_meta_task( task );
seanhalle@273 319 protoMetaTask->ID = req->ID; //may be NULL
seanhalle@273 320 protoMetaTask->topLevelFn = req->topLevelFn;
seanhalle@273 321 protoMetaTask->initData = req->initData;
seanhalle@273 322 protoMetaTask->processTaskIsIn = process;
seanhalle@273 323
seanhalle@273 324 process->numLiveTasks += 1;
seanhalle@273 325 protoLangEnv->numLiveWork += 1; //used in wait statements -- small added overhead
seanhalle@273 326
seanhalle@273 327 return;
seanhalle@273 328 }
seanhalle@273 329
seanhalle@273 330 /*When a task ends, have two scenarios: 1) task ran to completion, or 2) task
seanhalle@273 331 * has been suspended at some point in its code.
seanhalle@273 332 *For 1, just decr count of live tasks (and check for end condition) -- the
seanhalle@273 333 * master loop will decide what goes into the slot freed up by this task end,
seanhalle@273 334 * so, here, don't worry about assigning a new task to the slot slave.
seanhalle@273 335 *For 2, the task's slot slave has been converted to a free task slave, which
seanhalle@273 336 * now has nothing more to do, so send it to the recycle Q (which includes
seanhalle@273 337 * freeing all the langData and meta task structs alloc'd for it). Then
seanhalle@273 338 * decrement the live task count and check end condition.
seanhalle@273 339 *
seanhalle@273 340 *PR has to update count of live tasks, and check end of process condition.
seanhalle@273 341 * The "main" can invoke constructs that wait for a process to end, so when
seanhalle@273 342 * end detected, have to resume what's waiting..
seanhalle@273 343 *Thing is, that wait involves the main OS thread. That means
seanhalle@273 344 * PR internals have to do OS thread signaling. Want to do that in the
seanhalle@273 345 * core controller, which has the original stack of an OS thread. So the
seanhalle@273 346 * end process handling happens in the core controller.
seanhalle@273 347 *
seanhalle@273 348 *So here, when detect process end, signal to the core controller, which will
seanhalle@273 349 * then do the condition variable notify to the OS thread that's waiting.
seanhalle@273 350 *
seanhalle@273 351 *Note: slave may be either a slot slave or a free task slave.
seanhalle@273 352 */
seanhalle@273 353 inline
seanhalle@273 354 void
seanhalle@273 355 PRHandle__EndTask( PRReqst *req, SlaveVP *requestingSlv )
seanhalle@273 356 { void *langEnv;
seanhalle@273 357 PRLangEnv *protoLangEnv;
seanhalle@273 358 PRProcess *process;
seanhalle@273 359 void *langMetaTask;
seanhalle@273 360
seanhalle@273 361 process = requestingSlv->processSlaveIsIn;
seanhalle@273 362 langEnv = PR_int__give_lang_env_of_req( req, requestingSlv ); //magic num in req
seanhalle@273 363 protoLangEnv = PR_int__give_proto_lang_env( langEnv );
seanhalle@273 364
seanhalle@273 365 langMetaTask = PR_int__give_lang_meta_task_from_slave( requestingSlv, req->langMagicNumber);
seanhalle@273 366
seanhalle@273 367 //Do the langlet's request handler
seanhalle@273 368 //Want to keep PR structs hidden from plugin, so extract langReq..
seanhalle@273 369 //This is supposed to free any langlet-malloc'd mem, including meta task
seanhalle@273 370 (*req->handler)( req->langReq, requestingSlv, langEnv );
seanhalle@273 371
seanhalle@273 372 protoLangEnv->numLiveWork -= 1; //used in wait statements -- small added overhead
seanhalle@273 373 if( protoLangEnv->numLiveWork == 0 &&
seanhalle@273 374 numInPrivQ( protoLangEnv->waitingForWorkToEndQ ) > 0 )
seanhalle@273 375 { SlaveVP *
seanhalle@273 376 waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ );
seanhalle@273 377 //can't resume into langlet that just ended its last work!
seanhalle@273 378 // and don't have env that the waiter was created in, so resume
seanhalle@273 379 // into PRServ env..
seanhalle@273 380 void *
seanhalle@273 381 resumeEnv = PR_PI__give_lang_env_from_process( process, PRServ_MAGIC_NUMBER );
seanhalle@273 382 while( waitingSlave != NULL )
seanhalle@273 383 { //resume a slave that was waiting for work in this env to finish
seanhalle@273 384 PR_PI__make_slave_ready( waitingSlave, resumeEnv );
seanhalle@273 385 //get next waiting slave, repeat..
seanhalle@273 386 waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ );
seanhalle@273 387 }
seanhalle@273 388 }
seanhalle@273 389
seanhalle@273 390
seanhalle@273 391 //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv
seanhalle@273 392 if( requestingSlv->typeOfVP == FreeTaskSlv )
seanhalle@273 393 PR_int__recycle_slaveVP( requestingSlv ); //Doesn't decr num live slaves
seanhalle@273 394
seanhalle@273 395 process->numLiveTasks -= 1;
seanhalle@273 396 //NOTE: end-task is unrelated to work available (just in case wondering)
seanhalle@273 397
seanhalle@273 398 //check End Of Process Condition
seanhalle@273 399 if( process->numLiveTasks == 0 &&
seanhalle@273 400 process->numLiveGenericSlvs == 0 )
seanhalle@273 401 { //Tell the core controller to do wakeup of any waiting OS thread
seanhalle@273 402 PR_SS__end_process_normally( process );
seanhalle@273 403 }
seanhalle@273 404 }
seanhalle@273 405
seanhalle@273 406
seanhalle@268 407
seanhalle@268 408 /*This is first thing called when creating a slave.. it hands off to the
seanhalle@268 409 * langlet's creator, then adds updates of its own..
seanhalle@268 410 *
seanhalle@268 411 *There's a question of things like lang data, meta tasks, and such..
seanhalle@268 412 *In creator, only PR related things happen, and things for the langlet whose
seanhalle@261 413 * creator construct was used.
seanhalle@268 414 *
seanhalle@268 415 *Other langlets still get a chance to create langData -- but by registering a
seanhalle@268 416 * "createLangData" handler in the langEnv. When a construct of the langlet
seanhalle@268 417 * calls "PR__give_lang_data()", if there is no langData for that langlet,
seanhalle@268 418 * the PR will call the creator in the langlet's langEnv, place whatever it
seanhalle@268 419 * makes as the langData in that slave for that langlet, and return that langData
seanhalle@261 420 *
seanhalle@261 421 *So, as far as counting things, a langlet is only allowed to count creation
seanhalle@261 422 * of slaves it creates itself.. may have to change this later.. add a way for
seanhalle@261 423 * langlet to register a trigger Fn called each time a slave gets created..
seanhalle@261 424 * need more experience with what langlets will do at create time.. think Cilk
seanhalle@261 425 * has interesting create behavior.. not sure how that will differ in light
seanhalle@261 426 * of true tasks and langlet approach. Look at it after all done and start
seanhalle@261 427 * modifying the langs to be langlets..
seanhalle@261 428 *
seanhalle@261 429 *PR itself needs to create the slave, then update numLiveSlaves in process,
seanhalle@261 430 * copy processID from requestor to newly created
seanhalle@261 431 */
seanhalle@268 432 inline
seanhalle@268 433 void
seanhalle@272 434 PRHandle__CreateSlave( PRReqst *req, SlaveVP *slave )
seanhalle@268 435 { SlaveVP *newSlv;
seanhalle@261 436 PRProcess *process;
seanhalle@268 437 PRLangEnv *protoLangEnv;
seanhalle@261 438
seanhalle@268 439 process = slave->processSlaveIsIn;
seanhalle@273 440 protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, req->langMagicNumber );
seanhalle@272 441
seanhalle@272 442 //create handler, or a future request handler will call PR_PI__make_slave_ready
seanhalle@272 443 // which will in turn handle updating which langlets and which processes have
seanhalle@272 444 // work available.
seanhalle@272 445 //NOTE: create slv has diff prototype than standard reqst hdlr
seanhalle@268 446 newSlv =
seanhalle@268 447 (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv));
seanhalle@268 448
seanhalle@261 449 newSlv->typeOfVP = GenericSlv;
seanhalle@261 450 newSlv->processSlaveIsIn = process;
seanhalle@268 451 newSlv->ID = req->ID;
seanhalle@272 452 process->numLiveGenericSlvs += 1; //not same as work ready!
seanhalle@273 453 protoLangEnv->numLiveWork += 1; //used in wait statements -- small added overhead
seanhalle@260 454 }
seanhalle@260 455
seanhalle@268 456 /*The dissipate handler has to, update the number of slaves of the type, within
seanhalle@261 457 * the process, and call the langlet handler linked into the request,
seanhalle@261 458 * and after that returns, then call the PR function that frees the slave state
seanhalle@261 459 * (or recycles the slave).
seanhalle@261 460 *
seanhalle@261 461 *The PR function that frees the slave state has to also free all of the
seanhalle@268 462 * langData in the slave.. or else reset all of the langDatas.. by, say, marking
seanhalle@268 463 * them, then in PR__give_langData( magicNum ) call the langlet registered
seanhalle@268 464 * "resetLangData" Fn.
seanhalle@261 465 */
seanhalle@268 466 inline
seanhalle@268 467 void
seanhalle@272 468 PRHandle__EndSlave( PRReqst *req, SlaveVP *slave )
seanhalle@261 469 { PRProcess *process;
seanhalle@268 470 PRLangEnv *protoLangEnv;
seanhalle@261 471
seanhalle@261 472 process = slave->processSlaveIsIn;
seanhalle@261 473
seanhalle@261 474 //do the language's dissipate handler
seanhalle@273 475 protoLangEnv = PR_int__give_proto_lang_env_for_slave( slave, slave->request->langMagicNumber );
seanhalle@268 476
seanhalle@268 477 if(req->handler != NULL)
seanhalle@268 478 (*req->handler)( req->langReq, slave, PR_int__give_lang_env(protoLangEnv) );
seanhalle@261 479
seanhalle@273 480 protoLangEnv->numLiveWork -= 1; //used in wait statements -- small added overhead
seanhalle@273 481 if( protoLangEnv->numLiveWork == 0 &&
seanhalle@273 482 numInPrivQ( protoLangEnv->waitingForWorkToEndQ ) > 0 )
seanhalle@273 483 { SlaveVP *
seanhalle@273 484 waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ );
seanhalle@273 485 //can't resume into langlet that just ended its last work!
seanhalle@273 486 // and don't have env that the waiter was created in, so resume
seanhalle@273 487 // into PRServ env..
seanhalle@273 488 void *
seanhalle@273 489 resumeEnv = PR_PI__give_lang_env_from_process( process, PRServ_MAGIC_NUMBER );
seanhalle@273 490 while( waitingSlave != NULL )
seanhalle@273 491 { //resume a slave that was waiting for work in this env to finish
seanhalle@273 492 PR_PI__make_slave_ready( waitingSlave, resumeEnv );
seanhalle@273 493 //get next waiting slave, repeat..
seanhalle@273 494 waitingSlave = readPrivQ( protoLangEnv->waitingForWorkToEndQ );
seanhalle@273 495 }
seanhalle@273 496 }
seanhalle@273 497
seanhalle@272 498 process->numLiveGenericSlvs -= 1;
seanhalle@273 499 PR_int__recycle_slaveVP( slave );
seanhalle@272 500 //NOTE: dissipate is unrelated to work available (just in case wondering)
seanhalle@272 501
seanhalle@261 502 //check End Of Process Condition
seanhalle@261 503 if( process->numLiveTasks == 0 &&
seanhalle@266 504 process->numLiveGenericSlvs == 0 )
seanhalle@273 505 PR_SS__end_process_normally( process );
seanhalle@261 506 }
seanhalle@261 507
seanhalle@273 508 //=======================
seanhalle@273 509 //===
seanhalle@273 510 //=
seanhalle@273 511 /*Langlet shutdown triggers this, which calls the registered shutdown
seanhalle@273 512 * handler for the langlet, and removes the lang's env from the process
seanhalle@261 513 */
seanhalle@268 514 inline
seanhalle@268 515 void
seanhalle@273 516 PRHandle__LangShutdown( PRReqst *req, SlaveVP *requestingSlv )
seanhalle@273 517 { void *langEnv;
seanhalle@273 518 PRLangEnv *protoLangEnv;
seanhalle@273 519 PRProcess *process;
seanhalle@268 520
seanhalle@273 521 process = requestingSlv->processSlaveIsIn;
seanhalle@273 522 protoLangEnv = PR_int__give_proto_lang_env_from_process( process, req->langMagicNumber );
seanhalle@273 523 langEnv = PR_int__give_lang_env( protoLangEnv );
seanhalle@268 524
seanhalle@273 525 //call the langlet's registered handler
seanhalle@273 526 (*protoLangEnv->shutdownHdlr)( langEnv );
seanhalle@267 527
seanhalle@273 528 PR_int__remove_lang_env_from_process_and_free( langEnv ); //removes from process and frees
seanhalle@276 529
seanhalle@276 530 PR_PI__resume_slave_in_PRServ( requestingSlv );
seanhalle@261 531 }
seanhalle@261 532
seanhalle@272 533
seanhalle@272 534 /*This is for OS requests and PR infrastructure requests, which are not
seanhalle@272 535 * part of the PRServ language -- this is for things that have to be in the
seanhalle@272 536 * infrastructure of PR itself, such as I/O requests, which have to go through
seanhalle@272 537 * pthreads inside the core controller..
seanhalle@272 538 *
seanhalle@272 539 *As of Jan 2013, doesn't do much of anything..
seanhalle@272 540 */
seanhalle@272 541 void inline
seanhalle@272 542 PRHandle__ServiceReq( SlaveVP *requestingSlv )
seanhalle@273 543 { PRReqst *req;
seanhalle@273 544 PRServiceReq *langReq;
seanhalle@273 545 PRLangEnv *protoLangEnv;
seanhalle@273 546 int32 magicNumber;
seanhalle@272 547
seanhalle@272 548
seanhalle@272 549 req = requestingSlv->request;
seanhalle@272 550
seanhalle@272 551 magicNumber = req->langMagicNumber;
seanhalle@273 552 protoLangEnv = PR_int__give_proto_lang_env_for_slave( requestingSlv, magicNumber );
seanhalle@272 553
seanhalle@272 554 langReq = PR_PI__take_lang_reqst_from(req);
seanhalle@272 555 if( langReq == NULL ) return;
seanhalle@272 556 switch( langReq->reqType ) //lang handlers are all in other file
seanhalle@272 557 {
seanhalle@273 558 case make_probe: handleMakeProbe( langReq, protoLangEnv );
seanhalle@272 559 break;
seanhalle@273 560 case throw_excp: handleThrowException( langReq, protoLangEnv );
seanhalle@272 561 break;
seanhalle@272 562 }
seanhalle@272 563 }
seanhalle@273 564
seanhalle@273 565
seanhalle@273 566 /*These handlers are special -- they don't belong to a language, because they
seanhalle@273 567 * deal with things internal to PR, so put them here..
seanhalle@273 568 */
seanhalle@273 569 inline
seanhalle@273 570 void
seanhalle@273 571 handleMakeProbe( PRServiceReq *langReq, PRLangEnv *protoLangEnv )
seanhalle@273 572 { IntervalProbe *newProbe;
seanhalle@273 573
seanhalle@273 574 newProbe = PR_int__malloc( sizeof(IntervalProbe) );
seanhalle@273 575 newProbe->nameStr = PR_int__strDup( langReq->nameStr );
seanhalle@273 576 newProbe->hist = NULL;
seanhalle@273 577 newProbe->schedChoiceWasRecorded = FALSE;
seanhalle@273 578
seanhalle@273 579 //This runs in masterVP, so no race-condition worries
seanhalle@273 580 //BUG: move to process
seanhalle@273 581 newProbe->probeID =
seanhalle@273 582 addToDynArray( newProbe, _PRTopEnv->dynIntervalProbesInfo );
seanhalle@273 583
seanhalle@273 584 langReq->requestingSlv->dataRetFromReq = newProbe;
seanhalle@273 585
seanhalle@273 586 (*protoLangEnv->makeSlaveReadyFn)( langReq->requestingSlv, PR_int__give_lang_env(protoLangEnv) );
seanhalle@273 587 }
seanhalle@273 588
seanhalle@273 589 inline
seanhalle@273 590 void
seanhalle@273 591 handleThrowException( PRServiceReq *langReq, PRLangEnv *protoLangEnv )
seanhalle@273 592 {
seanhalle@273 593 PR_int__throw_exception( langReq->msgStr, langReq->requestingSlv, langReq->exceptionData );
seanhalle@273 594
seanhalle@273 595 (*protoLangEnv->makeSlaveReadyFn)( langReq->requestingSlv, PR_int__give_lang_env(protoLangEnv) );
seanhalle@273 596 }
seanhalle@273 597
seanhalle@285 598 void
seanhalle@285 599 debug_print_req(AnimSlot *slot, PRReqst *req)
seanhalle@285 600 {
seanhalle@285 601 if(dbgMaster)
seanhalle@285 602 { printf("top handle request: %d | reqType: ", slot->coreSlotIsOn );
seanhalle@285 603 switch(req->reqType)
seanhalle@285 604 { case TaskCreate: printf("TaskCreate \n"); break;
seanhalle@285 605 case TaskEnd: printf("TaskEnd \n"); break;
seanhalle@285 606 case SlvCreate: printf("SlvCreate \n"); break;
seanhalle@285 607 case SlvDissipate: printf("SlvDissipate \n"); break;
seanhalle@285 608 case Language: printf("Language \n"); break;
seanhalle@285 609 case Service: printf("Service \n"); break;
seanhalle@285 610 case Hardware: printf("Hardware \n"); break;
seanhalle@285 611 case IO: printf("IO \n"); break;
seanhalle@285 612 case OSCall: printf("OSCall \n"); break;
seanhalle@285 613 case LangShutdown: printf("LangShutdown \n"); break;
seanhalle@285 614 case ProcessEnd: printf("ProcessEnd \n"); break;
seanhalle@285 615 case PRShutdown: printf("PRShutdown \n"); break;
seanhalle@285 616 }
seanhalle@285 617 fflush(stdin);
seanhalle@285 618 }
seanhalle@285 619 }
seanhalle@285 620
seanhalle@285 621