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