Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
diff PR.c @ 273:40e7625e57bd
Compiles and runs, up to end of process, working on end process and shutdown
| author | Sean Halle <seanhalle@yahoo.com> |
|---|---|
| date | Sat, 02 Mar 2013 09:43:45 -0800 |
| parents | |
| children | 1d7ea1b0f176 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/PR.c Sat Mar 02 09:43:45 2013 -0800 1.3 @@ -0,0 +1,314 @@ 1.4 +/* 1.5 + * Copyright 2010 OpenSourceResearchInstitute 1.6 + * 1.7 + * Licensed under BSD 1.8 + */ 1.9 + 1.10 +#include <stdio.h> 1.11 +#include <stdlib.h> 1.12 +#include <string.h> 1.13 +#include <malloc.h> 1.14 +#include <inttypes.h> 1.15 +#include <sys/time.h> 1.16 +#include <pthread.h> 1.17 + 1.18 +#include "PR.h" 1.19 + 1.20 + 1.21 +#define thdAttrs NULL 1.22 + 1.23 + 1.24 +/* MEANING OF WL PI SS int 1.25 + * These indicate which places the function is safe to use. They stand for: 1.26 + * WL: Wrapper Library 1.27 + * PI: Plugin 1.28 + * SS: Startup and Shutdown 1.29 + * int: internal to the PR implementation 1.30 + */ 1.31 + 1.32 + 1.33 +//=========================================================================== 1.34 + 1.35 +//=========================================================================== 1.36 + 1.37 +/*Setup has two phases: 1.38 + * 1) Semantic layer first calls init_PR, which creates masterEnv, and puts 1.39 + * the master Slv into the work-queue, ready for first "call" 1.40 + * 2) Semantic layer then does its own init, which creates the seed virt 1.41 + * slave inside the semantic layer, ready to assign it when 1.42 + * asked by the first run of the animationMaster. 1.43 + * 1.44 + *This part is bit weird because PR really wants to be "always there", and 1.45 + * have applications attach and detach.. for now, this PR is part of 1.46 + * the app, so the PR system starts up as part of running the app. 1.47 + * 1.48 + *The semantic layer is isolated from the PR internals by making the 1.49 + * semantic layer do setup to a state that it's ready with its 1.50 + * initial Slvs, ready to assign them to slots when the animationMaster 1.51 + * asks. Without this pattern, the semantic layer's setup would 1.52 + * have to modify slots directly to assign the initial virt-procrs, and put 1.53 + * them into the readyToAnimateQ itself, breaking the isolation completely. 1.54 + * 1.55 + * 1.56 + *The semantic layer creates the initial Slv(s), and adds its 1.57 + * own environment to masterEnv, and fills in the pointers to 1.58 + * the requestHandler and slaveAssigner plug-in functions 1.59 + */ 1.60 + 1.61 +//Check the comments above -- likely out of sync 1.62 + 1.63 +/*This allocates PR data structures, populates the top environments. After 1.64 + * this call, processes can be started. 1.65 + */ 1.66 +void 1.67 +PR__start() 1.68 + { 1.69 + PR_SS__create_topEnv(); 1.70 + 1.71 + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 1.72 + printf( "\n\n Running in SEQUENTIAL mode \n\n" ); 1.73 + //Only difference between version with an OS thread pinned to each core and 1.74 + // the sequential version of PR is PR__init_Seq, this, and coreCtlr_Seq. 1.75 + 1.76 + //Don't do anything here -- using main thread for all PR activity, so 1.77 + // do PR activity when main thread calls "wait for process to end" 1.78 + #else 1.79 + DEBUG__printf1(dbgInfra,"Offset of lock in masterEnv: %d ", (int32)offsetof(TopEnv,masterLock) ); 1.80 + PR_SS__create_the_coreCtlr_OS_threads(); 1.81 + 1.82 + #endif 1.83 + } 1.84 + 1.85 + 1.86 +/*For now, this is ONLY called from the main thread -- seems this can be relaxed 1.87 + * at some point, but want to reduce complexity to get the first version working 1.88 + * so making this restriction for now.. 1.89 + * 1.90 + *It creates a seed slave, from the top-level fn and initial data passed into 1.91 + * this fn. 1.92 + *The only langlet in the created process is the default PRServ. The rest 1.93 + * must be started up via calls made by the seed VP's top-level fn (passed in 1.94 + * to this call). 1.95 + *That places the information about which langlets are used within the process 1.96 + * into the seed Fn of that process, where all the langlet start() calls are 1.97 + * made. 1.98 + * 1.99 + *A process is represented by a structure that holds all the process-specific 1.100 + * information: 1.101 + *-] The hash-array containing the language environs of any langlets started 1.102 + * inside the process. 1.103 + *-] Counter of num live slaves and num live tasks in the process 1.104 + * 1.105 + */ 1.106 +PRProcess * 1.107 +PR__create_process( TopLevelFnPtr seed_Fn, void *seedData ) 1.108 + { SlaveVP *seedSlv; 1.109 + PRProcess *process; 1.110 + PRLangEnv **langEnvs, **langEnvsList; 1.111 + 1.112 + //This runs outside of the master lock, so use PR_WL form of malloc 1.113 + process = PR_WL__malloc( sizeof(PRProcess) ); 1.114 + _PRTopEnv->processes[_PRTopEnv->numProcesses] = process; 1.115 + _PRTopEnv->numProcesses += 1; 1.116 + 1.117 + langEnvs = 1.118 + (PRLangEnv **)PR_int__make_collection_of_size( NUM_IN_COLLECTION ); 1.119 + langEnvsList = PR_WL__malloc( NUM_IN_COLLECTION * sizeof(PRCollElem *) ); 1.120 + process->langEnvs = langEnvs; 1.121 + process->protoLangEnvsList = langEnvsList; 1.122 + process->numLangEnvs = 0; 1.123 + 1.124 + //A Process starts with one slave, the seed slave 1.125 + seedSlv = PR_int__create_slaveVP( seed_Fn, seedData, process ); 1.126 + seedSlv->typeOfVP = SeedSlv; 1.127 + seedSlv->processSlaveIsIn = process; 1.128 + process->numLiveGenericSlvs = 1; //count the seed 1.129 + process->numLiveTasks = 0; 1.130 + 1.131 + PRServLangEnv * 1.132 + servicesLangEnv = 1.133 + PRServ__start(seedSlv); 1.134 + 1.135 + //resume seedVP into PR's built-in services language's lang env 1.136 + process->numEnvsWithWork = 0; //Seed is in PRServ lang env.. resume incrs this 1.137 + PR_PI__make_slave_ready( seedSlv, servicesLangEnv ); 1.138 + 1.139 + 1.140 + //The first process created has to unblock the core controllers. 1.141 + // This is the "magic" that starts the activity of PR going. 1.142 + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 1.143 + //Do nothing here.. in sequential mode, are using the main thread, so 1.144 + // don't use it to do anything yet.. do the PR activity when main thread 1.145 + // calls "wait for process to end" 1.146 + #else 1.147 + if( _PRTopEnv->numProcesses == 1 ) 1.148 + { 1.149 + //tell the core controller threads that a process is ready to be animated 1.150 + //get lock, to lock out any threads still starting up -- they'll see 1.151 + // that firstProcessReady is true before entering while loop, and so never 1.152 + // wait on the condition 1.153 + pthread_mutex_lock( &suspendLock ); 1.154 + _PRTopEnv->firstProcessReady = 1; 1.155 + pthread_mutex_unlock( &suspendLock ); 1.156 + pthread_cond_broadcast( &suspendCond ); 1.157 + } 1.158 + #endif 1.159 + pthread_mutex_init( &(process->doneLock), NULL ); 1.160 + pthread_cond_init( &(process->doneCond), NULL ); 1.161 + process->executionIsComplete = FALSE; 1.162 + 1.163 + return process; 1.164 + } 1.165 + 1.166 +PR__end_seedVP( SlaveVP *seedSlv ) 1.167 + { 1.168 + PR_WL__send_end_slave_req( NULL, (RequestHandler)&PRServ__handleDissipateSeed, seedSlv, 1.169 + PRServ_MAGIC_NUMBER ); 1.170 + } 1.171 + 1.172 +PR__end_process_from_inside( SlaveVP *seedSlv ) 1.173 + { 1.174 + PR_WL__send_lang_request( NULL, (RequestHandler)&PRServ__handle_end_process_from_inside, 1.175 + seedSlv, PRServ_MAGIC_NUMBER ); 1.176 + } 1.177 + 1.178 + 1.179 + 1.180 +/*When all work in the process has completed, then return from this call. 1.181 + * The seedVP of the process may still exist, but it has no work, nor do any 1.182 + * other VPs.. 1.183 + *The process must be shutdown via a separate call. That shutdown frees the 1.184 + * process struct and bookkeeping structs. 1.185 + *First checks whether the process is done, if yes, calls the clean-up fn then 1.186 + * returns the result extracted from the PRProcess struct. 1.187 + *If process not done yet, then performs a wait (in a loop to be sure the 1.188 + * wakeup is not spurious, which can happen). PR registers the wait, and upon 1.189 + * the process ending (last SlaveVP owned by it dissipates), then PR signals 1.190 + * this to wakeup. This then calls the cleanup fn and returns the result. 1.191 + */ 1.192 +void * 1.193 +PR__give_results_from_process_when_ready( PRProcess *process ) 1.194 + { void *result; 1.195 + //First get the "ACK" lock, then do normal wait for signal, then release 1.196 + // ACK lock, to let end-process know it can free the process struct 1.197 + pthread_mutex_lock( &(process->doneAckLock) ); 1.198 + 1.199 + pthread_mutex_lock( &(process->doneLock) ); 1.200 + while( process->executionIsComplete != TRUE ) 1.201 + { 1.202 + pthread_cond_wait( &(process->doneCond), 1.203 + &(process->doneLock) ); 1.204 + } 1.205 + pthread_mutex_unlock( &(process->doneLock) ); 1.206 + result = process->resultToReturn; 1.207 + 1.208 + //now send "ACK" signal to process_end Fn, that it may proceed 1.209 + pthread_mutex_unlock( &(process->doneAckLock) ); 1.210 + 1.211 + return result; 1.212 + //TODO: BUG? -- can process be created and end, before this acquires the 1.213 + // first lock? Can see some rare code that creates a bunch, before getting 1.214 + // to waiting.. leave for now.. pain to fix.. 1.215 + } 1.216 + 1.217 + 1.218 +void 1.219 +PR__wait_for_process_to_end( PRProcess *process ) 1.220 + { 1.221 + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 1.222 + // call the one and only core ctlr (sequential version), in the main thread. 1.223 + coreCtlr_Seq( NULL ); 1.224 + flushRegisters(); //Not sure why here, but leaving to be safe 1.225 + 1.226 + #else 1.227 + //First get the "ACK" lock, then do normal wait for signal, then release 1.228 + // ACK lock, to let end-process know it can free the process struct 1.229 + pthread_mutex_lock( &(process->doneAckLock) ); 1.230 + pthread_mutex_lock( &(process->doneLock) ); 1.231 + while( process->executionIsComplete != TRUE ) 1.232 + { 1.233 + pthread_cond_wait( &(process->doneCond), 1.234 + &(process->doneLock) ); 1.235 + } 1.236 + pthread_mutex_unlock( &(process->doneLock) ); 1.237 + //now send "ACK" signal to process_end Fn, that it may proceed 1.238 + pthread_mutex_unlock( &(process->doneAckLock) ); 1.239 + 1.240 + //TODO: BUG? -- can process be created and end, before this acquires the 1.241 + // first lock? Can see some rare code that creates a bunch, before getting 1.242 + // to waiting.. leave for now.. pain to fix.. 1.243 + #endif 1.244 + } 1.245 + 1.246 + 1.247 +void 1.248 +PR__wait_for_all_activity_to_end() 1.249 + { 1.250 + pthread_mutex_lock( &(_PRTopEnv->activityDoneLock) ); 1.251 + while( !(_PRTopEnv->allActivityIsDone) ) 1.252 + { 1.253 + pthread_cond_wait( &(_PRTopEnv->activityDoneCond), 1.254 + &(_PRTopEnv->activityDoneLock) ); 1.255 + } 1.256 + pthread_mutex_unlock( &(_PRTopEnv->activityDoneLock) ); 1.257 + } 1.258 + 1.259 + 1.260 +/*This info is retrieved by PRServ's "give environ string" function 1.261 + *These Fn s are meant to be called from main, or possibly the seed slave. 1.262 + */ 1.263 +void 1.264 +PR__set_app_info( char *info ) 1.265 + { int32 len; 1.266 + char *copy; 1.267 + len = strlen(info) +1; 1.268 + copy = PR_int__malloc(len); 1.269 + strcpy(copy, info); 1.270 + _PRTopEnv->metaInfo->appInfo = copy; 1.271 + } 1.272 +void 1.273 +PR__set_input_info( char *info ) 1.274 + { int32 len; 1.275 + char *copy; 1.276 + len = strlen(info) +1; 1.277 + copy = PR_int__malloc(len); 1.278 + strcpy(copy, info); 1.279 + _PRTopEnv->metaInfo->inputInfo = copy; 1.280 + } 1.281 + 1.282 + 1.283 + 1.284 + 1.285 +//========================== SHUT DOWN =========================== 1.286 + 1.287 +/*This is called from the main thread, and causes PR's OS threads to stop 1.288 + * then cleans up any memory allocated by PR from the OS. 1.289 + * 1.290 + *The main thread has a separate call it can use to wait for all work to 1.291 + * finish, so when this is called, it just shuts down, whether there's 1.292 + * unfinished work or not. 1.293 + * 1.294 + *However, cores that are performing work won't see this shutdown until 1.295 + * they finish their current work-unit. 1.296 + */ 1.297 +void 1.298 +PR__shutdown() 1.299 + { int32 coreIdx; 1.300 + 1.301 + PR_SS__shutdown_OS_threads(); 1.302 + 1.303 + //wait for the OS threads to exit 1.304 + for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ ) 1.305 + { 1.306 + pthread_join( coreCtlrThdHandles[coreIdx], NULL ); 1.307 + } 1.308 + 1.309 + //Before getting rid of everything, print out any measurements made 1.310 + PR_SS__print_out_measurements(); 1.311 + 1.312 + //free all memory allocated from the OS 1.313 + PR_SS__cleanup_at_end_of_shutdown(); 1.314 + } 1.315 + 1.316 + 1.317 +
