OSDN Git Service

Formatting changes.
[pf3gnuchains/gcc-fork.git] / gcc / objc / thr-win32.c
1 /* GNU Objective C Runtime Thread Interface - Win32 Implementation
2    Copyright (C) 1996 Free Software Foundation, Inc.
3    Contributed by Galen C. Hunt (gchunt@cs.rochester.edu)
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 along with
17 GNU CC; see the file COPYING.  If not, write to the Free Software
18 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 #ifndef __OBJC__
31 #define __OBJC__
32 #endif
33 #include <windows.h>
34
35 /********
36  *  This structure represents a single mutual exclusion lock.  Lock semantics
37  *  are detailed with the subsequent functions.  We use whatever lock is
38  *  provided by the system.  We augment it with depth and current owner id
39  *  fields to implement and re-entrant lock.
40  */
41 struct _objc_mutex 
42 {
43   volatile _objc_thread_t       owner;          /* Id of thread that owns.  */
44   volatile int                  depth;          /* # of acquires.           */
45   HANDLE                        handle;         /* Win32 mutex HANDLE.      */
46 };
47
48 /*****************************************************************************
49  *  Static variables.
50  */
51 static DWORD    __objc_data_tls = (DWORD)-1;    /* Win32 Thread Local Index.*/
52
53 /********
54  *  Initialize the threads subsystem.  Returns 0 if successful, or -1 if no
55  *  thread support is available.
56  */
57 int
58 __objc_init_thread_system(void)
59 {
60   DEBUG_PRINTF("__objc_init_thread_system\n");
61
62   if ((__objc_data_tls = TlsAlloc()) != (DWORD)-1)
63     return 0;                                   /* Yes, return success.     */
64     
65   return -1;                                    /* Failed.                  */
66 }
67
68 int
69 __objc_fini_thread_system(void)
70 {
71   if (__objc_data_tls != (DWORD)-1) {
72     TlsFree(__objc_data_tls);
73     return 0;
74   }
75   return -1;
76 }
77
78 /********
79  *  Create a new thread of execution and return its id.  Return NULL if fails.
80  *  The new thread starts in "func" with the given argument.
81  */
82 _objc_thread_t
83 objc_thread_create(void (*func)(void *arg), void *arg)
84 {
85   DWORD         thread_id = 0;                  /* Detached thread id.      */
86   HANDLE        win32_handle;                   /* Win32 thread handle.     */
87
88   objc_mutex_lock(__objc_runtime_mutex);
89   
90   if ((win32_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func,
91                                    arg, 0, &thread_id))) {
92       __objc_runtime_threads_alive++;
93   }
94   else
95       thread_id = 0;
96   
97   objc_mutex_unlock(__objc_runtime_mutex);
98   
99   return (_objc_thread_t)thread_id;
100 }
101
102 /********
103  *  Set the current thread's priority.
104  */
105 int
106 objc_thread_set_priority(int priority)
107 {
108   int           sys_priority = 0;
109
110   switch (priority) {
111   case OBJC_THREAD_INTERACTIVE_PRIORITY:
112     sys_priority = THREAD_PRIORITY_NORMAL;
113     break;
114   default:
115   case OBJC_THREAD_BACKGROUND_PRIORITY:
116     sys_priority = THREAD_PRIORITY_BELOW_NORMAL;
117     break;
118   case OBJC_THREAD_LOW_PRIORITY:
119     sys_priority = THREAD_PRIORITY_LOWEST;
120     break;
121   }
122   if (SetThreadPriority(GetCurrentThread(), sys_priority))
123     return 0;                                   /* Changed priority. End.   */
124     
125   return -1;                                    /* Failed.                  */
126 }
127
128 /********
129  *  Return the current thread's priority.
130  */
131 int
132 objc_thread_get_priority(void)
133 {
134   int           sys_priority;
135
136   sys_priority = GetThreadPriority(GetCurrentThread());
137   
138   switch (sys_priority) {
139   case THREAD_PRIORITY_HIGHEST:
140   case THREAD_PRIORITY_TIME_CRITICAL:
141   case THREAD_PRIORITY_ABOVE_NORMAL:
142   case THREAD_PRIORITY_NORMAL:
143     return OBJC_THREAD_INTERACTIVE_PRIORITY;
144
145   default:
146   case THREAD_PRIORITY_BELOW_NORMAL:
147     return OBJC_THREAD_BACKGROUND_PRIORITY;
148     
149   case THREAD_PRIORITY_IDLE:
150   case THREAD_PRIORITY_LOWEST:
151     return OBJC_THREAD_LOW_PRIORITY;
152   }
153   return -1;                                    /* Couldn't get priority.   */
154 }
155
156 /********
157  *  Yield our process time to another thread.  Any BUSY waiting that is done
158  *  by a thread should use this function to make sure that other threads can
159  *  make progress even on a lazy uniprocessor system.
160  */
161 void
162 objc_thread_yield(void)
163 {
164   Sleep(0);                                     /* Yield to equal thread.   */
165 }
166
167 /********
168  *  Terminate the current tread.  Doesn't return anything.  Doesn't return.
169  *  Actually, if it failed returns -1.
170  */
171 int
172 objc_thread_exit(void)
173 {
174   objc_mutex_lock(__objc_runtime_mutex);
175   __objc_runtime_threads_alive--;
176   objc_mutex_unlock(__objc_runtime_mutex);
177   
178   ExitThread(__objc_thread_exit_status);        /* Terminate thread.        */
179   return -1;
180 }
181
182 /********
183  *  Returns an integer value which uniquely describes a thread.  Must not be
184  *  -1 which is reserved as a marker for "no thread".
185  */
186 _objc_thread_t
187 objc_thread_id(void)
188 {
189   return (_objc_thread_t)GetCurrentThreadId();  /* Return thread id.        */
190 }
191
192 /********
193  *  Sets the thread's local storage pointer.  Returns 0 if successful or -1
194  *  if failed.
195  */
196 int
197 objc_thread_set_data(void *value)
198 {
199   if (TlsSetValue(__objc_data_tls, value))
200     return 0;                                   /* Return thread data.      */
201   return -1;
202 }
203
204 /********
205  *  Returns the thread's local storage pointer.  Returns NULL on failure.
206  */
207 void *
208 objc_thread_get_data(void)
209 {
210   return TlsGetValue(__objc_data_tls);          /* Return thread data.      */
211 }
212
213 /********
214  *  Allocate a mutex.  Return the mutex pointer if successful or NULL if
215  *  the allocation fails for any reason.
216  */
217 _objc_mutex_t
218 objc_mutex_allocate(void)
219 {
220     _objc_mutex_t mutex;
221     int         err = 0;
222
223     if (!(mutex = (_objc_mutex_t)__objc_xmalloc(sizeof(struct _objc_mutex))))
224         return NULL;                            /* Abort if malloc failed.  */
225
226     if ((mutex->handle = CreateMutex(NULL, 0, NULL)) == NULL) {
227         free(mutex);                            /* Failed, free memory.     */
228         return NULL;                            /* Abort.                   */
229     }
230     mutex->owner = NULL;                        /* No owner.                */
231     mutex->depth = 0;                           /* No locks.                */
232     return mutex;                               /* Return mutex handle.     */
233 }
234
235 /********
236  *  Deallocate a mutex.  Note that this includes an implicit mutex_lock to
237  *  insure that no one else is using the lock.  It is legal to deallocate
238  *  a lock if we have a lock on it, but illegal to deallotcate a lock held
239  *  by anyone else.
240  *  Returns the number of locks on the thread.  (1 for deallocate).
241  */
242 int
243 objc_mutex_deallocate(_objc_mutex_t mutex)
244 {
245     int         depth;                          /* # of locks on mutex.     */
246
247     if (!mutex)                                 /* Is argument bad?         */
248         return -1;                              /* Yes, abort.              */
249     depth = objc_mutex_lock(mutex);             /* Must have lock.          */
250
251     CloseHandle(mutex->handle);                 /* Close Win32 handle.      */
252     
253     free(mutex);                                /* Free memory.             */
254     return depth;                               /* Return last depth.       */
255 }
256
257 /********
258  *  Grab a lock on a mutex.  If this thread already has a lock on this mutex
259  *  then we increment the lock count.  If another thread has a lock on the 
260  *  mutex we block and wait for the thread to release the lock.
261  *  Returns the lock count on the mutex held by this thread.
262  */
263 int
264 objc_mutex_lock(_objc_mutex_t mutex)
265 {
266     _objc_thread_t      thread_id;              /* Cache our thread id.     */
267     int                 status;
268
269     if (!mutex)                                 /* Is argument bad?         */
270         return -1;                              /* Yes, abort.              */
271     thread_id = objc_thread_id();               /* Get this thread's id.    */
272     if (mutex->owner == thread_id)              /* Already own lock?        */
273         return ++mutex->depth;                  /* Yes, increment depth.    */
274
275     status = WaitForSingleObject(mutex->handle, INFINITE);
276     if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
277         return -1;                              /* Failed, abort.           */
278     
279     mutex->owner = thread_id;                   /* Mark thread as owner.    */
280
281     return ++mutex->depth;                      /* Increment depth to end.  */
282 }
283
284 /********
285  *  Try to grab a lock on a mutex.  If this thread already has a lock on
286  *  this mutex then we increment the lock count and return it.  If another
287  *  thread has a lock on the mutex returns -1.
288  */
289 int
290 objc_mutex_trylock(_objc_mutex_t mutex)
291 {
292     _objc_thread_t      thread_id;              /* Cache our thread id.     */
293     DWORD               status;                 /* Return status from Win32.*/
294
295     if (!mutex)                                 /* Is argument bad?         */
296         return -1;                              /* Yes, abort.              */
297     thread_id = objc_thread_id();               /* Get this thread's id.    */
298     if (mutex->owner == thread_id)              /* Already own lock?        */
299         return ++mutex->depth;                  /* Yes, increment depth.    */
300
301     status = WaitForSingleObject(mutex->handle, 0);
302     if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
303         return -1;                              /* Failed, abort.           */
304     
305     mutex->owner = thread_id;                   /* Mark thread as owner.    */
306     return ++mutex->depth;                      /* Increment depth to end.  */
307 }
308
309 /********
310  *  Decrements the lock count on this mutex by one.  If the lock count reaches
311  *  zero, release the lock on the mutex.  Returns the lock count on the mutex.
312  *  It is an error to attempt to unlock a mutex which this thread doesn't hold
313  *  in which case return -1 and the mutex is unaffected.
314  *  Will also return -1 if the mutex free fails.
315  */
316 int
317 objc_mutex_unlock(_objc_mutex_t mutex)
318 {
319     _objc_thread_t      thread_id;              /* Cache our thread id.     */
320     
321     if (!mutex)                                 /* Is argument bad?         */
322         return -1;                              /* Yes, abort.              */
323     thread_id = objc_thread_id();               /* Get this thread's id.    */
324     if (mutex->owner != thread_id)              /* Does some else own lock? */
325         return -1;                              /* Yes, abort.              */
326     if (mutex->depth > 1)                       /* Released last lock?      */
327         return --mutex->depth;                  /* No, Decrement depth, end.*/
328     mutex->depth = 0;                           /* Yes, reset depth to 0.   */
329     mutex->owner = NULL;                        /* Set owner to "no thread".*/
330     
331     if (ReleaseMutex(mutex->handle) == 0)
332         return -1;                              /* Failed, abort.           */
333     
334     return 0;                                   /* No, return success.      */
335 }
336
337 /* End of File */