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 +