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