Blame src/locking.c

Packit 5bd3a9
/*
Packit 5bd3a9
Packit 5bd3a9
Copyright 1992, 1998  The Open Group
Packit 5bd3a9
Packit 5bd3a9
Permission to use, copy, modify, distribute, and sell this software and its
Packit 5bd3a9
documentation for any purpose is hereby granted without fee, provided that
Packit 5bd3a9
the above copyright notice appear in all copies and that both that
Packit 5bd3a9
copyright notice and this permission notice appear in supporting
Packit 5bd3a9
documentation.
Packit 5bd3a9
Packit 5bd3a9
The above copyright notice and this permission notice shall be included in
Packit 5bd3a9
all copies or substantial portions of the Software.
Packit 5bd3a9
Packit 5bd3a9
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit 5bd3a9
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit 5bd3a9
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
Packit 5bd3a9
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
Packit 5bd3a9
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 5bd3a9
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit 5bd3a9
Packit 5bd3a9
Except as contained in this notice, the name of The Open Group shall not be
Packit 5bd3a9
used in advertising or otherwise to promote the sale, use or other dealings
Packit 5bd3a9
in this Software without prior written authorization from The Open Group.
Packit 5bd3a9
Packit 5bd3a9
*/
Packit 5bd3a9
Packit 5bd3a9
/*
Packit 5bd3a9
 * Author: Stephen Gildea, MIT X Consortium
Packit 5bd3a9
 *
Packit 5bd3a9
 * locking.c - multi-thread locking routines implemented in C Threads
Packit 5bd3a9
 */
Packit 5bd3a9
Packit 5bd3a9
#ifdef HAVE_CONFIG_H
Packit 5bd3a9
#include <config.h>
Packit 5bd3a9
#endif
Packit 5bd3a9
#include "Xlibint.h"
Packit 5bd3a9
#undef _XLockMutex
Packit 5bd3a9
#undef _XUnlockMutex
Packit 5bd3a9
#undef _XCreateMutex
Packit 5bd3a9
#undef _XFreeMutex
Packit 5bd3a9
Packit 5bd3a9
#ifdef XTHREADS
Packit 5bd3a9
Packit 5bd3a9
#ifdef __UNIXWARE__
Packit 5bd3a9
#include <dlfcn.h>
Packit 5bd3a9
#endif
Packit 5bd3a9
Packit 5bd3a9
#include "Xprivate.h"
Packit 5bd3a9
#include "locking.h"
Packit 5bd3a9
#ifdef XTHREADS_WARN
Packit 5bd3a9
#include <stdio.h>		/* for warn/debug stuff */
Packit 5bd3a9
#endif
Packit 5bd3a9
Packit 5bd3a9
/* Additional arguments for source code location lock call was made from */
Packit 5bd3a9
#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
Packit 5bd3a9
# define XTHREADS_FILE_LINE_ARGS \
Packit 5bd3a9
    ,								\
Packit 5bd3a9
    char* file,			/* source file, from macro */	\
Packit 5bd3a9
    int line
Packit 5bd3a9
#else
Packit 5bd3a9
# define XTHREADS_FILE_LINE_ARGS /* None */
Packit 5bd3a9
#endif
Packit 5bd3a9
Packit 5bd3a9
Packit 5bd3a9
#define NUM_FREE_CVLS 4
Packit 5bd3a9
Packit 5bd3a9
/* in lcWrap.c */
Packit 5bd3a9
extern LockInfoPtr _Xi18n_lock;
Packit 5bd3a9
Packit 5bd3a9
#ifdef WIN32
Packit 5bd3a9
static DWORD _X_TlsIndex = (DWORD)-1;
Packit 5bd3a9
Packit 5bd3a9
void _Xthread_init(void)
Packit 5bd3a9
{
Packit 5bd3a9
    if (_X_TlsIndex == (DWORD)-1)
Packit 5bd3a9
	_X_TlsIndex = TlsAlloc();
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
struct _xthread_waiter *
Packit 5bd3a9
_Xthread_waiter(void)
Packit 5bd3a9
{
Packit 5bd3a9
    struct _xthread_waiter *me;
Packit 5bd3a9
Packit 5bd3a9
    if (!(me = TlsGetValue(_X_TlsIndex))) {
Packit 5bd3a9
	me = xmalloc(sizeof(struct _xthread_waiter));
Packit 5bd3a9
	me->sem = CreateSemaphore(NULL, 0, 1, NULL);
Packit 5bd3a9
	me->next = NULL;
Packit 5bd3a9
	TlsSetValue(_X_TlsIndex, me);
Packit 5bd3a9
    }
Packit 5bd3a9
    return me;
Packit 5bd3a9
}
Packit 5bd3a9
#endif /* WIN32 */
Packit 5bd3a9
Packit 5bd3a9
static xthread_t _Xthread_self(void)
Packit 5bd3a9
{
Packit 5bd3a9
    return xthread_self();
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
static LockInfoRec global_lock;
Packit 5bd3a9
static LockInfoRec i18n_lock;
Packit 5bd3a9
Packit 5bd3a9
static void _XLockMutex(
Packit 5bd3a9
    LockInfoPtr lip
Packit 5bd3a9
    XTHREADS_FILE_LINE_ARGS
Packit 5bd3a9
    )
Packit 5bd3a9
{
Packit 5bd3a9
    xmutex_lock(lip->lock);
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
static void _XUnlockMutex(
Packit 5bd3a9
    LockInfoPtr lip
Packit 5bd3a9
    XTHREADS_FILE_LINE_ARGS
Packit 5bd3a9
    )
Packit 5bd3a9
{
Packit 5bd3a9
    xmutex_unlock(lip->lock);
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
static void _XCreateMutex(
Packit 5bd3a9
    LockInfoPtr lip)
Packit 5bd3a9
{
Packit 5bd3a9
    lip->lock = xmutex_malloc();
Packit 5bd3a9
    if (lip->lock) {
Packit 5bd3a9
	xmutex_init(lip->lock);
Packit 5bd3a9
	xmutex_set_name(lip->lock, "Xlib");
Packit 5bd3a9
    }
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
static void _XFreeMutex(
Packit 5bd3a9
    LockInfoPtr lip)
Packit 5bd3a9
{
Packit 5bd3a9
    xmutex_clear(lip->lock);
Packit 5bd3a9
    xmutex_free(lip->lock);
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
#ifdef XTHREADS_WARN
Packit 5bd3a9
static char *locking_file;
Packit 5bd3a9
static int locking_line;
Packit 5bd3a9
static xthread_t locking_thread;
Packit 5bd3a9
static Bool xlibint_unlock = False; /* XlibInt.c may Unlock and re-Lock */
Packit 5bd3a9
Packit 5bd3a9
/* history that is useful to examine in a debugger */
Packit 5bd3a9
#define LOCK_HIST_SIZE 21
Packit 5bd3a9
Packit 5bd3a9
static struct {
Packit 5bd3a9
    Bool lockp;			/* True for lock, False for unlock */
Packit 5bd3a9
    xthread_t thread;
Packit 5bd3a9
    char *file;
Packit 5bd3a9
    int line;
Packit 5bd3a9
} locking_history[LOCK_HIST_SIZE];
Packit 5bd3a9
Packit 5bd3a9
int lock_hist_loc = 0;		/* next slot to fill */
Packit 5bd3a9
Packit 5bd3a9
static void _XLockDisplayWarn(
Packit 5bd3a9
    Display *dpy,
Packit 5bd3a9
    char *file,			/* source file, from macro */
Packit 5bd3a9
    int line)
Packit 5bd3a9
{
Packit 5bd3a9
    xthread_t self;
Packit 5bd3a9
    xthread_t old_locker;
Packit 5bd3a9
Packit 5bd3a9
    self = xthread_self();
Packit 5bd3a9
    old_locker = locking_thread;
Packit 5bd3a9
    if (xthread_have_id(old_locker)) {
Packit 5bd3a9
	if (xthread_equal(old_locker, self))
Packit 5bd3a9
	    printf("Xlib ERROR: %s line %d thread %x: locking display already locked at %s line %d\n",
Packit 5bd3a9
		   file, line, self, locking_file, locking_line);
Packit 5bd3a9
#ifdef XTHREADS_DEBUG
Packit 5bd3a9
	else
Packit 5bd3a9
	    printf("%s line %d: thread %x waiting on lock held by %s line %d thread %x\n",
Packit 5bd3a9
		   file, line, self,
Packit 5bd3a9
		   locking_file, locking_line, old_locker);
Packit 5bd3a9
#endif /* XTHREADS_DEBUG */
Packit 5bd3a9
    }
Packit 5bd3a9
Packit 5bd3a9
    xmutex_lock(dpy->lock->mutex);
Packit 5bd3a9
Packit 5bd3a9
    if (strcmp(file, "XlibInt.c") == 0) {
Packit 5bd3a9
	if (!xlibint_unlock)
Packit 5bd3a9
	    printf("Xlib ERROR: XlibInt.c line %d thread %x locking display it did not unlock\n",
Packit 5bd3a9
		   line, self);
Packit 5bd3a9
	xlibint_unlock = False;
Packit 5bd3a9
    }
Packit 5bd3a9
Packit 5bd3a9
#ifdef XTHREADS_DEBUG
Packit 5bd3a9
    /* if (old_locker  &&  old_locker != self) */
Packit 5bd3a9
    if (strcmp("XClearArea.c", file) && strcmp("XDrSegs.c", file)) /* ico */
Packit 5bd3a9
	printf("%s line %d: thread %x got display lock\n", file, line, self);
Packit 5bd3a9
#endif /* XTHREADS_DEBUG */
Packit 5bd3a9
Packit 5bd3a9
    locking_thread = self;
Packit 5bd3a9
    if (strcmp(file, "XlibInt.c") != 0) {
Packit 5bd3a9
	locking_file = file;
Packit 5bd3a9
	locking_line = line;
Packit 5bd3a9
    }
Packit 5bd3a9
    locking_history[lock_hist_loc].file = file;
Packit 5bd3a9
    locking_history[lock_hist_loc].line = line;
Packit 5bd3a9
    locking_history[lock_hist_loc].thread = self;
Packit 5bd3a9
    locking_history[lock_hist_loc].lockp = True;
Packit 5bd3a9
    lock_hist_loc++;
Packit 5bd3a9
    if (lock_hist_loc >= LOCK_HIST_SIZE)
Packit 5bd3a9
	lock_hist_loc = 0;
Packit 5bd3a9
}
Packit 5bd3a9
#endif /* XTHREADS_WARN */
Packit 5bd3a9
Packit 5bd3a9
static void _XUnlockDisplay(
Packit 5bd3a9
    Display *dpy
Packit 5bd3a9
    XTHREADS_FILE_LINE_ARGS
Packit 5bd3a9
    )
Packit 5bd3a9
{
Packit 5bd3a9
#ifdef XTHREADS_WARN
Packit 5bd3a9
    xthread_t self = xthread_self();
Packit 5bd3a9
Packit 5bd3a9
#ifdef XTHREADS_DEBUG
Packit 5bd3a9
    if (strcmp("XClearArea.c", file) && strcmp("XDrSegs.c", file)) /* ico */
Packit 5bd3a9
	printf("%s line %d: thread %x unlocking display\n", file, line, self);
Packit 5bd3a9
#endif /* XTHREADS_DEBUG */
Packit 5bd3a9
Packit 5bd3a9
    if (!xthread_have_id(locking_thread))
Packit 5bd3a9
	printf("Xlib ERROR: %s line %d thread %x: unlocking display that is not locked\n",
Packit 5bd3a9
	       file, line, self);
Packit 5bd3a9
    else if (strcmp(file, "XlibInt.c") == 0)
Packit 5bd3a9
	xlibint_unlock = True;
Packit 5bd3a9
#ifdef XTHREADS_DEBUG
Packit 5bd3a9
    else if (strcmp(file, locking_file) != 0)
Packit 5bd3a9
	/* not always an error because locking_file is not per-thread */
Packit 5bd3a9
	printf("%s line %d: unlocking display locked from %s line %d (probably okay)\n",
Packit 5bd3a9
	       file, line, locking_file, locking_line);
Packit 5bd3a9
#endif /* XTHREADS_DEBUG */
Packit 5bd3a9
    xthread_clear_id(locking_thread);
Packit 5bd3a9
Packit 5bd3a9
    locking_history[lock_hist_loc].file = file;
Packit 5bd3a9
    locking_history[lock_hist_loc].line = line;
Packit 5bd3a9
    locking_history[lock_hist_loc].thread = self;
Packit 5bd3a9
    locking_history[lock_hist_loc].lockp = False;
Packit 5bd3a9
    lock_hist_loc++;
Packit 5bd3a9
    if (lock_hist_loc >= LOCK_HIST_SIZE)
Packit 5bd3a9
	lock_hist_loc = 0;
Packit 5bd3a9
#endif /* XTHREADS_WARN */
Packit 5bd3a9
    xmutex_unlock(dpy->lock->mutex);
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
Packit 5bd3a9
static struct _XCVList *_XCreateCVL(
Packit 5bd3a9
    Display *dpy)
Packit 5bd3a9
{
Packit 5bd3a9
    struct _XCVList *cvl;
Packit 5bd3a9
Packit 5bd3a9
    if ((cvl = dpy->lock->free_cvls) != NULL) {
Packit 5bd3a9
	dpy->lock->free_cvls = cvl->next;
Packit 5bd3a9
	dpy->lock->num_free_cvls--;
Packit 5bd3a9
    } else {
Packit 5bd3a9
	cvl = Xmalloc(sizeof(struct _XCVList));
Packit 5bd3a9
	if (!cvl)
Packit 5bd3a9
	    return NULL;
Packit 5bd3a9
	cvl->cv = xcondition_malloc();
Packit 5bd3a9
	if (!cvl->cv) {
Packit 5bd3a9
	    Xfree(cvl);
Packit 5bd3a9
	    return NULL;
Packit 5bd3a9
	}
Packit 5bd3a9
	xcondition_init(cvl->cv);
Packit 5bd3a9
	xcondition_set_name(cvl->cv, "Xlib read queue");
Packit 5bd3a9
    }
Packit 5bd3a9
    cvl->next = NULL;
Packit 5bd3a9
    return cvl;
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
/* Put ourselves on the queue to read the connection.
Packit 5bd3a9
   Allocates and returns a queue element. */
Packit 5bd3a9
Packit 5bd3a9
static struct _XCVList *
Packit 5bd3a9
_XPushReader(
Packit 5bd3a9
    Display *dpy,
Packit 5bd3a9
    struct _XCVList ***tail)
Packit 5bd3a9
{
Packit 5bd3a9
    struct _XCVList *cvl;
Packit 5bd3a9
Packit 5bd3a9
    cvl = _XCreateCVL(dpy);
Packit 5bd3a9
#ifdef XTHREADS_DEBUG
Packit 5bd3a9
    printf("_XPushReader called in thread %x, pushing %x\n",
Packit 5bd3a9
	   xthread_self(), cvl);
Packit 5bd3a9
#endif
Packit 5bd3a9
    **tail = cvl;
Packit 5bd3a9
    *tail = &cvl->next;
Packit 5bd3a9
    return cvl;
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
/* signal the next thread waiting to read the connection */
Packit 5bd3a9
Packit 5bd3a9
static void _XPopReader(
Packit 5bd3a9
    Display *dpy,
Packit 5bd3a9
    struct _XCVList **list,
Packit 5bd3a9
    struct _XCVList ***tail)
Packit 5bd3a9
{
Packit 5bd3a9
    register struct _XCVList *front = *list;
Packit 5bd3a9
Packit 5bd3a9
#ifdef XTHREADS_DEBUG
Packit 5bd3a9
    printf("_XPopReader called in thread %x, popping %x\n",
Packit 5bd3a9
	   xthread_self(), front);
Packit 5bd3a9
#endif
Packit 5bd3a9
Packit 5bd3a9
    if (dpy->flags & XlibDisplayProcConni)
Packit 5bd3a9
	/* we never added ourself in the first place */
Packit 5bd3a9
	return;
Packit 5bd3a9
Packit 5bd3a9
    if (front) {		/* check "front" for paranoia */
Packit 5bd3a9
	*list = front->next;
Packit 5bd3a9
	if (*tail == &front->next)	/* did we free the last elt? */
Packit 5bd3a9
	    *tail = list;
Packit 5bd3a9
	if (dpy->lock->num_free_cvls < NUM_FREE_CVLS) {
Packit 5bd3a9
	    front->next = dpy->lock->free_cvls;
Packit 5bd3a9
	    dpy->lock->free_cvls = front;
Packit 5bd3a9
	    dpy->lock->num_free_cvls++;
Packit 5bd3a9
	} else {
Packit 5bd3a9
	    xcondition_clear(front->cv);
Packit 5bd3a9
	    Xfree(front->cv);
Packit 5bd3a9
	    Xfree(front);
Packit 5bd3a9
	}
Packit 5bd3a9
    }
Packit 5bd3a9
Packit 5bd3a9
    /* signal new front after it is in place */
Packit 5bd3a9
    if ((dpy->lock->reply_first = (dpy->lock->reply_awaiters != NULL))) {
Packit 5bd3a9
	ConditionSignal(dpy, dpy->lock->reply_awaiters->cv);
Packit 5bd3a9
    } else if (dpy->lock->event_awaiters) {
Packit 5bd3a9
	ConditionSignal(dpy, dpy->lock->event_awaiters->cv);
Packit 5bd3a9
    }
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
static void _XConditionWait(
Packit 5bd3a9
    xcondition_t cv,
Packit 5bd3a9
    xmutex_t mutex
Packit 5bd3a9
    XTHREADS_FILE_LINE_ARGS
Packit 5bd3a9
    )
Packit 5bd3a9
{
Packit 5bd3a9
#ifdef XTHREADS_WARN
Packit 5bd3a9
    xthread_t self = xthread_self();
Packit 5bd3a9
    char *old_file = locking_file;
Packit 5bd3a9
    int old_line = locking_line;
Packit 5bd3a9
Packit 5bd3a9
#ifdef XTHREADS_DEBUG
Packit 5bd3a9
    printf("line %d thread %x in condition wait\n", line, self);
Packit 5bd3a9
#endif
Packit 5bd3a9
    xthread_clear_id(locking_thread);
Packit 5bd3a9
Packit 5bd3a9
    locking_history[lock_hist_loc].file = file;
Packit 5bd3a9
    locking_history[lock_hist_loc].line = line;
Packit 5bd3a9
    locking_history[lock_hist_loc].thread = self;
Packit 5bd3a9
    locking_history[lock_hist_loc].lockp = False;
Packit 5bd3a9
    lock_hist_loc++;
Packit 5bd3a9
    if (lock_hist_loc >= LOCK_HIST_SIZE)
Packit 5bd3a9
	lock_hist_loc = 0;
Packit 5bd3a9
#endif /* XTHREADS_WARN */
Packit 5bd3a9
Packit 5bd3a9
    xcondition_wait(cv, mutex);
Packit 5bd3a9
Packit 5bd3a9
#ifdef XTHREADS_WARN
Packit 5bd3a9
    locking_thread = self;
Packit 5bd3a9
    locking_file = old_file;
Packit 5bd3a9
    locking_line = old_line;
Packit 5bd3a9
Packit 5bd3a9
    locking_history[lock_hist_loc].file = file;
Packit 5bd3a9
    locking_history[lock_hist_loc].line = line;
Packit 5bd3a9
    locking_history[lock_hist_loc].thread = self;
Packit 5bd3a9
    locking_history[lock_hist_loc].lockp = True;
Packit 5bd3a9
    lock_hist_loc++;
Packit 5bd3a9
    if (lock_hist_loc >= LOCK_HIST_SIZE)
Packit 5bd3a9
	lock_hist_loc = 0;
Packit 5bd3a9
#ifdef XTHREADS_DEBUG
Packit 5bd3a9
    printf("line %d thread %x was signaled\n", line, self);
Packit 5bd3a9
#endif /* XTHREADS_DEBUG */
Packit 5bd3a9
#endif /* XTHREADS_WARN */
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
static void _XConditionSignal(
Packit 5bd3a9
    xcondition_t cv
Packit 5bd3a9
    XTHREADS_FILE_LINE_ARGS
Packit 5bd3a9
    )
Packit 5bd3a9
{
Packit 5bd3a9
#ifdef XTHREADS_WARN
Packit 5bd3a9
#ifdef XTHREADS_DEBUG
Packit 5bd3a9
    printf("line %d thread %x is signalling\n", line, xthread_self());
Packit 5bd3a9
#endif
Packit 5bd3a9
#endif
Packit 5bd3a9
    xcondition_signal(cv);
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
Packit 5bd3a9
static void _XConditionBroadcast(
Packit 5bd3a9
    xcondition_t cv
Packit 5bd3a9
    XTHREADS_FILE_LINE_ARGS
Packit 5bd3a9
    )
Packit 5bd3a9
{
Packit 5bd3a9
#ifdef XTHREADS_WARN
Packit 5bd3a9
#ifdef XTHREADS_DEBUG
Packit 5bd3a9
    printf("line %d thread %x is broadcasting\n", line, xthread_self());
Packit 5bd3a9
#endif
Packit 5bd3a9
#endif
Packit 5bd3a9
    xcondition_broadcast(cv);
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
Packit 5bd3a9
static void _XFreeDisplayLock(
Packit 5bd3a9
    Display *dpy)
Packit 5bd3a9
{
Packit 5bd3a9
    struct _XCVList *cvl;
Packit 5bd3a9
Packit 5bd3a9
    if (dpy->lock != NULL) {
Packit 5bd3a9
	if (dpy->lock->mutex != NULL) {
Packit 5bd3a9
	    xmutex_clear(dpy->lock->mutex);
Packit 5bd3a9
	    xmutex_free(dpy->lock->mutex);
Packit 5bd3a9
	}
Packit 5bd3a9
	if (dpy->lock->cv != NULL) {
Packit 5bd3a9
	    xcondition_clear(dpy->lock->cv);
Packit 5bd3a9
	    xcondition_free(dpy->lock->cv);
Packit 5bd3a9
	}
Packit 5bd3a9
	if (dpy->lock->writers != NULL) {
Packit 5bd3a9
	    xcondition_clear(dpy->lock->writers);
Packit 5bd3a9
	    xcondition_free(dpy->lock->writers);
Packit 5bd3a9
	}
Packit 5bd3a9
	while ((cvl = dpy->lock->free_cvls)) {
Packit 5bd3a9
	    dpy->lock->free_cvls = cvl->next;
Packit 5bd3a9
	    xcondition_clear(cvl->cv);
Packit 5bd3a9
	    Xfree(cvl->cv);
Packit 5bd3a9
	    Xfree(cvl);
Packit 5bd3a9
	}
Packit 5bd3a9
	Xfree(dpy->lock);
Packit 5bd3a9
	dpy->lock = NULL;
Packit 5bd3a9
    }
Packit 5bd3a9
    if (dpy->lock_fns != NULL) {
Packit 5bd3a9
	Xfree(dpy->lock_fns);
Packit 5bd3a9
	dpy->lock_fns = NULL;
Packit 5bd3a9
    }
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
/*
Packit 5bd3a9
 * wait for thread with user-level display lock to release it.
Packit 5bd3a9
 */
Packit 5bd3a9
Packit 5bd3a9
static void _XDisplayLockWait(
Packit 5bd3a9
    Display *dpy)
Packit 5bd3a9
{
Packit 5bd3a9
    xthread_t self;
Packit 5bd3a9
Packit 5bd3a9
    while (dpy->lock->locking_level > 0) {
Packit 5bd3a9
	self = xthread_self();
Packit 5bd3a9
	if (xthread_equal(dpy->lock->locking_thread, self))
Packit 5bd3a9
	    break;
Packit 5bd3a9
	ConditionWait(dpy, dpy->lock->cv);
Packit 5bd3a9
    }
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
static void _XLockDisplay(
Packit 5bd3a9
    Display *dpy
Packit 5bd3a9
    XTHREADS_FILE_LINE_ARGS
Packit 5bd3a9
    )
Packit 5bd3a9
{
Packit 5bd3a9
#ifdef XTHREADS_WARN
Packit 5bd3a9
    _XLockDisplayWarn(dpy, file, line);
Packit 5bd3a9
#else
Packit 5bd3a9
    xmutex_lock(dpy->lock->mutex);
Packit 5bd3a9
#endif
Packit 5bd3a9
    if (dpy->lock->locking_level > 0)
Packit 5bd3a9
	_XDisplayLockWait(dpy);
Packit 5bd3a9
    _XIDHandler(dpy);
Packit 5bd3a9
    _XSeqSyncFunction(dpy);
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
/*
Packit 5bd3a9
 * _XReply is allowed to exit from select/poll and clean up even if a
Packit 5bd3a9
 * user-level lock is in force, so it uses this instead of _XFancyLockDisplay.
Packit 5bd3a9
 */
Packit 5bd3a9
static void _XInternalLockDisplay(
Packit 5bd3a9
    Display *dpy,
Packit 5bd3a9
    Bool wskip
Packit 5bd3a9
    XTHREADS_FILE_LINE_ARGS
Packit 5bd3a9
    )
Packit 5bd3a9
{
Packit 5bd3a9
#ifdef XTHREADS_WARN
Packit 5bd3a9
    _XLockDisplayWarn(dpy, file, line);
Packit 5bd3a9
#else
Packit 5bd3a9
    xmutex_lock(dpy->lock->mutex);
Packit 5bd3a9
#endif
Packit 5bd3a9
    if (!wskip && dpy->lock->locking_level > 0)
Packit 5bd3a9
	_XDisplayLockWait(dpy);
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
static void _XUserLockDisplay(
Packit 5bd3a9
    register Display* dpy)
Packit 5bd3a9
{
Packit 5bd3a9
    _XDisplayLockWait(dpy);
Packit 5bd3a9
Packit 5bd3a9
    if (++dpy->lock->locking_level == 1) {
Packit 5bd3a9
	dpy->lock->lock_wait = _XDisplayLockWait;
Packit 5bd3a9
	dpy->lock->locking_thread = xthread_self();
Packit 5bd3a9
    }
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
static
Packit 5bd3a9
void _XUserUnlockDisplay(
Packit 5bd3a9
    register Display* dpy)
Packit 5bd3a9
{
Packit 5bd3a9
    if (dpy->lock->locking_level > 0 && --dpy->lock->locking_level == 0) {
Packit 5bd3a9
	/* signal other threads that might be waiting in XLockDisplay */
Packit 5bd3a9
	ConditionBroadcast(dpy, dpy->lock->cv);
Packit 5bd3a9
	dpy->lock->lock_wait = NULL;
Packit 5bd3a9
	xthread_clear_id(dpy->lock->locking_thread);
Packit 5bd3a9
    }
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
/* returns 0 if initialized ok, -1 if unable to allocate
Packit 5bd3a9
   a mutex or other memory */
Packit 5bd3a9
Packit 5bd3a9
static int _XInitDisplayLock(
Packit 5bd3a9
    Display *dpy)
Packit 5bd3a9
{
Packit 5bd3a9
    dpy->lock_fns = Xmalloc(sizeof(struct _XLockPtrs));
Packit 5bd3a9
    if (dpy->lock_fns == NULL)
Packit 5bd3a9
	return -1;
Packit 5bd3a9
    dpy->lock = Xmalloc(sizeof(struct _XLockInfo));
Packit 5bd3a9
    if (dpy->lock == NULL) {
Packit 5bd3a9
	_XFreeDisplayLock(dpy);
Packit 5bd3a9
	return -1;
Packit 5bd3a9
    }
Packit 5bd3a9
    dpy->lock->cv = xcondition_malloc();
Packit 5bd3a9
    dpy->lock->mutex = xmutex_malloc();
Packit 5bd3a9
    dpy->lock->writers = xcondition_malloc();
Packit 5bd3a9
    if (!dpy->lock->cv || !dpy->lock->mutex || !dpy->lock->writers) {
Packit 5bd3a9
	_XFreeDisplayLock(dpy);
Packit 5bd3a9
	return -1;
Packit 5bd3a9
    }
Packit 5bd3a9
Packit 5bd3a9
    dpy->lock->reply_bytes_left = 0;
Packit 5bd3a9
    dpy->lock->reply_was_read = False;
Packit 5bd3a9
    dpy->lock->reply_awaiters = NULL;
Packit 5bd3a9
    dpy->lock->reply_awaiters_tail = &dpy->lock->reply_awaiters;
Packit 5bd3a9
    dpy->lock->event_awaiters = NULL;
Packit 5bd3a9
    dpy->lock->event_awaiters_tail = &dpy->lock->event_awaiters;
Packit 5bd3a9
    dpy->lock->reply_first = False;
Packit 5bd3a9
    dpy->lock->locking_level = 0;
Packit 5bd3a9
    dpy->lock->num_free_cvls = 0;
Packit 5bd3a9
    dpy->lock->free_cvls = NULL;
Packit 5bd3a9
    xthread_clear_id(dpy->lock->locking_thread);
Packit 5bd3a9
    xthread_clear_id(dpy->lock->reading_thread);
Packit 5bd3a9
    xthread_clear_id(dpy->lock->conni_thread);
Packit 5bd3a9
    xmutex_init(dpy->lock->mutex);
Packit 5bd3a9
    xmutex_set_name(dpy->lock->mutex, "Xlib Display");
Packit 5bd3a9
    xcondition_init(dpy->lock->cv);
Packit 5bd3a9
    xcondition_set_name(dpy->lock->cv, "XLockDisplay");
Packit 5bd3a9
    xcondition_init(dpy->lock->writers);
Packit 5bd3a9
    xcondition_set_name(dpy->lock->writers, "Xlib wait for writable");
Packit 5bd3a9
    dpy->lock_fns->lock_display = _XLockDisplay;
Packit 5bd3a9
    dpy->lock->internal_lock_display = _XInternalLockDisplay;
Packit 5bd3a9
    dpy->lock_fns->unlock_display = _XUnlockDisplay;
Packit 5bd3a9
    dpy->lock->user_lock_display = _XUserLockDisplay;
Packit 5bd3a9
    dpy->lock->user_unlock_display = _XUserUnlockDisplay;
Packit 5bd3a9
    dpy->lock->pop_reader = _XPopReader;
Packit 5bd3a9
    dpy->lock->push_reader = _XPushReader;
Packit 5bd3a9
    dpy->lock->condition_wait = _XConditionWait;
Packit 5bd3a9
    dpy->lock->condition_signal = _XConditionSignal;
Packit 5bd3a9
    dpy->lock->condition_broadcast = _XConditionBroadcast;
Packit 5bd3a9
    dpy->lock->create_cvl = _XCreateCVL;
Packit 5bd3a9
    dpy->lock->lock_wait = NULL; /* filled in by XLockDisplay() */
Packit 5bd3a9
Packit 5bd3a9
    return 0;
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
#ifdef __UNIXWARE__
Packit 5bd3a9
xthread_t __x11_thr_self() { return 0; }
Packit 5bd3a9
xthread_t (*_x11_thr_self)() = __x11_thr_self;
Packit 5bd3a9
#endif
Packit 5bd3a9
Packit 5bd3a9
Packit 5bd3a9
Status XInitThreads(void)
Packit 5bd3a9
{
Packit 5bd3a9
    if (_Xglobal_lock)
Packit 5bd3a9
	return 1;
Packit 5bd3a9
#ifdef __UNIXWARE__
Packit 5bd3a9
    else {
Packit 5bd3a9
       void *dl_handle = dlopen(NULL, RTLD_LAZY);
Packit 5bd3a9
       if (!dl_handle ||
Packit 5bd3a9
         ((_x11_thr_self = (xthread_t(*)())dlsym(dl_handle,"thr_self")) == 0)) {
Packit 5bd3a9
	       _x11_thr_self = __x11_thr_self;
Packit 5bd3a9
	       (void) fprintf (stderr,
Packit 5bd3a9
	"XInitThreads called, but no libthread in the calling program!\n" );
Packit 5bd3a9
       }
Packit 5bd3a9
    }
Packit 5bd3a9
#endif /* __UNIXWARE__ */
Packit 5bd3a9
#ifdef xthread_init
Packit 5bd3a9
    xthread_init();		/* return value? */
Packit 5bd3a9
#endif
Packit 5bd3a9
    if (!(global_lock.lock = xmutex_malloc()))
Packit 5bd3a9
	return 0;
Packit 5bd3a9
    if (!(i18n_lock.lock = xmutex_malloc())) {
Packit 5bd3a9
	xmutex_free(global_lock.lock);
Packit 5bd3a9
	global_lock.lock = NULL;
Packit 5bd3a9
	return 0;
Packit 5bd3a9
    }
Packit 5bd3a9
    _Xglobal_lock = &global_lock;
Packit 5bd3a9
    xmutex_init(_Xglobal_lock->lock);
Packit 5bd3a9
    xmutex_set_name(_Xglobal_lock->lock, "Xlib global");
Packit 5bd3a9
    _Xi18n_lock = &i18n_lock;
Packit 5bd3a9
    xmutex_init(_Xi18n_lock->lock);
Packit 5bd3a9
    xmutex_set_name(_Xi18n_lock->lock, "Xlib i18n");
Packit 5bd3a9
    _XLockMutex_fn = _XLockMutex;
Packit 5bd3a9
    _XUnlockMutex_fn = _XUnlockMutex;
Packit 5bd3a9
    _XCreateMutex_fn = _XCreateMutex;
Packit 5bd3a9
    _XFreeMutex_fn = _XFreeMutex;
Packit 5bd3a9
    _XInitDisplayLock_fn = _XInitDisplayLock;
Packit 5bd3a9
    _XFreeDisplayLock_fn = _XFreeDisplayLock;
Packit 5bd3a9
    _Xthread_self_fn = _Xthread_self;
Packit 5bd3a9
Packit 5bd3a9
#ifdef XTHREADS_WARN
Packit 5bd3a9
#ifdef XTHREADS_DEBUG
Packit 5bd3a9
    setlinebuf(stdout);		/* for debugging messages */
Packit 5bd3a9
#endif
Packit 5bd3a9
#endif
Packit 5bd3a9
Packit 5bd3a9
    return 1;
Packit 5bd3a9
}
Packit 5bd3a9
Packit 5bd3a9
#else /* XTHREADS */
Packit 5bd3a9
Status XInitThreads(void)
Packit 5bd3a9
{
Packit 5bd3a9
    return 0;
Packit 5bd3a9
}
Packit 5bd3a9
#endif /* XTHREADS */