Threads.c revision 444c061a
1444c061aSmrg/* $Xorg: Threads.c,v 1.4 2001/02/09 02:03:59 xorgcvs Exp $ */
2444c061aSmrg
3444c061aSmrg/************************************************************
4444c061aSmrgCopyright 1993 by Sun Microsystems, Inc. Mountain View, CA.
5444c061aSmrg
6444c061aSmrg                    All Rights Reserved
7444c061aSmrg
8444c061aSmrgPermission  to  use,  copy,  modify,  and  distribute   this
9444c061aSmrgsoftware  and  its documentation for any purpose and without
10444c061aSmrgfee is hereby granted, provided that the above copyright no-
11444c061aSmrgtice  appear  in all copies and that both that copyright no-
12444c061aSmrgtice and this permission notice appear in  supporting  docu-
13444c061aSmrgmentation,  and  that the name Sun not be used in advertising
14444c061aSmrgor publicity pertaining to distribution  of  the software
15444c061aSmrgwithout specific prior written permission. Sun makes no
16444c061aSmrgrepresentations about the suitability of this software for
17444c061aSmrgany purpose. It is provided "as is" without any express or
18444c061aSmrgimplied warranty.
19444c061aSmrg
20444c061aSmrgSUN DISCLAIMS ALL WARRANTIES WITH REGARD TO  THIS  SOFTWARE,
21444c061aSmrgINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
22444c061aSmrgNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE  LI-
23444c061aSmrgABLE  FOR  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
24444c061aSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,  DATA  OR
25444c061aSmrgPROFITS,  WHETHER  IN  AN  ACTION OF CONTRACT, NEGLIGENCE OR
26444c061aSmrgOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
27444c061aSmrgTHE USE OR PERFORMANCE OF THIS SOFTWARE.
28444c061aSmrg
29444c061aSmrg********************************************************/
30444c061aSmrg
31444c061aSmrg/*
32444c061aSmrg
33444c061aSmrgCopyright 1994, 1998  The Open Group
34444c061aSmrg
35444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its
36444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that
37444c061aSmrgthe above copyright notice appear in all copies and that both that
38444c061aSmrgcopyright notice and this permission notice appear in supporting
39444c061aSmrgdocumentation.
40444c061aSmrg
41444c061aSmrgThe above copyright notice and this permission notice shall be included in
42444c061aSmrgall copies or substantial portions of the Software.
43444c061aSmrg
44444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
47444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
48444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
49444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
50444c061aSmrg
51444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be
52444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings
53444c061aSmrgin this Software without prior written authorization from The Open Group.
54444c061aSmrg
55444c061aSmrg*/
56444c061aSmrg/* $XFree86: xc/lib/Xt/Threads.c,v 3.6 2001/12/14 19:56:31 dawes Exp $ */
57444c061aSmrg
58444c061aSmrg#ifdef HAVE_CONFIG_H
59444c061aSmrg#include <config.h>
60444c061aSmrg#endif
61444c061aSmrg#include "IntrinsicI.h"
62444c061aSmrg
63444c061aSmrg#ifdef XTHREADS
64444c061aSmrg
65444c061aSmrg#define xmalloc __XtMalloc
66444c061aSmrg#define xfree XtFree
67444c061aSmrg#include <X11/Xthreads.h>
68444c061aSmrg
69444c061aSmrg#ifndef NDEBUG
70444c061aSmrg#define NDEBUG
71444c061aSmrg#endif
72444c061aSmrg#include <assert.h>
73444c061aSmrg#include <stdio.h>
74444c061aSmrg
75444c061aSmrgtypedef struct _ThreadStack {
76444c061aSmrg    unsigned int size;
77444c061aSmrg    int sp;
78444c061aSmrg    struct _Tstack {
79444c061aSmrg	xthread_t t;
80444c061aSmrg	xcondition_t c;
81444c061aSmrg    } *st;
82444c061aSmrg} ThreadStack;
83444c061aSmrg
84444c061aSmrgtypedef struct _LockRec {
85444c061aSmrg    xmutex_t mutex;
86444c061aSmrg    int level;
87444c061aSmrg    ThreadStack stack;
88444c061aSmrg#ifndef _XMUTEX_NESTS
89444c061aSmrg    xthread_t holder;
90444c061aSmrg    xcondition_t cond;
91444c061aSmrg#endif
92444c061aSmrg} LockRec;
93444c061aSmrg
94444c061aSmrg
95444c061aSmrg#define STACK_INCR 16
96444c061aSmrg
97444c061aSmrgstatic LockPtr process_lock = NULL;
98444c061aSmrg
99444c061aSmrgstatic void
100444c061aSmrgInitProcessLock(void)
101444c061aSmrg{
102444c061aSmrg    if(!process_lock) {
103444c061aSmrg    	process_lock = XtNew(LockRec);
104444c061aSmrg    	process_lock->mutex = xmutex_malloc();
105444c061aSmrg    	xmutex_init(process_lock->mutex);
106444c061aSmrg    	process_lock->level = 0;
107444c061aSmrg#ifndef _XMUTEX_NESTS
108444c061aSmrg    	process_lock->cond = xcondition_malloc();
109444c061aSmrg    	xcondition_init(process_lock->cond);
110444c061aSmrg    	xthread_clear_id(process_lock->holder);
111444c061aSmrg#endif
112444c061aSmrg    }
113444c061aSmrg}
114444c061aSmrg
115444c061aSmrgstatic void
116444c061aSmrgProcessLock(void)
117444c061aSmrg{
118444c061aSmrg#ifdef _XMUTEX_NESTS
119444c061aSmrg    xmutex_lock(process_lock->mutex);
120444c061aSmrg    process_lock->level++;
121444c061aSmrg#else
122444c061aSmrg    xthread_t this_thread = xthread_self();
123444c061aSmrg
124444c061aSmrg    xmutex_lock(process_lock->mutex);
125444c061aSmrg
126444c061aSmrg    if (!xthread_have_id(process_lock->holder)) {
127444c061aSmrg	process_lock->holder = this_thread;
128444c061aSmrg	xmutex_unlock(process_lock->mutex);
129444c061aSmrg	return;
130444c061aSmrg    }
131444c061aSmrg
132444c061aSmrg    if (xthread_equal(process_lock->holder,this_thread)) {
133444c061aSmrg	process_lock->level++;
134444c061aSmrg	xmutex_unlock(process_lock->mutex);
135444c061aSmrg	return;
136444c061aSmrg    }
137444c061aSmrg
138444c061aSmrg    while(xthread_have_id(process_lock->holder))
139444c061aSmrg	xcondition_wait(process_lock->cond, process_lock->mutex);
140444c061aSmrg
141444c061aSmrg    process_lock->holder = this_thread;
142444c061aSmrg    assert(xthread_equal(process_lock->holder, this_thread));
143444c061aSmrg    xmutex_unlock(process_lock->mutex);
144444c061aSmrg#endif
145444c061aSmrg}
146444c061aSmrg
147444c061aSmrgstatic void
148444c061aSmrgProcessUnlock(void)
149444c061aSmrg{
150444c061aSmrg#ifdef _XMUTEX_NESTS
151444c061aSmrg    process_lock->level--;
152444c061aSmrg    xmutex_unlock(process_lock->mutex);
153444c061aSmrg#else
154444c061aSmrg    xmutex_lock(process_lock->mutex);
155444c061aSmrg    assert(xthread_equal(process_lock->holder, xthread_self()));
156444c061aSmrg    if (process_lock->level != 0) {
157444c061aSmrg	process_lock->level--;
158444c061aSmrg	xmutex_unlock(process_lock->mutex);
159444c061aSmrg	return;
160444c061aSmrg    }
161444c061aSmrg
162444c061aSmrg    xthread_clear_id(process_lock->holder);
163444c061aSmrg    xcondition_signal(process_lock->cond);
164444c061aSmrg
165444c061aSmrg    xmutex_unlock(process_lock->mutex);
166444c061aSmrg#endif
167444c061aSmrg}
168444c061aSmrg
169444c061aSmrg
170444c061aSmrgstatic void
171444c061aSmrgAppLock(XtAppContext app)
172444c061aSmrg{
173444c061aSmrg    LockPtr app_lock = app->lock_info;
174444c061aSmrg#ifdef _XMUTEX_NESTS
175444c061aSmrg    xmutex_lock(app_lock->mutex);
176444c061aSmrg    app_lock->level++;
177444c061aSmrg#else
178444c061aSmrg    xthread_t self = xthread_self();
179444c061aSmrg    xmutex_lock(app_lock->mutex);
180444c061aSmrg    if (!xthread_have_id(app_lock->holder)) {
181444c061aSmrg	app_lock->holder = self;
182444c061aSmrg    	assert(xthread_equal(app_lock->holder, self));
183444c061aSmrg	xmutex_unlock(app_lock->mutex);
184444c061aSmrg	return;
185444c061aSmrg    }
186444c061aSmrg    if (xthread_equal(app_lock->holder, self)) {
187444c061aSmrg	app_lock->level++;
188444c061aSmrg	xmutex_unlock(app_lock->mutex);
189444c061aSmrg	return;
190444c061aSmrg    }
191444c061aSmrg    while(xthread_have_id(app_lock->holder)) {
192444c061aSmrg	xcondition_wait(app_lock->cond, app_lock->mutex);
193444c061aSmrg    }
194444c061aSmrg    app_lock->holder = self;
195444c061aSmrg    assert(xthread_equal(app_lock->holder, self));
196444c061aSmrg    xmutex_unlock(app_lock->mutex);
197444c061aSmrg#endif
198444c061aSmrg}
199444c061aSmrg
200444c061aSmrgstatic void
201444c061aSmrgAppUnlock(XtAppContext app)
202444c061aSmrg{
203444c061aSmrg    LockPtr app_lock = app->lock_info;
204444c061aSmrg#ifdef _XMUTEX_NESTS
205444c061aSmrg    app_lock->level--;
206444c061aSmrg    xmutex_unlock(app_lock->mutex);
207444c061aSmrg#else
208444c061aSmrg    xthread_t self;
209444c061aSmrg
210444c061aSmrg    self = xthread_self();
211444c061aSmrg    xmutex_lock(app_lock->mutex);
212444c061aSmrg    assert(xthread_equal(app_lock->holder, self));
213444c061aSmrg    if (app_lock->level != 0) {
214444c061aSmrg	app_lock->level--;
215444c061aSmrg	xmutex_unlock(app_lock->mutex);
216444c061aSmrg	return;
217444c061aSmrg    }
218444c061aSmrg    xthread_clear_id(app_lock->holder);
219444c061aSmrg    xcondition_signal(app_lock->cond);
220444c061aSmrg    xmutex_unlock(app_lock->mutex);
221444c061aSmrg#endif
222444c061aSmrg}
223444c061aSmrg
224444c061aSmrgstatic void
225444c061aSmrgYieldAppLock(
226444c061aSmrg    XtAppContext app,
227444c061aSmrg    Boolean* push_thread,
228444c061aSmrg    Boolean* pushed_thread,
229444c061aSmrg    int* level)
230444c061aSmrg{
231444c061aSmrg    LockPtr app_lock = app->lock_info;
232444c061aSmrg    xthread_t self = xthread_self();
233444c061aSmrg#ifndef _XMUTEX_NESTS
234444c061aSmrg    xmutex_lock(app_lock->mutex);
235444c061aSmrg    assert(xthread_equal(app_lock->holder, self));
236444c061aSmrg#endif
237444c061aSmrg    *level = app_lock->level;
238444c061aSmrg    if (*push_thread) {
239444c061aSmrg	*push_thread = FALSE;
240444c061aSmrg	*pushed_thread = TRUE;
241444c061aSmrg
242444c061aSmrg	if(app_lock->stack.sp == (int)app_lock->stack.size - 1) {
243444c061aSmrg	    unsigned ii;
244444c061aSmrg	    app_lock->stack.st = (struct _Tstack *)
245444c061aSmrg		XtRealloc ((char *)app_lock->stack.st,
246444c061aSmrg		(app_lock->stack.size + STACK_INCR) * sizeof (struct _Tstack));
247444c061aSmrg	    ii = app_lock->stack.size;
248444c061aSmrg	    app_lock->stack.size += STACK_INCR;
249444c061aSmrg	    for ( ; ii < app_lock->stack.size; ii++) {
250444c061aSmrg		app_lock->stack.st[ii].c = xcondition_malloc();
251444c061aSmrg		xcondition_init(app_lock->stack.st[ii].c);
252444c061aSmrg	    }
253444c061aSmrg	}
254444c061aSmrg	app_lock->stack.st[++(app_lock->stack.sp)].t = self;
255444c061aSmrg    }
256444c061aSmrg#ifdef _XMUTEX_NESTS
257444c061aSmrg    while (app_lock->level > 0) {
258444c061aSmrg	app_lock->level--;
259444c061aSmrg	xmutex_unlock(app_lock->mutex);
260444c061aSmrg    }
261444c061aSmrg#else
262444c061aSmrg    xcondition_signal(app_lock->cond);
263444c061aSmrg    app_lock->level = 0;
264444c061aSmrg    xthread_clear_id(app_lock->holder);
265444c061aSmrg    xmutex_unlock(app_lock->mutex);
266444c061aSmrg#endif
267444c061aSmrg}
268444c061aSmrg
269444c061aSmrgstatic void
270444c061aSmrgRestoreAppLock(
271444c061aSmrg    XtAppContext app,
272444c061aSmrg    int level,
273444c061aSmrg    Boolean* pushed_thread)
274444c061aSmrg{
275444c061aSmrg    LockPtr app_lock = app->lock_info;
276444c061aSmrg    xthread_t self = xthread_self();
277444c061aSmrg    xmutex_lock(app_lock->mutex);
278444c061aSmrg#ifdef _XMUTEX_NESTS
279444c061aSmrg    app_lock->level++;
280444c061aSmrg#else
281444c061aSmrg    while(xthread_have_id(app_lock->holder)) {
282444c061aSmrg	xcondition_wait(app_lock->cond, app_lock->mutex);
283444c061aSmrg    }
284444c061aSmrg#endif
285444c061aSmrg    if (!xthread_equal(app_lock->stack.st[app_lock->stack.sp].t, self)) {
286444c061aSmrg	int ii;
287444c061aSmrg	for (ii = app_lock->stack.sp - 1; ii >= 0; ii--) {
288444c061aSmrg	    if (xthread_equal(app_lock->stack.st[ii].t, self)) {
289444c061aSmrg		xcondition_wait(app_lock->stack.st[ii].c, app_lock->mutex);
290444c061aSmrg		break;
291444c061aSmrg	    }
292444c061aSmrg	}
293444c061aSmrg#ifndef _XMUTEX_NESTS
294444c061aSmrg	while(xthread_have_id(app_lock->holder)) {
295444c061aSmrg	    xcondition_wait(app_lock->cond, app_lock->mutex);
296444c061aSmrg	}
297444c061aSmrg#endif
298444c061aSmrg    }
299444c061aSmrg#ifdef _XMUTEX_NESTS
300444c061aSmrg    while (app_lock->level < level) {
301444c061aSmrg	xmutex_lock(app_lock->mutex);
302444c061aSmrg	app_lock->level++;
303444c061aSmrg    }
304444c061aSmrg#else
305444c061aSmrg    app_lock->holder = self;
306444c061aSmrg    app_lock->level = level;
307444c061aSmrg    assert(xthread_equal(app_lock->holder, self));
308444c061aSmrg#endif
309444c061aSmrg    if (*pushed_thread) {
310444c061aSmrg	*pushed_thread = FALSE;
311444c061aSmrg	(app_lock->stack.sp)--;
312444c061aSmrg	if (app_lock->stack.sp >= 0) {
313444c061aSmrg	    xcondition_signal (app_lock->stack.st[app_lock->stack.sp].c);
314444c061aSmrg	}
315444c061aSmrg    }
316444c061aSmrg#ifndef _XMUTEX_NESTS
317444c061aSmrg    xmutex_unlock(app_lock->mutex);
318444c061aSmrg#endif
319444c061aSmrg}
320444c061aSmrg
321444c061aSmrgstatic void
322444c061aSmrgFreeAppLock(XtAppContext app)
323444c061aSmrg{
324444c061aSmrg    unsigned ii;
325444c061aSmrg    LockPtr app_lock = app->lock_info;
326444c061aSmrg
327444c061aSmrg    if(app_lock) {
328444c061aSmrg	xmutex_clear(app_lock->mutex);
329444c061aSmrg	xmutex_free(app_lock->mutex);
330444c061aSmrg#ifndef _XMUTEX_NESTS
331444c061aSmrg	xcondition_clear(app_lock->cond);
332444c061aSmrg	xcondition_free(app_lock->cond);
333444c061aSmrg#endif
334444c061aSmrg	if(app_lock->stack.st != (struct _Tstack *)NULL) {
335444c061aSmrg	    for (ii = 0; ii < app_lock->stack.size; ii++) {
336444c061aSmrg		xcondition_clear(app_lock->stack.st[ii].c);
337444c061aSmrg		xcondition_free(app_lock->stack.st[ii].c);
338444c061aSmrg	    }
339444c061aSmrg	    XtFree((char *)app_lock->stack.st);
340444c061aSmrg	}
341444c061aSmrg	XtFree((char *)app_lock);
342444c061aSmrg	app->lock_info = NULL;
343444c061aSmrg    }
344444c061aSmrg}
345444c061aSmrg
346444c061aSmrgstatic void
347444c061aSmrgInitAppLock(XtAppContext app)
348444c061aSmrg{
349444c061aSmrg    int ii;
350444c061aSmrg    LockPtr app_lock;
351444c061aSmrg
352444c061aSmrg    app->lock = AppLock;
353444c061aSmrg    app->unlock = AppUnlock;
354444c061aSmrg    app->yield_lock = YieldAppLock;
355444c061aSmrg    app->restore_lock = RestoreAppLock;
356444c061aSmrg    app->free_lock = FreeAppLock;
357444c061aSmrg
358444c061aSmrg    app_lock = app->lock_info = XtNew(LockRec);
359444c061aSmrg    app_lock->mutex = xmutex_malloc();
360444c061aSmrg    xmutex_init(app_lock->mutex);
361444c061aSmrg    app_lock->level = 0;
362444c061aSmrg#ifndef _XMUTEX_NESTS
363444c061aSmrg    app_lock->cond = xcondition_malloc();
364444c061aSmrg    xcondition_init(app_lock->cond);
365444c061aSmrg    xthread_clear_id(app_lock->holder);
366444c061aSmrg#endif
367444c061aSmrg    app_lock->stack.size = STACK_INCR;
368444c061aSmrg    app_lock->stack.sp = -1;
369444c061aSmrg    app_lock->stack.st =
370444c061aSmrg	(struct _Tstack *)__XtMalloc(sizeof(struct _Tstack)*STACK_INCR);
371444c061aSmrg    for (ii = 0; ii < STACK_INCR; ii++) {
372444c061aSmrg	app_lock->stack.st[ii].c = xcondition_malloc();
373444c061aSmrg	xcondition_init(app_lock->stack.st[ii].c);
374444c061aSmrg    }
375444c061aSmrg}
376444c061aSmrg
377444c061aSmrg#endif /* defined(XTHREADS) */
378444c061aSmrg
379444c061aSmrgvoid XtAppLock(XtAppContext app)
380444c061aSmrg{
381444c061aSmrg#ifdef XTHREADS
382444c061aSmrg    if(app->lock)
383444c061aSmrg	(*app->lock)(app);
384444c061aSmrg#endif
385444c061aSmrg}
386444c061aSmrg
387444c061aSmrgvoid XtAppUnlock(XtAppContext app)
388444c061aSmrg{
389444c061aSmrg#ifdef XTHREADS
390444c061aSmrg    if(app->unlock)
391444c061aSmrg	(*app->unlock)(app);
392444c061aSmrg#endif
393444c061aSmrg}
394444c061aSmrg
395444c061aSmrgvoid XtProcessLock(void)
396444c061aSmrg{
397444c061aSmrg#ifdef XTHREADS
398444c061aSmrg    if(_XtProcessLock)
399444c061aSmrg	(*_XtProcessLock)();
400444c061aSmrg#endif
401444c061aSmrg}
402444c061aSmrg
403444c061aSmrgvoid XtProcessUnlock(void)
404444c061aSmrg{
405444c061aSmrg#ifdef XTHREADS
406444c061aSmrg    if(_XtProcessUnlock)
407444c061aSmrg	(*_XtProcessUnlock)();
408444c061aSmrg#endif
409444c061aSmrg}
410444c061aSmrg
411444c061aSmrgBoolean XtToolkitThreadInitialize(void)
412444c061aSmrg{
413444c061aSmrg#ifdef XTHREADS
414444c061aSmrg    if (_XtProcessLock == NULL) {
415444c061aSmrg#ifdef xthread_init
416444c061aSmrg	xthread_init();
417444c061aSmrg#endif
418444c061aSmrg	InitProcessLock();
419444c061aSmrg	_XtProcessLock = ProcessLock;
420444c061aSmrg	_XtProcessUnlock = ProcessUnlock;
421444c061aSmrg	_XtInitAppLock = InitAppLock;
422444c061aSmrg    }
423444c061aSmrg    return True;
424444c061aSmrg#else
425444c061aSmrg    return False;
426444c061aSmrg#endif
427444c061aSmrg}
428444c061aSmrg
429