VMS/VMS_Implementations/Vthread_impls/Vthread_MC_shared_impl

view Vthread.c @ 29:b94dc57e4455

refactored many files -- chgd names, moved code around -- doesn't compile
author Some Random Person <seanhalle@yahoo.com>
date Wed, 09 May 2012 13:24:19 -0700
parents
children
line source
1 /*
2 * Copyright 2010 OpenSourceCodeStewardshipFoundation
3 *
4 * Licensed under BSD
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
10 #include "VMS_impl/VMS.h"
11 #include "Vthread.h"
12 #include "Vthread_helper.h"
13 #include "C_Libraries/Queue_impl/PrivateQueue.h"
14 #include "C_Libraries/Hash_impl/PrivateHash.h"
17 //==========================================================================
19 void
20 Vthread__init();
22 void
23 Vthread__init_Seq();
25 void
26 Vthread__init_Helper();
29 //===========================================================================
31 /*These are the library functions *called in the application*
32 *
33 */
37 //===========================================================================
39 inline int32
40 Vthread__giveMinWorkUnitCycles( float32 percentOverhead )
41 {
42 return MIN_WORK_UNIT_CYCLES;
43 }
45 inline int32
46 Vthread__giveIdealNumWorkUnits()
47 {
48 return NUM_SCHED_SLOTS * NUM_CORES;
49 }
51 inline int32
52 Vthread__give_number_of_cores_to_schedule_onto()
53 {
54 return NUM_CORES;
55 }
57 /*For now, use TSC -- later, make these two macros with assembly that first
58 * saves jump point, and second jumps back several times to get reliable time
59 */
60 inline void
61 Vthread__start_primitive()
62 { saveLowTimeStampCountInto( ((VthdSemEnv *)(_VMSMasterEnv->semanticEnv))->
63 primitiveStartTime );
64 }
66 /*Just quick and dirty for now -- make reliable later
67 * will want this to jump back several times -- to be sure cache is warm
68 * because don't want comm time included in calc-time measurement -- and
69 * also to throw out any "weird" values due to OS interrupt or TSC rollover
70 */
71 inline int32
72 Vthread__end_primitive_and_give_cycles()
73 { int32 endTime, startTime;
74 //TODO: fix by repeating time-measurement
75 saveLowTimeStampCountInto( endTime );
76 startTime=((VthdSemEnv*)(_VMSMasterEnv->semanticEnv))->primitiveStartTime;
77 return (endTime - startTime);
78 }
82 //===========================================================================
84 /*Re-use this in the entry-point fn
85 */
86 inline SlaveVP *
87 Vthread__create_slaveVP_helper( TopLevelFnPtr fnPtr, void *initData,
88 VthdSemEnv *semEnv, int32 coreToScheduleOnto )
89 { SlaveVP *newSlv;
90 VthdSemData *semData;
92 //This is running in master, so use internal version
93 newSlv = VMS_WL__create_slaveVP( fnPtr, initData );
95 semData = VMS_WL__malloc( sizeof(VthdSemData) );
96 semData->highestTransEntered = -1;
97 semData->lastTransEntered = NULL;
99 newSlv->semanticData = semData;
101 //=================== Assign new processor to a core =====================
102 #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
103 newSlv->coreAnimatedBy = 0;
105 #else
107 if(coreToScheduleOnto < 0 || coreToScheduleOnto >= NUM_CORES )
108 { //out-of-range, so round-robin assignment
109 newSlv->coreAnimatedBy = semEnv->nextCoreToGetNewSlv;
111 if( semEnv->nextCoreToGetNewSlv >= NUM_CORES - 1 )
112 semEnv->nextCoreToGetNewSlv = 0;
113 else
114 semEnv->nextCoreToGetNewSlv += 1;
115 }
116 else //core num in-range, so use it
117 { newSlv->coreAnimatedBy = coreToScheduleOnto;
118 }
119 #endif
120 //========================================================================
122 return newSlv;
123 }
126 /*
127 */
128 inline SlaveVP *
129 Vthread__create_thread( TopLevelFnPtr fnPtr, void *initData,
130 SlaveVP *creatingSlv )
131 { VthdSemReq reqData;
133 //the semantic request data is on the stack and disappears when this
134 // call returns -- it's guaranteed to remain in the Slv's stack for as
135 // long as the Slv is suspended.
136 reqData.reqType = 0; //know the type because is a VMS create req
137 reqData.coreToScheduleOnto = -1; //means round-robin schedule
138 reqData.fnPtr = fnPtr;
139 reqData.initData = initData;
140 reqData.requestingSlv = creatingSlv;
142 VMS_WL__send_create_slaveVP_req( &reqData, creatingSlv );
144 return creatingSlv->dataRetFromReq;
145 }
148 inline SlaveVP *
149 Vthread__create_thread_with_affinity( TopLevelFnPtr fnPtr, void *initData,
150 SlaveVP *creatingSlv, int32 coreToScheduleOnto )
151 { VthdSemReq reqData;
153 //the semantic request data is on the stack and disappears when this
154 // call returns -- it's guaranteed to remain in the Slv's stack for as
155 // long as the Slv is suspended.
156 reqData.reqType = 0; //know type because in a VMS create req
157 reqData.coreToScheduleOnto = coreToScheduleOnto;
158 reqData.fnPtr = fnPtr;
159 reqData.initData = initData;
160 reqData.requestingSlv = creatingSlv;
162 VMS_WL__send_create_slaveVP_req( &reqData, creatingSlv );
163 }
165 inline void
166 Vthread__dissipate_thread( SlaveVP *procrToDissipate )
167 {
168 VMS_WL__send_dissipate_req( procrToDissipate );
169 }
172 //===========================================================================
174 void *
175 Vthread__malloc( size_t sizeToMalloc, SlaveVP *animSlv )
176 { VthdSemReq reqData;
178 reqData.reqType = malloc_req;
179 reqData.sizeToMalloc = sizeToMalloc;
180 reqData.requestingSlv = animSlv;
182 VMS_WL__send_sem_request( &reqData, animSlv );
184 return animSlv->dataRetFromReq;
185 }
188 /*Sends request to Master, which does the work of freeing
189 */
190 void
191 Vthread__free( void *ptrToFree, SlaveVP *animSlv )
192 { VthdSemReq reqData;
194 reqData.reqType = free_req;
195 reqData.ptrToFree = ptrToFree;
196 reqData.requestingSlv = animSlv;
198 VMS_WL__send_sem_request( &reqData, animSlv );
199 }
202 //===========================================================================
204 inline void
205 Vthread__set_globals_to( void *globals )
206 {
207 ((VthdSemEnv *)
208 (_VMSMasterEnv->semanticEnv))->applicationGlobals = globals;
209 }
211 inline void *
212 Vthread__give_globals()
213 {
214 return((VthdSemEnv *) (_VMSMasterEnv->semanticEnv))->applicationGlobals;
215 }
218 //===========================================================================
220 inline int32
221 Vthread__make_mutex( SlaveVP *animSlv )
222 { VthdSemReq reqData;
224 reqData.reqType = make_mutex;
225 reqData.requestingSlv = animSlv;
227 VMS_WL__send_sem_request( &reqData, animSlv );
229 return (int32)animSlv->dataRetFromReq; //mutexid is 32bit wide
230 }
232 inline void
233 Vthread__mutex_lock( int32 mutexIdx, SlaveVP *acquiringSlv )
234 { VthdSemReq reqData;
236 reqData.reqType = mutex_lock;
237 reqData.mutexIdx = mutexIdx;
238 reqData.requestingSlv = acquiringSlv;
240 VMS_WL__send_sem_request( &reqData, acquiringSlv );
241 }
243 inline void
244 Vthread__mutex_unlock( int32 mutexIdx, SlaveVP *releasingSlv )
245 { VthdSemReq reqData;
247 reqData.reqType = mutex_unlock;
248 reqData.mutexIdx = mutexIdx;
249 reqData.requestingSlv = releasingSlv;
251 VMS_WL__send_sem_request( &reqData, releasingSlv );
252 }
255 //=======================
256 inline int32
257 Vthread__make_cond( int32 ownedMutexIdx, SlaveVP *animSlv)
258 { VthdSemReq reqData;
260 reqData.reqType = make_cond;
261 reqData.mutexIdx = ownedMutexIdx;
262 reqData.requestingSlv = animSlv;
264 VMS_WL__send_sem_request( &reqData, animSlv );
266 return (int32)animSlv->dataRetFromReq; //condIdx is 32 bit wide
267 }
269 inline void
270 Vthread__cond_wait( int32 condIdx, SlaveVP *waitingSlv)
271 { VthdSemReq reqData;
273 reqData.reqType = cond_wait;
274 reqData.condIdx = condIdx;
275 reqData.requestingSlv = waitingSlv;
277 VMS_WL__send_sem_request( &reqData, waitingSlv );
278 }
280 inline void *
281 Vthread__cond_signal( int32 condIdx, SlaveVP *signallingSlv )
282 { VthdSemReq reqData;
284 reqData.reqType = cond_signal;
285 reqData.condIdx = condIdx;
286 reqData.requestingSlv = signallingSlv;
288 VMS_WL__send_sem_request( &reqData, signallingSlv );
289 }
292 //===========================================================================
293 //
294 /*A function singleton is a function whose body executes exactly once, on a
295 * single core, no matter how many times the fuction is called and no
296 * matter how many cores or the timing of cores calling it.
297 *
298 *A data singleton is a ticket attached to data. That ticket can be used
299 * to get the data through the function exactly once, no matter how many
300 * times the data is given to the function, and no matter the timing of
301 * trying to get the data through from different cores.
302 */
304 /*Fn singleton uses ID as index into array of singleton structs held in the
305 * semantic environment.
306 */
307 void
308 Vthread__start_fn_singleton( int32 singletonID, SlaveVP *animSlv )
309 {
310 VthdSemReq reqData;
312 //
313 reqData.reqType = singleton_fn_start;
314 reqData.singletonID = singletonID;
316 VMS_WL__send_sem_request( &reqData, animSlv );
317 if( animSlv->dataRetFromReq != 0 ) //addr of matching end-singleton
318 {
319 VthdSemEnv *semEnv = VMS_int__give_sem_env_for( animSlv ); //not protected!
320 VMS_int__return_to_addr_in_ptd_to_loc(
321 &((semEnv->fnSingletons[singletonID]).savedRetAddr) );
322 }
323 }
325 /*Data singleton hands addr of loc holding a pointer to a singleton struct.
326 * The start_data_singleton makes the structure and puts its addr into the
327 * location.
328 */
329 void
330 Vthread__start_data_singleton( VthdSingleton *singleton, SlaveVP *animSlv )
331 {
332 VthdSemReq reqData;
334 if( singleton->savedRetAddr && singleton->hasFinished )
335 goto JmpToEndSingleton;
337 reqData.reqType = singleton_data_start;
338 reqData.singleton = singleton;
340 VMS_WL__send_sem_request( &reqData, animSlv );
341 if( animSlv->dataRetFromReq ) //either 0 or end singleton's return addr
342 {
343 JmpToEndSingleton:
344 VMS_int__return_to_addr_in_ptd_to_loc(&(singleton->savedRetAddr));
345 }
346 //now, simply return
347 //will exit either from the start singleton call or the end-singleton call
348 }
350 /*Uses ID as index into array of flags. If flag already set, resumes from
351 * end-label. Else, sets flag and resumes normally.
352 *
353 *Note, this call cannot be inlined because the instr addr at the label
354 * inside is shared by all invocations of a given singleton ID.
355 */
356 void
357 Vthread__end_fn_singleton( int32 singletonID, SlaveVP *animSlv )
358 {
359 VthdSemReq reqData;
361 //don't need this addr until after at least one singleton has reached
362 // this function
363 VthdSemEnv *semEnv = VMS_int__give_sem_env_for( animSlv );
364 VMS_int__return_to_addr_in_ptd_to_loc(
365 &((semEnv->fnSingletons[singletonID]).savedRetAddr) );
367 reqData.reqType = singleton_fn_end;
368 reqData.singletonID = singletonID;
370 VMS_WL__send_sem_request( &reqData, animSlv );
371 }
373 void
374 Vthread__end_data_singleton( VthdSingleton *singleton, SlaveVP *animSlv )
375 {
376 VthdSemReq reqData;
378 //don't need this addr until after singleton struct has reached
379 // this function for first time
380 //do assembly that saves the return addr of this fn call into the
381 // data singleton -- that data-singleton can only be given to exactly
382 // one instance in the code of this function. However, can use this
383 // function in different places for different data-singletons.
385 VMS_int__save_return_into_ptd_to_loc_then_do_ret(&(singleton->savedRetAddr));
387 reqData.reqType = singleton_data_end;
388 reqData.singleton = singleton;
390 VMS_WL__send_sem_request( &reqData, animSlv );
391 }
394 /*This executes the function in the masterVP, so it executes in isolation
395 * from any other copies -- only one copy of the function can ever execute
396 * at a time.
397 *
398 *It suspends to the master, and the request handler takes the function
399 * pointer out of the request and calls it, then resumes the Slv.
400 *Only very short functions should be called this way -- for longer-running
401 * isolation, use transaction-start and transaction-end, which run the code
402 * between as work-code.
403 */
404 void
405 Vthread__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster,
406 void *data, SlaveVP *animSlv )
407 {
408 VthdSemReq reqData;
410 //
411 reqData.reqType = atomic;
412 reqData.fnToExecInMaster = ptrToFnToExecInMaster;
413 reqData.dataForFn = data;
415 VMS_WL__send_sem_request( &reqData, animSlv );
416 }
419 /*This suspends to the master.
420 *First, it looks at the Slv's data, to see the highest transactionID that Slv
421 * already has entered. If the current ID is not larger, it throws an
422 * exception stating a bug in the code. Otherwise it puts the current ID
423 * there, and adds the ID to a linked list of IDs entered -- the list is
424 * used to check that exits are properly ordered.
425 *Next it is uses transactionID as index into an array of transaction
426 * structures.
427 *If the "Slv_currently_executing" field is non-null, then put requesting Slv
428 * into queue in the struct. (At some point a holder will request
429 * end-transaction, which will take this Slv from the queue and resume it.)
430 *If NULL, then write requesting into the field and resume.
431 */
432 void
433 Vthread__start_transaction( int32 transactionID, SlaveVP *animSlv )
434 {
435 VthdSemReq reqData;
437 //
438 reqData.reqType = trans_start;
439 reqData.transID = transactionID;
441 VMS_WL__send_sem_request( &reqData, animSlv );
442 }
444 /*This suspends to the master, then uses transactionID as index into an
445 * array of transaction structures.
446 *It looks at Slv_currently_executing to be sure it's same as requesting Slv.
447 * If different, throws an exception, stating there's a bug in the code.
448 *Next it looks at the queue in the structure.
449 *If it's empty, it sets Slv_currently_executing field to NULL and resumes.
450 *If something in, gets it, sets Slv_currently_executing to that Slv, then
451 * resumes both.
452 */
453 void
454 Vthread__end_transaction( int32 transactionID, SlaveVP *animSlv )
455 {
456 VthdSemReq reqData;
458 //
459 reqData.reqType = trans_end;
460 reqData.transID = transactionID;
462 VMS_WL__send_sem_request( &reqData, animSlv );
463 }
464 //===========================================================================