Home | History | Annotate | Line # | Download | only in src
      1 /************************************************************
      2 Copyright (c) 1993, Oracle and/or its affiliates.
      3 
      4 Permission is hereby granted, free of charge, to any person obtaining a
      5 copy of this software and associated documentation files (the "Software"),
      6 to deal in the Software without restriction, including without limitation
      7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 and/or sell copies of the Software, and to permit persons to whom the
      9 Software is furnished to do so, subject to the following conditions:
     10 
     11 The above copyright notice and this permission notice (including the next
     12 paragraph) shall be included in all copies or substantial portions of the
     13 Software.
     14 
     15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21 DEALINGS IN THE SOFTWARE.
     22 
     23 ********************************************************/
     24 
     25 /*
     26 
     27 Copyright 1994, 1998  The Open Group
     28 
     29 Permission to use, copy, modify, distribute, and sell this software and its
     30 documentation for any purpose is hereby granted without fee, provided that
     31 the above copyright notice appear in all copies and that both that
     32 copyright notice and this permission notice appear in supporting
     33 documentation.
     34 
     35 The above copyright notice and this permission notice shall be included in
     36 all copies or substantial portions of the Software.
     37 
     38 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     39 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     40 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     41 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     42 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     43 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     44 
     45 Except as contained in this notice, the name of The Open Group shall not be
     46 used in advertising or otherwise to promote the sale, use or other dealings
     47 in this Software without prior written authorization from The Open Group.
     48 
     49 */
     50 
     51 #ifdef HAVE_CONFIG_H
     52 #include <config.h>
     53 #endif
     54 #include "IntrinsicI.h"
     55 
     56 #ifdef XTHREADS
     57 
     58 #define xmalloc __XtMalloc
     59 #define xfree XtFree
     60 #include <X11/Xthreads.h>
     61 
     62 #ifndef NDEBUG
     63 #define NDEBUG
     64 #endif
     65 #include <assert.h>
     66 #include <stdio.h>
     67 
     68 typedef struct _ThreadStack {
     69     unsigned int size;
     70     int sp;
     71     struct _Tstack {
     72         xthread_t t;
     73         xcondition_t c;
     74     } *st;
     75 } ThreadStack;
     76 
     77 typedef struct _LockRec {
     78     xmutex_t mutex;
     79     int level;
     80     ThreadStack stack;
     81 #ifndef _XMUTEX_NESTS
     82     xthread_t holder;
     83     xcondition_t cond;
     84 #endif
     85 } LockRec;
     86 
     87 #define STACK_INCR 16
     88 
     89 static LockPtr process_lock = NULL;
     90 
     91 static void
     92 InitProcessLock(void)
     93 {
     94     if (!process_lock) {
     95         process_lock = XtNew(LockRec);
     96         process_lock->mutex = xmutex_malloc();
     97         xmutex_init(process_lock->mutex);
     98         process_lock->level = 0;
     99 #ifndef _XMUTEX_NESTS
    100         process_lock->cond = xcondition_malloc();
    101         xcondition_init(process_lock->cond);
    102         xthread_clear_id(process_lock->holder);
    103 #endif
    104     }
    105 }
    106 
    107 static void
    108 ProcessLock(void)
    109 {
    110 #ifdef _XMUTEX_NESTS
    111     xmutex_lock(process_lock->mutex);
    112     process_lock->level++;
    113 #else
    114     xthread_t this_thread = xthread_self();
    115 
    116     xmutex_lock(process_lock->mutex);
    117 
    118     if (!xthread_have_id(process_lock->holder)) {
    119         process_lock->holder = this_thread;
    120         xmutex_unlock(process_lock->mutex);
    121         return;
    122     }
    123 
    124     if (xthread_equal(process_lock->holder, this_thread)) {
    125         process_lock->level++;
    126         xmutex_unlock(process_lock->mutex);
    127         return;
    128     }
    129 
    130     while (xthread_have_id(process_lock->holder))
    131         xcondition_wait(process_lock->cond, process_lock->mutex);
    132 
    133     process_lock->holder = this_thread;
    134     assert(xthread_equal(process_lock->holder, this_thread));
    135     xmutex_unlock(process_lock->mutex);
    136 #endif
    137 }
    138 
    139 static void
    140 ProcessUnlock(void)
    141 {
    142 #ifdef _XMUTEX_NESTS
    143     process_lock->level--;
    144     xmutex_unlock(process_lock->mutex);
    145 #else
    146     xmutex_lock(process_lock->mutex);
    147     assert(xthread_equal(process_lock->holder, xthread_self()));
    148     if (process_lock->level != 0) {
    149         process_lock->level--;
    150         xmutex_unlock(process_lock->mutex);
    151         return;
    152     }
    153 
    154     xthread_clear_id(process_lock->holder);
    155     xcondition_signal(process_lock->cond);
    156 
    157     xmutex_unlock(process_lock->mutex);
    158 #endif
    159 }
    160 
    161 static void
    162 AppLock(XtAppContext app)
    163 {
    164     LockPtr app_lock = app->lock_info;
    165 
    166 #ifdef _XMUTEX_NESTS
    167     xmutex_lock(app_lock->mutex);
    168     app_lock->level++;
    169 #else
    170     xthread_t self = xthread_self();
    171 
    172     xmutex_lock(app_lock->mutex);
    173     if (!xthread_have_id(app_lock->holder)) {
    174         app_lock->holder = self;
    175         assert(xthread_equal(app_lock->holder, self));
    176         xmutex_unlock(app_lock->mutex);
    177         return;
    178     }
    179     if (xthread_equal(app_lock->holder, self)) {
    180         app_lock->level++;
    181         xmutex_unlock(app_lock->mutex);
    182         return;
    183     }
    184     while (xthread_have_id(app_lock->holder)) {
    185         xcondition_wait(app_lock->cond, app_lock->mutex);
    186     }
    187     app_lock->holder = self;
    188     assert(xthread_equal(app_lock->holder, self));
    189     xmutex_unlock(app_lock->mutex);
    190 #endif
    191 }
    192 
    193 static void
    194 AppUnlock(XtAppContext app)
    195 {
    196     LockPtr app_lock = app->lock_info;
    197 
    198 #ifdef _XMUTEX_NESTS
    199     app_lock->level--;
    200     xmutex_unlock(app_lock->mutex);
    201 #else
    202     xthread_t self;
    203 
    204     self = xthread_self();
    205     (void) self;
    206 
    207     xmutex_lock(app_lock->mutex);
    208     assert(xthread_equal(app_lock->holder, self));
    209     if (app_lock->level != 0) {
    210         app_lock->level--;
    211         xmutex_unlock(app_lock->mutex);
    212         return;
    213     }
    214     xthread_clear_id(app_lock->holder);
    215     xcondition_signal(app_lock->cond);
    216     xmutex_unlock(app_lock->mutex);
    217 #endif
    218 }
    219 
    220 static void
    221 YieldAppLock(XtAppContext app,
    222              Boolean *push_thread,
    223              Boolean *pushed_thread,
    224              int *level)
    225 {
    226     LockPtr app_lock = app->lock_info;
    227     xthread_t self = xthread_self();
    228 
    229 #ifndef _XMUTEX_NESTS
    230     xmutex_lock(app_lock->mutex);
    231     assert(xthread_equal(app_lock->holder, self));
    232 #endif
    233     *level = app_lock->level;
    234     if (*push_thread) {
    235         *push_thread = FALSE;
    236         *pushed_thread = TRUE;
    237 
    238         if (app_lock->stack.sp == (int) app_lock->stack.size - 1) {
    239             unsigned ii;
    240 
    241             app_lock->stack.st = (struct _Tstack *)
    242                 XtReallocArray(app_lock->stack.st,
    243                                (Cardinal) (app_lock->stack.size + STACK_INCR),
    244                                (Cardinal) sizeof(struct _Tstack));
    245             ii = app_lock->stack.size;
    246             app_lock->stack.size += STACK_INCR;
    247             for (; ii < app_lock->stack.size; ii++) {
    248                 app_lock->stack.st[ii].c = xcondition_malloc();
    249                 xcondition_init(app_lock->stack.st[ii].c);
    250             }
    251         }
    252         app_lock->stack.st[++(app_lock->stack.sp)].t = self;
    253     }
    254 #ifdef _XMUTEX_NESTS
    255     while (app_lock->level > 0) {
    256         app_lock->level--;
    257         xmutex_unlock(app_lock->mutex);
    258     }
    259 #else
    260     xcondition_signal(app_lock->cond);
    261     app_lock->level = 0;
    262     xthread_clear_id(app_lock->holder);
    263     xmutex_unlock(app_lock->mutex);
    264 #endif
    265 }
    266 
    267 static void
    268 RestoreAppLock(XtAppContext app, int level, Boolean *pushed_thread)
    269 {
    270     LockPtr app_lock = app->lock_info;
    271     xthread_t self = xthread_self();
    272 
    273     xmutex_lock(app_lock->mutex);
    274 #ifdef _XMUTEX_NESTS
    275     app_lock->level++;
    276 #else
    277     while (xthread_have_id(app_lock->holder)) {
    278         xcondition_wait(app_lock->cond, app_lock->mutex);
    279     }
    280 #endif
    281     if (!xthread_equal(app_lock->stack.st[app_lock->stack.sp].t, self)) {
    282         int ii;
    283 
    284         for (ii = app_lock->stack.sp - 1; ii >= 0; ii--) {
    285             if (xthread_equal(app_lock->stack.st[ii].t, self)) {
    286                 xcondition_wait(app_lock->stack.st[ii].c, app_lock->mutex);
    287                 break;
    288             }
    289         }
    290 #ifndef _XMUTEX_NESTS
    291         while (xthread_have_id(app_lock->holder)) {
    292             xcondition_wait(app_lock->cond, app_lock->mutex);
    293         }
    294 #endif
    295     }
    296 #ifdef _XMUTEX_NESTS
    297     while (app_lock->level < level) {
    298         xmutex_lock(app_lock->mutex);
    299         app_lock->level++;
    300     }
    301 #else
    302     app_lock->holder = self;
    303     app_lock->level = level;
    304     assert(xthread_equal(app_lock->holder, self));
    305 #endif
    306     if (*pushed_thread) {
    307         *pushed_thread = FALSE;
    308         (app_lock->stack.sp)--;
    309         if (app_lock->stack.sp >= 0) {
    310             xcondition_signal(app_lock->stack.st[app_lock->stack.sp].c);
    311         }
    312     }
    313 #ifndef _XMUTEX_NESTS
    314     xmutex_unlock(app_lock->mutex);
    315 #endif
    316 }
    317 
    318 static void
    319 FreeAppLock(XtAppContext app)
    320 {
    321     unsigned ii;
    322     LockPtr app_lock = app->lock_info;
    323 
    324     if (app_lock) {
    325         xmutex_clear(app_lock->mutex);
    326         xmutex_free(app_lock->mutex);
    327 #ifndef _XMUTEX_NESTS
    328         xcondition_clear(app_lock->cond);
    329         xcondition_free(app_lock->cond);
    330 #endif
    331         if (app_lock->stack.st != (struct _Tstack *) NULL) {
    332             for (ii = 0; ii < app_lock->stack.size; ii++) {
    333                 xcondition_clear(app_lock->stack.st[ii].c);
    334                 xcondition_free(app_lock->stack.st[ii].c);
    335             }
    336             XtFree((char *) app_lock->stack.st);
    337         }
    338         XtFree((char *) app_lock);
    339         app->lock_info = NULL;
    340     }
    341 }
    342 
    343 static void
    344 InitAppLock(XtAppContext app)
    345 {
    346     int ii;
    347     LockPtr app_lock;
    348 
    349     app->lock = AppLock;
    350     app->unlock = AppUnlock;
    351     app->yield_lock = YieldAppLock;
    352     app->restore_lock = RestoreAppLock;
    353     app->free_lock = FreeAppLock;
    354 
    355     app_lock = app->lock_info = XtNew(LockRec);
    356     app_lock->mutex = xmutex_malloc();
    357     xmutex_init(app_lock->mutex);
    358     app_lock->level = 0;
    359 #ifndef _XMUTEX_NESTS
    360     app_lock->cond = xcondition_malloc();
    361     xcondition_init(app_lock->cond);
    362     xthread_clear_id(app_lock->holder);
    363 #endif
    364     app_lock->stack.size = STACK_INCR;
    365     app_lock->stack.sp = -1;
    366     app_lock->stack.st = XtMallocArray(STACK_INCR, sizeof(struct _Tstack));
    367     for (ii = 0; ii < STACK_INCR; ii++) {
    368         app_lock->stack.st[ii].c = xcondition_malloc();
    369         xcondition_init(app_lock->stack.st[ii].c);
    370     }
    371 }
    372 
    373 #endif                          /* defined(XTHREADS) */
    374 
    375 void
    376 XtAppLock(XtAppContext app)
    377 {
    378 #ifdef XTHREADS
    379     if (app->lock)
    380         (*app->lock) (app);
    381 #endif
    382 }
    383 
    384 void
    385 XtAppUnlock(XtAppContext app)
    386 {
    387 #ifdef XTHREADS
    388     if (app->unlock)
    389         (*app->unlock) (app);
    390 #endif
    391 }
    392 
    393 void
    394 XtProcessLock(void)
    395 {
    396 #ifdef XTHREADS
    397     if (_XtProcessLock)
    398         (*_XtProcessLock) ();
    399 #endif
    400 }
    401 
    402 void
    403 XtProcessUnlock(void)
    404 {
    405 #ifdef XTHREADS
    406     if (_XtProcessUnlock)
    407         (*_XtProcessUnlock) ();
    408 #endif
    409 }
    410 
    411 Boolean
    412 XtToolkitThreadInitialize(void)
    413 {
    414 #ifdef XTHREADS
    415     if (_XtProcessLock == NULL) {
    416 #ifdef xthread_init
    417         xthread_init();
    418 #endif
    419         InitProcessLock();
    420         _XtProcessLock = ProcessLock;
    421         _XtProcessUnlock = ProcessUnlock;
    422         _XtInitAppLock = InitAppLock;
    423     }
    424     return True;
    425 #else
    426     return False;
    427 #endif
    428 }
    429