VMS/VMS_Implementations/VMS_impls/VMS__MC_shared_impl

view VMS__int.c @ 248:da08f9717024

Moved VMS_defs__turn_on_and_off.h outside of VMS repo, into project repo
author Sean Halle <seanhalle@yahoo.com>
date Sat, 21 Jul 2012 15:20:40 -0700
parents f1267bc7b342
children 88fd330feef3
line source
1 /*
2 * Copyright 2010 OpenSourceStewardshipFoundation
3 *
4 * Licensed under BSD
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <malloc.h>
11 #include <inttypes.h>
12 #include <sys/time.h>
14 #include "VMS.h"
17 /* MEANING OF WL PI SS int
18 * These indicate which places the function is safe to use. They stand for:
19 * WL: Wrapper Library
20 * PI: Plugin
21 * SS: Startup and Shutdown
22 * int: internal to the VMS implementation
23 */
26 inline SlaveVP *
27 VMS_int__create_slaveVP( TopLevelFnPtr fnPtr, void *dataParam )
28 { SlaveVP *newSlv;
29 void *stackLocs;
31 newSlv = VMS_int__malloc( sizeof(SlaveVP) );
32 stackLocs = VMS_int__malloc( VIRT_PROCR_STACK_SIZE );
33 if( stackLocs == 0 )
34 { perror("VMS_int__malloc stack"); exit(1); }
36 _VMSMasterEnv->numSlavesAlive += 1;
38 return VMS_int__create_slaveVP_helper( newSlv, fnPtr, dataParam, stackLocs );
39 }
41 /* "ext" designates that it's for use outside the VMS system -- should only
42 * be called from main thread or other thread -- never from code animated by
43 * a VMS virtual processor.
44 */
45 inline SlaveVP *
46 VMS_ext__create_slaveVP( TopLevelFnPtr fnPtr, void *dataParam )
47 { SlaveVP *newSlv;
48 char *stackLocs;
50 newSlv = malloc( sizeof(SlaveVP) );
51 stackLocs = malloc( VIRT_PROCR_STACK_SIZE );
52 if( stackLocs == 0 )
53 { perror("malloc stack"); exit(1); }
55 _VMSMasterEnv->numSlavesAlive += 1;
57 return VMS_int__create_slaveVP_helper(newSlv, fnPtr, dataParam, stackLocs);
58 }
61 //===========================================================================
62 /*there is a label inside this function -- save the addr of this label in
63 * the callingSlv struc, as the pick-up point from which to start the next
64 * work-unit for that slave. If turns out have to save registers, then
65 * save them in the slave struc too. Then do assembly jump to the CoreCtlr's
66 * "done with work-unit" label. The slave struc is in the request in the
67 * slave that animated the just-ended work-unit, so all the state is saved
68 * there, and will get passed along, inside the request handler, to the
69 * next work-unit for that slave.
70 */
71 void
72 VMS_int__suspend_slaveVP_and_send_req( SlaveVP *animatingSlv )
73 {
75 //This suspended Slv will get assigned by Master again at some
76 // future point
78 //return ownership of the Slv and anim slot to Master virt pr
79 animatingSlv->animSlotAssignedTo->workIsDone = TRUE;
81 HOLISTIC__Record_HwResponderInvocation_start;
82 MEAS__Capture_Pre_Susp_Point;
83 //This assembly function is a VMS primitive that first saves the
84 // stack and frame pointer, plus an addr inside this assembly code.
85 //When core ctlr later gets this slave out of a sched slot, it
86 // restores the stack and frame and then jumps to the addr.. that
87 // jmp causes return from this function.
88 //So, in effect, this function takes a variable amount of wall-clock
89 // time to complete -- the amount of time is determined by the
90 // Master, which makes sure the memory is in a consistent state first.
91 switchToCoreCtlr(animatingSlv);
92 flushRegisters();
93 MEAS__Capture_Post_Susp_Point;
95 return;
96 }
99 /* "ext" designates that it's for use outside the VMS system -- should only
100 * be called from main thread or other thread -- never from code animated by
101 * a SlaveVP, nor from a masterVP.
102 *
103 *Use this version to dissipate Slvs created outside the VMS system.
104 */
105 void
106 VMS_ext__dissipate_slaveVP( SlaveVP *slaveToDissipate )
107 {
108 _VMSMasterEnv->numSlavesAlive -= 1;
109 if( _VMSMasterEnv->numSlavesAlive == 0 )
110 { //no more work, so shutdown
111 VMS_SS__shutdown(); //note, creates 4 shut-down slaves
112 }
114 //NOTE: dataParam was given to the processor, so should either have
115 // been alloc'd with VMS_int__malloc, or freed by the level above animSlv.
116 //So, all that's left to free here is the stack and the SlaveVP struc
117 // itself
118 //Note, should not stack-allocate the data param -- no guarantee, in
119 // general that creating processor will outlive ones it creates.
120 free( slaveToDissipate->startOfStack );
121 free( slaveToDissipate );
122 }
126 /*This must be called by the request handler plugin -- it cannot be called
127 * from the semantic library "dissipate processor" function -- instead, the
128 * semantic layer has to generate a request, and the plug-in calls this
129 * function.
130 *The reason is that this frees the virtual processor's stack -- which is
131 * still in use inside semantic library calls!
132 *
133 *This frees or recycles all the state owned by and comprising the VMS
134 * portion of the animating virtual procr. The request handler must first
135 * free any semantic data created for the processor that didn't use the
136 * VMS_malloc mechanism. Then it calls this, which first asks the malloc
137 * system to disown any state that did use VMS_malloc, and then frees the
138 * statck and the processor-struct itself.
139 *If the dissipated processor is the sole (remaining) owner of VMS_int__malloc'd
140 * state, then that state gets freed (or sent to recycling) as a side-effect
141 * of dis-owning it.
142 */
143 void
144 VMS_int__dissipate_slaveVP( SlaveVP *animatingSlv )
145 {
146 DEBUG__printf2(dbgRqstHdlr, "dissipate: %d, alive: %d",animatingSlv->slaveID, _VMSMasterEnv->numSlavesAlive-1);
147 //dis-own all locations owned by this processor, causing to be freed
148 // any locations that it is (was) sole owner of
149 _VMSMasterEnv->numSlavesAlive -= 1;
150 if( _VMSMasterEnv->numSlavesAlive == 0 )
151 { //no more work, so shutdown
152 VMS_SS__shutdown(); //note, creates 4 shut-down processors
153 }
155 //NOTE: dataParam was given to the processor, so should either have
156 // been alloc'd with VMS_int__malloc, or freed by the level above animSlv.
157 //So, all that's left to free here is the stack and the SlaveVP struc
158 // itself
159 //Note, should not stack-allocate initial data -- no guarantee, in
160 // general that creating processor will outlive ones it creates.
161 VMS_int__free( animatingSlv->startOfStack );
162 VMS_int__free( animatingSlv );
163 }
165 /*Anticipating multi-tasking
166 */
167 void *
168 VMS_int__give_sem_env_for( SlaveVP *animSlv )
169 {
170 return _VMSMasterEnv->semanticEnv;
171 }
173 /*
174 *
175 */
176 inline SlaveVP *
177 VMS_int__create_slaveVP_helper( SlaveVP *newSlv, TopLevelFnPtr fnPtr,
178 void *dataParam, void *stackLocs )
179 {
180 newSlv->startOfStack = stackLocs;
181 newSlv->slaveID = _VMSMasterEnv->numSlavesCreated++;
182 newSlv->requests = NULL;
183 newSlv->animSlotAssignedTo = NULL;
184 newSlv->typeOfVP = Slave;
185 newSlv->assignCount = 0;
187 VMS_int__reset_slaveVP_to_TopLvlFn( newSlv, fnPtr, dataParam );
189 //============================= MEASUREMENT STUFF ========================
190 #ifdef PROBES__TURN_ON_STATS_PROBES
191 //TODO: make this TSCHiLow or generic equivalent
192 //struct timeval timeStamp;
193 //gettimeofday( &(timeStamp), NULL);
194 //newSlv->createPtInSecs = timeStamp.tv_sec +(timeStamp.tv_usec/1000000.0) -
195 // _VMSMasterEnv->createPtInSecs;
196 #endif
197 //========================================================================
199 return newSlv;
200 }
203 /*Later, improve this -- for now, just exits the application after printing
204 * the error message.
205 */
206 void
207 VMS_int__throw_exception( char *msgStr, SlaveVP *reqstSlv, VMSExcp *excpData )
208 {
209 printf("%s",msgStr);
210 fflush(stdin);
211 exit(1);
212 }
215 inline char *
216 VMS_int__strDup( char *str )
217 { char *retStr;
219 if( str == NULL ) return (char *)NULL;
220 retStr = (char *)VMS_int__malloc( strlen(str) + 1 );
221 strcpy( retStr, str );
223 return (char *)retStr;
224 }
227 inline void
228 VMS_int__backoff_for_TooLongToGetLock( int32 numTriesToGetLock );
230 inline void
231 VMS_int__get_master_lock()
232 { int32 *addrOfMasterLock;
234 addrOfMasterLock = &(_VMSMasterEnv->masterLock);
236 int numTriesToGetLock = 0;
237 int gotLock = 0;
239 MEAS__Capture_Pre_Master_Lock_Point;
241 while( !gotLock ) //keep going until get master lock
242 {
243 numTriesToGetLock++; //if too many, means too much contention
244 if( numTriesToGetLock > NUM_TRIES_BEFORE_DO_BACKOFF )
245 { VMS_int__backoff_for_TooLongToGetLock( numTriesToGetLock );
246 }
247 if( numTriesToGetLock > MASTERLOCK_RETRIES_BEFORE_YIELD )
248 { numTriesToGetLock = 0;
249 pthread_yield();
250 }
252 //try to get the lock
253 gotLock = __sync_bool_compare_and_swap( addrOfMasterLock,
254 UNLOCKED, LOCKED );
255 }
256 MEAS__Capture_Post_Master_Lock_Point;
257 }
259 /*Used by the backoff to pick a random amount of busy-wait. Can't use the
260 * system rand because it takes much too long.
261 *Note, are passing pointers to the seeds, which are then modified
262 */
263 inline uint32_t
264 VMS_int__randomNumber()
265 {
266 _VMSMasterEnv->seed1 = 36969 * (_VMSMasterEnv->seed1 & 65535) +
267 (_VMSMasterEnv->seed1 >> 16);
268 _VMSMasterEnv->seed2 = 18000 * (_VMSMasterEnv->seed2 & 65535) +
269 (_VMSMasterEnv->seed2 >> 16);
270 return (_VMSMasterEnv->seed1 << 16) + _VMSMasterEnv->seed2;
271 }
274 /*Busy-waits for a random number of cycles -- chooses number of cycles
275 * differently than for the no-work backoff
276 */
277 inline void
278 VMS_int__backoff_for_TooLongToGetLock( int32 numTriesToGetLock )
279 { int32 i, waitIterations;
280 volatile double fakeWorkVar; //busy-wait fake work
282 waitIterations =
283 VMS_int__randomNumber()% (numTriesToGetLock * GET_LOCK_BACKOFF_WEIGHT);
284 //addToHist( wait_iterations, coreLoopThdParams->wait_iterations_hist );
285 for( i = 0; i < waitIterations; i++ )
286 { fakeWorkVar += (fakeWorkVar + 32.0) / 2.0; //busy-wait
287 }
288 }