annotate PR.c @ 282:72ffdb11ad8e

Removed files that interfere with build -- for probes and counter recording
author Sean Halle <seanhalle@yahoo.com>
date Wed, 22 May 2013 17:40:23 -0700
parents 1d7ea1b0f176
children 7b6f8cf08b1f 15ee3fe10e3d
rev   line source
seanhalle@273 1 /*
seanhalle@273 2 * Copyright 2010 OpenSourceResearchInstitute
seanhalle@273 3 *
seanhalle@273 4 * Licensed under BSD
seanhalle@273 5 */
seanhalle@273 6
seanhalle@273 7 #include <stdio.h>
seanhalle@273 8 #include <stdlib.h>
seanhalle@273 9 #include <string.h>
seanhalle@273 10 #include <malloc.h>
seanhalle@273 11 #include <inttypes.h>
seanhalle@273 12 #include <sys/time.h>
seanhalle@273 13
seanhalle@273 14 #include "PR.h"
seanhalle@273 15
seanhalle@273 16
seanhalle@273 17 #define thdAttrs NULL
seanhalle@273 18
seanhalle@273 19
seanhalle@273 20 /* MEANING OF WL PI SS int
seanhalle@273 21 * These indicate which places the function is safe to use. They stand for:
seanhalle@273 22 * WL: Wrapper Library
seanhalle@273 23 * PI: Plugin
seanhalle@273 24 * SS: Startup and Shutdown
seanhalle@273 25 * int: internal to the PR implementation
seanhalle@273 26 */
seanhalle@273 27
seanhalle@273 28
seanhalle@273 29 //===========================================================================
seanhalle@273 30
seanhalle@273 31 //===========================================================================
seanhalle@273 32
seanhalle@273 33 /*Setup has two phases:
seanhalle@273 34 * 1) Semantic layer first calls init_PR, which creates masterEnv, and puts
seanhalle@273 35 * the master Slv into the work-queue, ready for first "call"
seanhalle@273 36 * 2) Semantic layer then does its own init, which creates the seed virt
seanhalle@273 37 * slave inside the semantic layer, ready to assign it when
seanhalle@273 38 * asked by the first run of the animationMaster.
seanhalle@273 39 *
seanhalle@273 40 *This part is bit weird because PR really wants to be "always there", and
seanhalle@273 41 * have applications attach and detach.. for now, this PR is part of
seanhalle@273 42 * the app, so the PR system starts up as part of running the app.
seanhalle@273 43 *
seanhalle@273 44 *The semantic layer is isolated from the PR internals by making the
seanhalle@273 45 * semantic layer do setup to a state that it's ready with its
seanhalle@273 46 * initial Slvs, ready to assign them to slots when the animationMaster
seanhalle@273 47 * asks. Without this pattern, the semantic layer's setup would
seanhalle@273 48 * have to modify slots directly to assign the initial virt-procrs, and put
seanhalle@273 49 * them into the readyToAnimateQ itself, breaking the isolation completely.
seanhalle@273 50 *
seanhalle@273 51 *
seanhalle@273 52 *The semantic layer creates the initial Slv(s), and adds its
seanhalle@273 53 * own environment to masterEnv, and fills in the pointers to
seanhalle@273 54 * the requestHandler and slaveAssigner plug-in functions
seanhalle@273 55 */
seanhalle@273 56
seanhalle@273 57 //Check the comments above -- likely out of sync
seanhalle@273 58
seanhalle@273 59 /*This allocates PR data structures, populates the top environments. After
seanhalle@273 60 * this call, processes can be started.
seanhalle@273 61 */
seanhalle@273 62 void
seanhalle@273 63 PR__start()
seanhalle@273 64 {
seanhalle@273 65 PR_SS__create_topEnv();
seanhalle@273 66
seanhalle@273 67 #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
seanhalle@273 68 printf( "\n\n Running in SEQUENTIAL mode \n\n" );
seanhalle@273 69 //Only difference between version with an OS thread pinned to each core and
seanhalle@273 70 // the sequential version of PR is PR__init_Seq, this, and coreCtlr_Seq.
seanhalle@273 71
seanhalle@273 72 //Don't do anything here -- using main thread for all PR activity, so
seanhalle@273 73 // do PR activity when main thread calls "wait for process to end"
seanhalle@273 74 #else
seanhalle@273 75 DEBUG__printf1(dbgInfra,"Offset of lock in masterEnv: %d ", (int32)offsetof(TopEnv,masterLock) );
seanhalle@273 76 PR_SS__create_the_coreCtlr_OS_threads();
seanhalle@273 77
seanhalle@273 78 #endif
seanhalle@273 79 }
seanhalle@273 80
seanhalle@273 81
seanhalle@273 82 /*For now, this is ONLY called from the main thread -- seems this can be relaxed
seanhalle@273 83 * at some point, but want to reduce complexity to get the first version working
seanhalle@273 84 * so making this restriction for now..
seanhalle@273 85 *
seanhalle@273 86 *It creates a seed slave, from the top-level fn and initial data passed into
seanhalle@273 87 * this fn.
seanhalle@273 88 *The only langlet in the created process is the default PRServ. The rest
seanhalle@273 89 * must be started up via calls made by the seed VP's top-level fn (passed in
seanhalle@273 90 * to this call).
seanhalle@273 91 *That places the information about which langlets are used within the process
seanhalle@273 92 * into the seed Fn of that process, where all the langlet start() calls are
seanhalle@273 93 * made.
seanhalle@273 94 *
seanhalle@273 95 *A process is represented by a structure that holds all the process-specific
seanhalle@273 96 * information:
seanhalle@273 97 *-] The hash-array containing the language environs of any langlets started
seanhalle@273 98 * inside the process.
seanhalle@273 99 *-] Counter of num live slaves and num live tasks in the process
seanhalle@273 100 *
seanhalle@273 101 */
seanhalle@273 102 PRProcess *
seanhalle@273 103 PR__create_process( TopLevelFnPtr seed_Fn, void *seedData )
seanhalle@273 104 { SlaveVP *seedSlv;
seanhalle@273 105 PRProcess *process;
seanhalle@273 106 PRLangEnv **langEnvs, **langEnvsList;
seanhalle@273 107
seanhalle@273 108 //This runs outside of the master lock, so use PR_WL form of malloc
seanhalle@273 109 process = PR_WL__malloc( sizeof(PRProcess) );
seanhalle@273 110 _PRTopEnv->processes[_PRTopEnv->numProcesses] = process;
seanhalle@273 111 _PRTopEnv->numProcesses += 1;
seanhalle@273 112
seanhalle@273 113 langEnvs =
seanhalle@273 114 (PRLangEnv **)PR_int__make_collection_of_size( NUM_IN_COLLECTION );
seanhalle@273 115 langEnvsList = PR_WL__malloc( NUM_IN_COLLECTION * sizeof(PRCollElem *) );
seanhalle@273 116 process->langEnvs = langEnvs;
seanhalle@273 117 process->protoLangEnvsList = langEnvsList;
seanhalle@273 118 process->numLangEnvs = 0;
seanhalle@276 119 process->hasWaitingToEnd = FALSE;
seanhalle@276 120
seanhalle@273 121 //A Process starts with one slave, the seed slave
seanhalle@273 122 seedSlv = PR_int__create_slaveVP( seed_Fn, seedData, process );
seanhalle@273 123 seedSlv->typeOfVP = SeedSlv;
seanhalle@273 124 seedSlv->processSlaveIsIn = process;
seanhalle@273 125 process->numLiveGenericSlvs = 1; //count the seed
seanhalle@273 126 process->numLiveTasks = 0;
seanhalle@273 127
seanhalle@273 128 PRServLangEnv *
seanhalle@273 129 servicesLangEnv =
seanhalle@273 130 PRServ__start(seedSlv);
seanhalle@273 131
seanhalle@273 132 //resume seedVP into PR's built-in services language's lang env
seanhalle@273 133 process->numEnvsWithWork = 0; //Seed is in PRServ lang env.. resume incrs this
seanhalle@273 134 PR_PI__make_slave_ready( seedSlv, servicesLangEnv );
seanhalle@273 135
seanhalle@273 136
seanhalle@273 137 //The first process created has to unblock the core controllers.
seanhalle@273 138 // This is the "magic" that starts the activity of PR going.
seanhalle@273 139 #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
seanhalle@273 140 //Do nothing here.. in sequential mode, are using the main thread, so
seanhalle@273 141 // don't use it to do anything yet.. do the PR activity when main thread
seanhalle@273 142 // calls "wait for process to end"
seanhalle@273 143 #else
seanhalle@273 144 if( _PRTopEnv->numProcesses == 1 )
seanhalle@273 145 {
seanhalle@273 146 //tell the core controller threads that a process is ready to be animated
seanhalle@273 147 //get lock, to lock out any threads still starting up -- they'll see
seanhalle@273 148 // that firstProcessReady is true before entering while loop, and so never
seanhalle@273 149 // wait on the condition
seanhalle@273 150 pthread_mutex_lock( &suspendLock );
seanhalle@273 151 _PRTopEnv->firstProcessReady = 1;
seanhalle@273 152 pthread_mutex_unlock( &suspendLock );
seanhalle@273 153 pthread_cond_broadcast( &suspendCond );
seanhalle@273 154 }
seanhalle@273 155 #endif
seanhalle@273 156 pthread_mutex_init( &(process->doneLock), NULL );
seanhalle@273 157 pthread_cond_init( &(process->doneCond), NULL );
seanhalle@273 158 process->executionIsComplete = FALSE;
seanhalle@273 159
seanhalle@273 160 return process;
seanhalle@273 161 }
seanhalle@273 162
seanhalle@278 163 void
seanhalle@273 164 PR__end_seedVP( SlaveVP *seedSlv )
seanhalle@273 165 {
seanhalle@273 166 PR_WL__send_end_slave_req( NULL, (RequestHandler)&PRServ__handleDissipateSeed, seedSlv,
seanhalle@273 167 PRServ_MAGIC_NUMBER );
seanhalle@273 168 }
seanhalle@273 169
seanhalle@278 170 void
seanhalle@273 171 PR__end_process_from_inside( SlaveVP *seedSlv )
seanhalle@273 172 {
seanhalle@273 173 PR_WL__send_lang_request( NULL, (RequestHandler)&PRServ__handle_end_process_from_inside,
seanhalle@273 174 seedSlv, PRServ_MAGIC_NUMBER );
seanhalle@273 175 }
seanhalle@273 176
seanhalle@273 177
seanhalle@273 178
seanhalle@273 179 /*When all work in the process has completed, then return from this call.
seanhalle@273 180 * The seedVP of the process may still exist, but it has no work, nor do any
seanhalle@273 181 * other VPs..
seanhalle@273 182 *The process must be shutdown via a separate call. That shutdown frees the
seanhalle@273 183 * process struct and bookkeeping structs.
seanhalle@273 184 *First checks whether the process is done, if yes, calls the clean-up fn then
seanhalle@273 185 * returns the result extracted from the PRProcess struct.
seanhalle@273 186 *If process not done yet, then performs a wait (in a loop to be sure the
seanhalle@273 187 * wakeup is not spurious, which can happen). PR registers the wait, and upon
seanhalle@273 188 * the process ending (last SlaveVP owned by it dissipates), then PR signals
seanhalle@273 189 * this to wakeup. This then calls the cleanup fn and returns the result.
seanhalle@273 190 */
seanhalle@273 191 void *
seanhalle@273 192 PR__give_results_from_process_when_ready( PRProcess *process )
seanhalle@273 193 { void *result;
seanhalle@273 194 //First get the "ACK" lock, then do normal wait for signal, then release
seanhalle@273 195 // ACK lock, to let end-process know it can free the process struct
seanhalle@273 196 pthread_mutex_lock( &(process->doneAckLock) );
seanhalle@273 197
seanhalle@273 198 pthread_mutex_lock( &(process->doneLock) );
seanhalle@273 199 while( process->executionIsComplete != TRUE )
seanhalle@273 200 {
seanhalle@273 201 pthread_cond_wait( &(process->doneCond),
seanhalle@273 202 &(process->doneLock) );
seanhalle@273 203 }
seanhalle@273 204 pthread_mutex_unlock( &(process->doneLock) );
seanhalle@273 205 result = process->resultToReturn;
seanhalle@273 206
seanhalle@273 207 //now send "ACK" signal to process_end Fn, that it may proceed
seanhalle@273 208 pthread_mutex_unlock( &(process->doneAckLock) );
seanhalle@273 209
seanhalle@273 210 return result;
seanhalle@273 211 //TODO: BUG? -- can process be created and end, before this acquires the
seanhalle@273 212 // first lock? Can see some rare code that creates a bunch, before getting
seanhalle@273 213 // to waiting.. leave for now.. pain to fix..
seanhalle@273 214 }
seanhalle@273 215
seanhalle@273 216
seanhalle@276 217 /*This should only be called from main. It makes the OS thread that is animating
seanhalle@276 218 * main to suspend until the process completes shutdown.
seanhalle@276 219 */
seanhalle@273 220 void
seanhalle@273 221 PR__wait_for_process_to_end( PRProcess *process )
seanhalle@273 222 {
seanhalle@276 223 process->hasWaitingToEnd = TRUE;
seanhalle@276 224
seanhalle@273 225 #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
seanhalle@273 226 // call the one and only core ctlr (sequential version), in the main thread.
seanhalle@276 227 if( process->executionIsComplete )
seanhalle@276 228 return;
seanhalle@276 229 else
seanhalle@276 230 { coreCtlr_Seq( NULL );
seanhalle@276 231 flushRegisters(); //Not sure why here, but leaving to be safe
seanhalle@276 232 process->executionIsComplete = TRUE;
seanhalle@276 233 }
seanhalle@273 234 #else
seanhalle@273 235 //First get the "ACK" lock, then do normal wait for signal, then release
seanhalle@273 236 // ACK lock, to let end-process know it can free the process struct
seanhalle@273 237 pthread_mutex_lock( &(process->doneAckLock) );
seanhalle@273 238 pthread_mutex_lock( &(process->doneLock) );
seanhalle@273 239 while( process->executionIsComplete != TRUE )
seanhalle@273 240 {
seanhalle@273 241 pthread_cond_wait( &(process->doneCond),
seanhalle@273 242 &(process->doneLock) );
seanhalle@273 243 }
seanhalle@273 244 pthread_mutex_unlock( &(process->doneLock) );
seanhalle@273 245 //now send "ACK" signal to process_end Fn, that it may proceed
seanhalle@273 246 pthread_mutex_unlock( &(process->doneAckLock) );
seanhalle@273 247
seanhalle@273 248 //TODO: BUG? -- can process be created and end, before this acquires the
seanhalle@273 249 // first lock? Can see some rare code that creates a bunch, before getting
seanhalle@273 250 // to waiting.. leave for now.. pain to fix..
seanhalle@273 251 #endif
seanhalle@273 252 }
seanhalle@273 253
seanhalle@273 254
seanhalle@273 255 void
seanhalle@273 256 PR__wait_for_all_activity_to_end()
seanhalle@273 257 {
seanhalle@276 258 #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
seanhalle@276 259 //In sequential mode, can't reach this call unless all activity has
seanhalle@276 260 // already completed, so just return.
seanhalle@276 261 return;
seanhalle@276 262 #else
seanhalle@273 263 pthread_mutex_lock( &(_PRTopEnv->activityDoneLock) );
seanhalle@273 264 while( !(_PRTopEnv->allActivityIsDone) )
seanhalle@273 265 {
seanhalle@273 266 pthread_cond_wait( &(_PRTopEnv->activityDoneCond),
seanhalle@273 267 &(_PRTopEnv->activityDoneLock) );
seanhalle@273 268 }
seanhalle@273 269 pthread_mutex_unlock( &(_PRTopEnv->activityDoneLock) );
seanhalle@276 270 #endif
seanhalle@273 271 }
seanhalle@273 272
seanhalle@273 273
seanhalle@273 274 /*This info is retrieved by PRServ's "give environ string" function
seanhalle@273 275 *These Fn s are meant to be called from main, or possibly the seed slave.
seanhalle@273 276 */
seanhalle@273 277 void
seanhalle@273 278 PR__set_app_info( char *info )
seanhalle@273 279 { int32 len;
seanhalle@273 280 char *copy;
seanhalle@273 281 len = strlen(info) +1;
seanhalle@273 282 copy = PR_int__malloc(len);
seanhalle@273 283 strcpy(copy, info);
seanhalle@273 284 _PRTopEnv->metaInfo->appInfo = copy;
seanhalle@273 285 }
seanhalle@273 286 void
seanhalle@273 287 PR__set_input_info( char *info )
seanhalle@273 288 { int32 len;
seanhalle@273 289 char *copy;
seanhalle@273 290 len = strlen(info) +1;
seanhalle@273 291 copy = PR_int__malloc(len);
seanhalle@273 292 strcpy(copy, info);
seanhalle@273 293 _PRTopEnv->metaInfo->inputInfo = copy;
seanhalle@273 294 }
seanhalle@273 295
seanhalle@273 296
seanhalle@273 297
seanhalle@273 298
seanhalle@273 299 //========================== SHUT DOWN ===========================
seanhalle@273 300
seanhalle@273 301 /*This is called from the main thread, and causes PR's OS threads to stop
seanhalle@273 302 * then cleans up any memory allocated by PR from the OS.
seanhalle@273 303 *
seanhalle@273 304 *The main thread has a separate call it can use to wait for all work to
seanhalle@273 305 * finish, so when this is called, it just shuts down, whether there's
seanhalle@273 306 * unfinished work or not.
seanhalle@273 307 *
seanhalle@273 308 *However, cores that are performing work won't see this shutdown until
seanhalle@273 309 * they finish their current work-unit.
seanhalle@273 310 */
seanhalle@273 311 void
seanhalle@273 312 PR__shutdown()
seanhalle@273 313 { int32 coreIdx;
seanhalle@273 314
seanhalle@273 315 PR_SS__shutdown_OS_threads();
seanhalle@273 316
seanhalle@273 317 //wait for the OS threads to exit
seanhalle@273 318 for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ )
seanhalle@273 319 {
seanhalle@273 320 pthread_join( coreCtlrThdHandles[coreIdx], NULL );
seanhalle@273 321 }
seanhalle@273 322
seanhalle@273 323 //Before getting rid of everything, print out any measurements made
seanhalle@273 324 PR_SS__print_out_measurements();
seanhalle@273 325
seanhalle@273 326 //free all memory allocated from the OS
seanhalle@273 327 PR_SS__cleanup_at_end_of_shutdown();
seanhalle@273 328 }
seanhalle@273 329
seanhalle@273 330
seanhalle@273 331