[M3devel] Latest pthreads attempt
mika at async.caltech.edu
mika at async.caltech.edu
Tue Aug 12 21:52:02 CEST 2014
Hi Tony (and others),
I instrumented my ThreadPThread.m3 as follows:
added an argument "line" to each of mutex_lock, mutex_unlock, and cond_wait
called these with Compiler.ThisLine()
results are attached... (I only learned yesterday how to do attachments in my Unix mailer!)
Is there a document somewhere describing the invariants of ThreadPThread.m3? I can guess at many of
them but am not entirely sure of some of the implementation details.
In any case it looks to me:
l. 194 lock 0x10250a8 self 0x1009400 <----
l. 198 lock 0x1025140 self 0x1009400
l. 202 unlock 0x1025140 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400 <----
ERROR: pthread_mutex_lock:11
like we have a problem here somewhere:
188 PROCEDURE XWait (self: Activation; m: Mutex; c: Condition; alertable: BOOLEAN)
189 RAISES {Alerted} =
190 (* LL = m *)
191 VAR next, prev: Activation;
192 BEGIN
193 IF c.mutex = NIL THEN InitMutex(c.mutex, c, CleanCondition) END;
194 WITH r = pthread_mutex_lock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END; <=======
195 <*ASSERT self.waitingOn = NIL*>
196 <*ASSERT self.nextWaiter = NIL*>
197
198 WITH r = pthread_mutex_lock(c.mutex,ThisLine()) DO <*ASSERT r=0*> END;
199 self.waitingOn := c.mutex;
200 self.nextWaiter := c.waiters;
201 c.waiters := self;
202 WITH r = pthread_mutex_unlock(c.mutex,ThisLine()) DO <*ASSERT r=0*> END;
203
204 m.release();
205 IF perfOn THEN PerfChanged(State.waiting) END;
206 LOOP
207 IF alertable AND self.alerted THEN
208 self.alerted := FALSE;
209 <*ASSERT self.waitingOn = c.mutex*>
210 WITH r = pthread_mutex_lock(c.mutex,ThisLine()) DO <*ASSERT r=0*> END;
211 next := c.waiters; prev := NIL;
212 WHILE next # self DO
213 <*ASSERT next # NIL*>
214 prev := next; next := next.nextWaiter;
215 END;
216 IF prev = NIL
217 THEN c.waiters := self.nextWaiter;
218 ELSE prev.nextWaiter := self.nextWaiter;
219 END;
220 WITH r = pthread_mutex_unlock(c.mutex,ThisLine()) DO <*ASSERT r=0*> END;
221 self.nextWaiter := NIL;
222 self.waitingOn := NIL;
223 WITH r = pthread_mutex_unlock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
224 m.acquire();
225 RAISE Alerted;
226 END;
227 WITH r = pthread_cond_wait(self.cond, self.mutex, ThisLine()) DO <*ASSERT r=0*> END;
228 IF self.waitingOn = NIL THEN
229 <*ASSERT self.nextWaiter = NIL*>
230 WITH r = pthread_mutex_unlock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
231 m.acquire();
232 RETURN;
233 END;
234 END;
235 END XWait;
The self.mutex is locked at 194, m.release is called with the self.mutex locked in other words.
But that winds up here:
144 PROCEDURE UnlockMutex (m: Mutex) =
145 (* LL = m *)
146 VAR
147 self := GetActivation();
148 t, prev: Activation;
149 BEGIN
150 IF m.mutex = NIL THEN InitMutex(m.mutex, m, CleanMutex) END;
151 WITH r = pthread_mutex_lock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END; <========
And the traceback agrees....
ERROR: pthread_mutex_lock:11
[New Thread 801009400 (LWP 101206/cm3)]
Program received signal SIGABRT, Aborted.
[Switching to Thread 801009400 (LWP 101206/cm3)]
thr_kill () at thr_kill.S:3
3 RSYSCALL(thr_kill)
Current language: auto; currently asm
(gdb) where
#0 thr_kill () at thr_kill.S:3
#1 0x0000000000790ea9 in abort () at /usr/src/lib/libc/stdlib/abort.c:65
#2 0x000000000071ad1d in ThreadPThread__pthread_mutex_lock (mutex=Error accessing memory address 0x8000ffffc4f8: Bad address.
) at ../src/thread/PTHREAD/ThreadPThreadC.c:526
#3 0x0000000000714dad in ThreadPThread__UnlockMutex (M3_AYIbX3_m=Error accessing memory address 0x8000ffffc528: Bad address.
) at ../src/thread/PTHREAD/ThreadPThread.m3:151
#4 0x0000000000715298 in ThreadPThread__XWait (M3_DMxDjQ_self=Error accessing memory address 0x8000ffffc5a8: Bad address.
) at ../src/thread/PTHREAD/ThreadPThread.m3:204
#5 0x0000000000717633 in ThreadPThread__XJoin (M3_DMxDjQ_self=Error accessing memory address 0x8000ffffc608: Bad address.
) at ../src/thread/PTHREAD/ThreadPThread.m3:557
#6 0x0000000000717782 in Thread__Join (M3_BXP32l_t=Error accessing memory address 0x8000ffffc6d8: Bad address.
) at ../src/thread/PTHREAD/ThreadPThread.m3:569
#7 0x0000000000407d8d in Builder__ForceAllPromisesInParallel (M3_C58HwX_promises=Error accessing memory address 0x8000ffffc758: Bad address.
) at ../src/Builder.m3:1002
Mika
-------------- next part --------------
/* Copyright (C) 2005, Purdue Research Foundation */
/* All rights reserved. */
/* See the file COPYRIGHT-PURDUE for a full description. */
#include "m3core.h"
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
/* See ThreadApple.c, ThreadFreeBSD.c, ThreadOpenBSD.c. */
#define M3_DIRECT_SUSPEND
#endif
#define M3MODULE ThreadPThread
#if defined(__sparc) || defined(__ia64__)
#define M3_REGISTER_WINDOWS
#endif
#ifdef M3_DIRECT_SUSPEND
#define M3_DIRECT_SUSPEND_ASSERT_FALSE do { \
assert(0 && "MacOS X, FreeBSD, OpenBSD should not get here."); \
fprintf(stderr, "MacOS X, FreeBSD, OpenBSD should not get here.\n"); \
abort(); \
} while(0);
#endif
M3_EXTERNC_BEGIN
#define InitC ThreadPThread__InitC
#define SignalHandler ThreadPThread__SignalHandler
#define sizeof_pthread_mutex_t ThreadPThread__sizeof_pthread_mutex_t
#define sizeof_pthread_cond_t ThreadPThread__sizeof_pthread_cond_t
#define SIG_SUSPEND ThreadPThread__SIG_SUSPEND
void __cdecl SignalHandler(int signo, siginfo_t *info, void *context);
#if M3_HAS_VISIBILITY
#pragma GCC visibility push(hidden)
#endif
/* expected values for compat, if compat matters:
Solaris: 17 (at least 32bit SPARC?)
Cygwin: 19 -- er, but maybe that's wrong
Linux: 64
FreeBSD: 31 (not used)
OpenBSD: 31 (not used)
HPUX: 44
Look at the history of Usignal and RTMachine to find more values. There was
RTMachine.SIG_SUSPEND and SIG was aliased to it. Both SIG and SIG_SUSPEND
were only defined for systems using pthreads. SIG was shorthand. */
#ifdef M3_DIRECT_SUSPEND
EXTERN_CONST int SIG_SUSPEND = 0;
#elif defined(__sun) || defined(__CYGWIN__)
EXTERN_CONST int SIG_SUSPEND = SIGUSR2;
#elif defined(__linux)
EXTERN_CONST int SIG_SUSPEND = NSIG - 1;
#elif defined(__hpux)
EXTERN_CONST int SIG_SUSPEND = _SIGRTMAX;
#elif defined(SIGRTMAX) && !defined(__osf__)
/* This might be a function call, in which case try _SIGRTMAX or initializing
it somewhere. SIGRTMAX is sysconf(132) on OSF. We may be
able to use direct suspend/resume on OSF. */
EXTERN_CONST int SIG_SUSPEND = SIGRTMAX;
#elif defined(SIGUSR2)
EXTERN_CONST int SIG_SUSPEND = SIGUSR2;
#else
#error Unable to determine SIG_SUSPEND.
#endif
static int stack_grows_down;
#ifndef M3_DIRECT_SUSPEND
static sigset_t mask;
/* Signal based suspend/resume */
static sem_t ackSem;
static void __cdecl SignalHandlerC(int signo, siginfo_t *info, void *context)
/* wrapper to workaround on ALPHA_LINUX:
/usr/bin/ld: ThreadPThreadC.o: gp-relative relocation against dynamic symbol ThreadPThread__SignalHandler
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46861 */
{
SignalHandler(signo, info, context);
}
int __cdecl ThreadPThread__sem_wait(void) { return sem_wait(&ackSem); }
int __cdecl ThreadPThread__sem_post(void) { return sem_post(&ackSem); }
int __cdecl ThreadPThread__sem_getvalue(int *value) { return sem_getvalue(&ackSem, value); }
void
__cdecl
ThreadPThread__sigsuspend(void)
{
struct {
sigjmp_buf jb;
} s;
ZERO_MEMORY(s);
if (sigsetjmp(s.jb, 0) == 0) /* save registers to stack */
#ifdef M3_REGISTER_WINDOWS
siglongjmp(s.jb, 1); /* flush register windows */
else
#endif
sigsuspend(&mask);
}
void
__cdecl
ThreadPThread__SuspendThread (m3_pthread_t mt)
{
abort();
}
void
__cdecl
ThreadPThread__RestartThread (m3_pthread_t mt)
{
abort();
}
void
__cdecl
ThreadPThread__ProcessStopped (m3_pthread_t mt, char *bottom, char *context,
void (*p)(void *start, void *limit))
{
/* process stack */
if (!bottom) return;
if (stack_grows_down)
{
assert(context < bottom);
p(context, bottom);
}
else
{
assert(bottom < context);
p(bottom, context);
}
/* process register context */
p(context, context + sizeof(ucontext_t));
}
#else /* M3_DIRECT_SUSPEND */
void __cdecl ThreadPThread__sem_wait(void) { M3_DIRECT_SUSPEND_ASSERT_FALSE }
void __cdecl ThreadPThread__sem_post(void) { M3_DIRECT_SUSPEND_ASSERT_FALSE }
void __cdecl ThreadPThread__sem_getvalue(void) { M3_DIRECT_SUSPEND_ASSERT_FALSE }
void __cdecl ThreadPThread__sigsuspend(void) { M3_DIRECT_SUSPEND_ASSERT_FALSE }
#endif /* M3_DIRECT_SUSPEND */
void
__cdecl
ThreadPThread__ProcessLive(char *bottom, void (*p)(void *start, void *limit))
{
/*
cc: Warning: ThreadPThreadC.c, line 170: In this statement, & before array "jb" is ignored. (addrarray)
p(&jb, ((char *)&jb) + sizeof(jb));
------^
cc: Warning: ThreadPThreadC.c, line 170: In this statement, & before array "jb" is ignored. (addrarray)
p(&jb, ((char *)&jb) + sizeof(jb));
--------------------^
jb may or may not be an array, & is necessary, wrap it in struct.
*/
struct {
sigjmp_buf jb;
} s;
ZERO_MEMORY(s);
if (sigsetjmp(s.jb, 0) == 0) /* save registers to stack */
#ifdef M3_REGISTER_WINDOWS
siglongjmp(s.jb, 1); /* flush register windows */
else
#endif
{
/* capture top after longjmp because longjmp can clobber non-volatile locals */
char *top = (char*)⊤
assert(bottom);
if (stack_grows_down)
{
assert(top < bottom);
p(top, bottom);
}
else
{
assert(bottom < top);
p(bottom, top);
}
p(&s, sizeof(s) + (char *)&s);
}
}
#define M3_MAX(x, y) (((x) > (y)) ? (x) : (y))
typedef void *(*start_routine_t)(void *);
#define M3_RETRY(expr) \
r = (expr); \
if (r == EAGAIN || r == ENOMEM || r == ENOSPC) \
{ \
/* try again right away */ \
r = (expr); \
if (r == EAGAIN || r == ENOMEM || r == ENOSPC) \
{ \
/* try again after short delay */ \
sleep(1); \
r = (expr); \
} \
}
int
__cdecl
ThreadPThread__thread_create(WORD_T stackSize,
start_routine_t start_routine,
void *arg)
{
int r = { 0 };
WORD_T bytes = { 0 };
pthread_attr_t attr;
pthread_t pthread;
ZERO_MEMORY(pthread);
ZERO_MEMORY(attr);
M3_RETRY(pthread_attr_init(&attr));
#ifdef __hpux
if (r == ENOSYS)
{
fprintf(stderr,
"You got the nonfunctional pthread stubs on HP-UX. You need to"
" adjust your build commands, such as to link to -lpthread or"
" use -pthread, and not link explicitly to -lc.\n");
}
#endif
assert(r == 0);
r = pthread_attr_getstacksize(&attr, &bytes); assert(r == 0);
bytes = M3_MAX(bytes, stackSize);
pthread_attr_setstacksize(&attr, bytes);
M3_RETRY(pthread_create(&pthread, &attr, start_routine, arg));
#ifdef __sun
if (r == ENOENT)
{
fprintf(stderr,
"You got the nonfunctional pthread stubs on Solaris earlier than 5.10. "
"You need to adjust your build commands, such as to link to -lpthread "
" ahead of -lc.\n");
}
#endif
if (r != 0)
{
fprintf(stderr,
"pthread_create(stack_size:0x%X):0x%X errno:0x%X\n",
(unsigned)stackSize,
(unsigned)r,
(unsigned)errno);
}
pthread_attr_destroy(&attr);
return r;
}
#define MUTEX(name) \
static pthread_mutex_t name##Mu = PTHREAD_MUTEX_INITIALIZER; \
extern pthread_mutex_t * const ThreadPThread__##name##Mu; \
pthread_mutex_t * const ThreadPThread__##name##Mu = &name##Mu; \
#define CONDITION_VARIABLE(name) \
static pthread_cond_t name##Cond = PTHREAD_COND_INITIALIZER; \
extern pthread_cond_t * const ThreadPThread__##name##Cond; \
pthread_cond_t * const ThreadPThread__##name##Cond = &name##Cond; \
/* activeMu slotMu initMu perfMu heapMu heapCond */
MUTEX(active) /* global lock for list of active threads */
MUTEX(slots) /* global lock for thread slots table */
MUTEX(init) /* global lock for initializers */
MUTEX(perf) /* global lock for thread state tracing */
MUTEX(heap) /* global lock for heap atomicity */
CONDITION_VARIABLE(heap) /* CV for heap waiters */
/*
NetBSD 5.0.2 compiles __thread, but segfault at runtime.
OpenBSD 4.7 compiles __thread, but segfault at runtime.
Apple doesn't compile
FreeBSD not tested
AIX probably works, not tested
Solaris: failed to link on Solaris 2.9: http://hudson.modula3.com:8080/job/cm3-current-build-SOLsun-opencsw-current9s/166/console
HP-UX? AIX?
Linux/arm: /usr/bin/ld: /usr/local/cm3/pkg/m3core/ARMEL_LINUX/libm3core.a(ThreadPThreadC.o)(.stab+0x2e28): R_ARM_ABS32 used with TLS symbol activations
*/
#if 0 /* defined(__linux) && !defined(__arm__) */
#define M3_COMPILER_THREAD_LOCAL
static __thread void* activations;
void
__cdecl
ThreadPThread__SetActivation(void *value)
{
activations = value;
}
void*
__cdecl
ThreadPThread__GetActivation(void)
{
return activations;
}
#else
static pthread_key_t activations;
void
__cdecl
ThreadPThread__SetActivation(void *value)
{
int r = { 0 };
M3_RETRY(pthread_setspecific(activations, value));
assert(r == 0);
}
void *
__cdecl
ThreadPThread__GetActivation(void)
{
return pthread_getspecific(activations);
}
#endif
typedef int (*generic_init_t)(void *, const void *);
void *
__cdecl
ThreadPThread_pthread_generic_new(WORD_T size, generic_init_t init)
{
int r = ENOMEM;
void *p = calloc(1, size);
if (p == NULL)
goto Error;
M3_RETRY(init(p, NULL));
if (r == ENOMEM)
goto Error;
assert(r == 0);
if (r != 0)
goto Error;
return p;
Error:
if (r)
{
fprintf(stderr, "ERROR: pthread_generic_new:%d\n", r);
abort();
}
if (p) free(p);
return NULL;
}
#define THREADPTHREAD__PTHREAD_GENERIC_NEW(type) { \
typedef pthread_##type##_t T; \
typedef pthread_##type##attr_t attr_t; \
typedef int (*init_t)(T *, const attr_t *); \
/* make sure the type matches */ \
init_t init = pthread_##type##_init; \
return ThreadPThread_pthread_generic_new(sizeof(T), \
(generic_init_t)init); \
}
void *
__cdecl
ThreadPThread__pthread_mutex_new(void)
{
THREADPTHREAD__PTHREAD_GENERIC_NEW(mutex);
}
void *
__cdecl
ThreadPThread__pthread_cond_new(void)
{
THREADPTHREAD__PTHREAD_GENERIC_NEW(cond);
}
void
__cdecl
ThreadPThread__pthread_mutex_delete(pthread_mutex_t* p)
{
int e = { 0 };
if (p == NULL) return;
#if defined(__hpux) || defined(__osf)
/* workaround Tru64 5.1 and HP-UX bug: pthread_mutex_destroy()
intermittently returns EBUSY even when there are no threads accessing the
mutex. */
do { e = pthread_mutex_destroy(p); } while (e == EBUSY);
#else
e = pthread_mutex_destroy(p);
#endif
if (e)
{
if (e == EBUSY)
fprintf(stderr, "pthread_mutex_destroy:EBUSY\n");
else
fprintf(stderr, "pthread_mutex_destroy:%d\n", e);
abort();
}
free(p);
}
void
__cdecl
ThreadPThread__pthread_cond_delete(pthread_cond_t *p)
{
int r = { 0 };
if (p == NULL) return;
r = pthread_cond_destroy(p);
assert(r == 0);
free(p);
}
#define BILLION (1000 * 1000 * 1000)
void
__cdecl
ThreadPThread__Nanosleep(INTEGER nanoseconds)
{
#ifdef __INTERIX
assert(nanoseconds >= 0);
assert(nanoseconds < BILLION);
/* This is only an approximation. We don't try to complete the sleep
* if interrupted, because we don't cheaply know how much time has elapsed.
*/
usleep(nanoseconds / 1000);
#else
struct timespec wait;
struct timespec remaining;
assert(nanoseconds >= 0);
assert(nanoseconds < BILLION);
ZERO_MEMORY(wait);
ZERO_MEMORY(remaining);
wait.tv_sec = 0;
wait.tv_nsec = nanoseconds;
while (nanosleep(&wait, &remaining) == -1 && errno == EINTR)
wait = remaining;
#endif
}
/*M3WRAP2(int, pthread_cond_wait, pthread_cond_t*, pthread_mutex_t*)*/
M3WRAP1(int, pthread_cond_signal, pthread_cond_t*)
M3WRAP1(int, pthread_cond_broadcast, pthread_cond_t*)
int
__cdecl
ThreadPThread__pthread_cond_timedwait(pthread_cond_t* cond,
pthread_mutex_t* mutex,
LONGREAL m3timeout)
{
struct timespec timeout;
double n = { 0 };
ZERO_MEMORY(timeout);
timeout.tv_nsec = modf(m3timeout, &n) * BILLION;
timeout.tv_sec = n;
return pthread_cond_timedwait(cond, mutex, &timeout);
}
int
__cdecl
ThreadPThread__pthread_detach_self(void)
{
return pthread_detach(pthread_self());
}
m3_pthread_t
__cdecl
ThreadPThread__pthread_self(void)
{
pthread_t a = pthread_self();
return PTHREAD_TO_M3(a);
}
int
__cdecl
ThreadPThread__pthread_equal(m3_pthread_t t1, m3_pthread_t t2)
{
return pthread_equal(PTHREAD_FROM_M3(t1), PTHREAD_FROM_M3(t2));
}
int
__cdecl
ThreadPThread__pthread_kill(m3_pthread_t thread, int sig)
{
return pthread_kill(PTHREAD_FROM_M3(thread), sig);
}
int
__cdecl
ThreadPThread__pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m, int line)
{
fprintf(stderr, "l. %5d wait 0x%x self 0x%x\n",line,m,pthread_self());
return pthread_cond_wait(c,m);
}
int
__cdecl
ThreadPThread__pthread_mutex_lock(pthread_mutex_t* mutex, int line)
{
int a;
fprintf(stderr, "l. %5d lock 0x%x self 0x%x\n",line,mutex,pthread_self());
a = pthread_mutex_lock(mutex);
if (a)
{
if (a == EINVAL)
fprintf(stderr, "ERROR: pthread_mutex_lock:EINVAL\n");
else
fprintf(stderr, "ERROR: pthread_mutex_lock:%d\n", a);
abort();
}
return a;
}
int
__cdecl
ThreadPThread__pthread_mutex_unlock(pthread_mutex_t* mutex, int line)
{
int a;
fprintf(stderr, "l. %5d unlock 0x%x self 0x%x\n",line,mutex,pthread_self());
a = pthread_mutex_unlock(mutex);
if (a)
{
fprintf(stderr, "ERROR: pthread_mutex_unlock:%d\n", a);
abort();
}
return a;
}
void
__cdecl
InitC(int *bottom)
{
int r = { 0 };
#ifndef M3_DIRECT_SUSPEND
struct sigaction act;
ZERO_MEMORY(act);
#endif
stack_grows_down = (bottom > &r);
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__INTERIX)
assert(stack_grows_down); /* See ThreadApple.c, ThreadFreeBSD.c */
#endif
#ifndef M3_COMPILER_THREAD_LOCAL
M3_RETRY(pthread_key_create(&activations, NULL)); assert(r == 0);
#endif
#ifndef M3_DIRECT_SUSPEND
ZERO_MEMORY(act);
M3_RETRY(sem_init(&ackSem, 0, 0)); assert(r == 0);
r = sigfillset(&mask); assert(r == 0);
r = sigdelset(&mask, SIG_SUSPEND); assert(r == 0);
r = sigdelset(&mask, SIGINT); assert(r == 0);
r = sigdelset(&mask, SIGQUIT); assert(r == 0);
r = sigdelset(&mask, SIGABRT); assert(r == 0);
r = sigdelset(&mask, SIGTERM); assert(r == 0);
act.sa_flags = SA_RESTART | SA_SIGINFO;
act.sa_sigaction = SignalHandlerC;
r = sigfillset(&act.sa_mask); assert(r == 0);
r = sigaction(SIG_SUSPEND, &act, NULL); assert(r == 0);
#endif
}
M3_EXTERNC_END
-------------- next part --------------
(* Copyright (C) 2005, Purdue Research Foundation *)
(* All rights reserved. *)
(* See the file COPYRIGHT-PURDUE for a full description. *)
UNSAFE MODULE ThreadPThread EXPORTS Thread, ThreadF, RTThread, Scheduler,
SchedulerPosix, RTOS, RTHooks, ThreadPThread;
IMPORT Cerrno, FloatMode, MutexRep, RTCollectorSRC, RTError, RTHeapRep, RTIO,
RTParams, RTPerfTool, RTProcess, ThreadEvent, Time,
Word, Usched, Uerror, Uexec;
FROM Compiler IMPORT ThisFile, ThisLine;
FROM Ctypes IMPORT int;
IMPORT RuntimeError AS RTE;
FROM ThreadInternal IMPORT Poll;
(*----------------------------------------------------- types and globals ---*)
CONST
MILLION = 1000 * 1000;
WAIT_UNIT = MILLION; (* one million nanoseconds, one thousandth of a second *)
RETRY_INTERVAL = 10 * MILLION; (* 10 million nanoseconds, one hundredth of a second *)
REVEAL
Mutex = MutexRep.Public BRANDED "Mutex Pthread-1.0" OBJECT
mutex: pthread_mutex_t := NIL;
holder: Activation := NIL;
waiters: Activation := NIL;
OVERRIDES
acquire := LockMutex;
release := UnlockMutex;
END;
Condition = BRANDED "Thread.Condition Pthread-1.0" OBJECT
mutex: pthread_mutex_t := NIL;
waiters: Activation := NIL; (* LL = mutex *)
END;
T = BRANDED "Thread.T Pthread-1.6" OBJECT
act: Activation := NIL; (* live untraced thread data *)
closure: Closure := NIL; (* our work and its result *)
result: REFANY := NIL; (* our work and its result *)
join: Condition; (* wait here to join; NIL when done *)
joined: BOOLEAN := FALSE; (* Is anyone waiting yet? *)
END;
TYPE
ActState = { Starting, Started, Stopping, Stopped };
REVEAL Activation = UNTRACED BRANDED REF RECORD
frame: ADDRESS := NIL; (* exception handling support *)
mutex: pthread_mutex_t := NIL; (* write-once in CreateT *)
cond: pthread_cond_t := NIL; (* write-once in CreateT; a place to park while waiting *)
alerted : BOOLEAN := FALSE; (* LL = mutex; the alert flag *)
waitingOn: pthread_mutex_t := NIL; (* LL = mutex; The CV's mutex *)
nextWaiter: Activation := NIL; (* LL = mutex; waiting thread queue *)
next, prev: Activation := NIL; (* LL = activeMu; global doubly-linked, circular list of all active threads *)
handle: pthread_t := NIL; (* LL = activeMu; thread handle *)
stackbase: ADDRESS := NIL; (* LL = activeMu; stack base for GC *)
context: ADDRESS := NIL; (* LL = activeMu *)
state := ActState.Started; (* LL = activeMu *)
slot: CARDINAL := 0; (* LL = slotMu; index in slots *)
floatState : FloatMode.ThreadState; (* per-thread floating point state *)
heapState : RTHeapRep.ThreadState; (* per-thread heap state *)
END;
PROCEDURE SetState (act: Activation; state: ActState) =
CONST text = ARRAY ActState OF TEXT
{ "Starting", "Started", "Stopping", "Stopped" };
BEGIN
act.state := state;
IF DEBUG THEN
RTIO.PutText(text[state]);
RTIO.PutText(" act=");
RTIO.PutAddr(act);
RTIO.PutText("\n");
RTIO.Flush();
END;
END SetState;
(*----------------------------------------------------------------- Mutex ---*)
PROCEDURE Acquire (m: Mutex) =
BEGIN
m.acquire ();
END Acquire;
PROCEDURE Release (m: Mutex) =
BEGIN
m.release ();
END Release;
PROCEDURE CleanMutex (r: REFANY) =
VAR m := NARROW(r, Mutex);
BEGIN
pthread_mutex_delete(m.mutex);
m.mutex := NIL;
END CleanMutex;
PROCEDURE InitMutex (VAR m: pthread_mutex_t; root: REFANY;
Clean: PROCEDURE(root: REFANY)) =
VAR mutex := pthread_mutex_new();
BEGIN
TRY
WITH r = pthread_mutex_lock(initMu,ThisLine()) DO <*ASSERT r=0*> END;
(* Did someone else win the race? *)
IF m # NIL THEN RETURN END;
(* We won the race, but we might have failed to allocate. *)
IF mutex = NIL THEN RTE.Raise (RTE.T.OutOfMemory) END;
RTHeapRep.RegisterFinalCleanup (root, Clean);
m := mutex;
mutex := NIL;
FINALLY
WITH r = pthread_mutex_unlock(initMu,ThisLine()) DO <*ASSERT r=0*> END;
pthread_mutex_delete(mutex);
END;
END InitMutex;
PROCEDURE LockMutex (m: Mutex) =
VAR self := GetActivation();
BEGIN
IF m.mutex = NIL THEN InitMutex(m.mutex, m, CleanMutex) END;
WITH r = pthread_mutex_lock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
WITH r = pthread_mutex_lock(m.mutex,ThisLine()) DO <*ASSERT r=0*> END;
IF m.holder = NIL THEN
m.holder := self;
WITH r = pthread_mutex_unlock(m.mutex,ThisLine()) DO <*ASSERT r=0*> END;
WITH r = pthread_mutex_unlock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
IF perfOn THEN PerfRunning() END;
RETURN;
END;
<*ASSERT self.waitingOn = NIL*>
<*ASSERT self.nextWaiter = NIL*>
IF perfOn THEN PerfChanged(State.locking) END;
self.waitingOn := m.mutex;
self.nextWaiter := m.waiters;
m.waiters := self;
IF m.holder = self THEN Die(ThisLine(), "impossible acquire") END;
WITH r = pthread_mutex_unlock(m.mutex,ThisLine()) DO <*ASSERT r=0*> END;
REPEAT
WITH r = pthread_cond_wait(self.cond, self.mutex, ThisLine()) DO <*ASSERT r=0*> END;
UNTIL self.waitingOn = NIL; (* m.holder = self *)
WITH r = pthread_mutex_unlock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
END LockMutex;
PROCEDURE UnlockMutex (m: Mutex) =
(* LL = m *)
VAR
self := GetActivation();
t, prev: Activation;
BEGIN
IF m.mutex = NIL THEN InitMutex(m.mutex, m, CleanMutex) END;
WITH r = pthread_mutex_lock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
WITH r = pthread_mutex_lock(m.mutex,ThisLine()) DO <*ASSERT r=0*> END;
IF m.holder # self THEN Die(ThisLine(), "illegal release") END;
t := m.waiters;
IF t = NIL THEN
m.holder := NIL;
WITH r = pthread_mutex_unlock(m.mutex,ThisLine()) DO <*ASSERT r=0*> END;
WITH r = pthread_mutex_unlock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
RETURN;
END;
prev := NIL;
WHILE t.nextWaiter # NIL DO
prev := t;
t := t.nextWaiter;
END;
IF prev # NIL
THEN prev.nextWaiter := NIL;
ELSE m.waiters := NIL;
END;
m.holder := t;
WITH r = pthread_mutex_unlock(m.mutex,ThisLine()) DO <*ASSERT r=0*> END;
WITH r = pthread_mutex_lock(t.mutex,ThisLine()) DO <*ASSERT r=0*> END;
t.waitingOn := NIL;
WITH r = pthread_cond_signal(t.cond) DO <*ASSERT r=0*> END;
WITH r = pthread_mutex_unlock(t.mutex,ThisLine()) DO <*ASSERT r=0*> END;
WITH r = pthread_mutex_unlock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
END UnlockMutex;
(*---------------------------------------- Condition variables and Alerts ---*)
PROCEDURE CleanCondition (r: REFANY) =
VAR c := NARROW(r, Condition);
BEGIN
pthread_mutex_delete(c.mutex);
c.mutex := NIL;
END CleanCondition;
PROCEDURE XWait (self: Activation; m: Mutex; c: Condition; alertable: BOOLEAN)
RAISES {Alerted} =
(* LL = m *)
VAR next, prev: Activation;
BEGIN
IF c.mutex = NIL THEN InitMutex(c.mutex, c, CleanCondition) END;
WITH r = pthread_mutex_lock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
<*ASSERT self.waitingOn = NIL*>
<*ASSERT self.nextWaiter = NIL*>
WITH r = pthread_mutex_lock(c.mutex,ThisLine()) DO <*ASSERT r=0*> END;
self.waitingOn := c.mutex;
self.nextWaiter := c.waiters;
c.waiters := self;
WITH r = pthread_mutex_unlock(c.mutex,ThisLine()) DO <*ASSERT r=0*> END;
m.release();
IF perfOn THEN PerfChanged(State.waiting) END;
LOOP
IF alertable AND self.alerted THEN
self.alerted := FALSE;
<*ASSERT self.waitingOn = c.mutex*>
WITH r = pthread_mutex_lock(c.mutex,ThisLine()) DO <*ASSERT r=0*> END;
next := c.waiters; prev := NIL;
WHILE next # self DO
<*ASSERT next # NIL*>
prev := next; next := next.nextWaiter;
END;
IF prev = NIL
THEN c.waiters := self.nextWaiter;
ELSE prev.nextWaiter := self.nextWaiter;
END;
WITH r = pthread_mutex_unlock(c.mutex,ThisLine()) DO <*ASSERT r=0*> END;
self.nextWaiter := NIL;
self.waitingOn := NIL;
WITH r = pthread_mutex_unlock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
m.acquire();
RAISE Alerted;
END;
WITH r = pthread_cond_wait(self.cond, self.mutex, ThisLine()) DO <*ASSERT r=0*> END;
IF self.waitingOn = NIL THEN
<*ASSERT self.nextWaiter = NIL*>
WITH r = pthread_mutex_unlock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
m.acquire();
RETURN;
END;
END;
END XWait;
PROCEDURE AlertWait (m: Mutex; c: Condition) RAISES {Alerted} =
(* LL = m *)
VAR self := GetActivation();
BEGIN
XWait(self, m, c, alertable := TRUE);
END AlertWait;
PROCEDURE Wait (m: Mutex; c: Condition) =
<*FATAL Alerted*>
(* LL = m *)
VAR self := GetActivation();
BEGIN
XWait(self, m, c, alertable := FALSE);
END Wait;
PROCEDURE DequeueHead(c: Condition) =
(* LL = c *)
VAR t := c.waiters;
BEGIN
WITH r = pthread_mutex_lock(t.mutex,ThisLine()) DO <*ASSERT r=0*> END;
c.waiters := t.nextWaiter;
t.nextWaiter := NIL;
t.waitingOn := NIL;
WITH r = pthread_cond_signal(t.cond) DO <*ASSERT r=0*> END;
WITH r = pthread_mutex_unlock(t.mutex,ThisLine()) DO <*ASSERT r=0*> END;
END DequeueHead;
PROCEDURE Signal (c: Condition) =
BEGIN
IF c.mutex = NIL THEN InitMutex(c.mutex, c, CleanCondition) END;
WITH r = pthread_mutex_lock(c.mutex,ThisLine()) DO <*ASSERT r=0*> END;
IF c.waiters # NIL THEN DequeueHead(c) END;
WITH r = pthread_mutex_unlock(c.mutex,ThisLine()) DO <*ASSERT r=0*> END;
END Signal;
PROCEDURE Broadcast (c: Condition) =
BEGIN
IF c.mutex = NIL THEN InitMutex(c.mutex, c, CleanCondition) END;
WITH r = pthread_mutex_lock(c.mutex,ThisLine()) DO <*ASSERT r=0*> END;
WHILE c.waiters # NIL DO DequeueHead(c) END;
WITH r = pthread_mutex_unlock(c.mutex,ThisLine()) DO <*ASSERT r=0*> END;
END Broadcast;
PROCEDURE Alert (thread: T) =
VAR t := thread.act;
BEGIN
WITH r = pthread_mutex_lock(t.mutex,ThisLine()) DO <*ASSERT r=0*> END;
t.alerted := TRUE;
WITH r = pthread_cond_signal(t.cond) DO <*ASSERT r=0*> END;
WITH r = pthread_mutex_unlock(t.mutex,ThisLine()) DO <*ASSERT r=0*> END;
END Alert;
PROCEDURE XTestAlert (self: Activation): BOOLEAN =
VAR result: BOOLEAN;
BEGIN
WITH r = pthread_mutex_lock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
result := self.alerted;
self.alerted := FALSE;
WITH r = pthread_mutex_unlock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
RETURN result;
END XTestAlert;
PROCEDURE TestAlert (): BOOLEAN =
VAR self := GetActivation();
BEGIN
RETURN XTestAlert(self);
END TestAlert;
(*------------------------------------------------------------------ Self ---*)
VAR (* LL = slotMu *)
n_slotted: CARDINAL;
next_slot: CARDINAL; (* NOTE: we don't use slots[0] *)
slots: REF ARRAY OF T; (* NOTE: we don't use slots[0] *)
PROCEDURE InitActivations (me: Activation) =
BEGIN
me.handle := pthread_self();
me.next := me;
me.prev := me;
SetActivation(me);
(* Explicitly (re)initialize to handle fork(). *)
next_slot := 1; (* no threads created yet *)
slots := NIL; (* no threads created yet *)
n_slotted := 0; (* no threads created yet *)
allThreads := me;
FloatMode.InitThread(me.floatState);
END InitActivations;
PROCEDURE Self (): T =
(* If not the initial thread and not created by Fork, returns NIL *)
VAR
me := GetActivation();
t: T;
BEGIN
IF me = NIL THEN Die(ThisLine(), "Thread primitive called from non-Modula-3 thread") END;
WITH r = pthread_mutex_lock(slotsMu,ThisLine()) DO <*ASSERT r=0*> END;
t := slots[me.slot];
WITH r = pthread_mutex_unlock(slotsMu,ThisLine()) DO <*ASSERT r=0*> END;
IF (t.act # me) THEN Die(ThisLine(), "thread with bad slot!") END;
RETURN t;
END Self;
PROCEDURE AssignSlot (t: T): INTEGER =
(* LL = 0, cause we allocate stuff with NEW! *)
VAR n: CARDINAL; new_slots: REF ARRAY OF T; slot: CARDINAL;
BEGIN
WITH r = pthread_mutex_lock(slotsMu,ThisLine()) DO <*ASSERT r=0*> END;
(* make sure we have room to register this guy *)
IF (slots = NIL) THEN
WITH r = pthread_mutex_unlock(slotsMu,ThisLine()) DO <*ASSERT r=0*> END;
slots := NEW (REF ARRAY OF T, 20);
WITH r = pthread_mutex_lock(slotsMu,ThisLine()) DO <*ASSERT r=0*> END;
END;
IF (n_slotted >= LAST (slots^)) THEN
n := NUMBER (slots^);
WITH r = pthread_mutex_unlock(slotsMu,ThisLine()) DO <*ASSERT r=0*> END;
new_slots := NEW (REF ARRAY OF T, n+n);
WITH r = pthread_mutex_lock(slotsMu,ThisLine()) DO <*ASSERT r=0*> END;
IF (n = NUMBER (slots^)) THEN
(* we won any races that may have occurred. *)
SUBARRAY (new_slots^, 0, n) := slots^;
slots := new_slots;
ELSIF (n_slotted < LAST (slots^)) THEN
(* we lost a race while allocating a new slot table,
and the new table has room for us. *)
ELSE
(* ouch, the new table is full too! Bail out and retry *)
WITH r = pthread_mutex_unlock(slotsMu,ThisLine()) DO <*ASSERT r=0*> END;
RETURN AssignSlot (t);
END;
END;
(* look for an empty slot *)
WHILE (slots [next_slot] # NIL) DO
INC (next_slot);
IF (next_slot >= NUMBER (slots^)) THEN next_slot := 1; END;
END;
INC (n_slotted);
slot := next_slot;
slots [slot] := t;
WITH r = pthread_mutex_unlock(slotsMu,ThisLine()) DO <*ASSERT r=0*> END;
RETURN slot;
END AssignSlot;
PROCEDURE FreeSlot (self: T) =
(* LL = 0 *)
BEGIN
WITH r = pthread_mutex_lock(slotsMu,ThisLine()) DO <*ASSERT r=0*> END;
DEC (n_slotted);
WITH z = slots [self.act.slot] DO
IF z # self THEN Die (ThisLine(), "unslotted thread!"); END;
z := NIL;
END;
self.act.slot := 0;
WITH r = pthread_mutex_unlock(slotsMu,ThisLine()) DO <*ASSERT r=0*> END;
END FreeSlot;
PROCEDURE DumpThread (t: Activation) =
BEGIN
RTIO.PutText("Activation: "); RTIO.PutAddr(t); RTIO.PutChar('\n');
RTIO.PutText(" slot: "); RTIO.PutInt(t.slot); RTIO.PutChar('\n');
RTIO.PutText(" mutex: "); RTIO.PutAddr(t.mutex); RTIO.PutChar('\n');
RTIO.PutText(" cond: "); RTIO.PutAddr(t.cond); RTIO.PutChar('\n');
RTIO.PutText(" alerted: "); RTIO.PutInt(ORD(t.alerted)); RTIO.PutChar('\n');
RTIO.PutText(" waitingOn: "); RTIO.PutAddr(t.waitingOn); RTIO.PutChar('\n');
RTIO.PutText(" nextWaiter: "); RTIO.PutAddr(t.nextWaiter); RTIO.PutChar('\n');
RTIO.PutText(" frame: "); RTIO.PutAddr(t.frame); RTIO.PutChar('\n');
RTIO.PutText(" next: "); RTIO.PutAddr(t.next); RTIO.PutChar('\n');
RTIO.PutText(" prev: "); RTIO.PutAddr(t.prev); RTIO.PutChar('\n');
RTIO.PutText(" handle: "); RTIO.PutAddr(t.handle); RTIO.PutChar('\n');
RTIO.PutText(" stackbase: "); RTIO.PutAddr(t.stackbase); RTIO.PutChar('\n');
RTIO.PutText(" context: "); RTIO.PutAddr(t.context); RTIO.PutChar('\n');
RTIO.PutText(" state: ");
CASE t.state OF
| ActState.Started => RTIO.PutText("Started\n");
| ActState.Stopped => RTIO.PutText("Stopped\n");
| ActState.Starting => RTIO.PutText("Starting\n");
| ActState.Stopping => RTIO.PutText("Stopping\n");
END;
RTIO.Flush();
END DumpThread;
PROCEDURE DumpThreads () =
VAR t := allThreads;
BEGIN
REPEAT
DumpThread(t);
t := t.next
UNTIL t = allThreads;
END DumpThreads;
(*------------------------------------------------------------ Fork, Join ---*)
VAR (* LL=activeMu *)
allThreads: Activation := NIL; (* global list of active threads *)
PROCEDURE CleanThread (r: REFANY) =
VAR t := NARROW(r, T);
BEGIN
pthread_mutex_delete(t.act.mutex);
pthread_cond_delete(t.act.cond);
DISPOSE(t.act);
END CleanThread;
(* ThreadBase calls RunThread after finding (approximately) where
its stack begins. This dance ensures that all of ThreadMain's
traced references are within the stack scanned by the collector. *)
PROCEDURE ThreadBase (param: ADDRESS): ADDRESS =
VAR
me: Activation := param;
BEGIN
SetActivation(me);
me.stackbase := ADR(me); (* enable GC scanning of this stack *)
me.handle := pthread_self();
(* add to the list of active threads *)
WITH r = pthread_mutex_lock(activeMu,ThisLine()) DO <*ASSERT r=0*> END;
me.next := allThreads;
me.prev := allThreads.prev;
allThreads.prev.next := me;
allThreads.prev := me;
WITH r = pthread_mutex_unlock(activeMu,ThisLine()) DO <*ASSERT r=0*> END;
FloatMode.InitThread (me.floatState);
RunThread(me);
(* remove from the list of active threads *)
WITH r = pthread_mutex_lock(activeMu,ThisLine()) DO <*ASSERT r=0*> END;
<*ASSERT allThreads # me*>
me.stackbase := NIL; (* disable GC scanning of my stack *)
me.next.prev := me.prev;
me.prev.next := me.next;
WITH r = pthread_detach_self() DO <*ASSERT r=0*> END;
WITH r = pthread_mutex_unlock(activeMu,ThisLine()) DO <*ASSERT r=0*> END;
me.next := NIL;
me.prev := NIL;
RETURN NIL;
END ThreadBase;
PROCEDURE RunThread (me: Activation) =
VAR self: T;
BEGIN
IF perfOn THEN PerfChanged(State.alive) END;
WITH r = pthread_mutex_lock(slotsMu,ThisLine()) DO <*ASSERT r=0*> END;
self := slots [me.slot];
WITH r = pthread_mutex_unlock(slotsMu,ThisLine()) DO <*ASSERT r=0*> END;
IF perfOn THEN PerfRunning() END;
(*** Run the user-level code. ***)
self.result := self.closure.apply();
IF perfOn THEN PerfChanged(State.dying) END;
(* Join *)
LOCK joinMu DO
Broadcast(self.join);
self.join := NIL; (* mark me done *)
END;
IF perfOn THEN PerfChanged(State.dead) END;
(* we're dying *)
RTHeapRep.FlushThreadState(me.heapState);
IF perfOn THEN PerfDeleted() END;
FreeSlot(self); (* note: needs self.act ! *)
(* Since we're no longer slotted, we cannot touch traced refs. *)
END RunThread;
VAR joinMu: MUTEX;
PROCEDURE Fork (closure: Closure): T =
VAR
act := NEW(Activation,
mutex := pthread_mutex_new(),
cond := pthread_cond_new());
size := defaultStackSize;
t: T := NIL;
BEGIN
TRY
IF act.mutex = NIL OR act.cond = NIL THEN
RTE.Raise(RTE.T.OutOfMemory);
END;
t := NEW(T, act := act, closure := closure, join := NEW(Condition));
RTHeapRep.RegisterFinalCleanup(t, CleanThread);
act.slot := AssignSlot(t);
FINALLY
IF act.slot = 0 THEN
(* we failed, cleanup *)
pthread_mutex_delete(act.mutex);
pthread_cond_delete(act.cond);
DISPOSE(act);
END;
END;
(* determine the initial size of the stack for this thread *)
TYPECASE closure OF
| SizedClosure (scl) => size := scl.stackSize;
ELSE (*skip*)
END;
WITH r = thread_create(size * ADRSIZE(Word.T), ThreadBase, act) DO
IF r # 0 THEN DieI(ThisLine(), r) END;
END;
RETURN t;
END Fork;
PROCEDURE XJoin (self: Activation; t: T; alertable: BOOLEAN):
REFANY RAISES {Alerted} =
BEGIN
LOCK joinMu DO
IF t.joined THEN Die(ThisLine(), "attempt to join with thread twice") END;
TRY
t.joined := TRUE;
WHILE t.join # NIL DO XWait(self, joinMu, t.join, alertable) END;
FINALLY
IF t.join # NIL THEN t.joined := FALSE END;
END;
END;
RETURN t.result;
END XJoin;
PROCEDURE Join (t: T): REFANY =
<*FATAL Alerted*>
VAR self := GetActivation();
BEGIN
RETURN XJoin(self, t, alertable := FALSE);
END Join;
PROCEDURE AlertJoin (t: T): REFANY RAISES {Alerted} =
VAR self := GetActivation();
BEGIN
RETURN XJoin(self, t, alertable := TRUE);
END AlertJoin;
(*---------------------------------------------------- Scheduling support ---*)
PROCEDURE XPause (self: Activation; n: LONGREAL; alertable: BOOLEAN)
RAISES {Alerted} =
VAR until := Time.Now() + n;
BEGIN
IF perfOn THEN PerfChanged(State.pausing) END;
WITH r = pthread_mutex_lock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
<*ASSERT self.waitingOn = NIL*>
<*ASSERT self.nextWaiter = NIL*>
LOOP
IF alertable AND self.alerted THEN
self.alerted := FALSE;
WITH r = pthread_mutex_unlock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
IF perfOn THEN PerfRunning() END;
RAISE Alerted;
END;
WITH r = pthread_cond_timedwait(self.cond, self.mutex, until) DO
IF r = Uerror.ETIMEDOUT THEN
WITH r = pthread_mutex_unlock(self.mutex,ThisLine()) DO <*ASSERT r=0*> END;
IF perfOn THEN PerfRunning() END;
RETURN;
END;
<*ASSERT r=0*>
END;
END;
END XPause;
PROCEDURE Pause (n: LONGREAL) =
<*FATAL Alerted*>
VAR self := GetActivation();
BEGIN
XPause(self, n, alertable := FALSE);
END Pause;
PROCEDURE AlertPause (n: LONGREAL) RAISES {Alerted} =
VAR self := GetActivation();
BEGIN
XPause(self, n, alertable := TRUE);
END AlertPause;
PROCEDURE Yield () =
BEGIN
WITH r = Usched.yield() DO
IF r # 0 THEN DieI(ThisLine(), Cerrno.GetErrno()) END;
END;
END Yield;
PROCEDURE IOWait (fd: CARDINAL; read: BOOLEAN;
timeoutInterval: LONGREAL := -1.0D0): WaitResult =
<*FATAL Alerted*>
VAR self := GetActivation();
BEGIN
TRY
IF perfOn THEN PerfChanged(State.blocking) END;
RETURN XIOWait(self, fd, read, timeoutInterval, alertable := FALSE);
FINALLY
IF perfOn THEN PerfRunning() END;
END;
END IOWait;
PROCEDURE IOAlertWait (fd: CARDINAL; read: BOOLEAN;
timeoutInterval: LONGREAL := -1.0D0): WaitResult
RAISES {Alerted} =
VAR self := GetActivation();
BEGIN
TRY
IF perfOn THEN PerfChanged(State.blocking) END;
RETURN XIOWait(self, fd, read, timeoutInterval, alertable := TRUE);
FINALLY
IF perfOn THEN PerfRunning() END;
END;
END IOAlertWait;
PROCEDURE XIOWait (self: Activation; fd: CARDINAL; read: BOOLEAN;
interval: LONGREAL; alertable: BOOLEAN): WaitResult
RAISES {Alerted} =
VAR res: WaitResult;
subInterval: LONGREAL := 1.0d0;
err: int := 0;
again := FALSE;
BEGIN
IF NOT alertable THEN
subInterval := interval;
ELSIF interval < 0.0d0 THEN
interval := LAST(LONGREAL);
ELSIF interval < subInterval THEN
subInterval := interval;
END;
IF alertable AND XTestAlert(self) THEN RAISE Alerted END;
LOOP
res := VAL(Poll(fd, ORD(read), subInterval), WaitResult);
IF alertable AND XTestAlert(self) THEN RAISE Alerted END;
CASE res OF
| WaitResult.FDError, WaitResult.Ready =>
RETURN res;
| WaitResult.Error =>
err := Cerrno.GetErrno();
IF err = Uerror.EINTR THEN
(* spurious wakeups are OK *)
ELSIF err = Uerror.EAGAIN AND NOT again THEN
again := TRUE; (* try just once more *)
ELSE
RETURN WaitResult.Error;
END;
| WaitResult.Timeout =>
interval := interval - subInterval;
IF interval <= 0.0d0 THEN RETURN WaitResult.Timeout END;
IF interval < subInterval THEN
subInterval := interval;
END;
END;
END;
END XIOWait;
PROCEDURE WaitProcess (pid: int; VAR status: int): int =
(* ThreadPThread.m3 and ThreadPosix.m3 are very similar. *)
BEGIN
LOOP
WITH r = Uexec.waitpid(pid, ADR(status), 0) DO
<*ASSERT r # 0*>
IF r > 0 THEN RETURN r END;
IF Cerrno.GetErrno() # Uerror.EINTR THEN RETURN r END;
END;
END;
END WaitProcess;
(*--------------------------------------------------- Stack size controls ---*)
VAR defaultStackSize := 4096;
PROCEDURE GetDefaultStackSize (): CARDINAL =
BEGIN
RETURN defaultStackSize;
END GetDefaultStackSize;
PROCEDURE MinDefaultStackSize (size: CARDINAL) =
BEGIN
defaultStackSize := MAX(defaultStackSize, size);
END MinDefaultStackSize;
PROCEDURE IncDefaultStackSize (inc: CARDINAL) =
BEGIN
INC(defaultStackSize, inc);
END IncDefaultStackSize;
(*--------------------------------------------- Garbage collector support ---*)
(* NOTE: These routines are called indirectly by the low-level page fault
handler of the garbage collector. So, if they touched traced references,
they could trigger indefinite invocations of the fault handler. *)
(* In versions of SuspendOthers prior to the addition of the incremental
collector, it acquired 'cm' to guarantee that no suspended thread held it.
That way when the collector tried to acquire a mutex or signal a
condition, it wouldn't deadlock with the suspended thread that held cm.
With the VM-synchronized, incremental collector this design is inadequate.
Here's a deadlock that occurred:
Thread.Broadcast held cm,
then it touched its condition argument,
the page containing the condition was protected by the collector,
another thread started running the page fault handler,
the handler called SuspendOthers,
SuspendOthers tried to acquire cm.
So, SuspendOthers does not grab "cm" before shutting down the other
threads. If the collector tries to use any of the thread functions
that acquire "cm", it'll be deadlocked.
*)
VAR suspended: BOOLEAN := FALSE; (* LL=activeMu *)
PROCEDURE SuspendOthers () =
(* LL=0. Always bracketed with ResumeOthers which releases "activeMu" *)
BEGIN
WITH r = pthread_mutex_lock(activeMu,ThisLine()) DO <*ASSERT r=0*> END;
StopWorld();
<*ASSERT NOT suspended*>
suspended := TRUE;
END SuspendOthers;
PROCEDURE ResumeOthers () =
(* LL=activeMu. Always preceded by SuspendOthers. *)
BEGIN
<*ASSERT suspended*>
suspended := FALSE;
StartWorld();
WITH r = pthread_mutex_unlock(activeMu,ThisLine()) DO <*ASSERT r=0*> END;
END ResumeOthers;
PROCEDURE ProcessStacks (p: PROCEDURE (start, limit: ADDRESS)) =
(* LL=activeMu. Only called within {SuspendOthers, ResumeOthers} *)
VAR
me := GetActivation();
act: Activation;
BEGIN
ProcessMe(me, p);
act := me.next;
WHILE act # me DO
ProcessOther(act, p);
act := act.next;
END;
END ProcessStacks;
PROCEDURE ProcessEachStack (p: PROCEDURE (start, limit: ADDRESS)) =
(* LL=0 *)
VAR
me := GetActivation();
act: Activation;
acks: int;
nLive, nDead, newlySent: INTEGER := 0;
wait_nsecs := RETRY_INTERVAL;
BEGIN
WITH r = pthread_mutex_lock(activeMu,ThisLine()) DO <*ASSERT r=0*> END;
ProcessMe(me, p);
act := me.next;
WHILE act # me DO
(* stop *)
LOOP
<*ASSERT act.state = ActState.Started*>
SetState(act, ActState.Stopping);
IF SIG_SUSPEND = 0 THEN
IF StopThread(act) THEN
SetState(act, ActState.Stopped);
EXIT;
ELSE
SetState(act, ActState.Started);
END;
ELSE
SignalThread(act);
INC(nLive);
EXIT;
END;
Nanosleep(WAIT_UNIT);
END;
WHILE nLive > 0 DO
<*ASSERT SIG_SUSPEND # 0*>
WITH r = sem_getvalue(acks) DO <*ASSERT r=0*> END;
IF acks = nLive THEN EXIT END;
<*ASSERT acks < nLive*>
IF wait_nsecs <= 0 THEN
newlySent := 0;
<*ASSERT act.state # ActState.Starting*>
IF act.state # ActState.Stopped THEN
SetState(act, ActState.Stopping);
SignalThread(act);
INC(newlySent);
END;
WITH r = sem_getvalue(acks) DO <*ASSERT r=0*> END;
IF newlySent < nLive - acks THEN
(* how did we manage to lose some? *)
nLive := acks + newlySent;
END;
wait_nsecs := RETRY_INTERVAL;
ELSE
Nanosleep(WAIT_UNIT);
DEC(wait_nsecs, WAIT_UNIT);
END;
END;
FOR i := 0 TO nLive - 1 DO
WHILE sem_wait() # 0 DO
WITH r = Cerrno.GetErrno() DO
IF r # Uerror.EINTR THEN DieI(ThisLine(), r) END;
END;
(*retry*)
END;
END;
(* process *)
ProcessOther(act, p);
(* start *)
nDead := 0;
LOOP
<*ASSERT act.state = ActState.Stopped*>
SetState(act, ActState.Starting);
IF SIG_SUSPEND = 0 THEN
IF StartThread(act) THEN
SetState(act, ActState.Started);
EXIT;
ELSE
SetState(act, ActState.Stopped);
END;
ELSE
SignalThread(act);
INC(nDead);
EXIT;
END;
Nanosleep(WAIT_UNIT);
END;
WHILE nDead > 0 DO
<*ASSERT SIG_SUSPEND # 0*>
WITH r = sem_getvalue(acks) DO <*ASSERT r=0*> END;
IF acks = nDead THEN EXIT END;
<*ASSERT acks < nDead*>
IF wait_nsecs <= 0 THEN
newlySent := 0;
<*ASSERT act.state # ActState.Stopping*>
IF act.state # ActState.Started THEN
SignalThread(act);
INC(newlySent);
END;
WITH r = sem_getvalue(acks) DO <*ASSERT r=0*> END;
IF newlySent < nDead - acks THEN
(* how did we manage to lose some? *)
nDead := acks + newlySent;
END;
wait_nsecs := RETRY_INTERVAL;
ELSE
Nanosleep(WAIT_UNIT);
DEC(wait_nsecs, WAIT_UNIT);
END;
END;
FOR i := 0 TO nDead - 1 DO
WHILE sem_wait() # 0 DO
WITH r = Cerrno.GetErrno() DO
IF r # Uerror.EINTR THEN DieI(ThisLine(), r) END;
END;
(*retry*)
END;
END;
END;
WITH r = pthread_mutex_unlock(activeMu,ThisLine()) DO <*ASSERT r=0*> END;
END ProcessEachStack;
PROCEDURE ProcessMe (me: Activation; p: PROCEDURE (start, limit: ADDRESS)) =
(* LL=activeMu *)
BEGIN
<*ASSERT me.state # ActState.Stopped*>
IF DEBUG THEN
RTIO.PutText("Processing act="); RTIO.PutAddr(me); RTIO.PutText("\n"); RTIO.Flush();
END;
RTHeapRep.FlushThreadState(me.heapState);
ProcessLive(me.stackbase, p);
END ProcessMe;
PROCEDURE ProcessOther (act: Activation; p: PROCEDURE (start, stop: ADDRESS)) =
(* LL=activeMu *)
BEGIN
<*ASSERT act.state = ActState.Stopped*>
IF DEBUG THEN
RTIO.PutText("Processing act="); RTIO.PutAddr(act); RTIO.PutText("\n"); RTIO.Flush();
END;
RTHeapRep.FlushThreadState(act.heapState);
IF act.stackbase # NIL THEN
ProcessStopped(act.handle, act.stackbase, act.context, p);
END;
END ProcessOther;
(* Signal based suspend/resume *)
PROCEDURE SignalThread(act: Activation) =
(* LL=activeMu *)
BEGIN
<*ASSERT SIG_SUSPEND # 0*>
LOOP
WITH z = pthread_kill(act.handle, SIG_SUSPEND) DO
IF z = 0 THEN EXIT END;
IF z # Uerror.EAGAIN THEN DieI(ThisLine(), z) END;
(* try it again... *)
END;
END;
END SignalThread;
PROCEDURE StopThread (act: Activation): BOOLEAN =
(* LL=activeMu *)
BEGIN
<*ASSERT act.state = ActState.Stopping*>
<*ASSERT SIG_SUSPEND = 0*>
IF NOT SuspendThread(act.handle) THEN RETURN FALSE END;
IF act.heapState.inCritical # 0 THEN
IF NOT RestartThread(act.handle) THEN <*ASSERT FALSE*> END;
RETURN FALSE;
END;
RETURN TRUE;
END StopThread;
PROCEDURE StartThread (act: Activation): BOOLEAN =
(* LL=activeMu *)
BEGIN
<*ASSERT act.state = ActState.Starting*>
<*ASSERT SIG_SUSPEND = 0*>
RETURN RestartThread(act.handle);
END StartThread;
PROCEDURE StopWorld () =
(* LL=activeMu *)
VAR
me := GetActivation();
act: Activation;
acks: int;
nLive, newlySent: INTEGER;
retry: BOOLEAN;
wait_nsecs := RETRY_INTERVAL;
BEGIN
IF DEBUG THEN
RTIO.PutText("Stopping from act="); RTIO.PutAddr(me); RTIO.PutText("\n"); RTIO.Flush();
END;
nLive := 0;
LOOP
retry := FALSE;
act := me.next;
WHILE act # me DO
<*ASSERT act.state # ActState.Starting*>
IF act.state = ActState.Started THEN
SetState(act, ActState.Stopping);
IF SIG_SUSPEND = 0 THEN
IF StopThread(act) THEN
SetState(act, ActState.Stopped);
ELSE
SetState(act, ActState.Started);
retry := TRUE;
END;
ELSE
SignalThread(act);
INC(nLive);
END;
END;
act := act.next;
END;
IF NOT retry THEN EXIT END;
Nanosleep(WAIT_UNIT);
END;
WHILE nLive > 0 DO
<*ASSERT SIG_SUSPEND # 0*>
WITH r = sem_getvalue(acks) DO <*ASSERT r=0*> END;
IF acks = nLive THEN EXIT END;
<*ASSERT acks < nLive*>
IF wait_nsecs <= 0 THEN
newlySent := 0;
act := me.next;
WHILE act # me DO
<*ASSERT act.state # ActState.Starting*>
IF act.state # ActState.Stopped THEN
SetState(act, ActState.Stopping);
SignalThread(act);
INC(newlySent);
END;
act := act.next;
END;
WITH r = sem_getvalue(acks) DO <*ASSERT r=0*> END;
IF newlySent < nLive - acks THEN
(* how did we manage to lose some? *)
nLive := acks + newlySent;
END;
wait_nsecs := RETRY_INTERVAL;
ELSE
Nanosleep(WAIT_UNIT);
DEC(wait_nsecs, WAIT_UNIT);
END;
END;
(* drain semaphore *)
FOR i := 0 TO nLive-1 DO
WHILE sem_wait() # 0 DO
WITH r = Cerrno.GetErrno() DO
IF r # Uerror.EINTR THEN DieI(ThisLine(), r) END;
END;
(*retry*)
END;
END;
IF DEBUG THEN
RTIO.PutText("Stopped from act="); RTIO.PutAddr(me); RTIO.PutText("\n"); RTIO.Flush();
DumpThreads();
END;
END StopWorld;
PROCEDURE StartWorld () =
(* LL=activeMu *)
VAR
me := GetActivation();
act: Activation;
acks: int;
nDead, newlySent: INTEGER;
retry: BOOLEAN;
wait_nsecs := RETRY_INTERVAL;
BEGIN
IF DEBUG THEN
RTIO.PutText("Starting from act="); RTIO.PutAddr(me); RTIO.PutText("\n"); RTIO.Flush();
END;
nDead := 0;
LOOP
retry := FALSE;
act := me.next;
WHILE act # me DO
<*ASSERT act.state # ActState.Stopping*>
IF act.state # ActState.Started THEN
SetState(act, ActState.Starting);
IF SIG_SUSPEND = 0 THEN
IF StartThread(act) THEN
SetState(act, ActState.Started);
ELSE
SetState(act, ActState.Stopped);
retry := TRUE;
END;
ELSE
SignalThread(act);
INC(nDead);
END;
END;
act := act.next;
END;
IF NOT retry THEN EXIT END;
Nanosleep(WAIT_UNIT);
END;
WHILE nDead > 0 DO
<*ASSERT SIG_SUSPEND # 0*>
WITH r = sem_getvalue(acks) DO <*ASSERT r=0*> END;
IF acks = nDead THEN EXIT END;
<*ASSERT acks < nDead*>
IF wait_nsecs <= 0 THEN
newlySent := 0;
act := me.next;
WHILE act # me DO
<*ASSERT act.state # ActState.Stopping*>
IF act.state # ActState.Started THEN
SignalThread(act);
INC(newlySent);
END;
act := act.next;
END;
WITH r = sem_getvalue(acks) DO <*ASSERT r=0*> END;
IF newlySent < nDead - acks THEN
(* how did we manage to lose some? *)
nDead := acks + newlySent;
END;
wait_nsecs := RETRY_INTERVAL;
ELSE
Nanosleep(WAIT_UNIT);
DEC(wait_nsecs, WAIT_UNIT);
END;
END;
(* drain semaphore *)
FOR i := 0 TO nDead-1 DO
WHILE sem_wait() # 0 DO
WITH r = Cerrno.GetErrno() DO
IF r # Uerror.EINTR THEN DieI(ThisLine(), r) END;
END;
(*retry*)
END;
END;
IF DEBUG THEN
RTIO.PutText("Started from act="); RTIO.PutAddr(me); RTIO.PutText("\n"); RTIO.Flush();
DumpThreads();
END;
END StartWorld;
PROCEDURE SignalHandler (sig: int; <*UNUSED*>info: ADDRESS; context: ADDRESS) =
VAR
errno := Cerrno.GetErrno();
me := GetActivation();
BEGIN
<*ASSERT sig = SIG_SUSPEND*>
IF me.state = ActState.Stopping THEN
IF me.heapState.inCritical # 0 THEN
me.state := ActState.Started;
RETURN;
END;
me.state := ActState.Stopped;
<*ASSERT me.context = NIL*>
me.context := context;
WITH r = sem_post() DO <*ASSERT r=0*> END;
REPEAT sigsuspend() UNTIL me.state = ActState.Starting;
me.context := NIL;
me.state := ActState.Started;
WITH r = sem_post() DO <*ASSERT r=0*> END;
END;
Cerrno.SetErrno(errno);
END SignalHandler;
(*----------------------------------------------------------- misc. stuff ---*)
PROCEDURE MyId (): Id RAISES {} =
VAR me := GetActivation();
BEGIN
IF me = NIL
THEN RETURN 0
ELSE RETURN me.slot;
END;
END MyId;
PROCEDURE MyFPState (): UNTRACED REF FloatMode.ThreadState =
VAR me := GetActivation();
BEGIN
RETURN ADR(me.floatState);
END MyFPState;
PROCEDURE MyHeapState (): UNTRACED REF RTHeapRep.ThreadState =
VAR me := GetActivation();
BEGIN
RETURN ADR(me.heapState);
END MyHeapState;
PROCEDURE DisableSwitching () =
BEGIN
(* no user-level thread switching *)
END DisableSwitching;
PROCEDURE EnableSwitching () =
BEGIN
(* no user-level thread switching *)
END EnableSwitching;
(*---------------------------------------------------------------- errors ---*)
PROCEDURE Die (lineno: INTEGER; msg: TEXT) =
BEGIN
RTError.Msg (ThisFile(), lineno, "Thread client error: ", msg);
END Die;
PROCEDURE DieI (lineno: INTEGER; i: INTEGER) =
BEGIN
RTError.MsgI (ThisFile(), lineno, "Thread client error: ", i);
END DieI;
(*------------------------------------------------------ ShowThread hooks ---*)
VAR
perfW : RTPerfTool.Handle;
perfOn: BOOLEAN := FALSE; (* LL = perfMu *)
PROCEDURE PerfStart () =
BEGIN
IF RTPerfTool.Start ("showthread", perfW) THEN
perfOn := TRUE;
RTProcess.RegisterExitor (PerfStop);
END;
END PerfStart;
PROCEDURE PerfStop () =
BEGIN
(* UNSAFE, but needed to prevent deadlock if we're crashing! *)
RTPerfTool.Close (perfW);
END PerfStop;
CONST
EventSize = (BITSIZE(ThreadEvent.T) + BITSIZE(CHAR) - 1) DIV BITSIZE(CHAR);
TYPE
TE = ThreadEvent.Kind;
PROCEDURE PerfChanged (s: State) =
VAR
e := ThreadEvent.T {kind := TE.Changed, id := MyId(), state := s};
BEGIN
WITH r = pthread_mutex_lock(perfMu,ThisLine()) DO <*ASSERT r=0*> END;
perfOn := RTPerfTool.Send (perfW, ADR (e), EventSize);
WITH r = pthread_mutex_unlock(perfMu,ThisLine()) DO <*ASSERT r=0*> END;
END PerfChanged;
PROCEDURE PerfDeleted () =
VAR
e := ThreadEvent.T {kind := TE.Deleted, id := MyId()};
BEGIN
WITH r = pthread_mutex_lock(perfMu,ThisLine()) DO <*ASSERT r=0*> END;
perfOn := RTPerfTool.Send (perfW, ADR (e), EventSize);
WITH r = pthread_mutex_unlock(perfMu,ThisLine()) DO <*ASSERT r=0*> END;
END PerfDeleted;
PROCEDURE PerfRunning () =
VAR
e := ThreadEvent.T {kind := TE.Running, id := MyId()};
BEGIN
WITH r = pthread_mutex_lock(perfMu,ThisLine()) DO <*ASSERT r=0*> END;
perfOn := RTPerfTool.Send (perfW, ADR (e), EventSize);
WITH r = pthread_mutex_unlock(perfMu,ThisLine()) DO <*ASSERT r=0*> END;
END PerfRunning;
(*-------------------------------------------------------- Initialization ---*)
PROCEDURE InitWithStackBase (stackbase: ADDRESS) =
VAR
self: T;
me: Activation;
BEGIN
InitC(stackbase);
me := NEW(Activation,
mutex := pthread_mutex_new(),
cond := pthread_cond_new());
InitActivations(me);
me.stackbase := stackbase;
IF me.mutex = NIL OR me.cond = NIL THEN
Die(ThisLine(), "Thread initialization failed.");
END;
self := NEW(T, act := me, closure := NIL, join := NIL);
me.slot := AssignSlot(self);
joinMu := NEW(MUTEX);
PerfStart();
IF perfOn THEN PerfRunning() END;
IF RTParams.IsPresent("backgroundgc") THEN
RTCollectorSRC.StartBackgroundCollection();
END;
IF RTParams.IsPresent("foregroundgc") THEN
RTCollectorSRC.StartForegroundCollection();
END;
END InitWithStackBase;
PROCEDURE Init ()=
VAR r: INTEGER;
BEGIN
r := RTProcess.RegisterForkHandlers(AtForkPrepare,
AtForkParent,
AtForkChild);
IF r # 0 THEN DieI(ThisLine(), r) END;
InitWithStackBase(ADR(r)); (* not quite accurate but hopefully ok *)
END Init;
PROCEDURE PThreadLockMutex(mutex: pthread_mutex_t; line: INTEGER) =
BEGIN
IF mutex # NIL THEN
WITH r = pthread_mutex_lock(mutex,ThisLine()) DO
IF r # 0 THEN DieI(line, r) END;
END;
END;
END PThreadLockMutex;
PROCEDURE PThreadUnlockMutex(mutex: pthread_mutex_t; line: INTEGER) =
BEGIN
IF mutex # NIL THEN
WITH r = pthread_mutex_unlock(mutex,ThisLine()) DO
IF r # 0 THEN DieI(line, r) END;
END;
END;
END PThreadUnlockMutex;
PROCEDURE AtForkPrepare() =
VAR me := GetActivation();
act: Activation;
BEGIN
PThreadLockMutex(slotsMu, ThisLine());
PThreadLockMutex(perfMu, ThisLine());
PThreadLockMutex(initMu, ThisLine()); (* InitMutex => RegisterFinalCleanup => LockHeap *)
PThreadLockMutex(heapMu, ThisLine());
PThreadLockMutex(activeMu, ThisLine()); (* LockHeap => SuspendOthers => activeMu *)
(* Walk activations and lock all threads.
* NOTE: We have initMu, activeMu, so slots won't change, conditions and
* mutexes won't be initialized on-demand.
*)
act := me;
REPEAT
PThreadLockMutex(act.mutex, ThisLine());
act := act.next;
UNTIL act = me;
END AtForkPrepare;
PROCEDURE AtForkParent() =
VAR me := GetActivation();
act: Activation;
cond: Condition;
BEGIN
(* Walk activations and unlock all threads, conditions. *)
act := me;
REPEAT
cond := slots[act.slot].join;
IF cond # NIL THEN PThreadUnlockMutex(cond.mutex, ThisLine()) END;
PThreadUnlockMutex(act.mutex, ThisLine());
act := act.next;
UNTIL act = me;
PThreadUnlockMutex(activeMu, ThisLine());
PThreadUnlockMutex(heapMu, ThisLine());
PThreadUnlockMutex(initMu, ThisLine());
PThreadUnlockMutex(perfMu, ThisLine());
PThreadUnlockMutex(slotsMu, ThisLine());
END AtForkParent;
PROCEDURE AtForkChild() =
BEGIN
AtForkParent();
InitWithStackBase(GetActivation().stackbase);
END AtForkChild;
(*------------------------------------------------------------- collector ---*)
(* These procedures provide synchronization primitives for the allocator
and collector. *)
VAR
holder: pthread_t;
inCritical := 0;
PROCEDURE LockHeap () =
VAR self := pthread_self();
BEGIN
WITH r = pthread_mutex_lock(heapMu,ThisLine()) DO <*ASSERT r=0*> END;
IF inCritical = 0 THEN
holder := self;
ELSIF pthread_equal(holder, self) = 0 THEN
WITH r = pthread_cond_wait(heapCond, heapMu, ThisLine()) DO <*ASSERT r=0*> END;
END;
INC(inCritical);
WITH r = pthread_mutex_unlock(heapMu,ThisLine()) DO <*ASSERT r=0*> END;
END LockHeap;
PROCEDURE UnlockHeap () =
VAR self := pthread_self();
BEGIN
WITH r = pthread_mutex_lock(heapMu,ThisLine()) DO <*ASSERT r=0*> END;
<*ASSERT pthread_equal(holder, self) # 0*>
DEC(inCritical);
IF inCritical = 0 THEN
holder := NIL;
END;
WITH r = pthread_mutex_unlock(heapMu,ThisLine()) DO <*ASSERT r=0*> END;
END UnlockHeap;
PROCEDURE WaitHeap () =
VAR self := pthread_self();
BEGIN
WITH r = pthread_mutex_lock(heapMu,ThisLine()) DO <*ASSERT r=0*> END;
<*ASSERT pthread_equal(holder, self) # 0*>
DEC(inCritical);
<*ASSERT inCritical = 0*>
WITH r = pthread_cond_wait(heapCond, heapMu, ThisLine()) DO <*ASSERT r=0*> END;
holder := self;
<*ASSERT inCritical = 0*>
INC(inCritical);
WITH r = pthread_mutex_unlock(heapMu,ThisLine()) DO <*ASSERT r=0*> END;
END WaitHeap;
PROCEDURE BroadcastHeap () =
BEGIN
WITH r = pthread_cond_broadcast(heapCond) DO <*ASSERT r=0*> END;
END BroadcastHeap;
(*--------------------------------------------- exception handling support --*)
PROCEDURE GetCurrentHandlers (): ADDRESS =
VAR me := GetActivation();
BEGIN
RETURN me.frame;
END GetCurrentHandlers;
PROCEDURE SetCurrentHandlers (h: ADDRESS) =
VAR me := GetActivation();
BEGIN
me.frame := h;
END SetCurrentHandlers;
(*RTHooks.PushEFrame*)
PROCEDURE PushEFrame (frame: ADDRESS) =
TYPE Frame = UNTRACED REF RECORD next: ADDRESS END;
VAR
me := GetActivation();
f: Frame := frame;
BEGIN
f.next := me.frame;
me.frame := f;
END PushEFrame;
(*RTHooks.PopEFrame*)
PROCEDURE PopEFrame (frame: ADDRESS) =
VAR me := GetActivation();
BEGIN
me.frame := frame;
END PopEFrame;
VAR DEBUG := RTParams.IsPresent("debugthreads");
BEGIN
END ThreadPThread.
-------------- next part --------------
(* Copyright (C) 2005, Purdue Research Foundation *)
(* All rights reserved. *)
(* See the file COPYRIGHT-PURDUE for a full description. *)
(*---------------------------------------------------------------------------*)
UNSAFE INTERFACE ThreadPThread;
FROM Ctypes IMPORT int;
FROM Cstddef IMPORT size_t;
TYPE
(* These are opaque C references (not necessarily UNTRACED REF ADDRESS) *)
pthread_t = UNTRACED BRANDED REF ADDRESS;
pthread_mutex_t = UNTRACED BRANDED REF ADDRESS;
pthread_cond_t = UNTRACED BRANDED REF ADDRESS;
Activation <: ADDRESS; (* untraced thread stated stored in thread local *)
(*---------------------------------------------------------------------------*)
PROCEDURE SignalHandler(sig: int; info, uap: ADDRESS);
(*---------------------------------------------------------------------------*)
<*EXTERNAL "ThreadPThread__SIG_SUSPEND"*>
(*CONST*) VAR SIG_SUSPEND: int;
(*---------------------------------------------------------------------------*)
<*EXTERNAL "ThreadPThread__InitC"*>
PROCEDURE InitC(bottom: ADDRESS);
(*---------------------------------------------------------------------------*)
(* the semaphore is implied *)
<*EXTERNAL "ThreadPThread__sem_wait"*>
PROCEDURE sem_wait (): int;
<*EXTERNAL "ThreadPThread__sem_post"*>
PROCEDURE sem_post (): int;
<*EXTERNAL "ThreadPThread__sem_getvalue"*>
PROCEDURE sem_getvalue (VAR value: int): int;
(*---------------------------------------------------------------------------*)
(* the signal set is implied *)
<*EXTERNAL "ThreadPThread__sigsuspend"*>
PROCEDURE sigsuspend ();
(*---------------------------------------------------------------------------*)
(* pthread_create but replace attr with stackSize so that attr need not be known to Modula-3 *)
<*EXTERNAL "ThreadPThread__thread_create"*>
PROCEDURE thread_create(stackSize: size_t;
start_routine: PROCEDURE(arg: ADDRESS): ADDRESS; arg: ADDRESS): int;
<*EXTERNAL ThreadPThread__pthread_detach_self*>
PROCEDURE pthread_detach_self(): int;
<*EXTERNAL ThreadPThread__pthread_self*>
PROCEDURE pthread_self(): pthread_t;
<*EXTERNAL "ThreadPThread__pthread_equal"*>
PROCEDURE pthread_equal(t1, t2: pthread_t): int;
<*EXTERNAL "ThreadPThread__pthread_kill"*>
PROCEDURE pthread_kill(t: pthread_t; sig: int): int;
(*---------------------------------------------------------------------------*)
(* static mutexes and conditions *)
<*EXTERNAL "ThreadPThread__activeMu"*> VAR activeMu: pthread_mutex_t;
<*EXTERNAL "ThreadPThread__slotsMu"*> VAR slotsMu: pthread_mutex_t;
<*EXTERNAL "ThreadPThread__initMu"*> VAR initMu: pthread_mutex_t;
<*EXTERNAL "ThreadPThread__perfMu"*> VAR perfMu: pthread_mutex_t;
<*EXTERNAL "ThreadPThread__heapMu"*> VAR heapMu: pthread_mutex_t;
<*EXTERNAL "ThreadPThread__heapCond"*> VAR heapCond: pthread_cond_t;
(* thread local "activation" *)
<*EXTERNAL ThreadPThread__SetActivation*>
PROCEDURE SetActivation(value: Activation);
<*EXTERNAL ThreadPThread__GetActivation*>
PROCEDURE GetActivation(): Activation;
(*---------------------------------------------------------------------------*)
(* support for dynamically allocated mutexes and condition variables *)
<*EXTERNAL "ThreadPThread__pthread_mutex_new"*>
PROCEDURE pthread_mutex_new():pthread_mutex_t;
<*EXTERNAL "ThreadPThread__pthread_mutex_delete"*>
PROCEDURE pthread_mutex_delete(a:pthread_mutex_t);
<*EXTERNAL ThreadPThread__pthread_mutex_lock*>
PROCEDURE pthread_mutex_lock(mutex: pthread_mutex_t;line :int):int;
<*EXTERNAL ThreadPThread__pthread_mutex_unlock*>
PROCEDURE pthread_mutex_unlock(mutex: pthread_mutex_t;line :int):int;
<*EXTERNAL "ThreadPThread__pthread_cond_new"*>
PROCEDURE pthread_cond_new(): pthread_cond_t;
<*EXTERNAL "ThreadPThread__pthread_cond_delete"*>
PROCEDURE pthread_cond_delete(cond: pthread_cond_t);
<*EXTERNAL ThreadPThread__pthread_cond_wait*>
PROCEDURE pthread_cond_wait(cond: pthread_cond_t; mutex: pthread_mutex_t; line:int):int;
<*EXTERNAL ThreadPThread__pthread_cond_timedwait*>
PROCEDURE pthread_cond_timedwait(cond: pthread_cond_t;
mutex: pthread_mutex_t;
abs: LONGREAL(*Time.T*)):int;
<*EXTERNAL ThreadPThread__pthread_cond_signal*>
PROCEDURE pthread_cond_signal(cond: pthread_cond_t):int;
<*EXTERNAL ThreadPThread__pthread_cond_broadcast*>
PROCEDURE pthread_cond_broadcast(cond: pthread_cond_t):int;
(*---------------------------------------------------------------------------*)
<*EXTERNAL "ThreadPThread__Nanosleep"*>
PROCEDURE Nanosleep(nanoseconds: INTEGER);
(*---------------------------------------------------------------------------*)
<*EXTERNAL "ThreadPThread__SuspendThread"*>
PROCEDURE SuspendThread (t: pthread_t): BOOLEAN;
<*EXTERNAL "ThreadPThread__RestartThread"*>
PROCEDURE RestartThread (t: pthread_t): BOOLEAN;
<*EXTERNAL "ThreadPThread__ProcessLive"*>
PROCEDURE ProcessLive
(bottom: ADDRESS; p: PROCEDURE(start, limit: ADDRESS));
<*EXTERNAL "ThreadPThread__ProcessStopped"*>
PROCEDURE ProcessStopped
(t: pthread_t; bottom, context: ADDRESS; p: PROCEDURE(start, limit: ADDRESS));
(*---------------------------------------------------------------------------*)
END ThreadPThread.
-------------- next part --------------
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 344 lock 0x1383d70 self 0x1009400
l. 348 unlock 0x1383d70 self 0x1009400
l. 350 lock 0x1383d70 self 0x1009400
l. 381 unlock 0x1383d70 self 0x1009400
l. 103 lock 0x1383d78 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 112 unlock 0x1383d78 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250e0 self 0x1009400
l. 125 unlock 0x10250e0 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250e0 self 0x1009400
l. 157 unlock 0x10250e0 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250e0 self 0x1009400
l. 125 unlock 0x10250e0 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250e0 self 0x1009400
l. 157 unlock 0x10250e0 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250e0 self 0x1009400
l. 125 unlock 0x10250e0 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250e0 self 0x1009400
l. 157 unlock 0x10250e0 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250e0 self 0x1009400
l. 125 unlock 0x10250e0 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250e0 self 0x1009400
l. 157 unlock 0x10250e0 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250e0 self 0x1009400
l. 125 unlock 0x10250e0 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250e0 self 0x1009400
l. 157 unlock 0x10250e0 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 103 lock 0x1383d78 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 112 unlock 0x1383d78 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250e8 self 0x1009400
l. 125 unlock 0x10250e8 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250e8 self 0x1009400
l. 157 unlock 0x10250e8 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 103 lock 0x1383d78 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 112 unlock 0x1383d78 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250f0 self 0x1009400
l. 125 unlock 0x10250f0 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250f0 self 0x1009400
l. 157 unlock 0x10250f0 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 757 lock 0x1383d68 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 769 unlock 0x1383d68 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 757 lock 0x1383d68 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 769 unlock 0x1383d68 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 103 lock 0x1383d78 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 112 unlock 0x1383d78 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250f8 self 0x1009400
l. 125 unlock 0x10250f8 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250f8 self 0x1009400
l. 157 unlock 0x10250f8 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250f8 self 0x1009400
l. 125 unlock 0x10250f8 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250f8 self 0x1009400
l. 157 unlock 0x10250f8 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250f8 self 0x1009400
l. 125 unlock 0x10250f8 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250f8 self 0x1009400
l. 157 unlock 0x10250f8 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 103 lock 0x1383d78 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 112 unlock 0x1383d78 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025100 self 0x1009400
l. 125 unlock 0x1025100 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250e0 self 0x1009400
l. 125 unlock 0x10250e0 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250e0 self 0x1009400
l. 157 unlock 0x10250e0 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025100 self 0x1009400
l. 157 unlock 0x1025100 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 757 lock 0x1383d68 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 769 unlock 0x1383d68 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 757 lock 0x1383d68 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 769 unlock 0x1383d68 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250f0 self 0x1009400
l. 125 unlock 0x10250f0 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250f0 self 0x1009400
l. 157 unlock 0x10250f0 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 103 lock 0x1383d78 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 112 unlock 0x1383d78 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250f0 self 0x1009400
l. 125 unlock 0x10250f0 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250f0 self 0x1009400
l. 157 unlock 0x10250f0 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250f0 self 0x1009400
l. 125 unlock 0x10250f0 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250f0 self 0x1009400
l. 157 unlock 0x10250f0 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025108 self 0x1009400
l. 125 unlock 0x1025108 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025108 self 0x1009400
l. 157 unlock 0x1025108 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 103 lock 0x1383d78 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 112 unlock 0x1383d78 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025110 self 0x1009400
l. 125 unlock 0x1025110 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025110 self 0x1009400
l. 157 unlock 0x1025110 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 757 lock 0x1383d68 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 769 unlock 0x1383d68 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 103 lock 0x1383d78 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 112 unlock 0x1383d78 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025118 self 0x1009400
l. 125 unlock 0x1025118 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025118 self 0x1009400
l. 157 unlock 0x1025118 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 103 lock 0x1383d78 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 112 unlock 0x1383d78 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025120 self 0x1009400
l. 125 unlock 0x1025120 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025120 self 0x1009400
l. 157 unlock 0x1025120 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025120 self 0x1009400
l. 125 unlock 0x1025120 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025120 self 0x1009400
l. 157 unlock 0x1025120 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025120 self 0x1009400
l. 125 unlock 0x1025120 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025120 self 0x1009400
l. 157 unlock 0x1025120 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025120 self 0x1009400
l. 125 unlock 0x1025120 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025120 self 0x1009400
l. 157 unlock 0x1025120 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025120 self 0x1009400
l. 125 unlock 0x1025120 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025120 self 0x1009400
l. 157 unlock 0x1025120 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025120 self 0x1009400
l. 125 unlock 0x1025120 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025120 self 0x1009400
l. 157 unlock 0x1025120 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025120 self 0x1009400
l. 125 unlock 0x1025120 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025120 self 0x1009400
l. 157 unlock 0x1025120 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025120 self 0x1009400
l. 125 unlock 0x1025120 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025120 self 0x1009400
l. 157 unlock 0x1025120 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025120 self 0x1009400
l. 125 unlock 0x1025120 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025120 self 0x1009400
l. 157 unlock 0x1025120 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025120 self 0x1009400
l. 125 unlock 0x1025120 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025120 self 0x1009400
l. 157 unlock 0x1025120 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025120 self 0x1009400
l. 125 unlock 0x1025120 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025120 self 0x1009400
l. 157 unlock 0x1025120 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250f8 self 0x1009400
l. 125 unlock 0x10250f8 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250f8 self 0x1009400
l. 157 unlock 0x10250f8 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x10250f0 self 0x1009400
l. 125 unlock 0x10250f0 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x10250f0 self 0x1009400
l. 157 unlock 0x10250f0 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025100 self 0x1009400
l. 125 unlock 0x1025100 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 757 lock 0x1383d68 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 769 unlock 0x1383d68 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
l. 152 lock 0x1025100 self 0x1009400
l. 157 unlock 0x1025100 self 0x1009400
l. 158 unlock 0x10250a8 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 757 lock 0x1383d68 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 769 unlock 0x1383d68 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 344 lock 0x1383d70 self 0x1009400
l. 381 unlock 0x1383d70 self 0x1009400
l. 103 lock 0x1383d78 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 112 unlock 0x1383d78 self 0x1009400
l. 121 lock 0x10250a8 self 0x1009400
l. 122 lock 0x1025138 self 0x1009400
l. 125 unlock 0x1025138 self 0x1009400
l. 126 unlock 0x10250a8 self 0x1009400
l. 103 lock 0x1383d78 self 0x1009400
l. 1373 lock 0x1383d88 self 0x1009400
l. 1380 unlock 0x1383d88 self 0x1009400
l. 1386 lock 0x1383d88 self 0x1009400
l. 1392 unlock 0x1383d88 self 0x1009400
l. 112 unlock 0x1383d78 self 0x1009400
l. 194 lock 0x10250a8 self 0x1009400
l. 198 lock 0x1025140 self 0x1009400
l. 202 unlock 0x1025140 self 0x1009400
l. 151 lock 0x10250a8 self 0x1009400
ERROR: pthread_mutex_lock:11
More information about the M3devel
mailing list