1  /* This code implemented by cvale@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
PyThread__init_thread(void)28  PyThread__init_thread(void)
29  {
30  }
31  
32  /*
33   * Thread support.
34   */
35  long
PyThread_start_new_thread(void (* func)(void *),void * arg)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
PyThread_get_thread_ident(void)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
PyThread_exit_thread(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
PyThread_allocate_lock(void)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
PyThread_free_lock(PyThread_type_lock aLock)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
PyThread_acquire_lock(PyThread_type_lock aLock,int waitflag)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
PyThread_release_lock(PyThread_type_lock aLock)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
_pythread_os2_set_stacksize(size_t size)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