OSDN Git Service

Changes to support ObjC as a front-end language.
[pf3gnuchains/gcc-fork.git] / gcc / objc / thr-os2.c
1 /* GNU Objective C Runtime Thread Interface - OS/2 emx Implementation
2    Copyright (C) 1996, 1997 Free Software Foundation, Inc.
3    Contributed by Thomas Baier (baier@ci.tuwien.ac.at)
4
5 This file is part of GNU CC.
6
7 GNU CC is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 2, or (at your option) any later version.
10
11 GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14 details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING.  If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 /* As a special exception, if you link this library with files compiled with
22    GCC to produce an executable, this does not cause the resulting executable
23    to be covered by the GNU General Public License. This exception does not
24    however invalidate any other reasons why the executable file might be
25    covered by the GNU General Public License.  */
26
27 #include <objc/thr.h>
28 #include "runtime.h"
29
30 #define INCL_DOSSEMAPHORES
31 #define INCL_DOSPROCESS
32
33 /*
34  * conflicts with objc.h:       SEL, BOOL, id
35  * solution:  prefixing those with _OS2_ before including <os2.h>
36  */
37 #define SEL _OS2_SEL
38 #define BOOL _OS2_BOOL
39 #define id _OS2_id
40 #include <os2.h>
41 #undef id
42 #undef SEL
43 #undef BOOL
44
45 #include <stdlib.h>
46
47 /********
48  *  This structure represents a single mutual exclusion lock.  Lock semantics
49  *  are detailed with the subsequent functions.  We use whatever lock is
50  *  provided by the system.  We augment it with depth and current owner id
51  *  fields to implement and re-entrant lock.
52  */
53 struct objc_mutex 
54 {
55   volatile objc_thread_t owner;          /* Id of thread that owns.  */
56   volatile int            depth;          /* # of acquires.           */
57   HMTX                    handle;         /* OS/2 mutex HANDLE.      */
58 };
59
60 /*****************************************************************************
61  *  Static variables.
62  */
63 /* none needed for OS/2 */
64
65 /********
66  *  Initialize the threads subsystem.  Returns 0 if successful, or -1 if no
67  *  thread support is available.
68  */
69 int
70 __objc_init_thread_system(void)
71 {
72   DEBUG_PRINTF("__objc_init_thread_system (os2-emx)\n");
73
74   /* no initialization of thread subsystem */
75   return 0;                                     /* Yes, return success.     */
76 }
77
78 int
79 __objc_fini_thread_system(void)
80 {
81   /* no termination code for thread subsystem */
82   return 0;
83 }
84
85 /********
86  *  Create a new thread of execution and return its id.  Return NULL if fails.
87  *  The new thread starts in "func" with the given argument.
88  */
89 objc_thread_t
90 objc_thread_create(void (*func)(void *arg), void *arg)
91 {
92   int thread_id = 0;  /* id of the newly created thread */
93
94   objc_mutex_lock(__objc_runtime_mutex);
95
96   /* create a thread calling "func", args "arg", stack size 32768 bytes */
97   if ((thread_id = _beginthread (func,NULL,32768,arg)) < 0)
98     thread_id = 0;
99   else
100     __objc_runtime_threads_alive++;
101   
102   objc_mutex_unlock(__objc_runtime_mutex);
103   
104   return (objc_thread_t)thread_id;
105 }
106
107 /********
108  *  Set the current thread's priority.
109  */
110 int
111 objc_thread_set_priority(int priority)
112 {
113   ULONG sys_class = 0;
114   ULONG sys_priority = 0;
115
116   /* OBJC_THREAD_INTERACTIVE_PRIORITY -> PRTYC_FOREGROUNDSERVER
117    * OBJC_THREAD_BACKGROUND_PRIORITY  -> PRTYC_REGULSR
118    * OBJC_THREAD_LOW_PRIORITY         -> PRTYC_IDLETIME */
119   
120   switch (priority) {
121   case OBJC_THREAD_INTERACTIVE_PRIORITY:
122     sys_class = PRTYC_REGULAR;
123     sys_priority = 10;
124     break;
125   default:
126   case OBJC_THREAD_BACKGROUND_PRIORITY:
127     sys_class = PRTYC_IDLETIME;
128     sys_priority = 25;
129     break;
130   case OBJC_THREAD_LOW_PRIORITY:
131     sys_class = PRTYC_IDLETIME;
132     sys_priority = 0;
133     break;
134   }
135   if (!DosSetPriority (PRTYS_THREAD,sys_class,sys_priority,*_threadid))
136     return 0;                                   /* Changed priority. End.   */
137     
138   return -1;                                    /* Failed.                  */
139 }
140
141 /********
142  *  Return the current thread's priority.
143  */
144 int
145 objc_thread_get_priority(void)
146 {
147   PTIB ptib;
148   PPIB ppib;
149
150   DosGetInfoBlocks (&ptib,&ppib); /* get information about current thread */
151
152   switch (ptib->tib_ptib2->tib2_ulpri) {
153   case PRTYC_IDLETIME:
154   case PRTYC_REGULAR:
155   case PRTYC_TIMECRITICAL:
156   case PRTYC_FOREGROUNDSERVER:
157   default:
158     return OBJC_THREAD_INTERACTIVE_PRIORITY;
159   }
160   return -1;                                    /* Couldn't get priority.   */
161 }
162
163 /********
164  *  Yield our process time to another thread.  Any BUSY waiting that is done
165  *  by a thread should use this function to make sure that other threads can
166  *  make progress even on a lazy uniprocessor system.
167  */
168 void
169 objc_thread_yield(void)
170 {
171   DosSleep (0);                                 /* Yield to equal thread.   */
172 }
173
174 /********
175  *  Terminate the current tread.  Doesn't return anything.  Doesn't return.
176  *  Actually, if it failed returns -1.
177  */
178 int
179 objc_thread_exit(void)
180 {
181   objc_mutex_lock(__objc_runtime_mutex);
182   __objc_runtime_threads_alive--;
183   objc_mutex_unlock(__objc_runtime_mutex);
184
185   _endthread (); /* terminate the thread, NEVER use DosExit () */
186
187   return -1;
188 }
189
190 /********
191  *  Returns an integer value which uniquely describes a thread.  Must not be
192  *  -1 which is reserved as a marker for "no thread".
193  */
194 objc_thread_t
195 objc_thread_id(void)
196 {
197   return (objc_thread_t) *_threadid;  /* Return thread id.        */
198 }
199
200 /********
201  *  Sets the thread's local storage pointer.  Returns 0 if successful or -1
202  *  if failed.
203  */
204 int
205 objc_thread_set_data(void *value)
206 {
207   *_threadstore () = value;
208
209   return 0;
210 }
211
212 /********
213  *  Returns the thread's local storage pointer.  Returns NULL on failure.
214  */
215 void *
216 objc_thread_get_data(void)
217 {
218   return *_threadstore ();
219 }
220
221 /********
222  *  Allocate a mutex.  Return the mutex pointer if successful or NULL if
223  *  the allocation fails for any reason.
224  */
225 objc_mutex_t
226 objc_mutex_allocate(void)
227 {
228     objc_mutex_t mutex;
229     int         err = 0;
230
231     if (!(mutex = (objc_mutex_t)objc_malloc(sizeof(struct objc_mutex))))
232         return NULL;                            /* Abort if malloc failed.  */
233
234     if (DosCreateMutexSem (NULL,&(mutex->handle),0L,0) > 0) {
235       objc_free(mutex);
236       return NULL;
237     }
238
239     mutex->owner = NULL;                        /* No owner.                */
240     mutex->depth = 0;                           /* No locks.                */
241     return mutex;                               /* Return mutex handle.     */
242 }
243
244 /********
245  *  Deallocate a mutex.  Note that this includes an implicit mutex_lock to
246  *  insure that no one else is using the lock.  It is legal to deallocate
247  *  a lock if we have a lock on it, but illegal to deallotcate a lock held
248  *  by anyone else.
249  *  Returns the number of locks on the thread.  (1 for deallocate).
250  */
251 int
252 objc_mutex_deallocate(objc_mutex_t mutex)
253 {
254     int         depth;                          /* # of locks on mutex.     */
255
256     if (!mutex)                                 /* Is argument bad?         */
257         return -1;                              /* Yes, abort.              */
258     depth = objc_mutex_lock(mutex);             /* Must have lock.          */
259
260     DosCloseMutexSem (mutex->handle);
261     
262     objc_free(mutex);                           /* Free memory.             */
263     return depth;                               /* Return last depth.       */
264 }
265
266 /********
267  *  Grab a lock on a mutex.  If this thread already has a lock on this mutex
268  *  then we increment the lock count.  If another thread has a lock on the 
269  *  mutex we block and wait for the thread to release the lock.
270  *  Returns the lock count on the mutex held by this thread.
271  */
272 int
273 objc_mutex_lock(objc_mutex_t mutex)
274 {
275     objc_thread_t      thread_id;              /* Cache our thread id.     */
276
277     if (!mutex)                                 /* Is argument bad?         */
278         return -1;                              /* Yes, abort.              */
279
280     thread_id = objc_thread_id();               /* Get this thread's id.    */
281     if (mutex->owner == thread_id)              /* Already own lock?        */
282         return ++mutex->depth;                  /* Yes, increment depth.    */
283
284     if (DosRequestMutexSem (mutex->handle,-1L) != 0)
285       return -1;
286
287     mutex->owner = thread_id;                   /* Mark thread as owner.    */
288
289     return ++mutex->depth;                      /* Increment depth to end.  */
290 }
291
292 /********
293  *  Try to grab a lock on a mutex.  If this thread already has a lock on
294  *  this mutex then we increment the lock count and return it.  If another
295  *  thread has a lock on the mutex returns -1.
296  */
297 int
298 objc_mutex_trylock(objc_mutex_t mutex)
299 {
300     objc_thread_t      thread_id;              /* Cache our thread id.     */
301
302     if (!mutex)                                 /* Is argument bad?         */
303         return -1;                              /* Yes, abort.              */
304     thread_id = objc_thread_id();               /* Get this thread's id.    */
305     if (mutex->owner == thread_id)              /* Already own lock?        */
306         return ++mutex->depth;                  /* Yes, increment depth.    */
307
308     if (DosRequestMutexSem (mutex->handle,0L) != 0)
309       return -1;
310
311     mutex->owner = thread_id;                   /* Mark thread as owner.    */
312     return ++mutex->depth;                      /* Increment depth to end.  */
313 }
314
315 /********
316  *  Decrements the lock count on this mutex by one.  If the lock count reaches
317  *  zero, release the lock on the mutex.  Returns the lock count on the mutex.
318  *  It is an error to attempt to unlock a mutex which this thread doesn't hold
319  *  in which case return -1 and the mutex is unaffected.
320  *  Will also return -1 if the mutex free fails.
321  */
322 int
323 objc_mutex_unlock(objc_mutex_t mutex)
324 {
325     objc_thread_t      thread_id;              /* Cache our thread id.     */
326     
327     if (!mutex)                                 /* Is argument bad?         */
328         return -1;                              /* Yes, abort.              */
329     thread_id = objc_thread_id();               /* Get this thread's id.    */
330     if (mutex->owner != thread_id)              /* Does some else own lock? */
331         return -1;                              /* Yes, abort.              */
332     if (mutex->depth > 1)                       /* Released last lock?      */
333         return --mutex->depth;                  /* No, Decrement depth, end.*/
334     mutex->depth = 0;                           /* Yes, reset depth to 0.   */
335     mutex->owner = NULL;                        /* Set owner to "no thread".*/
336     
337     if (DosReleaseMutexSem(mutex->handle) != 0)
338         return -1;                              /* Failed, abort.           */
339     
340     return 0;                                   /* No, return success.      */
341 }