locking.c revision 2e9c7c8c
11ab64890Smrg/* $Xorg: locking.c,v 1.5 2001/02/09 02:03:40 xorgcvs Exp $ */
21ab64890Smrg/*
361b2299dSmrg
41ab64890SmrgCopyright 1992, 1998  The Open Group
51ab64890Smrg
61ab64890SmrgPermission to use, copy, modify, distribute, and sell this software and its
71ab64890Smrgdocumentation for any purpose is hereby granted without fee, provided that
81ab64890Smrgthe above copyright notice appear in all copies and that both that
91ab64890Smrgcopyright notice and this permission notice appear in supporting
101ab64890Smrgdocumentation.
111ab64890Smrg
121ab64890SmrgThe above copyright notice and this permission notice shall be included in
131ab64890Smrgall copies or substantial portions of the Software.
141ab64890Smrg
151ab64890SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161ab64890SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171ab64890SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
181ab64890SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
191ab64890SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
201ab64890SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
211ab64890Smrg
221ab64890SmrgExcept as contained in this notice, the name of The Open Group shall not be
231ab64890Smrgused in advertising or otherwise to promote the sale, use or other dealings
241ab64890Smrgin this Software without prior written authorization from The Open Group.
251ab64890Smrg
261ab64890Smrg*/
271ab64890Smrg/* $XFree86: xc/lib/X11/locking.c,v 1.5 2003/04/13 19:22:22 dawes Exp $ */
281ab64890Smrg
291ab64890Smrg/*
301ab64890Smrg * Author: Stephen Gildea, MIT X Consortium
311ab64890Smrg *
321ab64890Smrg * locking.c - multi-thread locking routines implemented in C Threads
331ab64890Smrg */
341ab64890Smrg
351ab64890Smrg#ifdef HAVE_CONFIG_H
361ab64890Smrg#include <config.h>
371ab64890Smrg#endif
381ab64890Smrg#include "Xlibint.h"
391ab64890Smrg#undef _XLockMutex
401ab64890Smrg#undef _XUnlockMutex
411ab64890Smrg#undef _XCreateMutex
421ab64890Smrg#undef _XFreeMutex
431ab64890Smrg
441ab64890Smrg#ifdef XTHREADS
451ab64890Smrg
461ab64890Smrg#ifdef __UNIXWARE__
471ab64890Smrg#include <dlfcn.h>
481ab64890Smrg#endif
491ab64890Smrg
501ab64890Smrg#include "locking.h"
511ab64890Smrg#ifdef XTHREADS_WARN
521ab64890Smrg#include <stdio.h>		/* for warn/debug stuff */
531ab64890Smrg#endif
541ab64890Smrg
552e9c7c8cSmrg/* Additional arguments for source code location lock call was made from */
562e9c7c8cSmrg#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
572e9c7c8cSmrg# define XTHREADS_FILE_LINE_ARGS \
582e9c7c8cSmrg    ,								\
592e9c7c8cSmrg    char* file,			/* source file, from macro */	\
602e9c7c8cSmrg    int line
612e9c7c8cSmrg#else
622e9c7c8cSmrg# define XTHREADS_FILE_LINE_ARGS /* None */
632e9c7c8cSmrg#endif
642e9c7c8cSmrg
652e9c7c8cSmrg
661ab64890Smrg#define NUM_FREE_CVLS 4
671ab64890Smrg
681ab64890Smrg/* in lcWrap.c */
691ab64890Smrgextern LockInfoPtr _Xi18n_lock;
701ab64890Smrg
711ab64890Smrg#ifdef WIN32
721ab64890Smrgstatic DWORD _X_TlsIndex = (DWORD)-1;
731ab64890Smrg
742e9c7c8cSmrgvoid _Xthread_init(void)
751ab64890Smrg{
761ab64890Smrg    if (_X_TlsIndex == (DWORD)-1)
771ab64890Smrg	_X_TlsIndex = TlsAlloc();
781ab64890Smrg}
791ab64890Smrg
801ab64890Smrgstruct _xthread_waiter *
812e9c7c8cSmrg_Xthread_waiter(void)
821ab64890Smrg{
831ab64890Smrg    struct _xthread_waiter *me;
841ab64890Smrg
851ab64890Smrg    if (!(me = TlsGetValue(_X_TlsIndex))) {
861ab64890Smrg	me = (struct _xthread_waiter *)xmalloc(sizeof(struct _xthread_waiter));
871ab64890Smrg	me->sem = CreateSemaphore(NULL, 0, 1, NULL);
881ab64890Smrg	me->next = NULL;
891ab64890Smrg	TlsSetValue(_X_TlsIndex, me);
901ab64890Smrg    }
911ab64890Smrg    return me;
921ab64890Smrg}
931ab64890Smrg#endif /* WIN32 */
941ab64890Smrg
951ab64890Smrgstatic xthread_t _Xthread_self(void)
961ab64890Smrg{
971ab64890Smrg    return xthread_self();
981ab64890Smrg}
991ab64890Smrg
1001ab64890Smrgstatic LockInfoRec global_lock;
1011ab64890Smrgstatic LockInfoRec i18n_lock;
1021ab64890Smrg
1031ab64890Smrgstatic void _XLockMutex(
1042e9c7c8cSmrg    LockInfoPtr lip
1052e9c7c8cSmrg    XTHREADS_FILE_LINE_ARGS
1062e9c7c8cSmrg    )
1071ab64890Smrg{
1081ab64890Smrg    xmutex_lock(lip->lock);
1091ab64890Smrg}
1101ab64890Smrg
1111ab64890Smrgstatic void _XUnlockMutex(
1122e9c7c8cSmrg    LockInfoPtr lip
1132e9c7c8cSmrg    XTHREADS_FILE_LINE_ARGS
1142e9c7c8cSmrg    )
1151ab64890Smrg{
1161ab64890Smrg    xmutex_unlock(lip->lock);
1171ab64890Smrg}
1181ab64890Smrg
1191ab64890Smrgstatic void _XCreateMutex(
1201ab64890Smrg    LockInfoPtr lip)
1211ab64890Smrg{
1221ab64890Smrg    lip->lock = xmutex_malloc();
1231ab64890Smrg    if (lip->lock) {
1241ab64890Smrg	xmutex_init(lip->lock);
1251ab64890Smrg	xmutex_set_name(lip->lock, "Xlib");
1261ab64890Smrg    }
1271ab64890Smrg}
1281ab64890Smrg
1291ab64890Smrgstatic void _XFreeMutex(
1301ab64890Smrg    LockInfoPtr lip)
1311ab64890Smrg{
1321ab64890Smrg    xmutex_clear(lip->lock);
1331ab64890Smrg    xmutex_free(lip->lock);
1341ab64890Smrg}
1351ab64890Smrg
1361ab64890Smrg#ifdef XTHREADS_WARN
1371ab64890Smrgstatic char *locking_file;
1381ab64890Smrgstatic int locking_line;
1391ab64890Smrgstatic xthread_t locking_thread;
1401ab64890Smrgstatic Bool xlibint_unlock = False; /* XlibInt.c may Unlock and re-Lock */
1411ab64890Smrg
1421ab64890Smrg/* history that is useful to examine in a debugger */
1431ab64890Smrg#define LOCK_HIST_SIZE 21
1441ab64890Smrg
1451ab64890Smrgstatic struct {
1461ab64890Smrg    Bool lockp;			/* True for lock, False for unlock */
1471ab64890Smrg    xthread_t thread;
1481ab64890Smrg    char *file;
1491ab64890Smrg    int line;
1501ab64890Smrg} locking_history[LOCK_HIST_SIZE];
1511ab64890Smrg
1521ab64890Smrgint lock_hist_loc = 0;		/* next slot to fill */
1531ab64890Smrg
1541ab64890Smrgstatic void _XLockDisplayWarn(
1551ab64890Smrg    Display *dpy,
1561ab64890Smrg    char *file,			/* source file, from macro */
1571ab64890Smrg    int line)
1581ab64890Smrg{
1591ab64890Smrg    xthread_t self;
1601ab64890Smrg    xthread_t old_locker;
1611ab64890Smrg
1621ab64890Smrg    self = xthread_self();
1631ab64890Smrg    old_locker = locking_thread;
1641ab64890Smrg    if (xthread_have_id(old_locker)) {
1651ab64890Smrg	if (xthread_equal(old_locker, self))
1661ab64890Smrg	    printf("Xlib ERROR: %s line %d thread %x: locking display already locked at %s line %d\n",
1671ab64890Smrg		   file, line, self, locking_file, locking_line);
1681ab64890Smrg#ifdef XTHREADS_DEBUG
1691ab64890Smrg	else
1701ab64890Smrg	    printf("%s line %d: thread %x waiting on lock held by %s line %d thread %x\n",
1711ab64890Smrg		   file, line, self,
1721ab64890Smrg		   locking_file, locking_line, old_locker);
1731ab64890Smrg#endif /* XTHREADS_DEBUG */
1741ab64890Smrg    }
1751ab64890Smrg
1761ab64890Smrg    xmutex_lock(dpy->lock->mutex);
1771ab64890Smrg
1781ab64890Smrg    if (strcmp(file, "XlibInt.c") == 0) {
1791ab64890Smrg	if (!xlibint_unlock)
1801ab64890Smrg	    printf("Xlib ERROR: XlibInt.c line %d thread %x locking display it did not unlock\n",
1811ab64890Smrg		   line, self);
1821ab64890Smrg	xlibint_unlock = False;
1831ab64890Smrg    }
1841ab64890Smrg
1851ab64890Smrg#ifdef XTHREADS_DEBUG
1861ab64890Smrg    /* if (old_locker  &&  old_locker != self) */
1871ab64890Smrg    if (strcmp("XClearArea.c", file) && strcmp("XDrSegs.c", file)) /* ico */
1881ab64890Smrg	printf("%s line %d: thread %x got display lock\n", file, line, self);
1891ab64890Smrg#endif /* XTHREADS_DEBUG */
1901ab64890Smrg
1911ab64890Smrg    locking_thread = self;
1921ab64890Smrg    if (strcmp(file, "XlibInt.c") != 0) {
1931ab64890Smrg	locking_file = file;
1941ab64890Smrg	locking_line = line;
1951ab64890Smrg    }
1961ab64890Smrg    locking_history[lock_hist_loc].file = file;
1971ab64890Smrg    locking_history[lock_hist_loc].line = line;
1981ab64890Smrg    locking_history[lock_hist_loc].thread = self;
1991ab64890Smrg    locking_history[lock_hist_loc].lockp = True;
2001ab64890Smrg    lock_hist_loc++;
2011ab64890Smrg    if (lock_hist_loc >= LOCK_HIST_SIZE)
2021ab64890Smrg	lock_hist_loc = 0;
2031ab64890Smrg}
2041ab64890Smrg#endif /* XTHREADS_WARN */
2051ab64890Smrg
2061ab64890Smrgstatic void _XUnlockDisplay(
2072e9c7c8cSmrg    Display *dpy
2082e9c7c8cSmrg    XTHREADS_FILE_LINE_ARGS
2092e9c7c8cSmrg    )
2101ab64890Smrg{
2111ab64890Smrg#ifdef XTHREADS_WARN
2121ab64890Smrg    xthread_t self = xthread_self();
2131ab64890Smrg
2141ab64890Smrg#ifdef XTHREADS_DEBUG
2151ab64890Smrg    if (strcmp("XClearArea.c", file) && strcmp("XDrSegs.c", file)) /* ico */
2161ab64890Smrg	printf("%s line %d: thread %x unlocking display\n", file, line, self);
2171ab64890Smrg#endif /* XTHREADS_DEBUG */
2181ab64890Smrg
2191ab64890Smrg    if (!xthread_have_id(locking_thread))
2201ab64890Smrg	printf("Xlib ERROR: %s line %d thread %x: unlocking display that is not locked\n",
2211ab64890Smrg	       file, line, self);
2221ab64890Smrg    else if (strcmp(file, "XlibInt.c") == 0)
2231ab64890Smrg	xlibint_unlock = True;
2241ab64890Smrg#ifdef XTHREADS_DEBUG
2251ab64890Smrg    else if (strcmp(file, locking_file) != 0)
2261ab64890Smrg	/* not always an error because locking_file is not per-thread */
2271ab64890Smrg	printf("%s line %d: unlocking display locked from %s line %d (probably okay)\n",
2281ab64890Smrg	       file, line, locking_file, locking_line);
2291ab64890Smrg#endif /* XTHREADS_DEBUG */
2301ab64890Smrg    xthread_clear_id(locking_thread);
2311ab64890Smrg
2321ab64890Smrg    locking_history[lock_hist_loc].file = file;
2331ab64890Smrg    locking_history[lock_hist_loc].line = line;
2341ab64890Smrg    locking_history[lock_hist_loc].thread = self;
2351ab64890Smrg    locking_history[lock_hist_loc].lockp = False;
2361ab64890Smrg    lock_hist_loc++;
2371ab64890Smrg    if (lock_hist_loc >= LOCK_HIST_SIZE)
2381ab64890Smrg	lock_hist_loc = 0;
2391ab64890Smrg#endif /* XTHREADS_WARN */
2401ab64890Smrg    xmutex_unlock(dpy->lock->mutex);
2411ab64890Smrg}
2421ab64890Smrg
2431ab64890Smrg
2441ab64890Smrgstatic struct _XCVList *_XCreateCVL(
2451ab64890Smrg    Display *dpy)
2461ab64890Smrg{
2471ab64890Smrg    struct _XCVList *cvl;
2481ab64890Smrg
2491ab64890Smrg    if ((cvl = dpy->lock->free_cvls) != NULL) {
2501ab64890Smrg	dpy->lock->free_cvls = cvl->next;
2511ab64890Smrg	dpy->lock->num_free_cvls--;
2521ab64890Smrg    } else {
2531ab64890Smrg	cvl = (struct _XCVList *)Xmalloc(sizeof(struct _XCVList));
2541ab64890Smrg	if (!cvl)
2551ab64890Smrg	    return NULL;
2561ab64890Smrg	cvl->cv = xcondition_malloc();
2571ab64890Smrg	if (!cvl->cv) {
2581ab64890Smrg	    Xfree(cvl);
2591ab64890Smrg	    return NULL;
2601ab64890Smrg	}
2611ab64890Smrg	xcondition_init(cvl->cv);
2621ab64890Smrg	xcondition_set_name(cvl->cv, "Xlib read queue");
2631ab64890Smrg    }
2641ab64890Smrg    cvl->next = NULL;
2651ab64890Smrg    return cvl;
2661ab64890Smrg}
2671ab64890Smrg
2681ab64890Smrg/* Put ourselves on the queue to read the connection.
2691ab64890Smrg   Allocates and returns a queue element. */
2701ab64890Smrg
2711ab64890Smrgstatic struct _XCVList *
2721ab64890Smrg_XPushReader(
2731ab64890Smrg    Display *dpy,
2741ab64890Smrg    struct _XCVList ***tail)
2751ab64890Smrg{
2761ab64890Smrg    struct _XCVList *cvl;
2771ab64890Smrg
2781ab64890Smrg    cvl = _XCreateCVL(dpy);
2791ab64890Smrg#ifdef XTHREADS_DEBUG
2801ab64890Smrg    printf("_XPushReader called in thread %x, pushing %x\n",
2811ab64890Smrg	   xthread_self(), cvl);
2821ab64890Smrg#endif
2831ab64890Smrg    **tail = cvl;
2841ab64890Smrg    *tail = &cvl->next;
2851ab64890Smrg    return cvl;
2861ab64890Smrg}
2871ab64890Smrg
2881ab64890Smrg/* signal the next thread waiting to read the connection */
2891ab64890Smrg
2901ab64890Smrgstatic void _XPopReader(
2911ab64890Smrg    Display *dpy,
2921ab64890Smrg    struct _XCVList **list,
2931ab64890Smrg    struct _XCVList ***tail)
2941ab64890Smrg{
2951ab64890Smrg    register struct _XCVList *front = *list;
2961ab64890Smrg
2971ab64890Smrg#ifdef XTHREADS_DEBUG
2981ab64890Smrg    printf("_XPopReader called in thread %x, popping %x\n",
2991ab64890Smrg	   xthread_self(), front);
3001ab64890Smrg#endif
3011ab64890Smrg
3021ab64890Smrg    if (dpy->flags & XlibDisplayProcConni)
3031ab64890Smrg	/* we never added ourself in the first place */
3041ab64890Smrg	return;
3051ab64890Smrg
3061ab64890Smrg    if (front) {		/* check "front" for paranoia */
3071ab64890Smrg	*list = front->next;
3081ab64890Smrg	if (*tail == &front->next)	/* did we free the last elt? */
3091ab64890Smrg	    *tail = list;
3101ab64890Smrg	if (dpy->lock->num_free_cvls < NUM_FREE_CVLS) {
3111ab64890Smrg	    front->next = dpy->lock->free_cvls;
3121ab64890Smrg	    dpy->lock->free_cvls = front;
3131ab64890Smrg	    dpy->lock->num_free_cvls++;
3141ab64890Smrg	} else {
3151ab64890Smrg	    xcondition_clear(front->cv);
3161ab64890Smrg	    Xfree((char *)front->cv);
3171ab64890Smrg	    Xfree((char *)front);
3181ab64890Smrg	}
3191ab64890Smrg    }
3201ab64890Smrg
3211ab64890Smrg    /* signal new front after it is in place */
3221ab64890Smrg    if ((dpy->lock->reply_first = (dpy->lock->reply_awaiters != NULL))) {
3231ab64890Smrg	ConditionSignal(dpy, dpy->lock->reply_awaiters->cv);
3241ab64890Smrg    } else if (dpy->lock->event_awaiters) {
3251ab64890Smrg	ConditionSignal(dpy, dpy->lock->event_awaiters->cv);
3261ab64890Smrg    }
3271ab64890Smrg}
3281ab64890Smrg
3291ab64890Smrgstatic void _XConditionWait(
3301ab64890Smrg    xcondition_t cv,
3312e9c7c8cSmrg    xmutex_t mutex
3322e9c7c8cSmrg    XTHREADS_FILE_LINE_ARGS
3332e9c7c8cSmrg    )
3341ab64890Smrg{
3351ab64890Smrg#ifdef XTHREADS_WARN
3361ab64890Smrg    xthread_t self = xthread_self();
3371ab64890Smrg    char *old_file = locking_file;
3381ab64890Smrg    int old_line = locking_line;
33961b2299dSmrg
3401ab64890Smrg#ifdef XTHREADS_DEBUG
3411ab64890Smrg    printf("line %d thread %x in condition wait\n", line, self);
3421ab64890Smrg#endif
3431ab64890Smrg    xthread_clear_id(locking_thread);
3441ab64890Smrg
3451ab64890Smrg    locking_history[lock_hist_loc].file = file;
3461ab64890Smrg    locking_history[lock_hist_loc].line = line;
3471ab64890Smrg    locking_history[lock_hist_loc].thread = self;
3481ab64890Smrg    locking_history[lock_hist_loc].lockp = False;
3491ab64890Smrg    lock_hist_loc++;
3501ab64890Smrg    if (lock_hist_loc >= LOCK_HIST_SIZE)
3511ab64890Smrg	lock_hist_loc = 0;
3521ab64890Smrg#endif /* XTHREADS_WARN */
3531ab64890Smrg
3541ab64890Smrg    xcondition_wait(cv, mutex);
3551ab64890Smrg
3561ab64890Smrg#ifdef XTHREADS_WARN
3571ab64890Smrg    locking_thread = self;
3581ab64890Smrg    locking_file = old_file;
3591ab64890Smrg    locking_line = old_line;
3601ab64890Smrg
3611ab64890Smrg    locking_history[lock_hist_loc].file = file;
3621ab64890Smrg    locking_history[lock_hist_loc].line = line;
3631ab64890Smrg    locking_history[lock_hist_loc].thread = self;
3641ab64890Smrg    locking_history[lock_hist_loc].lockp = True;
3651ab64890Smrg    lock_hist_loc++;
3661ab64890Smrg    if (lock_hist_loc >= LOCK_HIST_SIZE)
3671ab64890Smrg	lock_hist_loc = 0;
3681ab64890Smrg#ifdef XTHREADS_DEBUG
3691ab64890Smrg    printf("line %d thread %x was signaled\n", line, self);
3701ab64890Smrg#endif /* XTHREADS_DEBUG */
3711ab64890Smrg#endif /* XTHREADS_WARN */
3721ab64890Smrg}
3731ab64890Smrg
3741ab64890Smrgstatic void _XConditionSignal(
3752e9c7c8cSmrg    xcondition_t cv
3762e9c7c8cSmrg    XTHREADS_FILE_LINE_ARGS
3772e9c7c8cSmrg    )
3781ab64890Smrg{
3791ab64890Smrg#ifdef XTHREADS_WARN
3801ab64890Smrg#ifdef XTHREADS_DEBUG
3811ab64890Smrg    printf("line %d thread %x is signalling\n", line, xthread_self());
3821ab64890Smrg#endif
3831ab64890Smrg#endif
3841ab64890Smrg    xcondition_signal(cv);
3851ab64890Smrg}
38661b2299dSmrg
3871ab64890Smrg
3881ab64890Smrgstatic void _XConditionBroadcast(
3892e9c7c8cSmrg    xcondition_t cv
3902e9c7c8cSmrg    XTHREADS_FILE_LINE_ARGS
3912e9c7c8cSmrg    )
3921ab64890Smrg{
3931ab64890Smrg#ifdef XTHREADS_WARN
3941ab64890Smrg#ifdef XTHREADS_DEBUG
3951ab64890Smrg    printf("line %d thread %x is broadcasting\n", line, xthread_self());
3961ab64890Smrg#endif
3971ab64890Smrg#endif
3981ab64890Smrg    xcondition_broadcast(cv);
3991ab64890Smrg}
40061b2299dSmrg
4011ab64890Smrg
4021ab64890Smrgstatic void _XFreeDisplayLock(
4031ab64890Smrg    Display *dpy)
4041ab64890Smrg{
4051ab64890Smrg    struct _XCVList *cvl;
4061ab64890Smrg
4071ab64890Smrg    if (dpy->lock != NULL) {
4081ab64890Smrg	if (dpy->lock->mutex != NULL) {
4091ab64890Smrg	    xmutex_clear(dpy->lock->mutex);
4101ab64890Smrg	    xmutex_free(dpy->lock->mutex);
4111ab64890Smrg	}
4121ab64890Smrg	if (dpy->lock->cv != NULL) {
4131ab64890Smrg	    xcondition_clear(dpy->lock->cv);
4141ab64890Smrg	    xcondition_free(dpy->lock->cv);
4151ab64890Smrg	}
4161ab64890Smrg	if (dpy->lock->writers != NULL) {
4171ab64890Smrg	    xcondition_clear(dpy->lock->writers);
4181ab64890Smrg	    xcondition_free(dpy->lock->writers);
4191ab64890Smrg	}
4201ab64890Smrg	while ((cvl = dpy->lock->free_cvls)) {
4211ab64890Smrg	    dpy->lock->free_cvls = cvl->next;
4221ab64890Smrg	    xcondition_clear(cvl->cv);
4231ab64890Smrg	    Xfree((char *)cvl->cv);
4241ab64890Smrg	    Xfree((char *)cvl);
4251ab64890Smrg	}
4261ab64890Smrg	Xfree((char *)dpy->lock);
4271ab64890Smrg	dpy->lock = NULL;
4281ab64890Smrg    }
4291ab64890Smrg    if (dpy->lock_fns != NULL) {
4301ab64890Smrg	Xfree((char *)dpy->lock_fns);
4311ab64890Smrg	dpy->lock_fns = NULL;
4321ab64890Smrg    }
4331ab64890Smrg}
4341ab64890Smrg
4351ab64890Smrg/*
4361ab64890Smrg * wait for thread with user-level display lock to release it.
4371ab64890Smrg */
4381ab64890Smrg
4391ab64890Smrgstatic void _XDisplayLockWait(
4401ab64890Smrg    Display *dpy)
4411ab64890Smrg{
4421ab64890Smrg    xthread_t self;
4431ab64890Smrg
4441ab64890Smrg    while (dpy->lock->locking_level > 0) {
4451ab64890Smrg	self = xthread_self();
4461ab64890Smrg	if (xthread_equal(dpy->lock->locking_thread, self))
4471ab64890Smrg	    break;
4481ab64890Smrg	ConditionWait(dpy, dpy->lock->cv);
4491ab64890Smrg    }
4501ab64890Smrg}
4511ab64890Smrg
4521ab64890Smrgstatic void _XLockDisplay(
4532e9c7c8cSmrg    Display *dpy
4542e9c7c8cSmrg    XTHREADS_FILE_LINE_ARGS
4552e9c7c8cSmrg    )
4561ab64890Smrg{
4571ab64890Smrg#ifdef XTHREADS_WARN
4581ab64890Smrg    _XLockDisplayWarn(dpy, file, line);
4591ab64890Smrg#else
4601ab64890Smrg    xmutex_lock(dpy->lock->mutex);
4611ab64890Smrg#endif
4621ab64890Smrg    if (dpy->lock->locking_level > 0)
4631ab64890Smrg	_XDisplayLockWait(dpy);
4641ab64890Smrg}
4651ab64890Smrg
4661ab64890Smrg/*
4671ab64890Smrg * _XReply is allowed to exit from select/poll and clean up even if a
4681ab64890Smrg * user-level lock is in force, so it uses this instead of _XFancyLockDisplay.
4691ab64890Smrg */
4701ab64890Smrgstatic void _XInternalLockDisplay(
4711ab64890Smrg    Display *dpy,
4722e9c7c8cSmrg    Bool wskip
4732e9c7c8cSmrg    XTHREADS_FILE_LINE_ARGS
4742e9c7c8cSmrg    )
4751ab64890Smrg{
4761ab64890Smrg#ifdef XTHREADS_WARN
4771ab64890Smrg    _XLockDisplayWarn(dpy, file, line);
4781ab64890Smrg#else
4791ab64890Smrg    xmutex_lock(dpy->lock->mutex);
4801ab64890Smrg#endif
4811ab64890Smrg    if (!wskip && dpy->lock->locking_level > 0)
4821ab64890Smrg	_XDisplayLockWait(dpy);
4831ab64890Smrg}
4841ab64890Smrg
4851ab64890Smrgstatic void _XUserLockDisplay(
4861ab64890Smrg    register Display* dpy)
4871ab64890Smrg{
4881ab64890Smrg    if (++dpy->lock->locking_level == 1) {
4891ab64890Smrg	dpy->lock->lock_wait = _XDisplayLockWait;
4901ab64890Smrg	dpy->lock->locking_thread = xthread_self();
4911ab64890Smrg    }
4921ab64890Smrg}
4931ab64890Smrg
4941ab64890Smrgstatic
4951ab64890Smrgvoid _XUserUnlockDisplay(
4961ab64890Smrg    register Display* dpy)
4971ab64890Smrg{
4981ab64890Smrg    if (dpy->lock->locking_level > 0 && --dpy->lock->locking_level == 0) {
4991ab64890Smrg	/* signal other threads that might be waiting in XLockDisplay */
5001ab64890Smrg	ConditionBroadcast(dpy, dpy->lock->cv);
5011ab64890Smrg	dpy->lock->lock_wait = NULL;
5021ab64890Smrg	xthread_clear_id(dpy->lock->locking_thread);
5031ab64890Smrg    }
5041ab64890Smrg}
5051ab64890Smrg
5061ab64890Smrg/* returns 0 if initialized ok, -1 if unable to allocate
5071ab64890Smrg   a mutex or other memory */
5081ab64890Smrg
5091ab64890Smrgstatic int _XInitDisplayLock(
5101ab64890Smrg    Display *dpy)
5111ab64890Smrg{
5121ab64890Smrg    dpy->lock_fns = (struct _XLockPtrs*)Xmalloc(sizeof(struct _XLockPtrs));
5131ab64890Smrg    if (dpy->lock_fns == NULL)
5141ab64890Smrg	return -1;
5151ab64890Smrg    dpy->lock = (struct _XLockInfo *)Xmalloc(sizeof(struct _XLockInfo));
5161ab64890Smrg    if (dpy->lock == NULL) {
5171ab64890Smrg	_XFreeDisplayLock(dpy);
5181ab64890Smrg	return -1;
5191ab64890Smrg    }
5201ab64890Smrg    dpy->lock->cv = xcondition_malloc();
5211ab64890Smrg    dpy->lock->mutex = xmutex_malloc();
5221ab64890Smrg    dpy->lock->writers = xcondition_malloc();
5231ab64890Smrg    if (!dpy->lock->cv || !dpy->lock->mutex || !dpy->lock->writers) {
5241ab64890Smrg	_XFreeDisplayLock(dpy);
5251ab64890Smrg	return -1;
5261ab64890Smrg    }
5271ab64890Smrg
5281ab64890Smrg    dpy->lock->reply_bytes_left = 0;
5291ab64890Smrg    dpy->lock->reply_was_read = False;
5301ab64890Smrg    dpy->lock->reply_awaiters = NULL;
5311ab64890Smrg    dpy->lock->reply_awaiters_tail = &dpy->lock->reply_awaiters;
5321ab64890Smrg    dpy->lock->event_awaiters = NULL;
5331ab64890Smrg    dpy->lock->event_awaiters_tail = &dpy->lock->event_awaiters;
5341ab64890Smrg    dpy->lock->reply_first = False;
5351ab64890Smrg    dpy->lock->locking_level = 0;
5361ab64890Smrg    dpy->lock->num_free_cvls = 0;
5371ab64890Smrg    dpy->lock->free_cvls = NULL;
5381ab64890Smrg    xthread_clear_id(dpy->lock->locking_thread);
5391ab64890Smrg    xthread_clear_id(dpy->lock->reading_thread);
5401ab64890Smrg    xthread_clear_id(dpy->lock->conni_thread);
5411ab64890Smrg    xmutex_init(dpy->lock->mutex);
5421ab64890Smrg    xmutex_set_name(dpy->lock->mutex, "Xlib Display");
5431ab64890Smrg    xcondition_init(dpy->lock->cv);
5441ab64890Smrg    xcondition_set_name(dpy->lock->cv, "XLockDisplay");
5451ab64890Smrg    xcondition_init(dpy->lock->writers);
5461ab64890Smrg    xcondition_set_name(dpy->lock->writers, "Xlib wait for writable");
5471ab64890Smrg    dpy->lock_fns->lock_display = _XLockDisplay;
5481ab64890Smrg    dpy->lock->internal_lock_display = _XInternalLockDisplay;
5491ab64890Smrg    dpy->lock_fns->unlock_display = _XUnlockDisplay;
5501ab64890Smrg    dpy->lock->user_lock_display = _XUserLockDisplay;
5511ab64890Smrg    dpy->lock->user_unlock_display = _XUserUnlockDisplay;
5521ab64890Smrg    dpy->lock->pop_reader = _XPopReader;
5531ab64890Smrg    dpy->lock->push_reader = _XPushReader;
5541ab64890Smrg    dpy->lock->condition_wait = _XConditionWait;
5551ab64890Smrg    dpy->lock->condition_signal = _XConditionSignal;
5561ab64890Smrg    dpy->lock->condition_broadcast = _XConditionBroadcast;
5571ab64890Smrg    dpy->lock->create_cvl = _XCreateCVL;
5581ab64890Smrg    dpy->lock->lock_wait = NULL; /* filled in by XLockDisplay() */
5591ab64890Smrg
5601ab64890Smrg    return 0;
5611ab64890Smrg}
5621ab64890Smrg
5631ab64890Smrg#ifdef __UNIXWARE__
5641ab64890Smrgxthread_t __x11_thr_self() { return 0; }
5651ab64890Smrgxthread_t (*_x11_thr_self)() = __x11_thr_self;
5661ab64890Smrg#endif
5671ab64890Smrg
5681ab64890Smrg
56961b2299dSmrgStatus XInitThreads(void)
5701ab64890Smrg{
5711ab64890Smrg    if (_Xglobal_lock)
5721ab64890Smrg	return 1;
5731ab64890Smrg#ifdef __UNIXWARE__
5741ab64890Smrg    else {
5751ab64890Smrg       void *dl_handle = dlopen(NULL, RTLD_LAZY);
5761ab64890Smrg       if (!dl_handle ||
5771ab64890Smrg         ((_x11_thr_self = (xthread_t(*)())dlsym(dl_handle,"thr_self")) == 0)) {
5781ab64890Smrg	       _x11_thr_self = __x11_thr_self;
5791ab64890Smrg	       (void) fprintf (stderr,
5801ab64890Smrg	"XInitThreads called, but no libthread in the calling program!\n" );
5811ab64890Smrg       }
5821ab64890Smrg    }
5831ab64890Smrg#endif /* __UNIXWARE__ */
5841ab64890Smrg#ifdef xthread_init
5851ab64890Smrg    xthread_init();		/* return value? */
5861ab64890Smrg#endif
5871ab64890Smrg    if (!(global_lock.lock = xmutex_malloc()))
5881ab64890Smrg	return 0;
5891ab64890Smrg    if (!(i18n_lock.lock = xmutex_malloc())) {
5901ab64890Smrg	xmutex_free(global_lock.lock);
5911ab64890Smrg	global_lock.lock = NULL;
5921ab64890Smrg	return 0;
5931ab64890Smrg    }
5941ab64890Smrg    _Xglobal_lock = &global_lock;
5951ab64890Smrg    xmutex_init(_Xglobal_lock->lock);
5961ab64890Smrg    xmutex_set_name(_Xglobal_lock->lock, "Xlib global");
5971ab64890Smrg    _Xi18n_lock = &i18n_lock;
5981ab64890Smrg    xmutex_init(_Xi18n_lock->lock);
5991ab64890Smrg    xmutex_set_name(_Xi18n_lock->lock, "Xlib i18n");
6001ab64890Smrg    _XLockMutex_fn = _XLockMutex;
6011ab64890Smrg    _XUnlockMutex_fn = _XUnlockMutex;
6021ab64890Smrg    _XCreateMutex_fn = _XCreateMutex;
6031ab64890Smrg    _XFreeMutex_fn = _XFreeMutex;
6041ab64890Smrg    _XInitDisplayLock_fn = _XInitDisplayLock;
6051ab64890Smrg    _XFreeDisplayLock_fn = _XFreeDisplayLock;
6061ab64890Smrg    _Xthread_self_fn = _Xthread_self;
6071ab64890Smrg
6081ab64890Smrg#ifdef XTHREADS_WARN
6091ab64890Smrg#ifdef XTHREADS_DEBUG
6101ab64890Smrg    setlinebuf(stdout);		/* for debugging messages */
6111ab64890Smrg#endif
6121ab64890Smrg#endif
6131ab64890Smrg
6141ab64890Smrg    return 1;
6151ab64890Smrg}
6161ab64890Smrg
6171ab64890Smrg#else /* XTHREADS */
6182e9c7c8cSmrgStatus XInitThreads(void)
6191ab64890Smrg{
6201ab64890Smrg    return 0;
6211ab64890Smrg}
6221ab64890Smrg#endif /* XTHREADS */
623