Edit

IABSD.fr/xenocara/lib/libX11/src/locking.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2010-09-04 10:33:11
    Hash : 6c940574
    Message : Update to libX11 1.3.5

  • lib/libX11/src/locking.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;
    
    #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 = (struct _xthread_waiter *)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 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);
    }
    
    #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 = (struct _XCVList *)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((char *)front->cv);
    	    Xfree((char *)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((char *)cvl->cv);
    	    Xfree((char *)cvl);
    	}
    	Xfree((char *)dpy->lock);
    	dpy->lock = NULL;
        }
        if (dpy->lock_fns != NULL) {
    	Xfree((char *)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_WARN
        _XLockDisplayWarn(dpy, file, line);
    #else
        xmutex_lock(dpy->lock->mutex);
    #endif
        if (dpy->lock->locking_level > 0)
    	_XDisplayLockWait(dpy);
        _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)
    {
        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 = (struct _XLockPtrs*)Xmalloc(sizeof(struct _XLockPtrs));
        if (dpy->lock_fns == NULL)
    	return -1;
        dpy->lock = (struct _XLockInfo *)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;
        }
        _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");
        _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 */