1 /****************************************************************************
2 **
3 ** This file is part of GAP, a system for computational discrete algebra.
4 **
5 ** Copyright of GAP belongs to its developers, whose names are too numerous
6 ** to list here. Please refer to the COPYRIGHT file for details.
7 **
8 ** SPDX-License-Identifier: GPL-2.0-or-later
9 **
10 ** This file contains the GAP interface for thread primitives.
11 */
12
13 #include "hpc/threadapi.h"
14
15 #include "bool.h"
16 #include "calls.h"
17 #include "code.h"
18 #include "error.h"
19 #include "funcs.h"
20 #include "gapstate.h"
21 #include "gvars.h"
22 #include "intrprtr.h"
23 #include "io.h"
24 #include "lists.h"
25 #include "modules.h"
26 #include "objects.h"
27 #include "plist.h"
28 #include "read.h"
29 #include "records.h"
30 #include "set.h"
31 #include "stats.h"
32 #include "stringobj.h"
33
34 #include "hpc/guards.h"
35 #include "hpc/misc.h"
36 #include "hpc/region.h"
37 #include "hpc/thread.h"
38 #include "hpc/tls.h"
39 #include "hpc/traverse.h"
40
41 #include <stdio.h>
42 #include <signal.h>
43 #include <sys/time.h>
44
45 #include <pthread.h>
46
47
48 #define RequireThread(funcname, op, argname) \
49 RequireArgumentConditionEx(funcname, op, "<" argname ">", \
50 TNUM_OBJ(op) == T_THREAD, \
51 "must be a thread object")
52
53 #define RequireChannel(funcname, op) \
54 RequireArgumentCondition(funcname, op, IsChannel(op), "must be a channel")
55
56 #define RequireSemaphore(funcname, op) \
57 RequireArgumentCondition(funcname, op, TNUM_OBJ(op) == T_SEMAPHORE, \
58 "must be a semaphore")
59
60 #define RequireBarrier(funcname, op) \
61 RequireArgumentCondition(funcname, op, IsBarrier(op), "must be a barrier")
62
63 #define RequireSyncVar(funcname, op) \
64 RequireArgumentCondition(funcname, op, IsSyncVar(op), \
65 "must be a synchronization variable")
66
67
68 struct WaitList {
69 struct WaitList * prev;
70 struct WaitList * next;
71 ThreadLocalStorage * thread;
72 };
73
74 typedef struct {
75 pthread_mutex_t lock;
76 struct WaitList *head, *tail;
77 } Monitor;
78
79 typedef struct Channel {
80 Obj monitor;
81 Obj queue;
82 int waiting;
83 int dynamic;
84 UInt head, tail;
85 UInt size, capacity;
86 } Channel;
87
88 typedef struct Semaphore {
89 Obj monitor;
90 UInt count;
91 int waiting;
92 } Semaphore;
93
94 typedef struct Barrier {
95 Obj monitor;
96 UInt count;
97 UInt phase;
98 int waiting;
99 } Barrier;
100
101 typedef struct SyncVar {
102 Obj monitor;
103 Obj value;
104 int written;
105 } SyncVar;
106
107
AddWaitList(Monitor * monitor,struct WaitList * node)108 static void AddWaitList(Monitor * monitor, struct WaitList * node)
109 {
110 if (monitor->tail) {
111 monitor->tail->next = node;
112 node->prev = monitor->tail;
113 node->next = NULL;
114 monitor->tail = node;
115 }
116 else {
117 monitor->head = monitor->tail = node;
118 node->next = node->prev = NULL;
119 }
120 }
121
RemoveWaitList(Monitor * monitor,struct WaitList * node)122 static void RemoveWaitList(Monitor * monitor, struct WaitList * node)
123 {
124 if (monitor->head) {
125 if (node->prev)
126 node->prev->next = node->next;
127 else
128 monitor->head = node->next;
129 if (node->next)
130 node->next->prev = node->prev;
131 else
132 monitor->tail = node->prev;
133 }
134 }
135
136 #ifndef WARD_ENABLED
ObjPtr(Obj obj)137 static inline void * ObjPtr(Obj obj)
138 {
139 return PTR_BAG(obj);
140 }
141 #endif
142
NewThreadObject(UInt id)143 Obj NewThreadObject(UInt id)
144 {
145 Obj result = NewBag(T_THREAD, sizeof(ThreadObject));
146 ThreadObject *thread = (ThreadObject *)ADDR_OBJ(result);
147 thread->id = id;
148 return result;
149 }
150
ThreadID(Obj obj)151 static inline Int ThreadID(Obj obj)
152 {
153 GAP_ASSERT(TNUM_OBJ(obj) == T_THREAD);
154 const ThreadObject *thread = (const ThreadObject *)CONST_ADDR_OBJ(obj);
155 return thread->id;
156 }
157
NewMonitor(void)158 Obj NewMonitor(void)
159 {
160 Bag monitorBag;
161 Monitor * monitor;
162 monitorBag = NewBag(T_MONITOR, sizeof(Monitor));
163 monitor = ObjPtr(monitorBag);
164 pthread_mutex_init(&monitor->lock, 0);
165 monitor->head = monitor->tail = NULL;
166 return monitorBag;
167 }
168
LockThread(ThreadLocalStorage * thread)169 static void LockThread(ThreadLocalStorage * thread)
170 {
171 pthread_mutex_lock(thread->threadLock);
172 }
173
UnlockThread(ThreadLocalStorage * thread)174 static void UnlockThread(ThreadLocalStorage * thread)
175 {
176 pthread_mutex_unlock(thread->threadLock);
177 }
178
SignalThread(ThreadLocalStorage * thread)179 static void SignalThread(ThreadLocalStorage * thread)
180 {
181 pthread_cond_signal(thread->threadSignal);
182 }
183
WaitThreadSignal(void)184 static void WaitThreadSignal(void)
185 {
186 int id = TLS(threadID);
187 if (!UpdateThreadState(id, TSTATE_RUNNING, TSTATE_BLOCKED))
188 HandleInterrupts(1, 0);
189 pthread_cond_wait(TLS(threadSignal), TLS(threadLock));
190 if (!UpdateThreadState(id, TSTATE_BLOCKED, TSTATE_RUNNING) &&
191 GetThreadState(id) != TSTATE_RUNNING)
192 HandleInterrupts(1, 0);
193 }
194
LockMonitor(Monitor * monitor)195 void LockMonitor(Monitor * monitor)
196 {
197 pthread_mutex_lock(&monitor->lock);
198 }
199
TryLockMonitor(Monitor * monitor)200 int TryLockMonitor(Monitor * monitor)
201 {
202 return !pthread_mutex_trylock(&monitor->lock);
203 }
204
UnlockMonitor(Monitor * monitor)205 static void UnlockMonitor(Monitor * monitor)
206 {
207 pthread_mutex_unlock(&monitor->lock);
208 }
209
210 /****************************************************************************
211 **
212 *F WaitForMonitor(monitor) . . . . . .. . wait for a monitor to be ready
213 **
214 ** 'WaitForMonitor' waits for the monitor to be signaled by another
215 ** thread. The monitor must be locked upon entry and will be locked
216 ** again upon exit.
217 */
218
WaitForMonitor(Monitor * monitor)219 static void WaitForMonitor(Monitor * monitor)
220 {
221 struct WaitList node;
222 node.thread = GetTLS();
223 AddWaitList(monitor, &node);
224 UnlockMonitor(monitor);
225 LockThread(GetTLS());
226 while (!TLS(acquiredMonitor))
227 WaitThreadSignal();
228 if (!TryLockMonitor(monitor)) {
229 UnlockThread(GetTLS());
230 LockMonitor(monitor);
231 LockThread(GetTLS());
232 }
233 TLS(acquiredMonitor) = NULL;
234 RemoveWaitList(monitor, &node);
235 UnlockThread(GetTLS());
236 }
237
ChannelOrder(const void * c1,const void * c2)238 static int ChannelOrder(const void * c1, const void * c2)
239 {
240 const char * p1 = (const char *)ObjPtr((*(Channel **)c1)->monitor);
241 const char * p2 = (const char *)ObjPtr((*(Channel **)c2)->monitor);
242 return p1 < p2;
243 }
244
SortChannels(UInt count,Channel ** channels)245 static void SortChannels(UInt count, Channel ** channels)
246 {
247 MergeSort(channels, count, sizeof(Channel *), ChannelOrder);
248 }
249
MonitorsAreSorted(UInt count,Monitor ** monitors)250 static int MonitorsAreSorted(UInt count, Monitor ** monitors)
251 {
252 UInt i;
253 for (i = 1; i < count; i++)
254 if ((char *)(monitors[i - 1]) > (char *)(monitors[i]))
255 return 0;
256 return 1;
257 }
258
LockMonitors(UInt count,Monitor ** monitors)259 void LockMonitors(UInt count, Monitor ** monitors)
260 {
261 UInt i;
262 assert(MonitorsAreSorted(count, monitors));
263 for (i = 0; i < count; i++)
264 LockMonitor(monitors[i]);
265 }
266
UnlockMonitors(UInt count,Monitor ** monitors)267 void UnlockMonitors(UInt count, Monitor ** monitors)
268 {
269 UInt i;
270 for (i = 0; i < count; i++)
271 UnlockMonitor(monitors[i]);
272 }
273
274
275 /****************************************************************************
276 **
277 *F WaitForAnyMonitor(count, monitors) . . wait for a monitor to be ready
278 **
279 ** 'WaitForAnyMonitor' waits for any one of the monitors in the list to
280 ** be signaled. The function returns when any of them is signaled via
281 ** 'SignalMonitor'. The first argument is the number of monitors in the
282 ** list, the second argument is an array of monitor pointers.
283 **
284 ** The list must be sorted by 'MonitorOrder' before passing it to the
285 ** function; all monitors must also be locked before calling the function
286 ** by calling 'LockMonitors'.
287 **
288 ** Upon return, all monitors but the one that was signaled will be
289 ** unlocked.
290 */
291
WaitForAnyMonitor(UInt count,Monitor ** monitors)292 UInt WaitForAnyMonitor(UInt count, Monitor ** monitors)
293 {
294 struct WaitList * nodes;
295 Monitor * monitor;
296 UInt i;
297 Int result;
298 assert(MonitorsAreSorted(count, monitors));
299 nodes = alloca(sizeof(struct WaitList) * count);
300 for (i = 0; i < count; i++)
301 nodes[i].thread = GetTLS();
302 for (i = 0; i < count; i++)
303 AddWaitList(monitors[i], &nodes[i]);
304 for (i = 0; i < count; i++)
305 UnlockMonitor(monitors[i]);
306 LockThread(GetTLS());
307 while (!TLS(acquiredMonitor))
308 WaitThreadSignal();
309 monitor = TLS(acquiredMonitor);
310 UnlockThread(GetTLS());
311
312 // The following loops will initialize <result>, but the compiler
313 // cannot know this; to avoid warnings, we set result to an
314 // initial nonsense value.
315 result = -1;
316 for (i = 0; i < count; i++) {
317 LockMonitor(monitors[i]);
318 if (monitors[i] == monitor) {
319 RemoveWaitList(monitors[i], &nodes[i]);
320 result = i;
321 /* keep it locked for further processing by caller */
322 }
323 else {
324 RemoveWaitList(monitors[i], &nodes[i]);
325 UnlockMonitor(monitors[i]);
326 }
327 }
328 LockThread(GetTLS());
329 TLS(acquiredMonitor) = NULL;
330 UnlockThread(GetTLS());
331 return result;
332 }
333
334 /****************************************************************************
335 **
336 *F SignalMonitor(monitor) . . . . . . . . . . send a signal to a monitor
337 **
338 ** Sends a signal to a monitor that is being waited for by another thread.
339 ** The monitor must be locked upon entry and will be locked again upon
340 ** exit. If no thread is waiting for the monitor, no operation will occur.
341 */
342
SignalMonitor(Monitor * monitor)343 void SignalMonitor(Monitor * monitor)
344 {
345 struct WaitList * queue = monitor->head;
346 while (queue != NULL) {
347 ThreadLocalStorage * thread = queue->thread;
348 LockThread(thread);
349 if (!thread->acquiredMonitor) {
350 thread->acquiredMonitor = monitor;
351 SignalThread(thread);
352 UnlockThread(thread);
353 break;
354 }
355 UnlockThread(thread);
356 queue = queue->next;
357 }
358 }
359
ArgumentError(const char * message)360 static Obj ArgumentError(const char * message)
361 {
362 ErrorQuit(message, 0, 0);
363 return 0;
364 }
365
366 /* TODO: register globals */
367 static Obj FirstKeepAlive;
368 static Obj LastKeepAlive;
369 static pthread_mutex_t KeepAliveLock;
370
371 #define KEPTALIVE(obj) (ADDR_OBJ(obj)[1])
372 #define PREV_KEPT(obj) (ADDR_OBJ(obj)[2])
373 #define NEXT_KEPT(obj) (ADDR_OBJ(obj)[3])
374
KeepAlive(Obj obj)375 Obj KeepAlive(Obj obj)
376 {
377 Obj newKeepAlive = NEW_PLIST(T_PLIST, 4);
378 SET_REGION(newKeepAlive, NULL); // public region
379 pthread_mutex_lock(&KeepAliveLock);
380 SET_LEN_PLIST(newKeepAlive, 3);
381 KEPTALIVE(newKeepAlive) = obj;
382 PREV_KEPT(newKeepAlive) = LastKeepAlive;
383 NEXT_KEPT(newKeepAlive) = (Obj)0;
384 if (LastKeepAlive)
385 NEXT_KEPT(LastKeepAlive) = newKeepAlive;
386 else
387 FirstKeepAlive = LastKeepAlive = newKeepAlive;
388 pthread_mutex_unlock(&KeepAliveLock);
389 return newKeepAlive;
390 }
391
StopKeepAlive(Obj node)392 void StopKeepAlive(Obj node)
393 {
394 #ifndef WARD_ENABLED
395 Obj pred, succ;
396 pthread_mutex_lock(&KeepAliveLock);
397 pred = PREV_KEPT(node);
398 succ = NEXT_KEPT(node);
399 if (pred)
400 NEXT_KEPT(pred) = succ;
401 else
402 FirstKeepAlive = succ;
403 if (succ)
404 PREV_KEPT(succ) = pred;
405 else
406 LastKeepAlive = pred;
407 pthread_mutex_unlock(&KeepAliveLock);
408 #endif
409 }
410
411 static GVarDescriptor GVarTHREAD_INIT;
412 static GVarDescriptor GVarTHREAD_EXIT;
413
ThreadedInterpreter(void * funcargs)414 static void ThreadedInterpreter(void * funcargs)
415 {
416 Obj tmp, func;
417 int i;
418
419 /* initialize everything and begin an interpreter */
420 STATE(NrError) = 0;
421 STATE(ThrownObject) = 0;
422
423 IntrBegin(STATE(BottomLVars));
424 tmp = KEPTALIVE(funcargs);
425 StopKeepAlive(funcargs);
426 func = ELM_PLIST(tmp, 1);
427 for (i = 2; i <= LEN_PLIST(tmp); i++) {
428 Obj item = ELM_PLIST(tmp, i);
429 SET_ELM_PLIST(tmp, i - 1, item);
430 }
431 SET_LEN_PLIST(tmp, LEN_PLIST(tmp) - 1);
432
433 TRY_IF_NO_ERROR
434 {
435 Obj init, exit;
436 if (sySetjmp(TLS(threadExit)))
437 return;
438 init = GVarOptFunction(&GVarTHREAD_INIT);
439 if (init)
440 CALL_0ARGS(init);
441 CallFuncList(func, tmp);
442 exit = GVarOptFunction(&GVarTHREAD_EXIT);
443 if (exit)
444 CALL_0ARGS(exit);
445 PushVoidObj();
446 /* end the interpreter */
447 IntrEnd(0, NULL);
448 }
449 CATCH_ERROR
450 {
451 IntrEnd(1, NULL);
452 ClearError();
453 }
454 }
455
456
457 /****************************************************************************
458 **
459 *F FuncCreateThread ... create a new thread
460 **
461 ** The function creates a new thread with a new interpreter and executes
462 ** the function passed as an argument in it. It returns an integer that
463 ** is a unique identifier for the thread.
464 */
465
FuncCreateThread(Obj self,Obj funcargs)466 static Obj FuncCreateThread(Obj self, Obj funcargs)
467 {
468 Int i, n;
469 Obj thread;
470 Obj templist;
471 n = LEN_PLIST(funcargs);
472 if (n == 0 || !IS_FUNC(ELM_PLIST(funcargs, 1)))
473 return ArgumentError(
474 "CreateThread: Needs at least one function argument");
475 templist = NEW_PLIST(T_PLIST, n);
476 SET_LEN_PLIST(templist, n);
477 SET_REGION(templist, NULL); /* make it public */
478 for (i = 1; i <= n; i++)
479 SET_ELM_PLIST(templist, i, ELM_PLIST(funcargs, i));
480 thread = RunThread(ThreadedInterpreter, KeepAlive(templist));
481 if (!thread)
482 return Fail;
483 return thread;
484 }
485
486 /****************************************************************************
487 **
488 *F FuncWaitThread ... wait for a created thread to finish.
489 **
490 ** The function waits for an existing thread to finish.
491 */
492
FuncWaitThread(Obj self,Obj obj)493 static Obj FuncWaitThread(Obj self, Obj obj)
494 {
495 const char * error = NULL;
496 RequireThread("WaitThread", obj, "thread");
497 LockThreadControl(1);
498 ThreadObject *thread = (ThreadObject *)ADDR_OBJ(obj);
499 if (thread->status & THREAD_JOINED)
500 error = "ThreadObject is already being waited for";
501 thread->status |= THREAD_JOINED;
502 UnlockThreadControl();
503 if (error)
504 ErrorQuit("WaitThread: %s", (UInt)error, 0L);
505 if (!JoinThread(thread->id))
506 ErrorQuit("WaitThread: Invalid thread id", 0L, 0L);
507 return (Obj)0;
508 }
509
510 /****************************************************************************
511 **
512 *F FuncCurrentThread ... return thread object of current thread.
513 **
514 */
515
FuncCurrentThread(Obj self)516 static Obj FuncCurrentThread(Obj self)
517 {
518 return TLS(threadObject);
519 }
520
521 /****************************************************************************
522 **
523 *F FuncThreadID ... return numerical thread id of thread.
524 **
525 */
526
FuncThreadID(Obj self,Obj thread)527 static Obj FuncThreadID(Obj self, Obj thread)
528 {
529 RequireThread("ThreadID", thread, "thread");
530 return INTOBJ_INT(ThreadID(thread));
531 }
532
533 /****************************************************************************
534 **
535 *F FuncKillThread ... kill a given thread
536 **
537 */
538
FuncKillThread(Obj self,Obj thread)539 static Obj FuncKillThread(Obj self, Obj thread)
540 {
541 int id;
542 if (IS_INTOBJ(thread)) {
543 id = INT_INTOBJ(thread);
544 if (id < 0 || id >= MAX_THREADS)
545 return ArgumentError("KillThread: Thread ID out of range");
546 }
547 else if (TNUM_OBJ(thread) == T_THREAD) {
548 id = ThreadID(thread);
549 }
550 else
551 return ArgumentError("KillThread: Argument must be a thread object");
552 KillThread(id);
553 return (Obj)0;
554 }
555
556
557 /****************************************************************************
558 **
559 *F FuncInterruptThread ... interrupt a given thread
560 **
561 */
562
563 #define AS_STRING(s) #s
564
565
FuncInterruptThread(Obj self,Obj thread,Obj handler)566 static Obj FuncInterruptThread(Obj self, Obj thread, Obj handler)
567 {
568 int id;
569 if (IS_INTOBJ(thread)) {
570 id = INT_INTOBJ(thread);
571 if (id < 0 || id >= MAX_THREADS)
572 return ArgumentError("InterruptThread: Thread ID out of range");
573 }
574 else if (TNUM_OBJ(thread) == T_THREAD) {
575 id = ThreadID(thread);
576 }
577 else
578 return ArgumentError(
579 "InterruptThread: First argument must identify a thread");
580 if (!IS_INTOBJ(handler) || INT_INTOBJ(handler) < 0 ||
581 INT_INTOBJ(handler) > MAX_INTERRUPT)
582 return ArgumentError(
583 "InterruptThread: Second argument must be an integer "
584 "between 0 and " AS_STRING(MAX_INTERRUPT));
585 InterruptThread(id, (int)(INT_INTOBJ(handler)));
586 return (Obj)0;
587 }
588
589 /****************************************************************************
590 **
591 *F FuncSetInterruptHandler ... set interrupt handler for current thread
592 **
593 */
594
FuncSetInterruptHandler(Obj self,Obj handler,Obj func)595 static Obj FuncSetInterruptHandler(Obj self, Obj handler, Obj func)
596 {
597 if (!IS_INTOBJ(handler) || INT_INTOBJ(handler) < 1 ||
598 INT_INTOBJ(handler) > MAX_INTERRUPT)
599 return ArgumentError(
600 "SetInterruptHandler: First argument must be an integer "
601 "between 1 and " AS_STRING(MAX_INTERRUPT));
602 if (func == Fail) {
603 SetInterruptHandler((int)(INT_INTOBJ(handler)), (Obj)0);
604 return (Obj)0;
605 }
606 if (TNUM_OBJ(func) != T_FUNCTION || NARG_FUNC(func) != 0 ||
607 !BODY_FUNC(func))
608 return ArgumentError("SetInterruptHandler: Second argument must be a "
609 "parameterless function or 'fail'");
610 SetInterruptHandler((int)(INT_INTOBJ(handler)), func);
611 return (Obj)0;
612 }
613
614 #undef AS_STRING
615
616
617 /****************************************************************************
618 **
619 *F FuncPauseThread ... pause a given thread
620 **
621 */
622
623
FuncPauseThread(Obj self,Obj thread)624 static Obj FuncPauseThread(Obj self, Obj thread)
625 {
626 int id;
627 if (IS_INTOBJ(thread)) {
628 id = INT_INTOBJ(thread);
629 if (id < 0 || id >= MAX_THREADS)
630 return ArgumentError("PauseThread: Thread ID out of range");
631 }
632 else if (TNUM_OBJ(thread) == T_THREAD) {
633 id = ThreadID(thread);
634 }
635 else
636 return ArgumentError("PauseThread: Argument must be a thread object");
637 PauseThread(id);
638 return (Obj)0;
639 }
640
641
642 /****************************************************************************
643 **
644 *F FuncResumeThread ... resume a given thread
645 **
646 */
647
648
FuncResumeThread(Obj self,Obj thread)649 static Obj FuncResumeThread(Obj self, Obj thread)
650 {
651 int id;
652 if (IS_INTOBJ(thread)) {
653 id = INT_INTOBJ(thread);
654 if (id < 0 || id >= MAX_THREADS)
655 return ArgumentError("ResumeThread: Thread ID out of range");
656 }
657 else if (TNUM_OBJ(thread) == T_THREAD) {
658 id = ThreadID(thread);
659 }
660 else
661 return ArgumentError(
662 "ResumeThread: Argument must be a thread object");
663 ResumeThread(id);
664 return (Obj)0;
665 }
666
667
668 /****************************************************************************
669 **
670 *F FuncRegionOf ... return region of an object
671 **
672 */
673 static Obj PublicRegion;
674
FuncRegionOf(Obj self,Obj obj)675 static Obj FuncRegionOf(Obj self, Obj obj)
676 {
677 Region * region = GetRegionOf(obj);
678 return region == NULL ? PublicRegion : region->obj;
679 }
680
681
682 /****************************************************************************
683 **
684 *F FuncSetRegionName ... set the name of an object's region
685 *F FuncClearRegionName ... clear the name of an object's region
686 *F FuncRegionName ... get the name of an object's region
687 **
688 */
689
690
FuncSetRegionName(Obj self,Obj obj,Obj name)691 static Obj FuncSetRegionName(Obj self, Obj obj, Obj name)
692 {
693 Region * region = GetRegionOf(obj);
694 if (!region)
695 return ArgumentError(
696 "SetRegionName: Cannot change name of the public region");
697 if (!IsStringConv(name))
698 return ArgumentError("SetRegionName: Region name must be a string");
699 SetRegionName(region, name);
700 return (Obj)0;
701 }
702
FuncClearRegionName(Obj self,Obj obj)703 static Obj FuncClearRegionName(Obj self, Obj obj)
704 {
705 Region * region = GetRegionOf(obj);
706 if (!region)
707 return ArgumentError(
708 "ClearRegionName: Cannot change name of the public region");
709 SetRegionName(region, (Obj)0);
710 return (Obj)0;
711 }
712
FuncRegionName(Obj self,Obj obj)713 static Obj FuncRegionName(Obj self, Obj obj)
714 {
715 Obj result;
716 Region * region = GetRegionOf(obj);
717 result = GetRegionName(region);
718 if (!result)
719 result = Fail;
720 return result;
721 }
722
723
724 /****************************************************************************
725 **
726 *F FuncIsShared ... return whether a region is shared
727 **
728 */
729
FuncIsShared(Obj self,Obj obj)730 static Obj FuncIsShared(Obj self, Obj obj)
731 {
732 Region * region = GetRegionOf(obj);
733 return (region && !region->fixed_owner) ? True : False;
734 }
735
736 /****************************************************************************
737 **
738 *F FuncIsPublic ... return whether a region is public
739 **
740 */
741
FuncIsPublic(Obj self,Obj obj)742 static Obj FuncIsPublic(Obj self, Obj obj)
743 {
744 Region * region = GetRegionOf(obj);
745 return region == NULL ? True : False;
746 }
747
748 /****************************************************************************
749 **
750 *F FuncIsThreadLocal ... return whether a region is thread-local
751 **
752 */
753
FuncIsThreadLocal(Obj self,Obj obj)754 static Obj FuncIsThreadLocal(Obj self, Obj obj)
755 {
756 Region * region = GetRegionOf(obj);
757 return (region && region->fixed_owner && region->owner == GetTLS())
758 ? True
759 : False;
760 }
761
762 /****************************************************************************
763 **
764 *F FuncHaveWriteAccess ... return if we have a write lock on the region
765 **
766 */
767
FuncHaveWriteAccess(Obj self,Obj obj)768 static Obj FuncHaveWriteAccess(Obj self, Obj obj)
769 {
770 Region * region = GetRegionOf(obj);
771 if (region != NULL &&
772 (region->owner == GetTLS() || region->alt_owner == GetTLS()))
773 return True;
774 else
775 return False;
776 }
777
778 /****************************************************************************
779 **
780 *F FuncHaveReadAccess ... return if we have a read lock on the region
781 **
782 */
783
FuncHaveReadAccess(Obj self,Obj obj)784 static Obj FuncHaveReadAccess(Obj self, Obj obj)
785 {
786 Region * region = GetRegionOf(obj);
787 if (region != NULL && CheckReadAccess(obj))
788 return True;
789 else
790 return False;
791 }
792
793
794 /****************************************************************************
795 **
796 *F FuncHASH_LOCK ........... acquire write lock on an object.
797 *F FuncHASH_UNLOCK ......... release write lock on an object.
798 *F FuncHASH_LOCK_SHARED ..... acquire read lock on an object.
799 *F FuncHASH_UNLOCK_SHARED ... release read lock on an object.
800 **
801 */
802
803
FuncHASH_LOCK(Obj self,Obj target)804 static Obj FuncHASH_LOCK(Obj self, Obj target)
805 {
806 HashLock(target);
807 return (Obj)0;
808 }
809
FuncHASH_UNLOCK(Obj self,Obj target)810 static Obj FuncHASH_UNLOCK(Obj self, Obj target)
811 {
812 HashUnlock(target);
813 return (Obj)0;
814 }
815
FuncHASH_LOCK_SHARED(Obj self,Obj target)816 static Obj FuncHASH_LOCK_SHARED(Obj self, Obj target)
817 {
818 HashLockShared(target);
819 return (Obj)0;
820 }
FuncHASH_UNLOCK_SHARED(Obj self,Obj target)821 static Obj FuncHASH_UNLOCK_SHARED(Obj self, Obj target)
822 {
823 HashUnlockShared(target);
824 return (Obj)0;
825 }
826
827 /****************************************************************************
828 **
829 *F FuncHASH_SYNCHRONIZED ......... execute a function while holding a write
830 *lock.
831 *F FuncHASH_SYNCHRONIZED_SHARED ... execute a function while holding a read
832 *lock.
833 **
834 */
835
FuncHASH_SYNCHRONIZED(Obj self,Obj target,Obj function)836 static Obj FuncHASH_SYNCHRONIZED(Obj self, Obj target, Obj function)
837 {
838 volatile int locked = 0;
839 jmp_buf readJmpError;
840 memcpy(readJmpError, STATE(ReadJmpError), sizeof(jmp_buf));
841 TRY_IF_NO_ERROR
842 {
843 HashLock(target);
844 locked = 1;
845 CALL_0ARGS(function);
846 locked = 0;
847 HashUnlock(target);
848 }
849 if (locked)
850 HashUnlock(target);
851 memcpy(STATE(ReadJmpError), readJmpError, sizeof(jmp_buf));
852 return (Obj)0;
853 }
854
FuncHASH_SYNCHRONIZED_SHARED(Obj self,Obj target,Obj function)855 static Obj FuncHASH_SYNCHRONIZED_SHARED(Obj self, Obj target, Obj function)
856 {
857 volatile int locked = 0;
858 jmp_buf readJmpError;
859 memcpy(readJmpError, STATE(ReadJmpError), sizeof(jmp_buf));
860 TRY_IF_NO_ERROR
861 {
862 HashLockShared(target);
863 locked = 1;
864 CALL_0ARGS(function);
865 locked = 0;
866 HashUnlockShared(target);
867 }
868 if (locked)
869 HashUnlockShared(target);
870 memcpy(STATE(ReadJmpError), readJmpError, sizeof(jmp_buf));
871 return (Obj)0;
872 }
873
874 /****************************************************************************
875 **
876 *F FuncCREATOR_OF ... return function that created an object
877 **
878 */
879
FuncCREATOR_OF(Obj self,Obj obj)880 static Obj FuncCREATOR_OF(Obj self, Obj obj)
881 {
882 #ifdef TRACK_CREATOR
883 Obj result = NEW_PLIST_IMM(T_PLIST, 2);
884 SET_LEN_PLIST(result, 2);
885 if (!IS_BAG_REF(obj)) {
886 SET_ELM_PLIST(result, 1, Fail);
887 SET_ELM_PLIST(result, 2, Fail);
888 return result;
889 }
890 if (obj[2])
891 SET_ELM_PLIST(result, 1, (Obj)(obj[2]));
892 else
893 SET_ELM_PLIST(result, 1, Fail);
894 if (obj[3])
895 SET_ELM_PLIST(result, 2, (Obj)(obj[3]));
896 else
897 SET_ELM_PLIST(result, 2, Fail);
898 return result;
899 #else
900 return Fail;
901 #endif
902 }
903
FuncDISABLE_GUARDS(Obj self,Obj flag)904 static Obj FuncDISABLE_GUARDS(Obj self, Obj flag)
905 {
906 if (flag == False)
907 TLS(DisableGuards) = 0;
908 else if (flag == True)
909 TLS(DisableGuards) = 1;
910 else if (IS_INTOBJ(flag))
911 TLS(DisableGuards) = (int)(INT_INTOBJ(flag));
912 else
913 ErrorQuit("DISABLE_GUARDS: Argument must be boolean or integer", 0L,
914 0L);
915 return (Obj)0;
916 }
917
FuncWITH_TARGET_REGION(Obj self,Obj obj,Obj func)918 static Obj FuncWITH_TARGET_REGION(Obj self, Obj obj, Obj func)
919 {
920 Region * volatile oldRegion = TLS(currentRegion);
921 Region * volatile region = GetRegionOf(obj);
922 syJmp_buf readJmpError;
923
924 RequireFunction("WITH_TARGET_REGION", func);
925 if (!region || !CheckExclusiveWriteAccess(obj))
926 return ArgumentError(
927 "WITH_TARGET_REGION: Requires write access to target region");
928 memcpy(readJmpError, STATE(ReadJmpError), sizeof(syJmp_buf));
929 if (sySetjmp(STATE(ReadJmpError))) {
930 memcpy(STATE(ReadJmpError), readJmpError, sizeof(syJmp_buf));
931 TLS(currentRegion) = oldRegion;
932 syLongjmp(&(STATE(ReadJmpError)), 1);
933 }
934 TLS(currentRegion) = region;
935 CALL_0ARGS(func);
936 memcpy(STATE(ReadJmpError), readJmpError, sizeof(syJmp_buf));
937 TLS(currentRegion) = oldRegion;
938 return (Obj)0;
939 }
940
941
942 static Obj TYPE_THREAD;
943 static Obj TYPE_SEMAPHORE;
944 static Obj TYPE_CHANNEL;
945 static Obj TYPE_BARRIER;
946 static Obj TYPE_SYNCVAR;
947 static Obj TYPE_REGION;
948
TypeThread(Obj obj)949 static Obj TypeThread(Obj obj)
950 {
951 return TYPE_THREAD;
952 }
953
TypeSemaphore(Obj obj)954 static Obj TypeSemaphore(Obj obj)
955 {
956 return TYPE_SEMAPHORE;
957 }
958
TypeChannel(Obj obj)959 static Obj TypeChannel(Obj obj)
960 {
961 return TYPE_CHANNEL;
962 }
963
TypeBarrier(Obj obj)964 static Obj TypeBarrier(Obj obj)
965 {
966 return TYPE_BARRIER;
967 }
968
TypeSyncVar(Obj obj)969 static Obj TypeSyncVar(Obj obj)
970 {
971 return TYPE_SYNCVAR;
972 }
973
TypeRegion(Obj obj)974 static Obj TypeRegion(Obj obj)
975 {
976 return TYPE_REGION;
977 }
978
979 #ifdef USE_GASMAN
980 static void MarkSemaphoreBag(Bag);
981 static void MarkChannelBag(Bag);
982 static void MarkBarrierBag(Bag);
983 static void MarkSyncVarBag(Bag);
984 #endif
985 static void FinalizeMonitor(Bag);
986 static void PrintThread(Obj);
987 static void PrintSemaphore(Obj);
988 static void PrintChannel(Obj);
989 static void PrintBarrier(Obj);
990 static void PrintSyncVar(Obj);
991 static void PrintRegion(Obj);
992
993 GVarDescriptor LastInaccessibleGVar;
994 static GVarDescriptor MAX_INTERRUPTGVar;
995
996 static UInt RNAM_SIGINT;
997 static UInt RNAM_SIGCHLD;
998 static UInt RNAM_SIGVTALRM;
999 #ifdef SIGWINCH
1000 static UInt RNAM_SIGWINCH;
1001 #endif
1002
1003 #ifndef WARD_ENABLED
1004 #ifdef USE_GASMAN
MarkSemaphoreBag(Bag bag)1005 static void MarkSemaphoreBag(Bag bag)
1006 {
1007 Semaphore * sem = (Semaphore *)(PTR_BAG(bag));
1008 MarkBag(sem->monitor);
1009 }
1010
MarkChannelBag(Bag bag)1011 static void MarkChannelBag(Bag bag)
1012 {
1013 Channel * channel = (Channel *)(PTR_BAG(bag));
1014 MarkBag(channel->queue);
1015 MarkBag(channel->monitor);
1016 }
1017
MarkBarrierBag(Bag bag)1018 static void MarkBarrierBag(Bag bag)
1019 {
1020 Barrier * barrier = (Barrier *)(PTR_BAG(bag));
1021 MarkBag(barrier->monitor);
1022 }
1023
MarkSyncVarBag(Bag bag)1024 static void MarkSyncVarBag(Bag bag)
1025 {
1026 SyncVar * syncvar = (SyncVar *)(PTR_BAG(bag));
1027 MarkBag(syncvar->queue);
1028 MarkBag(syncvar->monitor);
1029 }
1030 #endif
1031
FinalizeMonitor(Bag bag)1032 static void FinalizeMonitor(Bag bag)
1033 {
1034 Monitor * monitor = (Monitor *)(PTR_BAG(bag));
1035 pthread_mutex_destroy(&monitor->lock);
1036 }
1037
LockChannel(Channel * channel)1038 static void LockChannel(Channel * channel)
1039 {
1040 LockMonitor(ObjPtr(channel->monitor));
1041 }
1042
UnlockChannel(Channel * channel)1043 static void UnlockChannel(Channel * channel)
1044 {
1045 UnlockMonitor(ObjPtr(channel->monitor));
1046 }
1047
SignalChannel(Channel * channel)1048 static void SignalChannel(Channel * channel)
1049 {
1050 if (channel->waiting)
1051 SignalMonitor(ObjPtr(channel->monitor));
1052 }
1053
WaitChannel(Channel * channel)1054 static void WaitChannel(Channel * channel)
1055 {
1056 channel->waiting++;
1057 WaitForMonitor(ObjPtr(channel->monitor));
1058 channel->waiting--;
1059 }
1060
ExpandChannel(Channel * channel)1061 static void ExpandChannel(Channel * channel)
1062 {
1063 /* Growth ratio should be less than the golden ratio */
1064 const UInt oldCapacity = channel->capacity;
1065 const UInt newCapacity = ((oldCapacity * 25 / 16) | 1) + 1;
1066 GAP_ASSERT(newCapacity > oldCapacity);
1067
1068 UInt i, tail;
1069 Obj newqueue;
1070 newqueue = NEW_PLIST(T_PLIST, newCapacity);
1071 SET_LEN_PLIST(newqueue, newCapacity);
1072 SET_REGION(newqueue, REGION(channel->queue));
1073 channel->capacity = newCapacity;
1074 for (i = channel->head; i < oldCapacity; i++)
1075 ADDR_OBJ(newqueue)[i + 1] = ADDR_OBJ(channel->queue)[i + 1];
1076 for (i = 0; i < channel->tail; i++) {
1077 UInt d = oldCapacity + i;
1078 if (d >= newCapacity)
1079 d -= newCapacity;
1080 ADDR_OBJ(newqueue)[d + 1] = ADDR_OBJ(channel->queue)[i + 1];
1081 }
1082 tail = channel->head + oldCapacity;
1083 if (tail >= newCapacity)
1084 tail -= newCapacity;
1085 channel->tail = tail;
1086 channel->queue = newqueue;
1087 }
1088
AddToChannel(Channel * channel,Obj obj,int migrate)1089 static void AddToChannel(Channel * channel, Obj obj, int migrate)
1090 {
1091 Obj children;
1092 Region * region = REGION(channel->queue);
1093 UInt i, len;
1094 if (migrate && IS_BAG_REF(obj) && REGION(obj) &&
1095 REGION(obj)->owner == GetTLS() && REGION(obj)->fixed_owner) {
1096 children = ReachableObjectsFrom(obj);
1097 len = children ? LEN_PLIST(children) : 0;
1098 }
1099 else {
1100 children = 0;
1101 len = 0;
1102 }
1103 for (i = 1; i <= len; i++) {
1104 Obj item = ELM_PLIST(children, i);
1105 SET_REGION(item, region);
1106 }
1107 ADDR_OBJ(channel->queue)[++channel->tail] = obj;
1108 ADDR_OBJ(channel->queue)[++channel->tail] = children;
1109 if (channel->tail == channel->capacity)
1110 channel->tail = 0;
1111 channel->size += 2;
1112 }
1113
RetrieveFromChannel(Channel * channel)1114 static Obj RetrieveFromChannel(Channel * channel)
1115 {
1116 Obj obj = ADDR_OBJ(channel->queue)[++channel->head];
1117 Obj children = ADDR_OBJ(channel->queue)[++channel->head];
1118 Region * region = TLS(currentRegion);
1119 UInt i, len = children ? LEN_PLIST(children) : 0;
1120 ADDR_OBJ(channel->queue)[channel->head - 1] = 0;
1121 ADDR_OBJ(channel->queue)[channel->head] = 0;
1122 if (channel->head == channel->capacity)
1123 channel->head = 0;
1124 for (i = 1; i <= len; i++) {
1125 Obj item = ELM_PLIST(children, i);
1126 SET_REGION(item, region);
1127 }
1128 channel->size -= 2;
1129 return obj;
1130 }
1131
TallyChannel(Channel * channel)1132 static Int TallyChannel(Channel * channel)
1133 {
1134 Int result;
1135 LockChannel(channel);
1136 result = channel->size / 2;
1137 UnlockChannel(channel);
1138 return result;
1139 }
1140
SendChannel(Channel * channel,Obj obj,int migrate)1141 static void SendChannel(Channel * channel, Obj obj, int migrate)
1142 {
1143 LockChannel(channel);
1144 if (channel->size == channel->capacity && channel->dynamic)
1145 ExpandChannel(channel);
1146 while (channel->size == channel->capacity)
1147 WaitChannel(channel);
1148 AddToChannel(channel, obj, migrate);
1149 SignalChannel(channel);
1150 UnlockChannel(channel);
1151 }
1152
MultiSendChannel(Channel * channel,Obj list,int migrate)1153 static void MultiSendChannel(Channel * channel, Obj list, int migrate)
1154 {
1155 int listsize = LEN_LIST(list);
1156 int i;
1157 Obj obj;
1158 LockChannel(channel);
1159 for (i = 1; i <= listsize; i++) {
1160 if (channel->size == channel->capacity && channel->dynamic)
1161 ExpandChannel(channel);
1162 while (channel->size == channel->capacity)
1163 WaitChannel(channel);
1164 obj = ELM_LIST(list, i);
1165 AddToChannel(channel, obj, migrate);
1166 }
1167 SignalChannel(channel);
1168 UnlockChannel(channel);
1169 }
1170
TryMultiSendChannel(Channel * channel,Obj list,int migrate)1171 static int TryMultiSendChannel(Channel * channel, Obj list, int migrate)
1172 {
1173 int result = 0;
1174 int listsize = LEN_LIST(list);
1175 int i;
1176 Obj obj;
1177 LockChannel(channel);
1178 for (i = 1; i <= listsize; i++) {
1179 if (channel->size == channel->capacity && channel->dynamic)
1180 ExpandChannel(channel);
1181 if (channel->size == channel->capacity)
1182 break;
1183 obj = ELM_LIST(list, i);
1184 AddToChannel(channel, obj, migrate);
1185 result++;
1186 }
1187 SignalChannel(channel);
1188 UnlockChannel(channel);
1189 return result;
1190 }
1191
TrySendChannel(Channel * channel,Obj obj,int migrate)1192 static int TrySendChannel(Channel * channel, Obj obj, int migrate)
1193 {
1194 LockChannel(channel);
1195 if (channel->size == channel->capacity && channel->dynamic)
1196 ExpandChannel(channel);
1197 if (channel->size == channel->capacity) {
1198 UnlockChannel(channel);
1199 return 0;
1200 }
1201 AddToChannel(channel, obj, migrate);
1202 SignalChannel(channel);
1203 UnlockChannel(channel);
1204 return 1;
1205 }
1206
ReceiveChannel(Channel * channel)1207 static Obj ReceiveChannel(Channel * channel)
1208 {
1209 Obj result;
1210 LockChannel(channel);
1211 while (channel->size == 0)
1212 WaitChannel(channel);
1213 result = RetrieveFromChannel(channel);
1214 SignalChannel(channel);
1215 UnlockChannel(channel);
1216 return result;
1217 }
1218
ReceiveAnyChannel(Obj channelList,int with_index)1219 static Obj ReceiveAnyChannel(Obj channelList, int with_index)
1220 {
1221 UInt count = LEN_PLIST(channelList);
1222 UInt i, p;
1223 Monitor ** monitors = alloca(count * sizeof(Monitor *));
1224 Channel ** channels = alloca(count * sizeof(Channel *));
1225 Obj result;
1226 Channel * channel;
1227 for (i = 0; i < count; i++)
1228 channels[i] = ObjPtr(ELM_PLIST(channelList, i + 1));
1229 SortChannels(count, channels);
1230 for (i = 0; i < count; i++)
1231 monitors[i] = ObjPtr(channels[i]->monitor);
1232 LockMonitors(count, monitors);
1233 p = TLS(multiplexRandomSeed);
1234 p = (p * 5 + 1);
1235 TLS(multiplexRandomSeed) = p;
1236 p %= count;
1237 for (i = 0; i < count; i++) {
1238 channel = channels[p];
1239 if (channel->size > 0)
1240 break;
1241 p++;
1242 if (p >= count)
1243 p = 0;
1244 }
1245 if (i < count) /* found a channel with data */
1246 {
1247 p = i;
1248 for (i = 0; i < count; i++)
1249 if (i != p)
1250 UnlockMonitor(monitors[i]);
1251 }
1252 else /* all channels are empty */
1253 for (;;) {
1254 for (i = 0; i < count; i++)
1255 channels[i]->waiting++;
1256 p = WaitForAnyMonitor(count, monitors);
1257 for (i = 0; i < count; i++)
1258 channels[i]->waiting--;
1259 channel = channels[p];
1260 if (channel->size > 0)
1261 break;
1262 UnlockMonitor(monitors[p]);
1263 LockMonitors(count, monitors);
1264 }
1265 result = RetrieveFromChannel(channel);
1266 SignalChannel(channel);
1267 UnlockMonitor(monitors[p]);
1268 if (with_index) {
1269 Obj list = NEW_PLIST(T_PLIST, 2);
1270 SET_LEN_PLIST(list, 2);
1271 SET_ELM_PLIST(list, 1, result);
1272 for (i = 1; i <= count; i++)
1273 if (ObjPtr(ELM_PLIST(channelList, i)) == channel) {
1274 SET_ELM_PLIST(list, 2, INTOBJ_INT(i));
1275 break;
1276 }
1277 return list;
1278 }
1279 else
1280 return result;
1281 }
1282
MultiReceiveChannel(Channel * channel,UInt max)1283 static Obj MultiReceiveChannel(Channel * channel, UInt max)
1284 {
1285 Obj result;
1286 UInt count;
1287 UInt i;
1288 LockChannel(channel);
1289 if (max > channel->size / 2)
1290 count = channel->size / 2;
1291 else
1292 count = max;
1293 result = NEW_PLIST(T_PLIST, count);
1294 SET_LEN_PLIST(result, count);
1295 for (i = 0; i < count; i++) {
1296 Obj item = RetrieveFromChannel(channel);
1297 SET_ELM_PLIST(result, i + 1, item);
1298 }
1299 SignalChannel(channel);
1300 UnlockChannel(channel);
1301 return result;
1302 }
1303
InspectChannel(Channel * channel)1304 static Obj InspectChannel(Channel * channel)
1305 {
1306 LockChannel(channel);
1307 const UInt count = channel->size / 2;
1308 Obj result = NEW_PLIST(T_PLIST, count);
1309 SET_LEN_PLIST(result, count);
1310 for (UInt i = 0, p = channel->head; i < count; i++) {
1311 SET_ELM_PLIST(result, i + 1, ELM_PLIST(channel->queue, p + 1));
1312 p += 2;
1313 if (p == channel->capacity)
1314 p = 0;
1315 }
1316 UnlockChannel(channel);
1317 return result;
1318 }
1319
TryReceiveChannel(Channel * channel,Obj defaultobj)1320 static Obj TryReceiveChannel(Channel * channel, Obj defaultobj)
1321 {
1322 Obj result;
1323 LockChannel(channel);
1324 if (channel->size == 0) {
1325 UnlockChannel(channel);
1326 return defaultobj;
1327 }
1328 result = RetrieveFromChannel(channel);
1329 SignalChannel(channel);
1330 UnlockChannel(channel);
1331 return result;
1332 }
1333
CreateChannel(int capacity)1334 static Obj CreateChannel(int capacity)
1335 {
1336 Channel * channel;
1337 Bag channelBag;
1338 channelBag = NewBag(T_CHANNEL, sizeof(Channel));
1339 channel = ObjPtr(channelBag);
1340 channel->monitor = NewMonitor();
1341 channel->size = channel->head = channel->tail = 0;
1342 channel->capacity = (capacity < 0) ? 20 : capacity * 2;
1343 channel->dynamic = (capacity < 0);
1344 channel->waiting = 0;
1345 channel->queue = NEW_PLIST(T_PLIST, channel->capacity);
1346 SET_REGION(channel->queue, LimboRegion);
1347 SET_LEN_PLIST(channel->queue, channel->capacity);
1348 return channelBag;
1349 }
1350
DestroyChannel(Channel * channel)1351 static int DestroyChannel(Channel * channel)
1352 {
1353 return 1;
1354 }
1355 #endif
1356
FuncCreateChannel(Obj self,Obj args)1357 static Obj FuncCreateChannel(Obj self, Obj args)
1358 {
1359 int capacity;
1360 switch (LEN_PLIST(args)) {
1361 case 0:
1362 capacity = -1;
1363 break;
1364 case 1:
1365 if (IS_INTOBJ(ELM_PLIST(args, 1))) {
1366 capacity = INT_INTOBJ(ELM_PLIST(args, 1));
1367 if (capacity <= 0)
1368 return ArgumentError(
1369 "CreateChannel: Capacity must be positive");
1370 break;
1371 }
1372 return ArgumentError(
1373 "CreateChannel: Argument must be capacity of the channel");
1374 default:
1375 return ArgumentError(
1376 "CreateChannel: Function takes up to two arguments");
1377 }
1378 return CreateChannel(capacity);
1379 }
1380
IsChannel(Obj obj)1381 static int IsChannel(Obj obj)
1382 {
1383 return obj && TNUM_OBJ(obj) == T_CHANNEL;
1384 }
1385
FuncDestroyChannel(Obj self,Obj channel)1386 static Obj FuncDestroyChannel(Obj self, Obj channel)
1387 {
1388 RequireChannel("DestroyChannel", channel);
1389 if (!DestroyChannel(ObjPtr(channel)))
1390 return ArgumentError("DestroyChannel: Channel is in use");
1391 return (Obj)0;
1392 }
1393
FuncTallyChannel(Obj self,Obj channel)1394 static Obj FuncTallyChannel(Obj self, Obj channel)
1395 {
1396 RequireChannel("TallyChannel", channel);
1397 return INTOBJ_INT(TallyChannel(ObjPtr(channel)));
1398 }
1399
FuncSendChannel(Obj self,Obj channel,Obj obj)1400 static Obj FuncSendChannel(Obj self, Obj channel, Obj obj)
1401 {
1402 RequireChannel("SendChannel", channel);
1403 SendChannel(ObjPtr(channel), obj, 1);
1404 return (Obj)0;
1405 }
1406
FuncTransmitChannel(Obj self,Obj channel,Obj obj)1407 static Obj FuncTransmitChannel(Obj self, Obj channel, Obj obj)
1408 {
1409 RequireChannel("TransmitChannel", channel);
1410 SendChannel(ObjPtr(channel), obj, 0);
1411 return (Obj)0;
1412 }
1413
FuncMultiSendChannel(Obj self,Obj channel,Obj list)1414 static Obj FuncMultiSendChannel(Obj self, Obj channel, Obj list)
1415 {
1416 RequireChannel("MultiSendChannel", channel);
1417 RequireDenseList("MultiSendChannel", list);
1418 MultiSendChannel(ObjPtr(channel), list, 1);
1419 return (Obj)0;
1420 }
1421
FuncMultiTransmitChannel(Obj self,Obj channel,Obj list)1422 static Obj FuncMultiTransmitChannel(Obj self, Obj channel, Obj list)
1423 {
1424 RequireChannel("MultiTransmitChannel", channel);
1425 RequireDenseList("MultiTransmitChannel", list);
1426 MultiSendChannel(ObjPtr(channel), list, 0);
1427 return (Obj)0;
1428 }
1429
FuncTryMultiSendChannel(Obj self,Obj channel,Obj list)1430 static Obj FuncTryMultiSendChannel(Obj self, Obj channel, Obj list)
1431 {
1432 RequireChannel("TryMultiSendChannel", channel);
1433 RequireDenseList("TryMultiSendChannel", list);
1434 return INTOBJ_INT(TryMultiSendChannel(ObjPtr(channel), list, 1));
1435 }
1436
1437
FuncTryMultiTransmitChannel(Obj self,Obj channel,Obj list)1438 static Obj FuncTryMultiTransmitChannel(Obj self, Obj channel, Obj list)
1439 {
1440 RequireChannel("TryMultiTransmitChannel", channel);
1441 RequireDenseList("TryMultiTransmitChannel", list);
1442 return INTOBJ_INT(TryMultiSendChannel(ObjPtr(channel), list, 0));
1443 }
1444
1445
FuncTrySendChannel(Obj self,Obj channel,Obj obj)1446 static Obj FuncTrySendChannel(Obj self, Obj channel, Obj obj)
1447 {
1448 RequireChannel("TrySendChannel", channel);
1449 return TrySendChannel(ObjPtr(channel), obj, 1) ? True : False;
1450 }
1451
FuncTryTransmitChannel(Obj self,Obj channel,Obj obj)1452 static Obj FuncTryTransmitChannel(Obj self, Obj channel, Obj obj)
1453 {
1454 RequireChannel("TryTransmitChannel", channel);
1455 return TrySendChannel(ObjPtr(channel), obj, 0) ? True : False;
1456 }
1457
FuncReceiveChannel(Obj self,Obj channel)1458 static Obj FuncReceiveChannel(Obj self, Obj channel)
1459 {
1460 RequireChannel("ReceiveChannel", channel);
1461 return ReceiveChannel(ObjPtr(channel));
1462 }
1463
IsChannelList(Obj list)1464 static int IsChannelList(Obj list)
1465 {
1466 int len = LEN_PLIST(list);
1467 int i;
1468 for (i = 1; i <= len; i++)
1469 if (!IsChannel(ELM_PLIST(list, i)))
1470 return 0;
1471 return 1;
1472 }
1473
FuncReceiveAnyChannel(Obj self,Obj args)1474 static Obj FuncReceiveAnyChannel(Obj self, Obj args)
1475 {
1476 if (IsChannelList(args))
1477 return ReceiveAnyChannel(args, 0);
1478 else {
1479 if (LEN_PLIST(args) == 1 && IS_PLIST(ELM_PLIST(args, 1)) &&
1480 IsChannelList(ELM_PLIST(args, 1)))
1481 return ReceiveAnyChannel(ELM_PLIST(args, 1), 0);
1482 else
1483 return ArgumentError(
1484 "ReceiveAnyChannel: Argument list must be channels");
1485 }
1486 }
1487
FuncReceiveAnyChannelWithIndex(Obj self,Obj args)1488 static Obj FuncReceiveAnyChannelWithIndex(Obj self, Obj args)
1489 {
1490 if (IsChannelList(args))
1491 return ReceiveAnyChannel(args, 1);
1492 else {
1493 if (LEN_PLIST(args) == 1 && IS_PLIST(ELM_PLIST(args, 1)) &&
1494 IsChannelList(ELM_PLIST(args, 1)))
1495 return ReceiveAnyChannel(ELM_PLIST(args, 1), 1);
1496 else
1497 return ArgumentError(
1498 "ReceiveAnyChannel: Argument list must be channels");
1499 }
1500 }
1501
FuncMultiReceiveChannel(Obj self,Obj channel,Obj count)1502 static Obj FuncMultiReceiveChannel(Obj self, Obj channel, Obj count)
1503 {
1504 RequireChannel("MultiReceiveChannel", channel);
1505 RequireNonnegativeSmallInt("MultiReceiveChannel", count);
1506 return MultiReceiveChannel(ObjPtr(channel), INT_INTOBJ(count));
1507 }
1508
FuncInspectChannel(Obj self,Obj channel)1509 static Obj FuncInspectChannel(Obj self, Obj channel)
1510 {
1511 RequireChannel("InspectChannel", channel);
1512 return InspectChannel(ObjPtr(channel));
1513 }
1514
FuncTryReceiveChannel(Obj self,Obj channel,Obj obj)1515 static Obj FuncTryReceiveChannel(Obj self, Obj channel, Obj obj)
1516 {
1517 RequireChannel("TryReceiveChannel", channel);
1518 return TryReceiveChannel(ObjPtr(channel), obj);
1519 }
1520
CreateSemaphore(UInt count)1521 static Obj CreateSemaphore(UInt count)
1522 {
1523 Semaphore * sem;
1524 Bag semBag;
1525 semBag = NewBag(T_SEMAPHORE, sizeof(Semaphore));
1526 sem = ObjPtr(semBag);
1527 sem->monitor = NewMonitor();
1528 sem->count = count;
1529 sem->waiting = 0;
1530 return semBag;
1531 }
1532
FuncCreateSemaphore(Obj self,Obj args)1533 static Obj FuncCreateSemaphore(Obj self, Obj args)
1534 {
1535 Int count;
1536 switch (LEN_PLIST(args)) {
1537 case 0:
1538 count = 0;
1539 break;
1540 case 1:
1541 if (IS_INTOBJ(ELM_PLIST(args, 1))) {
1542 count = INT_INTOBJ(ELM_PLIST(args, 1));
1543 if (count < 0)
1544 return ArgumentError(
1545 "CreateSemaphore: Initial count must be non-negative");
1546 break;
1547 }
1548 return ArgumentError(
1549 "CreateSemaphore: Argument must be initial count");
1550 default:
1551 return ArgumentError(
1552 "CreateSemaphore: Function takes up to two arguments");
1553 }
1554 return CreateSemaphore(count);
1555 }
1556
FuncSignalSemaphore(Obj self,Obj semaphore)1557 static Obj FuncSignalSemaphore(Obj self, Obj semaphore)
1558 {
1559 Semaphore * sem;
1560 RequireSemaphore("SignalSemaphore", semaphore);
1561 sem = ObjPtr(semaphore);
1562 LockMonitor(ObjPtr(sem->monitor));
1563 sem->count++;
1564 if (sem->waiting)
1565 SignalMonitor(ObjPtr(sem->monitor));
1566 UnlockMonitor(ObjPtr(sem->monitor));
1567 return (Obj)0;
1568 }
1569
FuncWaitSemaphore(Obj self,Obj semaphore)1570 static Obj FuncWaitSemaphore(Obj self, Obj semaphore)
1571 {
1572 Semaphore * sem;
1573 RequireSemaphore("WaitSemaphore", semaphore);
1574 sem = ObjPtr(semaphore);
1575 LockMonitor(ObjPtr(sem->monitor));
1576 sem->waiting++;
1577 while (sem->count == 0)
1578 WaitForMonitor(ObjPtr(sem->monitor));
1579 sem->count--;
1580 sem->waiting--;
1581 if (sem->waiting && sem->count > 0)
1582 SignalMonitor(ObjPtr(sem->monitor));
1583 UnlockMonitor(ObjPtr(sem->monitor));
1584 return (Obj)0;
1585 }
1586
FuncTryWaitSemaphore(Obj self,Obj semaphore)1587 static Obj FuncTryWaitSemaphore(Obj self, Obj semaphore)
1588 {
1589 Semaphore * sem;
1590 int success;
1591 RequireSemaphore("TryWaitSemaphore", semaphore);
1592 sem = ObjPtr(semaphore);
1593 LockMonitor(ObjPtr(sem->monitor));
1594 success = (sem->count > 0);
1595 if (success)
1596 sem->count--;
1597 sem->waiting--;
1598 if (sem->waiting && sem->count > 0)
1599 SignalMonitor(ObjPtr(sem->monitor));
1600 UnlockMonitor(ObjPtr(sem->monitor));
1601 return success ? True : False;
1602 }
1603
LockBarrier(Barrier * barrier)1604 static void LockBarrier(Barrier * barrier)
1605 {
1606 LockMonitor(ObjPtr(barrier->monitor));
1607 }
1608
UnlockBarrier(Barrier * barrier)1609 static void UnlockBarrier(Barrier * barrier)
1610 {
1611 UnlockMonitor(ObjPtr(barrier->monitor));
1612 }
1613
JoinBarrier(Barrier * barrier)1614 static void JoinBarrier(Barrier * barrier)
1615 {
1616 barrier->waiting++;
1617 WaitForMonitor(ObjPtr(barrier->monitor));
1618 barrier->waiting--;
1619 }
1620
SignalBarrier(Barrier * barrier)1621 static void SignalBarrier(Barrier * barrier)
1622 {
1623 if (barrier->waiting)
1624 SignalMonitor(ObjPtr(barrier->monitor));
1625 }
1626
CreateBarrier(void)1627 static Obj CreateBarrier(void)
1628 {
1629 Bag barrierBag;
1630 Barrier * barrier;
1631 barrierBag = NewBag(T_BARRIER, sizeof(Barrier));
1632 barrier = ObjPtr(barrierBag);
1633 barrier->monitor = NewMonitor();
1634 barrier->count = 0;
1635 barrier->phase = 0;
1636 barrier->waiting = 0;
1637 return barrierBag;
1638 }
1639
StartBarrier(Barrier * barrier,UInt count)1640 static void StartBarrier(Barrier * barrier, UInt count)
1641 {
1642 LockBarrier(barrier);
1643 barrier->count = count;
1644 barrier->phase++;
1645 UnlockBarrier(barrier);
1646 }
1647
WaitBarrier(Barrier * barrier)1648 static void WaitBarrier(Barrier * barrier)
1649 {
1650 UInt phaseDelta;
1651 LockBarrier(barrier);
1652 phaseDelta = barrier->phase;
1653 if (--barrier->count > 0)
1654 JoinBarrier(barrier);
1655 SignalBarrier(barrier);
1656 phaseDelta -= barrier->phase;
1657 UnlockBarrier(barrier);
1658 if (phaseDelta != 0)
1659 ArgumentError("WaitBarrier: Barrier was reset");
1660 }
1661
FuncCreateBarrier(Obj self)1662 static Obj FuncCreateBarrier(Obj self)
1663 {
1664 return CreateBarrier();
1665 }
1666
IsBarrier(Obj obj)1667 static int IsBarrier(Obj obj)
1668 {
1669 return obj && TNUM_OBJ(obj) == T_BARRIER;
1670 }
1671
FuncStartBarrier(Obj self,Obj barrier,Obj count)1672 static Obj FuncStartBarrier(Obj self, Obj barrier, Obj count)
1673 {
1674 RequireBarrier("StartBarrier", barrier);
1675 Int c = GetSmallInt("StartBarrier", count);
1676 StartBarrier(ObjPtr(barrier), c);
1677 return (Obj)0;
1678 }
1679
FuncWaitBarrier(Obj self,Obj barrier)1680 static Obj FuncWaitBarrier(Obj self, Obj barrier)
1681 {
1682 RequireBarrier("WaitBarrier", barrier);
1683 WaitBarrier(ObjPtr(barrier));
1684 return (Obj)0;
1685 }
1686
SyncWrite(SyncVar * var,Obj value)1687 static void SyncWrite(SyncVar * var, Obj value)
1688 {
1689 Monitor * monitor = ObjPtr(var->monitor);
1690 LockMonitor(monitor);
1691 if (var->written) {
1692 UnlockMonitor(monitor);
1693 ArgumentError("SyncWrite: Variable already has a value");
1694 return;
1695 }
1696 var->written = 1;
1697 var->value = value;
1698 SignalMonitor(monitor);
1699 UnlockMonitor(monitor);
1700 }
1701
SyncTryWrite(SyncVar * var,Obj value)1702 static int SyncTryWrite(SyncVar * var, Obj value)
1703 {
1704 Monitor * monitor = ObjPtr(var->monitor);
1705 LockMonitor(monitor);
1706 if (var->written) {
1707 UnlockMonitor(monitor);
1708 return 0;
1709 }
1710 var->written = 1;
1711 var->value = value;
1712 SignalMonitor(monitor);
1713 UnlockMonitor(monitor);
1714 return 1;
1715 }
1716
CreateSyncVar(void)1717 static Obj CreateSyncVar(void)
1718 {
1719 Bag syncvarBag;
1720 SyncVar * syncvar;
1721 syncvarBag = NewBag(T_SYNCVAR, sizeof(SyncVar));
1722 syncvar = ObjPtr(syncvarBag);
1723 syncvar->monitor = NewMonitor();
1724 syncvar->written = 0;
1725 syncvar->value = (Obj)0;
1726 return syncvarBag;
1727 }
1728
1729
SyncRead(SyncVar * var)1730 static Obj SyncRead(SyncVar * var)
1731 {
1732 Monitor * monitor = ObjPtr(var->monitor);
1733 LockMonitor(monitor);
1734 while (!var->written)
1735 WaitForMonitor(monitor);
1736 if (monitor->head != NULL)
1737 SignalMonitor(monitor);
1738 UnlockMonitor(monitor);
1739 return var->value;
1740 }
1741
SyncIsBound(SyncVar * var)1742 static Obj SyncIsBound(SyncVar * var)
1743 {
1744 return var->value ? True : False;
1745 }
1746
IsSyncVar(Obj var)1747 static int IsSyncVar(Obj var)
1748 {
1749 return var && TNUM_OBJ(var) == T_SYNCVAR;
1750 }
1751
FuncCreateSyncVar(Obj self)1752 static Obj FuncCreateSyncVar(Obj self)
1753 {
1754 return CreateSyncVar();
1755 }
1756
FuncSyncWrite(Obj self,Obj syncvar,Obj value)1757 static Obj FuncSyncWrite(Obj self, Obj syncvar, Obj value)
1758 {
1759 RequireSyncVar("SyncWrite", syncvar);
1760 SyncWrite(ObjPtr(syncvar), value);
1761 return (Obj)0;
1762 }
1763
FuncSyncTryWrite(Obj self,Obj syncvar,Obj value)1764 static Obj FuncSyncTryWrite(Obj self, Obj syncvar, Obj value)
1765 {
1766 RequireSyncVar("SyncTryWrite", syncvar);
1767 return SyncTryWrite(ObjPtr(syncvar), value) ? True : False;
1768 }
1769
FuncSyncRead(Obj self,Obj syncvar)1770 static Obj FuncSyncRead(Obj self, Obj syncvar)
1771 {
1772 RequireSyncVar("SyncRead", syncvar);
1773 return SyncRead(ObjPtr(syncvar));
1774 }
1775
FuncSyncIsBound(Obj self,Obj syncvar)1776 static Obj FuncSyncIsBound(Obj self, Obj syncvar)
1777 {
1778 RequireSyncVar("SyncIsBound", syncvar);
1779 return SyncIsBound(ObjPtr(syncvar));
1780 }
1781
1782
PrintThread(Obj obj)1783 static void PrintThread(Obj obj)
1784 {
1785 char buf[100];
1786 const char * status_message;
1787 LockThreadControl(0);
1788 const ThreadObject *thread = (const ThreadObject *)CONST_ADDR_OBJ(obj);
1789 switch (thread->status) {
1790 case 0:
1791 status_message = "running";
1792 break;
1793 case THREAD_TERMINATED:
1794 status_message = "terminated";
1795 break;
1796 case THREAD_JOINED:
1797 status_message = "running, waited for";
1798 break;
1799 case THREAD_TERMINATED | THREAD_JOINED:
1800 status_message = "terminated, waited for";
1801 break;
1802 default:
1803 status_message = "unknown status";
1804 break;
1805 }
1806 sprintf(buf, "<thread #%ld: %s>", (long)thread->id, status_message);
1807 UnlockThreadControl();
1808 Pr("%s", (Int)buf, 0L);
1809 }
1810
PrintSemaphore(Obj obj)1811 static void PrintSemaphore(Obj obj)
1812 {
1813 Semaphore * sem = ObjPtr(obj);
1814 Int count;
1815 char buffer[100];
1816 LockMonitor(ObjPtr(sem->monitor));
1817 count = sem->count;
1818 UnlockMonitor(ObjPtr(sem->monitor));
1819 sprintf(buffer, "<semaphore %p: count = %ld>", (void *)sem, (long)count);
1820 Pr("%s", (Int)buffer, 0L);
1821 }
1822
PrintChannel(Obj obj)1823 static void PrintChannel(Obj obj)
1824 {
1825 Channel * channel = ObjPtr(obj);
1826 Int size, waiting, capacity;
1827 char buffer[20];
1828 Pr("<channel ", 0L, 0L);
1829 sprintf(buffer, "%p: ", (void *)channel);
1830 Pr(buffer, 0L, 0L);
1831 LockChannel(channel);
1832 size = channel->size;
1833 waiting = channel->waiting;
1834 if (channel->dynamic)
1835 capacity = -1;
1836 else
1837 capacity = channel->capacity;
1838 UnlockChannel(channel);
1839 if (capacity < 0)
1840 Pr("%d elements, %d waiting>", size / 2, waiting);
1841 else {
1842 Pr("%d/%d elements, ", size / 2, capacity / 2);
1843 Pr("%d waiting>", waiting, 0L);
1844 }
1845 }
1846
PrintBarrier(Obj obj)1847 static void PrintBarrier(Obj obj)
1848 {
1849 Barrier * barrier = ObjPtr(obj);
1850 Int count, waiting;
1851 char buffer[20];
1852 Pr("<barrier ", 0L, 0L);
1853 sprintf(buffer, "%p: ", (void *)barrier);
1854 Pr(buffer, 0L, 0L);
1855 LockBarrier(barrier);
1856 count = barrier->count;
1857 waiting = barrier->waiting;
1858 UnlockBarrier(barrier);
1859 Pr("%d of %d threads arrived>", waiting, count);
1860 }
1861
PrintSyncVar(Obj obj)1862 static void PrintSyncVar(Obj obj)
1863 {
1864 SyncVar * syncvar = ObjPtr(obj);
1865 char buffer[20];
1866 int written;
1867 LockMonitor(ObjPtr(syncvar->monitor));
1868 written = syncvar->written;
1869 UnlockMonitor(ObjPtr(syncvar->monitor));
1870 if (written)
1871 Pr("<initialized syncvar ", 0L, 0L);
1872 else
1873 Pr("<uninitialized syncvar ", 0L, 0L);
1874 sprintf(buffer, "%p>", (void *)syncvar);
1875 Pr(buffer, 0L, 0L);
1876 }
1877
PrintRegion(Obj obj)1878 static void PrintRegion(Obj obj)
1879 {
1880 char buffer[32];
1881 Region * region = GetRegionOf(obj);
1882 Obj name = GetRegionName(region);
1883
1884 if (name) {
1885 Pr("<region: %g", (Int)name, 0L);
1886 }
1887 else {
1888 snprintf(buffer, 32, "<region %p", (void *)GetRegionOf(obj));
1889 Pr(buffer, 0L, 0L);
1890 }
1891 if (region && region->count_active) {
1892 snprintf(buffer, 32, " (locked %zu/contended %zu)",
1893 region->locks_acquired, region->locks_contended);
1894 Pr(buffer, 0L, 0L);
1895 }
1896 Pr(">", 0L, 0L);
1897 }
1898
FuncIS_LOCKED(Obj self,Obj obj)1899 static Obj FuncIS_LOCKED(Obj self, Obj obj)
1900 {
1901 Region * region = IS_BAG_REF(obj) ? REGION(obj) : NULL;
1902 if (!region)
1903 return INTOBJ_INT(0);
1904 return INTOBJ_INT(IsLocked(region));
1905 }
1906
FuncLOCK(Obj self,Obj args)1907 static Obj FuncLOCK(Obj self, Obj args)
1908 {
1909 int numargs = LEN_PLIST(args);
1910 int count = 0;
1911 Obj * objects;
1912 LockMode * modes;
1913 LockMode mode = LOCK_MODE_DEFAULT;
1914 int i;
1915 int result;
1916
1917 if (numargs > 1024)
1918 return ArgumentError("LOCK: Too many arguments");
1919 objects = alloca(sizeof(Obj) * numargs);
1920 modes = alloca(sizeof(LockMode) * numargs);
1921 for (i = 1; i <= numargs; i++) {
1922 Obj obj;
1923 obj = ELM_PLIST(args, i);
1924 if (obj == True)
1925 mode = LOCK_MODE_READWRITE;
1926 else if (obj == False)
1927 mode = LOCK_MODE_READONLY;
1928 else {
1929 objects[count] = obj;
1930 modes[count] = mode;
1931 count++;
1932 }
1933 }
1934 result = LockObjects(count, objects, modes);
1935 if (result >= 0)
1936 return INTOBJ_INT(result);
1937 return Fail;
1938 }
1939
FuncDO_LOCK(Obj self,Obj args)1940 static Obj FuncDO_LOCK(Obj self, Obj args)
1941 {
1942 Obj result = FuncLOCK(self, args);
1943 if (result == Fail)
1944 ErrorMayQuit("Cannot lock required regions", 0L, 0L);
1945 return result;
1946 }
1947
FuncWRITE_LOCK(Obj self,Obj obj)1948 static Obj FuncWRITE_LOCK(Obj self, Obj obj)
1949 {
1950 const LockMode modes[] = { LOCK_MODE_READWRITE };
1951 int result = LockObjects(1, &obj, modes);
1952 if (result < 0)
1953 ErrorMayQuit("Cannot lock required regions", 0L, 0L);
1954 return INTOBJ_INT(result);
1955 }
1956
FuncREAD_LOCK(Obj self,Obj obj)1957 static Obj FuncREAD_LOCK(Obj self, Obj obj)
1958 {
1959 const LockMode modes[] = { LOCK_MODE_READONLY };
1960 int result = LockObjects(1, &obj, modes);
1961 if (result < 0)
1962 ErrorMayQuit("Cannot lock required regions", 0L, 0L);
1963 return INTOBJ_INT(result);
1964 }
1965
FuncTRYLOCK(Obj self,Obj args)1966 static Obj FuncTRYLOCK(Obj self, Obj args)
1967 {
1968 int numargs = LEN_PLIST(args);
1969 int count = 0;
1970 Obj * objects;
1971 LockMode * modes;
1972 LockMode mode = LOCK_MODE_DEFAULT;
1973 int i;
1974 int result;
1975
1976 if (numargs > 1024)
1977 return ArgumentError("TRYLOCK: Too many arguments");
1978 objects = alloca(sizeof(Obj) * numargs);
1979 modes = alloca(sizeof(int) * numargs);
1980 for (i = 1; i <= numargs; i++) {
1981 Obj obj;
1982 obj = ELM_PLIST(args, i);
1983 if (obj == True)
1984 mode = LOCK_MODE_READWRITE;
1985 else if (obj == False)
1986 mode = LOCK_MODE_READONLY;
1987 else {
1988 objects[count] = obj;
1989 modes[count] = mode;
1990 count++;
1991 }
1992 }
1993 result = TryLockObjects(count, objects, modes);
1994 if (result >= 0)
1995 return INTOBJ_INT(result);
1996 return Fail;
1997 }
1998
FuncUNLOCK(Obj self,Obj sp)1999 static Obj FuncUNLOCK(Obj self, Obj sp)
2000 {
2001 RequireNonnegativeSmallInt("UNLOCK", sp);
2002 PopRegionLocks(INT_INTOBJ(sp));
2003 return (Obj)0;
2004 }
2005
FuncCURRENT_LOCKS(Obj self)2006 static Obj FuncCURRENT_LOCKS(Obj self)
2007 {
2008 UInt i, len = TLS(lockStackPointer);
2009 Obj result = NEW_PLIST(T_PLIST, len);
2010 SET_LEN_PLIST(result, len);
2011 for (i = 1; i <= len; i++)
2012 SET_ELM_PLIST(result, i, ELM_PLIST(TLS(lockStack), i));
2013 return result;
2014 }
2015
2016 static int AutoRetyping = 0;
2017
2018 static int
MigrateObjects(int count,Obj * objects,Region * target,int retype)2019 MigrateObjects(int count, Obj * objects, Region * target, int retype)
2020 {
2021 int i;
2022 if (count && retype && IS_BAG_REF(objects[0]) &&
2023 REGION(objects[0])->owner == GetTLS() && AutoRetyping) {
2024 for (i = 0; i < count; i++)
2025 if (REGION(objects[i])->owner == GetTLS())
2026 CLEAR_OBJ_FLAG(objects[i], TESTED);
2027 for (i = 0; i < count; i++) {
2028 if (REGION(objects[i])->owner == GetTLS() &&
2029 IS_PLIST(objects[i])) {
2030 if (!TEST_OBJ_FLAG(objects[i], TESTED))
2031 TYPE_OBJ(objects[i]);
2032 if (retype >= 2)
2033 IsSet(objects[i]);
2034 }
2035 }
2036 }
2037 for (i = 0; i < count; i++) {
2038 Region * region;
2039 if (IS_BAG_REF(objects[i])) {
2040 region = REGION(objects[i]);
2041 if (!region || region->owner != GetTLS())
2042 return 0;
2043 }
2044 }
2045 for (i = 0; i < count; i++)
2046 SET_REGION(objects[i], target);
2047 return 1;
2048 }
2049
FuncREFINE_TYPE(Obj self,Obj obj)2050 static Obj FuncREFINE_TYPE(Obj self, Obj obj)
2051 {
2052 if (IS_BAG_REF(obj) && CheckExclusiveWriteAccess(obj)) {
2053 TYPE_OBJ(obj);
2054 }
2055 return obj;
2056 }
2057
FuncMAKE_PUBLIC_NORECURSE(Obj self,Obj obj)2058 static Obj FuncMAKE_PUBLIC_NORECURSE(Obj self, Obj obj)
2059 {
2060 if (!MigrateObjects(1, &obj, NULL, 0))
2061 return ArgumentError("MAKE_PUBLIC_NORECURSE: Thread does not have "
2062 "exclusive access to objects");
2063 return obj;
2064 }
2065
FuncFORCE_MAKE_PUBLIC(Obj self,Obj obj)2066 static Obj FuncFORCE_MAKE_PUBLIC(Obj self, Obj obj)
2067 {
2068 if (!IS_BAG_REF(obj))
2069 return ArgumentError("FORCE_MAKE_PUBLIC: Argument is a small integer "
2070 "or finite-field element");
2071 MakeBagPublic(obj);
2072 return obj;
2073 }
2074
FuncSHARE_NORECURSE(Obj self,Obj obj,Obj name,Obj prec)2075 static Obj FuncSHARE_NORECURSE(Obj self, Obj obj, Obj name, Obj prec)
2076 {
2077 Region * region = NewRegion();
2078 if (name != Fail && !IsStringConv(name))
2079 return ArgumentError(
2080 "SHARE_NORECURSE: Second argument must be a string or fail");
2081 Int p = GetSmallInt("SHARE_NORECURSE", prec);
2082 region->prec = p;
2083 if (!MigrateObjects(1, &obj, region, 0))
2084 return ArgumentError("SHARE_NORECURSE: Thread does not have "
2085 "exclusive access to objects");
2086 if (name != Fail)
2087 SetRegionName(region, name);
2088 return obj;
2089 }
2090
FuncMIGRATE_NORECURSE(Obj self,Obj obj,Obj target)2091 static Obj FuncMIGRATE_NORECURSE(Obj self, Obj obj, Obj target)
2092 {
2093 Region * target_region = GetRegionOf(target);
2094 if (!target_region ||
2095 IsLocked(target_region) != LOCK_STATUS_READWRITE_LOCKED)
2096 return ArgumentError("MIGRATE_NORECURSE: Thread does not have "
2097 "exclusive access to target region");
2098 if (!MigrateObjects(1, &obj, target_region, 0))
2099 return ArgumentError("MIGRATE_NORECURSE: Thread does not have "
2100 "exclusive access to object");
2101 return obj;
2102 }
2103
FuncADOPT_NORECURSE(Obj self,Obj obj)2104 static Obj FuncADOPT_NORECURSE(Obj self, Obj obj)
2105 {
2106 if (!MigrateObjects(1, &obj, TLS(threadRegion), 0))
2107 return ArgumentError("ADOPT_NORECURSE: Thread does not have "
2108 "exclusive access to objects");
2109 return obj;
2110 }
2111
FuncREACHABLE(Obj self,Obj obj)2112 static Obj FuncREACHABLE(Obj self, Obj obj)
2113 {
2114 Obj result = ReachableObjectsFrom(obj);
2115 if (result == NULL) {
2116 result = NEW_PLIST(T_PLIST, 1);
2117 SET_LEN_PLIST(result, 1);
2118 SET_ELM_PLIST(result, 1, obj);
2119 }
2120 return result;
2121 }
2122
FuncCLONE_REACHABLE(Obj self,Obj obj)2123 static Obj FuncCLONE_REACHABLE(Obj self, Obj obj)
2124 {
2125 return CopyReachableObjectsFrom(obj, 0, 0, 0);
2126 }
2127
FuncCLONE_DELIMITED(Obj self,Obj obj)2128 static Obj FuncCLONE_DELIMITED(Obj self, Obj obj)
2129 {
2130 return CopyReachableObjectsFrom(obj, 1, 0, 0);
2131 }
2132
FuncNEW_REGION(Obj self,Obj name,Obj prec)2133 static Obj FuncNEW_REGION(Obj self, Obj name, Obj prec)
2134 {
2135 Region * region = NewRegion();
2136 if (name != Fail && !IsStringConv(name))
2137 return ArgumentError(
2138 "NEW_REGION: Second argument must be a string or fail");
2139 Int p = GetSmallInt("NEW_REGION", prec);
2140 region->prec = p;
2141 if (name != Fail)
2142 SetRegionName(region, name);
2143 return region->obj;
2144 }
2145
FuncREGION_PRECEDENCE(Obj self,Obj regobj)2146 static Obj FuncREGION_PRECEDENCE(Obj self, Obj regobj)
2147 {
2148 Region * region = GetRegionOf(regobj);
2149 return region == NULL ? INTOBJ_INT(0) : INTOBJ_INT(region->prec);
2150 }
2151
FuncSHARE(Obj self,Obj obj,Obj name,Obj prec)2152 static Obj FuncSHARE(Obj self, Obj obj, Obj name, Obj prec)
2153 {
2154 Region * region = NewRegion();
2155 Obj reachable;
2156 if (name != Fail && !IsStringConv(name))
2157 return ArgumentError(
2158 "SHARE: Second argument must be a string or fail");
2159 Int p = GetSmallInt("SHARE", prec);
2160 region->prec = p;
2161 reachable = ReachableObjectsFrom(obj);
2162 if (!MigrateObjects(LEN_PLIST(reachable), ADDR_OBJ(reachable) + 1, region,
2163 1))
2164 return ArgumentError(
2165 "SHARE: Thread does not have exclusive access to objects");
2166 if (name != Fail)
2167 SetRegionName(region, name);
2168 return obj;
2169 }
2170
FuncSHARE_RAW(Obj self,Obj obj,Obj name,Obj prec)2171 static Obj FuncSHARE_RAW(Obj self, Obj obj, Obj name, Obj prec)
2172 {
2173 Region * region = NewRegion();
2174 Obj reachable;
2175 if (name != Fail && !IsStringConv(name))
2176 return ArgumentError(
2177 "SHARE_RAW: Second argument must be a string or fail");
2178 Int p = GetSmallInt("SHARE_RAW", prec);
2179 region->prec = p;
2180 reachable = ReachableObjectsFrom(obj);
2181 if (!MigrateObjects(LEN_PLIST(reachable), ADDR_OBJ(reachable) + 1, region,
2182 0))
2183 return ArgumentError(
2184 "SHARE_RAW: Thread does not have exclusive access to objects");
2185 if (name != Fail)
2186 SetRegionName(region, name);
2187 return obj;
2188 }
2189
FuncADOPT(Obj self,Obj obj)2190 static Obj FuncADOPT(Obj self, Obj obj)
2191 {
2192 Obj reachable = ReachableObjectsFrom(obj);
2193 if (!MigrateObjects(LEN_PLIST(reachable), ADDR_OBJ(reachable) + 1,
2194 TLS(threadRegion), 0))
2195 return ArgumentError(
2196 "ADOPT: Thread does not have exclusive access to objects");
2197 return obj;
2198 }
2199
FuncMAKE_PUBLIC(Obj self,Obj obj)2200 static Obj FuncMAKE_PUBLIC(Obj self, Obj obj)
2201 {
2202 Obj reachable = ReachableObjectsFrom(obj);
2203 if (!MigrateObjects(LEN_PLIST(reachable), ADDR_OBJ(reachable) + 1, NULL,
2204 0))
2205 return ArgumentError(
2206 "MAKE_PUBLIC: Thread does not have exclusive access to objects");
2207 return obj;
2208 }
2209
FuncMIGRATE(Obj self,Obj obj,Obj target)2210 static Obj FuncMIGRATE(Obj self, Obj obj, Obj target)
2211 {
2212 Region * target_region = GetRegionOf(target);
2213 Obj reachable;
2214 if (!target_region ||
2215 IsLocked(target_region) != LOCK_STATUS_READWRITE_LOCKED)
2216 return ArgumentError("MIGRATE: Thread does not have exclusive access "
2217 "to target region");
2218 reachable = ReachableObjectsFrom(obj);
2219 if (!MigrateObjects(LEN_PLIST(reachable), ADDR_OBJ(reachable) + 1,
2220 target_region, 1))
2221 return ArgumentError(
2222 "MIGRATE: Thread does not have exclusive access to objects");
2223 return obj;
2224 }
2225
FuncMIGRATE_RAW(Obj self,Obj obj,Obj target)2226 static Obj FuncMIGRATE_RAW(Obj self, Obj obj, Obj target)
2227 {
2228 Region * target_region = GetRegionOf(target);
2229 Obj reachable;
2230 if (!target_region ||
2231 IsLocked(target_region) != LOCK_STATUS_READWRITE_LOCKED)
2232 return ArgumentError("MIGRATE: Thread does not have exclusive access "
2233 "to target region");
2234 reachable = ReachableObjectsFrom(obj);
2235 if (!MigrateObjects(LEN_PLIST(reachable), ADDR_OBJ(reachable) + 1,
2236 target_region, 0))
2237 return ArgumentError(
2238 "MIGRATE: Thread does not have exclusive access to objects");
2239 return obj;
2240 }
2241
FuncMakeThreadLocal(Obj self,Obj var)2242 static Obj FuncMakeThreadLocal(Obj self, Obj var)
2243 {
2244 char * name;
2245 UInt gvar;
2246 if (!IsStringConv(var) || GET_LEN_STRING(var) == 0)
2247 return ArgumentError(
2248 "MakeThreadLocal: Argument must be a variable name");
2249 name = CSTR_STRING(var);
2250 gvar = GVarName(name);
2251 name = CSTR_STRING(NameGVar(gvar)); /* to apply namespace scopes where needed. */
2252 MakeThreadLocalVar(gvar, RNamName(name));
2253 return (Obj)0;
2254 }
2255
FuncMakeReadOnlyObj(Obj self,Obj obj)2256 static Obj FuncMakeReadOnlyObj(Obj self, Obj obj)
2257 {
2258 Region * region = GetRegionOf(obj);
2259 Obj reachable;
2260 if (!region || region == ReadOnlyRegion)
2261 return obj;
2262 reachable = ReachableObjectsFrom(obj);
2263 if (!MigrateObjects(LEN_PLIST(reachable), ADDR_OBJ(reachable) + 1,
2264 ReadOnlyRegion, 1))
2265 return ArgumentError(
2266 "MakeReadOnlyObj: Thread does not have exclusive access to objects");
2267 return obj;
2268 }
2269
FuncMakeReadOnlyRaw(Obj self,Obj obj)2270 static Obj FuncMakeReadOnlyRaw(Obj self, Obj obj)
2271 {
2272 Region * region = GetRegionOf(obj);
2273 Obj reachable;
2274 if (!region || region == ReadOnlyRegion)
2275 return obj;
2276 reachable = ReachableObjectsFrom(obj);
2277 if (!MigrateObjects(LEN_PLIST(reachable), ADDR_OBJ(reachable) + 1,
2278 ReadOnlyRegion, 0))
2279 return ArgumentError(
2280 "MakeReadOnlyObj: Thread does not have exclusive access to objects");
2281 return obj;
2282 }
2283
FuncMakeReadOnlySingleObj(Obj self,Obj obj)2284 static Obj FuncMakeReadOnlySingleObj(Obj self, Obj obj)
2285 {
2286 Region * region = GetRegionOf(obj);
2287 if (!region || region == ReadOnlyRegion)
2288 return obj;
2289 if (!MigrateObjects(1, &obj, ReadOnlyRegion, 0))
2290 return ArgumentError("MakeReadOnlySingleObj: Thread does not have "
2291 "exclusive access to object");
2292 return obj;
2293 }
2294
FuncIsReadOnlyObj(Obj self,Obj obj)2295 static Obj FuncIsReadOnlyObj(Obj self, Obj obj)
2296 {
2297 Region * region = GetRegionOf(obj);
2298 return (region == ReadOnlyRegion) ? True : False;
2299 }
2300
FuncENABLE_AUTO_RETYPING(Obj self)2301 static Obj FuncENABLE_AUTO_RETYPING(Obj self)
2302 {
2303 AutoRetyping = 1;
2304 return (Obj)0;
2305 }
2306
FuncORDERED_READ(Obj self,Obj obj)2307 static Obj FuncORDERED_READ(Obj self, Obj obj)
2308 {
2309 MEMBAR_READ();
2310 return obj;
2311 }
2312
FuncORDERED_WRITE(Obj self,Obj obj)2313 static Obj FuncORDERED_WRITE(Obj self, Obj obj)
2314 {
2315 MEMBAR_WRITE();
2316 return obj;
2317 }
2318
FuncDEFAULT_SIGINT_HANDLER(Obj self)2319 static Obj FuncDEFAULT_SIGINT_HANDLER(Obj self)
2320 {
2321 /* do nothing */
2322 return (Obj)0;
2323 }
2324
2325 static UInt SigVTALRMCounter = 0;
2326
FuncDEFAULT_SIGVTALRM_HANDLER(Obj self)2327 static Obj FuncDEFAULT_SIGVTALRM_HANDLER(Obj self)
2328 {
2329 SigVTALRMCounter++;
2330 return (Obj)0;
2331 }
2332
2333 #ifdef SIGWINCH
2334 extern void syWindowChangeIntr(int signr);
2335 #endif
2336
FuncDEFAULT_SIGWINCH_HANDLER(Obj self)2337 static Obj FuncDEFAULT_SIGWINCH_HANDLER(Obj self)
2338 {
2339 #ifdef SIGWINCH
2340 syWindowChangeIntr(SIGWINCH);
2341 #endif
2342 return (Obj)0;
2343 }
2344
HandleSignal(Obj handlers,UInt rnam)2345 static void HandleSignal(Obj handlers, UInt rnam)
2346 {
2347 Obj func = ELM_REC(handlers, rnam);
2348 if (!func || TNUM_OBJ(func) != T_FUNCTION || NARG_FUNC(func) > 0)
2349 return;
2350 CALL_0ARGS(func);
2351 }
2352
2353 static sigset_t GAPSignals;
2354
FuncSIGWAIT(Obj self,Obj handlers)2355 static Obj FuncSIGWAIT(Obj self, Obj handlers)
2356 {
2357 int sig;
2358 if (!IS_REC(handlers))
2359 return ArgumentError("SIGWAIT: Argument must be a record");
2360 if (sigwait(&GAPSignals, &sig) >= 0) {
2361 switch (sig) {
2362 case SIGINT:
2363 HandleSignal(handlers, RNAM_SIGINT);
2364 break;
2365 case SIGCHLD:
2366 HandleSignal(handlers, RNAM_SIGCHLD);
2367 break;
2368 case SIGVTALRM:
2369 HandleSignal(handlers, RNAM_SIGVTALRM);
2370 break;
2371 #ifdef SIGWINCH
2372 case SIGWINCH:
2373 HandleSignal(handlers, RNAM_SIGWINCH);
2374 break;
2375 #endif
2376 }
2377 }
2378 return (Obj)0;
2379 }
2380
InitSignals(void)2381 void InitSignals(void)
2382 {
2383 struct itimerval timer;
2384 sigemptyset(&GAPSignals);
2385 sigaddset(&GAPSignals, SIGINT);
2386 sigaddset(&GAPSignals, SIGCHLD);
2387 sigaddset(&GAPSignals, SIGVTALRM);
2388 #ifdef SIGWINCH
2389 sigaddset(&GAPSignals, SIGWINCH);
2390 #endif
2391 pthread_sigmask(SIG_BLOCK, &GAPSignals, NULL);
2392 /* Run a timer signal every 10 ms, i.e. 100 times per second */
2393 timer.it_interval.tv_sec = 0;
2394 timer.it_interval.tv_usec = 10000;
2395 timer.it_value.tv_sec = 0;
2396 timer.it_value.tv_usec = 10000;
2397 setitimer(ITIMER_VIRTUAL, &timer, NULL);
2398 }
2399
FuncPERIODIC_CHECK(Obj self,Obj count,Obj func)2400 static Obj FuncPERIODIC_CHECK(Obj self, Obj count, Obj func)
2401 {
2402 UInt n;
2403 RequireNonnegativeSmallInt("PERIODIC_CHECK", count);
2404 RequireFunction("PERIODIC_CHECK", func);
2405 /*
2406 * The following read of SigVTALRMCounter is a dirty read. We don't
2407 * need to synchronize access to it because it's a monotonically
2408 * increasing value and we only need it to succeed eventually.
2409 */
2410 n = INT_INTOBJ(count) / 10;
2411 if (TLS(PeriodicCheckCount) + n < SigVTALRMCounter) {
2412 TLS(PeriodicCheckCount) = SigVTALRMCounter;
2413 CALL_0ARGS(func);
2414 }
2415 return (Obj)0;
2416 }
2417
2418
2419 /*
2420 * Region lock performance counters
2421 */
FuncREGION_COUNTERS_ENABLE(Obj self,Obj obj)2422 static Obj FuncREGION_COUNTERS_ENABLE(Obj self, Obj obj)
2423 {
2424 Region * region = GetRegionOf(obj);
2425
2426 if (!region)
2427 return ArgumentError(
2428 "REGION_COUNTERS_ENABLE: Cannot enable counters for this region");
2429
2430 region->count_active = 1;
2431 return (Obj)0;
2432 }
2433
FuncREGION_COUNTERS_DISABLE(Obj self,Obj obj)2434 static Obj FuncREGION_COUNTERS_DISABLE(Obj self, Obj obj)
2435 {
2436 Region * region = GetRegionOf(obj);
2437
2438 if (!region)
2439 return ArgumentError("REGION_COUNTERS_DISABLE: Cannot disable "
2440 "counters for this region");
2441
2442 region->count_active = 0;
2443 return (Obj)0;
2444 }
2445
FuncREGION_COUNTERS_GET_STATE(Obj self,Obj obj)2446 static Obj FuncREGION_COUNTERS_GET_STATE(Obj self, Obj obj)
2447 {
2448 Obj result;
2449 Region * region = GetRegionOf(obj);
2450
2451 if (!region)
2452 return ArgumentError(
2453 "REGION_COUNTERS_GET_STATE: Cannot get counters for this region");
2454
2455 result = INTOBJ_INT(region->count_active);
2456
2457 return result;
2458 }
2459
FuncREGION_COUNTERS_GET(Obj self,Obj obj)2460 static Obj FuncREGION_COUNTERS_GET(Obj self, Obj obj)
2461 {
2462 Region * region = GetRegionOf(obj);
2463
2464 if (!region)
2465 return ArgumentError(
2466 "REGION_COUNTERS_GET: Cannot get counters for this region");
2467
2468 return GetRegionLockCounters(region);
2469 }
2470
FuncREGION_COUNTERS_RESET(Obj self,Obj obj)2471 static Obj FuncREGION_COUNTERS_RESET(Obj self, Obj obj)
2472 {
2473 Region * region = GetRegionOf(obj);
2474
2475 if (!region)
2476 return ArgumentError(
2477 "REGION_COUNTERS_RESET: Cannot reset counters for this region");
2478
2479 ResetRegionLockCounters(region);
2480
2481 return (Obj)0;
2482 }
2483
FuncTHREAD_COUNTERS_ENABLE(Obj self)2484 static Obj FuncTHREAD_COUNTERS_ENABLE(Obj self)
2485 {
2486 TLS(CountActive) = 1;
2487
2488 return (Obj)0;
2489 }
2490
FuncTHREAD_COUNTERS_DISABLE(Obj self)2491 static Obj FuncTHREAD_COUNTERS_DISABLE(Obj self)
2492 {
2493 TLS(CountActive) = 0;
2494
2495 return (Obj)0;
2496 }
2497
FuncTHREAD_COUNTERS_GET_STATE(Obj self)2498 static Obj FuncTHREAD_COUNTERS_GET_STATE(Obj self)
2499 {
2500 Obj result;
2501
2502 result = INTOBJ_INT(TLS(CountActive));
2503
2504 return result;
2505 }
2506
FuncTHREAD_COUNTERS_RESET(Obj self)2507 static Obj FuncTHREAD_COUNTERS_RESET(Obj self)
2508 {
2509 TLS(LocksAcquired) = TLS(LocksContended) = 0;
2510
2511 return (Obj)0;
2512 }
2513
FuncTHREAD_COUNTERS_GET(Obj self)2514 static Obj FuncTHREAD_COUNTERS_GET(Obj self)
2515 {
2516 Obj result;
2517
2518 result = NEW_PLIST(T_PLIST, 2);
2519 SET_LEN_PLIST(result, 2);
2520 SET_ELM_PLIST(result, 1, INTOBJ_INT(TLS(LocksAcquired)));
2521 SET_ELM_PLIST(result, 2, INTOBJ_INT(TLS(LocksContended)));
2522
2523 return result;
2524 }
2525
2526
2527 /****************************************************************************
2528 **
2529 *F * * * * * * * * * * * * * initialize module * * * * * * * * * * * * * * *
2530 */
2531
2532
2533 /****************************************************************************
2534 **
2535 *V BagNames . . . . . . . . . . . . . . . . . . . . . . . list of bag names
2536 */
2537 static StructBagNames BagNames[] = {
2538 // install info string
2539 { T_THREAD, "thread" },
2540 { T_MONITOR, "monitor" },
2541 { T_REGION, "region" },
2542 { T_SEMAPHORE, "semaphore" },
2543 { T_CHANNEL, "channel" },
2544 { T_BARRIER, "barrier" },
2545 { T_SYNCVAR, "syncvar" },
2546 { -1, "" }
2547 };
2548
2549
2550 /****************************************************************************
2551 **
2552 *V GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export
2553 */
2554 static StructGVarFunc GVarFuncs[] = {
2555
2556 GVAR_FUNC(CreateThread, -1, "function"),
2557 GVAR_FUNC(CurrentThread, 0, ""),
2558 GVAR_FUNC(ThreadID, 1, "thread"),
2559 GVAR_FUNC(WaitThread, 1, "thread"),
2560 GVAR_FUNC(KillThread, 1, "thread"),
2561 GVAR_FUNC(InterruptThread, 2, "thread, handler"),
2562 GVAR_FUNC(SetInterruptHandler, 2, "handler, function"),
2563 GVAR_FUNC(PauseThread, 1, "thread"),
2564 GVAR_FUNC(ResumeThread, 1, "thread"),
2565 GVAR_FUNC(HASH_LOCK, 1, "object"),
2566 GVAR_FUNC(HASH_LOCK_SHARED, 1, "object"),
2567 GVAR_FUNC(HASH_UNLOCK, 1, "object"),
2568 GVAR_FUNC(HASH_UNLOCK_SHARED, 1, "object"),
2569 GVAR_FUNC(HASH_SYNCHRONIZED, 2, "object, function"),
2570 GVAR_FUNC(HASH_SYNCHRONIZED_SHARED, 2, "object, function"),
2571 GVAR_FUNC(RegionOf, 1, "object"),
2572 GVAR_FUNC(SetRegionName, 2, "obj, name"),
2573 GVAR_FUNC(ClearRegionName, 1, "obj"),
2574 GVAR_FUNC(RegionName, 1, "obj"),
2575 GVAR_FUNC(WITH_TARGET_REGION, 2, "region, function"),
2576 GVAR_FUNC(IsShared, 1, "object"),
2577 GVAR_FUNC(IsPublic, 1, "object"),
2578 GVAR_FUNC(IsThreadLocal, 1, "object"),
2579 GVAR_FUNC(HaveWriteAccess, 1, "object"),
2580 GVAR_FUNC(HaveReadAccess, 1, "object"),
2581 GVAR_FUNC(CreateSemaphore, -1, "[count]"),
2582 GVAR_FUNC(SignalSemaphore, 1, "semaphore"),
2583 GVAR_FUNC(WaitSemaphore, 1, "semaphore"),
2584 GVAR_FUNC(TryWaitSemaphore, 1, "semaphore"),
2585 GVAR_FUNC(CreateChannel, -1, "[size]"),
2586 GVAR_FUNC(DestroyChannel, 1, "channel"),
2587 GVAR_FUNC(TallyChannel, 1, "channel"),
2588 GVAR_FUNC(SendChannel, 2, "channel, obj"),
2589 GVAR_FUNC(TransmitChannel, 2, "channel, obj"),
2590 GVAR_FUNC(ReceiveChannel, 1, "channel"),
2591 GVAR_FUNC(ReceiveAnyChannel, -1, "channel list"),
2592 GVAR_FUNC(ReceiveAnyChannelWithIndex, -1, "channel list"),
2593 GVAR_FUNC(MultiReceiveChannel, 2, "channel, count"),
2594 GVAR_FUNC(TryReceiveChannel, 2, "channel, obj"),
2595 GVAR_FUNC(MultiSendChannel, 2, "channel, list"),
2596 GVAR_FUNC(TryMultiSendChannel, 2, "channel, list"),
2597 GVAR_FUNC(TrySendChannel, 2, "channel, obj"),
2598 GVAR_FUNC(MultiTransmitChannel, 2, "channel, list"),
2599 GVAR_FUNC(TryMultiTransmitChannel, 2, "channel, list"),
2600 GVAR_FUNC(TryTransmitChannel, 2, "channel, obj"),
2601 GVAR_FUNC(InspectChannel, 1, "channel"),
2602 GVAR_FUNC(CreateBarrier, 0, ""),
2603 GVAR_FUNC(StartBarrier, 2, "barrier, count"),
2604 GVAR_FUNC(WaitBarrier, 1, "barrier"),
2605 GVAR_FUNC(CreateSyncVar, 0, ""),
2606 GVAR_FUNC(SyncWrite, 2, "syncvar, obj"),
2607 GVAR_FUNC(SyncTryWrite, 2, "syncvar, obj"),
2608 GVAR_FUNC(SyncRead, 1, "syncvar"),
2609 GVAR_FUNC(SyncIsBound, 1, "syncvar"),
2610 GVAR_FUNC(IS_LOCKED, 1, "obj"),
2611 GVAR_FUNC(LOCK, -1, "obj, ..."),
2612 GVAR_FUNC(DO_LOCK, -1, "obj, ..."),
2613 GVAR_FUNC(WRITE_LOCK, 1, "obj"),
2614 GVAR_FUNC(READ_LOCK, 1, "obj"),
2615 GVAR_FUNC(TRYLOCK, -1, "obj, ..."),
2616 GVAR_FUNC(UNLOCK, 1, "sp"),
2617 GVAR_FUNC(CURRENT_LOCKS, 0, ""),
2618 GVAR_FUNC(REFINE_TYPE, 1, "obj"),
2619 GVAR_FUNC(SHARE_NORECURSE, 3, "obj, string, integer"),
2620 GVAR_FUNC(ADOPT_NORECURSE, 1, "obj"),
2621 GVAR_FUNC(MIGRATE_NORECURSE, 2, "obj, target"),
2622 GVAR_FUNC(NEW_REGION, 2, "string, integer"),
2623 GVAR_FUNC(REGION_PRECEDENCE, 1, "obj"),
2624 GVAR_FUNC(SHARE, 3, "obj, string, integer"),
2625 GVAR_FUNC(SHARE_RAW, 3, "obj, string, integer"),
2626 GVAR_FUNC(ADOPT, 1, "obj"),
2627 GVAR_FUNC(MIGRATE, 2, "obj, target"),
2628 GVAR_FUNC(MIGRATE_RAW, 2, "obj, target"),
2629 GVAR_FUNC(MAKE_PUBLIC_NORECURSE, 1, "obj"),
2630 GVAR_FUNC(MAKE_PUBLIC, 1, "obj"),
2631 GVAR_FUNC(FORCE_MAKE_PUBLIC, 1, "obj"),
2632 GVAR_FUNC(REACHABLE, 1, "obj"),
2633 GVAR_FUNC(CLONE_REACHABLE, 1, "obj"),
2634 GVAR_FUNC(CLONE_DELIMITED, 1, "obj"),
2635 GVAR_FUNC(MakeThreadLocal, 1, "var"),
2636 GVAR_FUNC(MakeReadOnlyObj, 1, "obj"),
2637 GVAR_FUNC(MakeReadOnlyRaw, 1, "obj"),
2638 GVAR_FUNC(MakeReadOnlySingleObj, 1, "obj"),
2639 GVAR_FUNC(IsReadOnlyObj, 1, "obj"),
2640 GVAR_FUNC(ENABLE_AUTO_RETYPING, 0, ""),
2641 GVAR_FUNC(ORDERED_READ, 1, "obj"),
2642 GVAR_FUNC(ORDERED_WRITE, 1, "obj"),
2643 GVAR_FUNC(CREATOR_OF, 1, "obj"),
2644 GVAR_FUNC(DISABLE_GUARDS, 1, "flag"),
2645 GVAR_FUNC(DEFAULT_SIGINT_HANDLER, 0, ""),
2646 GVAR_FUNC(DEFAULT_SIGVTALRM_HANDLER, 0, ""),
2647 GVAR_FUNC(DEFAULT_SIGWINCH_HANDLER, 0, ""),
2648 GVAR_FUNC(SIGWAIT, 1, "record"),
2649 GVAR_FUNC(PERIODIC_CHECK, 2, "count, function"),
2650 GVAR_FUNC(REGION_COUNTERS_ENABLE, 1, "region"),
2651 GVAR_FUNC(REGION_COUNTERS_DISABLE, 1, "region"),
2652 GVAR_FUNC(REGION_COUNTERS_GET_STATE, 1, "region"),
2653 GVAR_FUNC(REGION_COUNTERS_GET, 1, "region"),
2654 GVAR_FUNC(REGION_COUNTERS_RESET, 1, "region"),
2655 GVAR_FUNC(THREAD_COUNTERS_ENABLE, 0, ""),
2656 GVAR_FUNC(THREAD_COUNTERS_DISABLE, 0, ""),
2657 GVAR_FUNC(THREAD_COUNTERS_GET_STATE, 0, ""),
2658 GVAR_FUNC(THREAD_COUNTERS_GET, 0, ""),
2659 GVAR_FUNC(THREAD_COUNTERS_RESET, 0, ""),
2660 { 0, 0, 0, 0, 0 }
2661
2662 };
2663
2664
2665 /****************************************************************************
2666 **
2667 *F InitKernel( <module> ) . . . . . . . . initialise kernel data structures
2668 */
InitKernel(StructInitInfo * module)2669 static Int InitKernel(StructInitInfo * module)
2670 {
2671 // set the bag type names (for error messages and debugging)
2672 InitBagNamesFromTable(BagNames);
2673
2674 // install the type methods
2675 TypeObjFuncs[T_THREAD] = TypeThread;
2676 TypeObjFuncs[T_REGION] = TypeRegion;
2677 TypeObjFuncs[T_SEMAPHORE] = TypeSemaphore;
2678 TypeObjFuncs[T_CHANNEL] = TypeChannel;
2679 TypeObjFuncs[T_BARRIER] = TypeBarrier;
2680 TypeObjFuncs[T_SYNCVAR] = TypeSyncVar;
2681
2682 // install global variables
2683 InitCopyGVar("TYPE_THREAD", &TYPE_THREAD);
2684 InitCopyGVar("TYPE_REGION", &TYPE_REGION);
2685 InitCopyGVar("TYPE_SEMAPHORE", &TYPE_SEMAPHORE);
2686 InitCopyGVar("TYPE_CHANNEL", &TYPE_CHANNEL);
2687 InitCopyGVar("TYPE_BARRIER", &TYPE_BARRIER);
2688 InitCopyGVar("TYPE_SYNCVAR", &TYPE_SYNCVAR);
2689
2690 DeclareGVar(&LastInaccessibleGVar, "LastInaccessible");
2691 DeclareGVar(&MAX_INTERRUPTGVar, "MAX_INTERRUPT");
2692
2693 // install mark functions
2694 InitMarkFuncBags(T_THREAD, MarkNoSubBags);
2695 InitMarkFuncBags(T_MONITOR, MarkNoSubBags);
2696 InitMarkFuncBags(T_REGION, MarkAllSubBags);
2697 #ifdef USE_GASMAN
2698 InitMarkFuncBags(T_SEMAPHORE, MarkSemaphoreBag);
2699 InitMarkFuncBags(T_CHANNEL, MarkChannelBag);
2700 InitMarkFuncBags(T_BARRIER, MarkBarrierBag);
2701 InitMarkFuncBags(T_SYNCVAR, MarkSyncVarBag);
2702 #endif
2703
2704 // install finalizer functions
2705 InitFreeFuncBag(T_MONITOR, FinalizeMonitor);
2706
2707 // install print functions
2708 PrintObjFuncs[T_THREAD] = PrintThread;
2709 PrintObjFuncs[T_REGION] = PrintRegion;
2710 PrintObjFuncs[T_SEMAPHORE] = PrintSemaphore;
2711 PrintObjFuncs[T_CHANNEL] = PrintChannel;
2712 PrintObjFuncs[T_BARRIER] = PrintBarrier;
2713 PrintObjFuncs[T_SYNCVAR] = PrintSyncVar;
2714
2715 // install mutability functions
2716 IsMutableObjFuncs[T_THREAD] = AlwaysNo;
2717 IsMutableObjFuncs[T_REGION] = AlwaysYes;
2718 IsMutableObjFuncs[T_SEMAPHORE] = AlwaysYes;
2719 IsMutableObjFuncs[T_CHANNEL] = AlwaysYes;
2720 IsMutableObjFuncs[T_BARRIER] = AlwaysYes;
2721 IsMutableObjFuncs[T_SYNCVAR] = AlwaysYes;
2722
2723 // make bag types public
2724 MakeBagTypePublic(T_THREAD);
2725 MakeBagTypePublic(T_REGION);
2726 MakeBagTypePublic(T_SEMAPHORE);
2727 MakeBagTypePublic(T_CHANNEL);
2728 MakeBagTypePublic(T_SYNCVAR);
2729 MakeBagTypePublic(T_BARRIER);
2730
2731 PublicRegion = NewBag(T_REGION, sizeof(Region *));
2732
2733 #ifdef HPCGAP
2734 DeclareGVar(&GVarTHREAD_INIT, "THREAD_INIT");
2735 DeclareGVar(&GVarTHREAD_EXIT, "THREAD_EXIT");
2736 #endif
2737
2738 return 0;
2739 }
2740
2741
2742 /****************************************************************************
2743 **
2744 *F InitLibrary( <module> ) . . . . . . . initialise library data structures
2745 */
InitLibrary(StructInitInfo * module)2746 static Int InitLibrary(StructInitInfo * module)
2747 {
2748 /* init filters and functions */
2749 InitGVarFuncsFromTable(GVarFuncs);
2750 SetGVar(&MAX_INTERRUPTGVar, INTOBJ_INT(MAX_INTERRUPT));
2751 MakeReadOnlyGVar(GVarName("MAX_INTERRUPT"));
2752 /* define signal handler values */
2753 RNAM_SIGINT = RNamName("SIGINT");
2754 RNAM_SIGCHLD = RNamName("SIGCHLD");
2755 RNAM_SIGVTALRM = RNamName("SIGVTALRM");
2756 #ifdef SIGWINCH
2757 RNAM_SIGWINCH = RNamName("SIGWINCH");
2758 #endif
2759
2760 /* synchronization */
2761 pthread_mutex_init(&KeepAliveLock, NULL);
2762
2763 /* return success */
2764 return 0;
2765 }
2766
2767
2768 /****************************************************************************
2769 **
2770 *F InitInfoThreadAPI() . . . . . . . . . . . . . . . table of init functions
2771 */
2772 static StructInitInfo module = {
2773 // init struct using C99 designated initializers; for a full list of
2774 // fields, please refer to the definition of StructInitInfo
2775 .type = MODULE_BUILTIN,
2776 .name = "threadapi",
2777 .initKernel = InitKernel,
2778 .initLibrary = InitLibrary,
2779 };
2780
InitInfoThreadAPI(void)2781 StructInitInfo * InitInfoThreadAPI(void)
2782 {
2783 return &module;
2784 }
2785