annotate AnimationMaster.c @ 287:15ee3fe10e3d

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