(decl_function_context): Handle QUAL_UNION_TYPE.
[official-gcc.git] / gcc / objc / thr-win32.c
blob37e9876416df83b18fb62b7194763967649c864b
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)
5 This file is part of GNU CC.
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.
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.
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. */
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. */
27 #include <objc/thr.h>
28 #include "runtime.h"
30 #ifndef __OBJC__
31 #define __OBJC__
32 #endif
33 #include <windows.h>
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.
41 struct _objc_mutex
43 volatile _objc_thread_t owner; /* Id of thread that owns. */
44 volatile int depth; /* # of acquires. */
45 HANDLE handle; /* Win32 mutex HANDLE. */
48 /*****************************************************************************
49 * Static variables.
51 static DWORD __objc_data_tls = (DWORD)-1; /* Win32 Thread Local Index.*/
53 /********
54 * Initialize the threads subsystem. Returns 0 if successful, or -1 if no
55 * thread support is available.
57 int
58 __objc_init_thread_system(void)
60 DEBUG_PRINTF("__objc_init_thread_system\n");
62 if ((__objc_data_tls = TlsAlloc()) != (DWORD)-1)
63 return 0; /* Yes, return success. */
65 return -1; /* Failed. */
68 int
69 __objc_fini_thread_system(void)
71 if (__objc_data_tls != (DWORD)-1) {
72 TlsFree(__objc_data_tls);
73 return 0;
75 return -1;
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.
82 _objc_thread_t
83 objc_thread_create(void (*func)(void *arg), void *arg)
85 DWORD thread_id = 0; /* Detached thread id. */
86 HANDLE win32_handle; /* Win32 thread handle. */
88 objc_mutex_lock(__objc_runtime_mutex);
90 if ((win32_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func,
91 arg, 0, &thread_id))) {
92 __objc_runtime_threads_alive++;
94 else
95 thread_id = 0;
97 objc_mutex_unlock(__objc_runtime_mutex);
99 return (_objc_thread_t)thread_id;
102 /********
103 * Set the current thread's priority.
106 objc_thread_set_priority(int priority)
108 int sys_priority = 0;
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;
122 if (SetThreadPriority(GetCurrentThread(), sys_priority))
123 return 0; /* Changed priority. End. */
125 return -1; /* Failed. */
128 /********
129 * Return the current thread's priority.
132 objc_thread_get_priority(void)
134 int sys_priority;
136 sys_priority = GetThreadPriority(GetCurrentThread());
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;
145 default:
146 case THREAD_PRIORITY_BELOW_NORMAL:
147 return OBJC_THREAD_BACKGROUND_PRIORITY;
149 case THREAD_PRIORITY_IDLE:
150 case THREAD_PRIORITY_LOWEST:
151 return OBJC_THREAD_LOW_PRIORITY;
153 return -1; /* Couldn't get priority. */
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.
161 void
162 objc_thread_yield(void)
164 Sleep(0); /* Yield to equal thread. */
167 /********
168 * Terminate the current tread. Doesn't return anything. Doesn't return.
169 * Actually, if it failed returns -1.
172 objc_thread_exit(void)
174 objc_mutex_lock(__objc_runtime_mutex);
175 __objc_runtime_threads_alive--;
176 objc_mutex_unlock(__objc_runtime_mutex);
178 ExitThread(__objc_thread_exit_status); /* Terminate thread. */
179 return -1;
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".
186 _objc_thread_t
187 objc_thread_id(void)
189 return (_objc_thread_t)GetCurrentThreadId(); /* Return thread id. */
192 /********
193 * Sets the thread's local storage pointer. Returns 0 if successful or -1
194 * if failed.
197 objc_thread_set_data(void *value)
199 if (TlsSetValue(__objc_data_tls, value))
200 return 0; /* Return thread data. */
201 return -1;
204 /********
205 * Returns the thread's local storage pointer. Returns NULL on failure.
207 void *
208 objc_thread_get_data(void)
210 return TlsGetValue(__objc_data_tls); /* Return thread data. */
213 /********
214 * Allocate a mutex. Return the mutex pointer if successful or NULL if
215 * the allocation fails for any reason.
217 _objc_mutex_t
218 objc_mutex_allocate(void)
220 _objc_mutex_t mutex;
221 int err = 0;
223 if (!(mutex = (_objc_mutex_t) objc_malloc(sizeof(struct _objc_mutex))))
224 return NULL; /* Abort if malloc failed. */
226 if ((mutex->handle = CreateMutex(NULL, 0, NULL)) == NULL) {
227 objc_free(mutex); /* Failed, free memory. */
228 return NULL; /* Abort. */
230 mutex->owner = NULL; /* No owner. */
231 mutex->depth = 0; /* No locks. */
232 return mutex; /* Return mutex handle. */
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).
243 objc_mutex_deallocate(_objc_mutex_t mutex)
245 int depth; /* # of locks on mutex. */
247 if (!mutex) /* Is argument bad? */
248 return -1; /* Yes, abort. */
249 depth = objc_mutex_lock(mutex); /* Must have lock. */
251 CloseHandle(mutex->handle); /* Close Win32 handle. */
253 objc_free(mutex); /* Free memory. */
254 return depth; /* Return last depth. */
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.
264 objc_mutex_lock(_objc_mutex_t mutex)
266 _objc_thread_t thread_id; /* Cache our thread id. */
267 int status;
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. */
275 status = WaitForSingleObject(mutex->handle, INFINITE);
276 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
277 return -1; /* Failed, abort. */
279 mutex->owner = thread_id; /* Mark thread as owner. */
281 return ++mutex->depth; /* Increment depth to end. */
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.
290 objc_mutex_trylock(_objc_mutex_t mutex)
292 _objc_thread_t thread_id; /* Cache our thread id. */
293 DWORD status; /* Return status from Win32.*/
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. */
301 status = WaitForSingleObject(mutex->handle, 0);
302 if (status != WAIT_OBJECT_0 && status != WAIT_ABANDONED)
303 return -1; /* Failed, abort. */
305 mutex->owner = thread_id; /* Mark thread as owner. */
306 return ++mutex->depth; /* Increment depth to end. */
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.
317 objc_mutex_unlock(_objc_mutex_t mutex)
319 _objc_thread_t thread_id; /* Cache our thread id. */
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".*/
331 if (ReleaseMutex(mutex->handle) == 0)
332 return -1; /* Failed, abort. */
334 return 0; /* No, return success. */
337 /* End of File */