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