SCM Repository
Annotation of /sml/branches/SMLNJ/src/runtime/mp/solaris-mp.c
Parent Directory
|
Revision Log
Revision 249 - (view) (download) (as text)
1 : | monnier | 249 | /* solaris-mp.c |
2 : | * | ||
3 : | * MP support for Sparc multiprocessor machines running Solaris 2.5 | ||
4 : | * | ||
5 : | * Solaris implementation of externals defined in $(INCLUDE)/ml-mp.h | ||
6 : | */ | ||
7 : | |||
8 : | #include <stdio.h> | ||
9 : | #include <sys/mman.h> | ||
10 : | #include <unistd.h> | ||
11 : | #include <errno.h> | ||
12 : | #include <thread.h> | ||
13 : | #include <synch.h> | ||
14 : | #include <sys/types.h> | ||
15 : | #include <sys/processor.h> | ||
16 : | #include <sys/procset.h> | ||
17 : | #include "ml-limits.h" | ||
18 : | #include "ml-values.h" | ||
19 : | #include "ml-objects.h" | ||
20 : | #include "tags.h" | ||
21 : | #include "ml-mp.h" | ||
22 : | #include "ml-state.h" | ||
23 : | #include "ml-globals.h" | ||
24 : | #include "vproc-state.h" | ||
25 : | |||
26 : | |||
27 : | #define INT_MLinc(n,i) ((ml_val_t)INT_CtoML(INT_MLtoC(n) + (i))) | ||
28 : | #define INT_MLdec(n,i) (INT_MLinc(n,(-i))) | ||
29 : | |||
30 : | /* local functions */ | ||
31 : | PVT mp_lock_t AllocLock(); | ||
32 : | PVT mp_barrier_t *AllocBarrier(); | ||
33 : | PVT void *AllocArenaMem(int sz); | ||
34 : | PVT void FreeArenaMem(void *, int); | ||
35 : | PVT void *ProcMain(void *msp); | ||
36 : | PVT void *ResumeProc(void *vmsp); | ||
37 : | PVT void SuspendProc(ml_state_t *msp); | ||
38 : | PVT ml_state_t **InitProcStatesArray(); | ||
39 : | PVT void BindToRealProc(processorid_t *); | ||
40 : | |||
41 : | /* locals */ | ||
42 : | PVT caddr_t arena; /* arena for shared sync objects */ | ||
43 : | PVT mp_lock_t arenaLock; /* must be held to alloc/free a lock */ | ||
44 : | PVT mp_lock_t MP_ProcLock; /* must be used to acquire/release procs */ | ||
45 : | PVT ml_state_t **procStates; /*[MAX_NUM_PROCS]*/ /* list of states of suspended | ||
46 : | procs */ | ||
47 : | #if defined(MP_PROFILE) | ||
48 : | PVT int *doProfile; | ||
49 : | #endif | ||
50 : | |||
51 : | #define LEAST_PROCESSOR_ID 0 | ||
52 : | #define GREATEST_PROCESSOR_ID 3 | ||
53 : | |||
54 : | #define NextProcessorId(id) (((id) == GREATEST_PROCESSOR_ID) ? LEAST_PROCESSOR_ID : (id) + 1) | ||
55 : | |||
56 : | PVT processorid_t *processorId; /* processor id of the next processor a lwp | ||
57 : | will be bound to */ | ||
58 : | /* globals */ | ||
59 : | mp_lock_t MP_GCLock; | ||
60 : | mp_lock_t MP_GCGenLock; | ||
61 : | mp_barrier_t *MP_GCBarrier; | ||
62 : | mp_lock_t MP_TimerLock; | ||
63 : | |||
64 : | #if defined(MP_PROFILE) | ||
65 : | int mutex_trylock_calls; | ||
66 : | int trylock_calls; | ||
67 : | #endif | ||
68 : | |||
69 : | /* MP_Init: | ||
70 : | */ | ||
71 : | void MP_Init() | ||
72 : | { | ||
73 : | int fd; | ||
74 : | |||
75 : | if ((fd = open("/dev/zero",O_RDWR)) == -1) | ||
76 : | Die("MP_Init:Couldn't open /dev/zero"); | ||
77 : | |||
78 : | arena = mmap((caddr_t) 0, sysconf(_SC_PAGESIZE),PROT_READ | PROT_WRITE ,MAP_PRIVATE,fd,0); | ||
79 : | |||
80 : | arenaLock = AllocLock(); | ||
81 : | MP_ProcLock = AllocLock(); | ||
82 : | MP_GCLock = AllocLock(); | ||
83 : | MP_GCGenLock = AllocLock(); | ||
84 : | MP_TimerLock = AllocLock(); | ||
85 : | MP_GCBarrier = AllocBarrier(); | ||
86 : | procStates = InitProcStatesArray(); | ||
87 : | ASSIGN(ActiveProcs, INT_CtoML(1)); | ||
88 : | #ifdef MP_NONBLOCKING_IO | ||
89 : | MP_InitStdInReader (); | ||
90 : | #endif | ||
91 : | processorId = (processorid_t *) AllocArenaMem(sizeof(processorid_t)); | ||
92 : | *processorId = -1; | ||
93 : | BindToRealProc(processorId); | ||
94 : | |||
95 : | #ifdef MP_PROFILE | ||
96 : | doProfile = (int *) AllocArenaMem(sizeof(int)); | ||
97 : | *doProfile = 0; | ||
98 : | #endif | ||
99 : | NextProcessorId(*processorId); | ||
100 : | |||
101 : | /* thr_setconcurrency(MAX_NUM_PROCS); */ | ||
102 : | |||
103 : | } /* end of MP_Init */ | ||
104 : | |||
105 : | /************************************************************************* | ||
106 : | * Function: PVT mp_state_t **InitProcStatesArray() | ||
107 : | * Purpose: Initialize the array of pointers to ml states of suspended | ||
108 : | * processors | ||
109 : | * Return: The initialized array as a pointer to pointers. | ||
110 : | *************************************************************************/ | ||
111 : | PVT ml_state_t **InitProcStatesArray() | ||
112 : | { | ||
113 : | ml_state_t **array; | ||
114 : | ml_state_t **ptr; | ||
115 : | int i; | ||
116 : | |||
117 : | array = (ml_state_t **) AllocArenaMem(sizeof(ml_state_t *)); | ||
118 : | |||
119 : | for (i=1; i < MAX_NUM_PROCS; i++) | ||
120 : | { | ||
121 : | ptr = (ml_state_t **) AllocArenaMem(sizeof(ml_state_t *)); | ||
122 : | *ptr = (ml_state_t *) NULL; | ||
123 : | ptr++; | ||
124 : | } | ||
125 : | |||
126 : | return (array); | ||
127 : | |||
128 : | } /* end of InitProcStatesArray */ | ||
129 : | /************************************************************************* | ||
130 : | * Function: PVT mp_lock_t AllocLock() | ||
131 : | * Purpose: Allocate a portion of the arena of synch objects for a spin | ||
132 : | lock. | ||
133 : | * Returns: returns a pointer to the allocated region. | ||
134 : | * Created: 5-14-96 | ||
135 : | *************************************************************************/ | ||
136 : | PVT mp_lock_t AllocLock() | ||
137 : | { | ||
138 : | mp_lock_t lock; | ||
139 : | |||
140 : | lock = (mp_lock_t) AllocArenaMem(MP_LOCK_SZ); | ||
141 : | |||
142 : | lock->value = UNSET; | ||
143 : | |||
144 : | if (mutex_init(&lock->mutex, USYNC_THREAD, NULL) == -1) | ||
145 : | Die("AllocLock: unable to initialize mutex"); | ||
146 : | |||
147 : | return lock; | ||
148 : | |||
149 : | } /* end of AllocLock */ | ||
150 : | |||
151 : | /************************************************************************** | ||
152 : | * Function: FreeLock | ||
153 : | * Purpose : Destroy the mutex. In addition, if the lock was the last object | ||
154 : | allocated in the arena then recapture the space occupied by the | ||
155 : | lock. Otherwise, zero out the space occupied by the lock. | ||
156 : | * Created : 5-14-96 | ||
157 : | **************************************************************************/ | ||
158 : | PVT void FreeLock(mp_lock_t lock) | ||
159 : | { | ||
160 : | #if defined(MP_LOCK_DEBUG) | ||
161 : | printf("arena = %ld\t lock = %ld\n",(int) arena, lock); | ||
162 : | #endif | ||
163 : | |||
164 : | mutex_destroy(&lock->mutex); | ||
165 : | |||
166 : | FreeArenaMem(lock,MP_LOCK_SZ); | ||
167 : | |||
168 : | } /* end of FreeLock */ | ||
169 : | |||
170 : | /************************************************************************* | ||
171 : | * Function: void BindToRealProc(processorid_t *) | ||
172 : | * Purpose: Bind the current lwp to a real processor. Attempt to bind the | ||
173 : | lwp to a processor different from the last processor a lwp was | ||
174 : | bound to. | ||
175 : | * Created: 7-22-96 | ||
176 : | *************************************************************************/ | ||
177 : | void BindToRealProc(processorid_t *processorId) | ||
178 : | { | ||
179 : | processorid_t procId = *processorId; | ||
180 : | processorid_t obind; | ||
181 : | int lwpBoundP = 0; | ||
182 : | |||
183 : | while (!lwpBoundP) | ||
184 : | { | ||
185 : | procId = NextProcessorId(procId); | ||
186 : | if (procId == *processorId) /* attempts made to bind on all processors */ | ||
187 : | { | ||
188 : | fprintf(stderr, "lwp was not bound to a processor.\n"); | ||
189 : | lwpBoundP = 1; | ||
190 : | } | ||
191 : | else | ||
192 : | { | ||
193 : | if (processor_bind(P_LWPID, P_MYID, procId, &obind) == -1) | ||
194 : | { | ||
195 : | fprintf(stderr, "error attempting to bind lwp to processor [%d]\n",(int) procId); | ||
196 : | lwpBoundP = 1; | ||
197 : | } | ||
198 : | else | ||
199 : | { | ||
200 : | if (obind == PBIND_NONE) /* couldn't bind to lwp */ | ||
201 : | fprintf(stderr, "couldn't bind current lwp to processor [%d]\n", (int) procId); | ||
202 : | else | ||
203 : | { | ||
204 : | fprintf(stderr,"lwp bound to processor [%d]\n",procId); | ||
205 : | lwpBoundP = 1; | ||
206 : | *processorId = procId; | ||
207 : | } | ||
208 : | } | ||
209 : | } | ||
210 : | } | ||
211 : | |||
212 : | } /* end of BindToRealProc */ | ||
213 : | |||
214 : | /************************************************************************* | ||
215 : | * Function: bool_t MP_TryLock(mp_lock_t lock) | ||
216 : | * Purpose: Return FALSE if cannot set lock; otherwise set lock and return | ||
217 : | TRUE. | ||
218 : | * Created: 5-14-96 | ||
219 : | * Invariant: If more than one processes calls MP_TryLock at the same time, | ||
220 : | then only one of the processes will have TRUE returned. | ||
221 : | *************************************************************************/ | ||
222 : | |||
223 : | bool_t MP_TryLock(mp_lock_t lock) | ||
224 : | { | ||
225 : | #if defined(MP_PROFILE) | ||
226 : | long cpuTime; | ||
227 : | #endif | ||
228 : | |||
229 : | #if defined(MP_LOCK_DEBUG) | ||
230 : | printf("MP_TryLock: lock value is %d\n",lock->value); | ||
231 : | #endif | ||
232 : | |||
233 : | #if defined(MP_PROFILE) | ||
234 : | if (*doProfile) | ||
235 : | { | ||
236 : | cpuTime = (long) clock(); | ||
237 : | printf("trylock_calls = %d\n",++trylock_calls); | ||
238 : | } | ||
239 : | #endif | ||
240 : | |||
241 : | /* We test to see if the lock is set here so that we can reduce the number | ||
242 : | of calls to mutex_trylock when we are waiting for the lock to be | ||
243 : | released. Apparently repeated calls to mutex_trylock floods the bus. | ||
244 : | I don't know why. I found this out from the Threads Primer book. | ||
245 : | */ | ||
246 : | if (lock->value == SET) | ||
247 : | #if defined(MP_PROFILE) | ||
248 : | { | ||
249 : | if (*doProfile) | ||
250 : | fprintf(stderr,"MP_Trylock:cpu time %ld\n",(long) clock() - cpuTime); | ||
251 : | return(FALSE); | ||
252 : | } | ||
253 : | #else | ||
254 : | return(FALSE); | ||
255 : | #endif | ||
256 : | else | ||
257 : | { | ||
258 : | #if defined(MP_LOCK_DEBUG) | ||
259 : | printf("MP_TryLock: calling mutex_trylock\n"); | ||
260 : | #endif | ||
261 : | |||
262 : | #if defined(MP_PROFILE) | ||
263 : | if (*doProfile) | ||
264 : | printf("mutex_trylock_calls = %d\n",++mutex_trylock_calls); | ||
265 : | #endif | ||
266 : | |||
267 : | if (mutex_trylock(&lock->mutex) == EBUSY) | ||
268 : | #if defined(MP_PROFILE) | ||
269 : | if (*doProfile) | ||
270 : | fprintf(stderr,"MP_Trylock:cpu time %ld\n",(long) clock() - cpuTime); | ||
271 : | #else | ||
272 : | return(FALSE); | ||
273 : | #endif | ||
274 : | else | ||
275 : | { | ||
276 : | if (lock->value == SET) | ||
277 : | { | ||
278 : | mutex_unlock(&lock->mutex); | ||
279 : | #if defined(MP_PROFILE) | ||
280 : | if (*doProfile) | ||
281 : | fprintf(stderr,"MP_Trylock:cpu time %ld\n",(long) clock() - cpuTime); | ||
282 : | #endif | ||
283 : | return(FALSE); | ||
284 : | } | ||
285 : | |||
286 : | lock->value = SET; | ||
287 : | mutex_unlock(&lock->mutex); | ||
288 : | #if defined(MP_PROFILE) | ||
289 : | if (*doProfile) | ||
290 : | fprintf(stderr,"MP_Trylock:cpu time %ld\n",(long) clock() - cpuTime); | ||
291 : | #endif | ||
292 : | return(TRUE); | ||
293 : | } | ||
294 : | } | ||
295 : | } /* end of MP_TryLock */ | ||
296 : | |||
297 : | |||
298 : | /************************************************************************* | ||
299 : | * Function: void MP_UnsetLock(mp_lock_t lock) | ||
300 : | * Purpose: Assign lock->value the value of 0. | ||
301 : | * Created: 5-14-96 | ||
302 : | *************************************************************************/ | ||
303 : | |||
304 : | void MP_UnsetLock(mp_lock_t lock) | ||
305 : | { | ||
306 : | lock->value = UNSET; | ||
307 : | } | ||
308 : | |||
309 : | /************************************************************************* | ||
310 : | * Function: void MP_SetLock(mp_lock_t lock) | ||
311 : | * Purpose: Busy wait until able set the lock. | ||
312 : | * Created: 5-14-96 | ||
313 : | *************************************************************************/ | ||
314 : | void MP_SetLock(mp_lock_t lock) | ||
315 : | { | ||
316 : | while (MP_TryLock(lock) == FALSE) ; | ||
317 : | } | ||
318 : | |||
319 : | |||
320 : | /* MP_AllocLock: | ||
321 : | */ | ||
322 : | mp_lock_t MP_AllocLock() | ||
323 : | { | ||
324 : | mp_lock_t lock; | ||
325 : | |||
326 : | MP_SetLock(arenaLock); | ||
327 : | lock = AllocLock(); | ||
328 : | MP_UnsetLock(arenaLock); | ||
329 : | |||
330 : | return lock; | ||
331 : | } /* end of MP_AllocLock */ | ||
332 : | |||
333 : | /************************************************************************* | ||
334 : | * Function: void MP_FreeLock (mp_lock_t lock) | ||
335 : | * Purpose: Destroy mutex of lock and free memory occupied by lock. | ||
336 : | * Returns: returns non-negative int if OK, -1 on error | ||
337 : | * Created: 5-13-96 | ||
338 : | *************************************************************************/ | ||
339 : | |||
340 : | void MP_FreeLock (mp_lock_t lock) | ||
341 : | { | ||
342 : | MP_SetLock(arenaLock); | ||
343 : | FreeLock(lock); | ||
344 : | MP_UnsetLock(arenaLock); | ||
345 : | } | ||
346 : | |||
347 : | /************************************************************************* | ||
348 : | * Function: AllocBarrier | ||
349 : | * Purpose: Get a chunk of memory from the arena for a barrier and | ||
350 : | initialize it. | ||
351 : | * Returns: Return a pointer to the barrier. | ||
352 : | * Created: 5-15-96 | ||
353 : | *************************************************************************/ | ||
354 : | |||
355 : | PVT mp_barrier_t *AllocBarrier () | ||
356 : | { | ||
357 : | mp_barrier_t *barrierp; | ||
358 : | |||
359 : | barrierp = (mp_barrier_t *) arena; | ||
360 : | arena += MP_BARRIER_SZ; | ||
361 : | |||
362 : | barrierp->n_waiting = 0; | ||
363 : | barrierp->phase = 0; | ||
364 : | |||
365 : | if (mutex_init(&barrierp->lock, USYNC_THREAD, NULL) == -1) | ||
366 : | Die("MP_Barrier: could not init barrier mutex lock"); | ||
367 : | |||
368 : | if (cond_init(&barrierp->wait_cv, USYNC_THREAD, NULL) == -1) | ||
369 : | Die("MP_Barrier: could not init conditional var of barrier"); | ||
370 : | |||
371 : | |||
372 : | return barrierp; | ||
373 : | |||
374 : | } /* end of AllocBarrier */ | ||
375 : | |||
376 : | |||
377 : | /************************************************************************* | ||
378 : | * Function: MP_AllocBarrier | ||
379 : | * Purpose: Allocate a barrier from the synch object arena. Allocation is | ||
380 : | mutually exclusive. Note the barrier is not initialized. | ||
381 : | * Returns: Return a pointer to the barrier. | ||
382 : | * Created: 5-15-96 | ||
383 : | *************************************************************************/ | ||
384 : | mp_barrier_t *MP_AllocBarrier () | ||
385 : | { | ||
386 : | mp_barrier_t *barrierp; | ||
387 : | |||
388 : | MP_SetLock(arenaLock); | ||
389 : | barrierp = AllocBarrier (); | ||
390 : | MP_UnsetLock(arenaLock); | ||
391 : | |||
392 : | return barrierp; | ||
393 : | |||
394 : | } /* end of MP_AllocBarrier */ | ||
395 : | |||
396 : | /************************************************************************* | ||
397 : | * Function: MP_AllocBarrier | ||
398 : | * Purpose: destroy mutex and conditional variables of the barrier. | ||
399 : | Regain memory if barrier was last object allocated in arena; | ||
400 : | otherwise zero out the memory occupied by the barrier. | ||
401 : | * Returns: Nothing. | ||
402 : | * Created: 5-15-96 | ||
403 : | *************************************************************************/ | ||
404 : | void FreeBarrier(mp_barrier_t *barrierp) | ||
405 : | { | ||
406 : | mutex_destroy(&barrierp->lock); | ||
407 : | cond_destroy(&barrierp->wait_cv); | ||
408 : | |||
409 : | FreeArenaMem(barrierp, MP_BARRIER_SZ); | ||
410 : | } /* end of FreeBarrier */ | ||
411 : | |||
412 : | void MP_FreeBarrier(mp_barrier_t *barrierp) | ||
413 : | { | ||
414 : | MP_SetLock(arenaLock); | ||
415 : | FreeBarrier(barrierp); | ||
416 : | MP_UnsetLock(arenaLock); | ||
417 : | } /* end of MP_FreeBarrier */ | ||
418 : | |||
419 : | |||
420 : | /************************************************************************* | ||
421 : | * Function: MP_Barrier | ||
422 : | * Purpose: Wait until the required number of threads enter the barrier. | ||
423 : | * Returns: Nothing. | ||
424 : | * Created: 5-15-96 | ||
425 : | * Invariant: barrierp->n_waiting <= n_clients | ||
426 : | *************************************************************************/ | ||
427 : | |||
428 : | void MP_Barrier(mp_barrier_t *barrierp, unsigned n_clients) | ||
429 : | { | ||
430 : | int my_phase; | ||
431 : | |||
432 : | mutex_lock(&barrierp->lock); | ||
433 : | |||
434 : | my_phase = barrierp->phase; | ||
435 : | barrierp->n_waiting++; | ||
436 : | |||
437 : | if (barrierp->n_waiting == n_clients) | ||
438 : | { | ||
439 : | barrierp->n_waiting = 0; | ||
440 : | barrierp->phase = 1 - my_phase; | ||
441 : | cond_broadcast(&barrierp->wait_cv); | ||
442 : | } | ||
443 : | |||
444 : | /* Wait for the end of this synchronization phase */ | ||
445 : | while (barrierp->phase == my_phase) | ||
446 : | { | ||
447 : | cond_wait(&barrierp->wait_cv, &barrierp->lock); | ||
448 : | } | ||
449 : | |||
450 : | mutex_unlock(&barrierp->lock); | ||
451 : | |||
452 : | } /* end of MP_Barrier */ | ||
453 : | |||
454 : | /************************************************************************* | ||
455 : | * Function: MP_ResetBarrier | ||
456 : | * Purpose: Set the various values of the barrier to zero. | ||
457 : | * Returns: Nothing. | ||
458 : | * Created: 5-15-96 | ||
459 : | *************************************************************************/ | ||
460 : | void MP_ResetBarrier(mp_barrier_t *barrierp) | ||
461 : | { | ||
462 : | barrierp->n_waiting = 0; | ||
463 : | barrierp->phase = 0; | ||
464 : | |||
465 : | } /* end of MP_ResetBarrier */ | ||
466 : | |||
467 : | |||
468 : | |||
469 : | /************************************************************************* | ||
470 : | * Function: AllocArenaMem | ||
471 : | ************************************************************************/ | ||
472 : | |||
473 : | PVT void *AllocArenaMem(int sz) | ||
474 : | { | ||
475 : | void *obj; | ||
476 : | |||
477 : | obj = arena; | ||
478 : | arena += sz; | ||
479 : | |||
480 : | return obj; | ||
481 : | } | ||
482 : | |||
483 : | /************************************************************************* | ||
484 : | * Function: FreeArenaMem | ||
485 : | ************************************************************************/ | ||
486 : | PVT void FreeArenaMem(void *p, int sz) | ||
487 : | { | ||
488 : | if (arena == (caddr_t) p + sz) | ||
489 : | arena -= sz; | ||
490 : | else | ||
491 : | memset(p,0,sz); | ||
492 : | } | ||
493 : | |||
494 : | /************************************************************************* | ||
495 : | * Function: ResumeProc(ml_state_t *msp) | ||
496 : | * Purpose: Resumes a proc to either perform garbage collection or to | ||
497 : | * run ml with the given ml state. | ||
498 : | * Return: Nothing | ||
499 : | ************************************************************************/ | ||
500 : | PVT void *ResumeProc(void *vmsp) | ||
501 : | { | ||
502 : | ml_state_t *msp = (ml_state_t *) vmsp; | ||
503 : | |||
504 : | MP_SetLock(MP_ProcLock); | ||
505 : | if (msp->ml_vproc->vp_mpState == MP_PROC_SUSPENDED) | ||
506 : | { | ||
507 : | /* proc only resumed to do a gc */ | ||
508 : | #ifdef MP_DEBUG | ||
509 : | SayDebug("resuming %d to perform a gc\n",msp->ml_vproc->vp_mpSelf); | ||
510 : | #endif | ||
511 : | msp->ml_vproc->vp_mpState == MP_PROC_GC; | ||
512 : | MP_UnsetLock(MP_ProcLock); | ||
513 : | |||
514 : | /* the GC will be performed when we call MP_ReleaseProc */ | ||
515 : | |||
516 : | MP_ReleaseProc(msp); | ||
517 : | } | ||
518 : | else | ||
519 : | { | ||
520 : | #ifdef MP_DEBUG | ||
521 : | SayDebug("[release_proc: resuming proc %d]\n",msp->ml_vproc->vp_mpSelf); | ||
522 : | #endif | ||
523 : | MP_UnsetLock(MP_ProcLock); | ||
524 : | RunML(msp); | ||
525 : | Die ("return after RunML(msp) in mp_release_proc\n"); | ||
526 : | } | ||
527 : | } /* end of ResumeProc */ | ||
528 : | |||
529 : | /************************************************************************* | ||
530 : | * Function: MP_ResumeVProcs(int n_procs) | ||
531 : | * Purpose: Remove n_procs states from the list of states and spawn threads | ||
532 : | * to execute them. | ||
533 : | * Note: We assume that calls to this function are mutually exclusive. | ||
534 : | * Return: Return a pointer to the last state resumed. | ||
535 : | ************************************************************************/ | ||
536 : | vproc_state_t *MP_ResumeVProcs(int n_procs) | ||
537 : | { | ||
538 : | ml_state_t *statep; | ||
539 : | int i = 0; | ||
540 : | |||
541 : | while(i < MAX_NUM_PROCS && n_procs > 0) { | ||
542 : | |||
543 : | if ((statep = procStates[i]) != (ml_state_t *) NULL) /* get a state */ | ||
544 : | { | ||
545 : | /* spawn a thread to execute the state */ | ||
546 : | #ifdef MP_DEBUG | ||
547 : | SayDebug("Resuming proc %d\n",statep->ml_vproc->vp_mpSelf); | ||
548 : | #endif | ||
549 : | if(thr_create(NULL,0,ResumeProc,(void *)statep,NULL,NULL) != 0) | ||
550 : | Die("Could create a thread to resume processors"); | ||
551 : | |||
552 : | procStates[i] = NULL; | ||
553 : | i++; | ||
554 : | n_procs--; | ||
555 : | } | ||
556 : | else | ||
557 : | i++; | ||
558 : | } | ||
559 : | |||
560 : | if (statep == (ml_state_t *) NULL) | ||
561 : | return (vproc_state_t *) NULL; | ||
562 : | |||
563 : | return statep->ml_vproc; | ||
564 : | |||
565 : | } /* end of MP_ResumeVProcs */ | ||
566 : | |||
567 : | /************************************************************************* | ||
568 : | * Function: SuspendProc(ml_state_t *msp) | ||
569 : | * Purpose: Suspend the calling proc, add its state, msp, to the suspended | ||
570 : | * proc state list, and kill the thread the proc is running on. | ||
571 : | * Return: Nothing. | ||
572 : | ************************************************************************/ | ||
573 : | PVT void SuspendProc(ml_state_t *msp) | ||
574 : | { | ||
575 : | int i=0; | ||
576 : | |||
577 : | MP_SetLock(MP_ProcLock); | ||
578 : | |||
579 : | /* check if proc has actually been suspended */ | ||
580 : | |||
581 : | if (msp->ml_vproc->vp_mpState != MP_PROC_SUSPENDED) | ||
582 : | { | ||
583 : | #ifdef MP_DEBUG | ||
584 : | SayDebug("proc state is not PROC_SUSPENDED; not suspended"); | ||
585 : | #endif | ||
586 : | MP_UnsetLock(MP_ProcLock); | ||
587 : | return; | ||
588 : | } | ||
589 : | |||
590 : | |||
591 : | while (i < MAX_NUM_PROCS) { | ||
592 : | if (procStates[i] == NULL) | ||
593 : | { | ||
594 : | procStates[i] = msp; | ||
595 : | i = MAX_NUM_PROCS; | ||
596 : | } | ||
597 : | else | ||
598 : | i++; | ||
599 : | } | ||
600 : | |||
601 : | MP_UnsetLock(MP_ProcLock); | ||
602 : | |||
603 : | /* exit the thread */ | ||
604 : | thr_exit(NULL); | ||
605 : | |||
606 : | } /* end of SuspendProc */ | ||
607 : | |||
608 : | /************************************************************************* | ||
609 : | * Function: MP_ReleaseProc(ml_state_t *msp) | ||
610 : | ************************************************************************/ | ||
611 : | void MP_ReleaseProc(ml_state_t *msp) | ||
612 : | { | ||
613 : | |||
614 : | |||
615 : | InvokeGC(msp,1); | ||
616 : | |||
617 : | MP_SetLock(MP_ProcLock); | ||
618 : | msp->ml_vproc->vp_mpState = MP_PROC_SUSPENDED; | ||
619 : | MP_UnsetLock(MP_ProcLock); | ||
620 : | |||
621 : | /* suspend the proc */ | ||
622 : | #ifdef MP_DEBUG | ||
623 : | SayDebug("suspending proc %d\n",msp->ml_vproc->vp_mpSelf); | ||
624 : | #endif | ||
625 : | SuspendProc(msp); | ||
626 : | |||
627 : | } /* end of MP_ReleaseProc */ | ||
628 : | |||
629 : | /************************************************************************* | ||
630 : | * Function: ProcMain(ml_state_t *msp) | ||
631 : | * Purpose: Invoke RunML on msp; die if RunML returns | ||
632 : | ************************************************************************/ | ||
633 : | PVT void *ProcMain(void *vmsp) | ||
634 : | { | ||
635 : | ml_state_t *msp = (ml_state_t *) vmsp; | ||
636 : | |||
637 : | /* spin until we get our id (from return of call to thr_create) */ | ||
638 : | while (msp->ml_vproc->vp_mpSelf == NIL(mp_pid_t)) { | ||
639 : | #ifdef MP_DEBUG | ||
640 : | SayDebug("[waiting for self]\n"); | ||
641 : | #endif | ||
642 : | continue; | ||
643 : | } | ||
644 : | #ifdef MP_DEBUG | ||
645 : | SayDebug ("[new proc main: releasing lock]\n"); | ||
646 : | #endif | ||
647 : | |||
648 : | BindToRealProc(processorId); | ||
649 : | |||
650 : | MP_UnsetLock(MP_ProcLock); /* implicitly handed to us by the parent */ | ||
651 : | RunML(msp); /* should never return */ | ||
652 : | Die("proc returned after run_ml() in ProcMain().\n"); | ||
653 : | |||
654 : | } /* end of ProcMain */ | ||
655 : | /************************************************************************* | ||
656 : | * Function: MP_AcquireProc(ml_state_t *msp, ml_val_t arg) | ||
657 : | ************************************************************************/ | ||
658 : | ml_val_t MP_AcquireProc(ml_state_t *msp, ml_val_t arg) | ||
659 : | { | ||
660 : | ml_state_t *p; | ||
661 : | vproc_state_t *vsp; | ||
662 : | ml_val_t v = REC_SEL(arg, 0); | ||
663 : | ml_val_t f = REC_SEL(arg, 1); | ||
664 : | int i; | ||
665 : | |||
666 : | #ifdef MP_DEBUG | ||
667 : | SayDebug("[acquiring proc]\n"); | ||
668 : | #endif | ||
669 : | |||
670 : | MP_SetLock(MP_ProcLock); | ||
671 : | |||
672 : | /* search for a suspended proc to reuse */ | ||
673 : | for (i = 0; | ||
674 : | (i < NumVProcs) && (VProc[i]->vp_mpState != MP_PROC_SUSPENDED); | ||
675 : | i++) | ||
676 : | continue; | ||
677 : | |||
678 : | #ifdef MP_DEBUG | ||
679 : | SayDebug("[checking for suspended processor]\n"); | ||
680 : | #endif | ||
681 : | if (i == NumVProcs) | ||
682 : | { | ||
683 : | if (DEREF(ActiveProcs) == INT_CtoML(MAX_NUM_PROCS)) | ||
684 : | { | ||
685 : | MP_UnsetLock(MP_ProcLock); | ||
686 : | Error("[processors maxed]\n"); | ||
687 : | return ML_false; | ||
688 : | } | ||
689 : | #ifdef MP_DEBUG | ||
690 : | SayDebug("[checking for NO_PROC]\n"); | ||
691 : | #endif | ||
692 : | |||
693 : | /* search for a slot in which to put a new proc */ | ||
694 : | for (i = 0; | ||
695 : | (i < NumVProcs) && (VProc[i]->vp_mpState != MP_PROC_NO_PROC); | ||
696 : | i++) | ||
697 : | continue; | ||
698 : | |||
699 : | if (i == NumVProcs) | ||
700 : | { | ||
701 : | MP_UnsetLock(MP_ProcLock); | ||
702 : | Error("[no processor to allocate]\n"); | ||
703 : | return ML_false; | ||
704 : | } | ||
705 : | |||
706 : | /* use processor at index i */ | ||
707 : | vsp = VProc[i]; | ||
708 : | |||
709 : | } /* end of then */ | ||
710 : | |||
711 : | else /* using a suspended processor */ | ||
712 : | { | ||
713 : | #ifdef MP_DEBUG | ||
714 : | SayDebug("[using a suspended processor]\n"); | ||
715 : | #endif | ||
716 : | vsp = MP_ResumeVProcs(1); | ||
717 : | } | ||
718 : | |||
719 : | p = vsp->vp_state; | ||
720 : | |||
721 : | p->ml_exnCont = PTR_CtoML(handle_v+1); | ||
722 : | p->ml_arg = ML_unit; | ||
723 : | p->ml_cont = PTR_CtoML(return_c); | ||
724 : | p->ml_closure = f; | ||
725 : | p->ml_pc = | ||
726 : | p->ml_linkReg = GET_CODE_ADDR(f); | ||
727 : | p->ml_varReg = v; | ||
728 : | |||
729 : | if (vsp->vp_mpState == MP_PROC_NO_PROC) | ||
730 : | { | ||
731 : | mp_pid_t procId; | ||
732 : | |||
733 : | /* assume we get one */ | ||
734 : | ASSIGN(ActiveProcs, INT_MLinc(DEREF(ActiveProcs), 1)); | ||
735 : | if (thr_create(NULL,0,ProcMain,(void *)p,THR_NEW_LWP,&((thread_t) procId)) == 0) | ||
736 : | { | ||
737 : | #ifdef MP_DEBUG | ||
738 : | SayDebug ("[got a processor: %d,]\n",procId); | ||
739 : | #endif | ||
740 : | vsp->vp_mpState = MP_PROC_RUNNING; | ||
741 : | vsp->vp_mpSelf = procId; | ||
742 : | /* NewProc will release MP_ProcLock */ | ||
743 : | return ML_true; | ||
744 : | } | ||
745 : | else | ||
746 : | { | ||
747 : | ASSIGN(ActiveProcs, INT_MLdec(DEREF(ActiveProcs), 1)); | ||
748 : | MP_UnsetLock(MP_ProcLock); | ||
749 : | return ML_false; | ||
750 : | } | ||
751 : | } | ||
752 : | else | ||
753 : | { | ||
754 : | /* the thread executing the processor has already been invoked */ | ||
755 : | vsp->vp_mpState = MP_PROC_RUNNING; | ||
756 : | #ifdef MP_DEBUG | ||
757 : | SayDebug ("[reusing a processor %d]\n",vsp->vp_mpSelf); | ||
758 : | #endif | ||
759 : | MP_UnsetLock(MP_ProcLock); | ||
760 : | return ML_true; | ||
761 : | } | ||
762 : | |||
763 : | } /* end of MP_AcquireProc */ | ||
764 : | |||
765 : | |||
766 : | /************************************************************************* | ||
767 : | * Function: MP_Shutdown | ||
768 : | ************************************************************************/ | ||
769 : | void MP_Shutdown () | ||
770 : | { | ||
771 : | munmap(arena,sysconf(_SC_PAGESIZE)); | ||
772 : | } /* end of MP_Shutdown */ | ||
773 : | |||
774 : | |||
775 : | /************************************************************************* | ||
776 : | * Function: MP_MaxProcs | ||
777 : | ************************************************************************/ | ||
778 : | int MP_MaxProcs () | ||
779 : | { | ||
780 : | return MAX_NUM_PROCS; | ||
781 : | |||
782 : | } /* end of MP_MaxProcs */ | ||
783 : | |||
784 : | /************************************************************************* | ||
785 : | * Function: MP_ProcId | ||
786 : | ************************************************************************/ | ||
787 : | mp_pid_t MP_ProcId () | ||
788 : | { | ||
789 : | |||
790 : | return (thr_self()); | ||
791 : | |||
792 : | } /* end of MP_ProcId */ | ||
793 : | |||
794 : | /************************************************************************* | ||
795 : | * Function: MP_ActiveProcs | ||
796 : | ************************************************************************/ | ||
797 : | int MP_ActiveProcs () | ||
798 : | { | ||
799 : | int ap; | ||
800 : | |||
801 : | MP_SetLock(MP_ProcLock); | ||
802 : | ap = INT_MLtoC(DEREF(ActiveProcs)); | ||
803 : | MP_UnsetLock(MP_ProcLock); | ||
804 : | |||
805 : | return ap; | ||
806 : | |||
807 : | } /* end of MP_ActiveProcs */ | ||
808 : | |||
809 : | |||
810 : | /* EndSourceFile */ | ||
811 : |
root@smlnj-gforge.cs.uchicago.edu | ViewVC Help |
Powered by ViewVC 1.0.0 |