Home | History | Annotate | Download | only in Python
      1 /* This code implemented by cvale (at) netcom.com */
      2 
      3 #define INCL_DOSPROCESS
      4 #define INCL_DOSSEMAPHORES
      5 #include "os2.h"
      6 #include "limits.h"
      7 
      8 #include "process.h"
      9 
     10 #if defined(PYCC_GCC)
     11 #include <sys/builtin.h>
     12 #include <sys/fmutex.h>
     13 #else
     14 long PyThread_get_thread_ident(void);
     15 #endif
     16 
     17 /* default thread stack size of 64kB */
     18 #if !defined(THREAD_STACK_SIZE)
     19 #define THREAD_STACK_SIZE       0x10000
     20 #endif
     21 
     22 #define OS2_STACKSIZE(x)        (x ? x : THREAD_STACK_SIZE)
     23 
     24 /*
     25  * Initialization of the C package, should not be needed.
     26  */
     27 static void
     28 PyThread__init_thread(void)
     29 {
     30 }
     31 
     32 /*
     33  * Thread support.
     34  */
     35 long
     36 PyThread_start_new_thread(void (*func)(void *), void *arg)
     37 {
     38     int thread_id;
     39 
     40     thread_id = _beginthread(func,
     41                             NULL,
     42                             OS2_STACKSIZE(_pythread_stacksize),
     43                             arg);
     44 
     45     if (thread_id == -1) {
     46         dprintf(("_beginthread failed. return %ld\n", errno));
     47     }
     48 
     49     return thread_id;
     50 }
     51 
     52 long
     53 PyThread_get_thread_ident(void)
     54 {
     55 #if !defined(PYCC_GCC)
     56     PPIB pib;
     57     PTIB tib;
     58 #endif
     59 
     60     if (!initialized)
     61         PyThread_init_thread();
     62 
     63 #if defined(PYCC_GCC)
     64     return _gettid();
     65 #else
     66     DosGetInfoBlocks(&tib, &pib);
     67     return tib->tib_ptib2->tib2_ultid;
     68 #endif
     69 }
     70 
     71 void
     72 PyThread_exit_thread(void)
     73 {
     74     dprintf(("%ld: PyThread_exit_thread called\n",
     75              PyThread_get_thread_ident()));
     76     if (!initialized)
     77         exit(0);
     78     _endthread();
     79 }
     80 
     81 /*
     82  * Lock support.  This is implemented with an event semaphore and critical
     83  * sections to make it behave more like a posix mutex than its OS/2
     84  * counterparts.
     85  */
     86 
     87 typedef struct os2_lock_t {
     88     int is_set;
     89     HEV changed;
     90 } *type_os2_lock;
     91 
     92 PyThread_type_lock
     93 PyThread_allocate_lock(void)
     94 {
     95 #if defined(PYCC_GCC)
     96     _fmutex *sem = malloc(sizeof(_fmutex));
     97     if (!initialized)
     98         PyThread_init_thread();
     99     dprintf(("%ld: PyThread_allocate_lock() -> %lx\n",
    100              PyThread_get_thread_ident(),
    101              (long)sem));
    102     if (_fmutex_create(sem, 0)) {
    103         free(sem);
    104         sem = NULL;
    105     }
    106     return (PyThread_type_lock)sem;
    107 #else
    108     APIRET rc;
    109     type_os2_lock lock = (type_os2_lock)malloc(sizeof(struct os2_lock_t));
    110 
    111     dprintf(("PyThread_allocate_lock called\n"));
    112     if (!initialized)
    113         PyThread_init_thread();
    114 
    115     lock->is_set = 0;
    116 
    117     DosCreateEventSem(NULL, &lock->changed, 0, 0);
    118 
    119     dprintf(("%ld: PyThread_allocate_lock() -> %p\n",
    120              PyThread_get_thread_ident(),
    121              lock->changed));
    122 
    123     return (PyThread_type_lock)lock;
    124 #endif
    125 }
    126 
    127 void
    128 PyThread_free_lock(PyThread_type_lock aLock)
    129 {
    130 #if !defined(PYCC_GCC)
    131     type_os2_lock lock = (type_os2_lock)aLock;
    132 #endif
    133 
    134     dprintf(("%ld: PyThread_free_lock(%p) called\n",
    135              PyThread_get_thread_ident(),aLock));
    136 
    137 #if defined(PYCC_GCC)
    138     if (aLock) {
    139         _fmutex_close((_fmutex *)aLock);
    140         free((_fmutex *)aLock);
    141     }
    142 #else
    143     DosCloseEventSem(lock->changed);
    144     free(aLock);
    145 #endif
    146 }
    147 
    148 /*
    149  * Return 1 on success if the lock was acquired
    150  *
    151  * and 0 if the lock was not acquired.
    152  */
    153 int
    154 PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
    155 {
    156 #if !defined(PYCC_GCC)
    157     int   done = 0;
    158     ULONG count;
    159     PID   pid = 0;
    160     TID   tid = 0;
    161     type_os2_lock lock = (type_os2_lock)aLock;
    162 #endif
    163 
    164     dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n",
    165              PyThread_get_thread_ident(),
    166              aLock,
    167              waitflag));
    168 
    169 #if defined(PYCC_GCC)
    170     /* always successful if the lock doesn't exist */
    171     if (aLock &&
    172         _fmutex_request((_fmutex *)aLock, waitflag ? 0 : _FMR_NOWAIT))
    173         return 0;
    174 #else
    175     while (!done) {
    176         /* if the lock is currently set, we have to wait for
    177          * the state to change
    178          */
    179         if (lock->is_set) {
    180             if (!waitflag)
    181                 return 0;
    182             DosWaitEventSem(lock->changed, SEM_INDEFINITE_WAIT);
    183         }
    184 
    185         /* enter a critical section and try to get the semaphore.  If
    186          * it is still locked, we will try again.
    187          */
    188         if (DosEnterCritSec())
    189             return 0;
    190 
    191         if (!lock->is_set) {
    192             lock->is_set = 1;
    193             DosResetEventSem(lock->changed, &count);
    194             done = 1;
    195         }
    196 
    197         DosExitCritSec();
    198     }
    199 #endif
    200 
    201     return 1;
    202 }
    203 
    204 void
    205 PyThread_release_lock(PyThread_type_lock aLock)
    206 {
    207 #if !defined(PYCC_GCC)
    208     type_os2_lock lock = (type_os2_lock)aLock;
    209 #endif
    210 
    211     dprintf(("%ld: PyThread_release_lock(%p) called\n",
    212              PyThread_get_thread_ident(),
    213              aLock));
    214 
    215 #if defined(PYCC_GCC)
    216     if (aLock)
    217         _fmutex_release((_fmutex *)aLock);
    218 #else
    219     if (!lock->is_set) {
    220         dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n",
    221                  PyThread_get_thread_ident(),
    222                  aLock,
    223                  GetLastError()));
    224         return;
    225     }
    226 
    227     if (DosEnterCritSec()) {
    228         dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n",
    229                  PyThread_get_thread_ident(),
    230                  aLock,
    231                  GetLastError()));
    232         return;
    233     }
    234 
    235     lock->is_set = 0;
    236     DosPostEventSem(lock->changed);
    237 
    238     DosExitCritSec();
    239 #endif
    240 }
    241 
    242 /* minimum/maximum thread stack sizes supported */
    243 #define THREAD_MIN_STACKSIZE    0x8000          /* 32kB */
    244 #define THREAD_MAX_STACKSIZE    0x2000000       /* 32MB */
    245 
    246 /* set the thread stack size.
    247  * Return 0 if size is valid, -1 otherwise.
    248  */
    249 static int
    250 _pythread_os2_set_stacksize(size_t size)
    251 {
    252     /* set to default */
    253     if (size == 0) {
    254         _pythread_stacksize = 0;
    255         return 0;
    256     }
    257 
    258     /* valid range? */
    259     if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
    260         _pythread_stacksize = size;
    261         return 0;
    262     }
    263 
    264     return -1;
    265 }
    266 
    267 #define THREAD_SET_STACKSIZE(x) _pythread_os2_set_stacksize(x)
    268