1 /* Threads compatibility routines for libgcc2 and libobjc.  */
2 /* Compile this one with gcc.  */
3 /* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
4 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11 
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING.  If not, write to the Free
19 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.  */
21 
22 /* As a special exception, if you link this library with other files,
23    some of which are compiled with GCC, to produce an executable,
24    this library does not by itself cause the resulting executable
25    to be covered by the GNU General Public License.
26    This exception does not however invalidate any other reasons why
27    the executable file might be covered by the GNU General Public License.  */
28 
29 #ifndef GCC_GTHR_NKS_H
30 #define GCC_GTHR_NKS_H
31 
32 /* NKS threads specific definitions.
33    Easy, since the interface is mostly one-to-one mapping.  */
34 
35 #define __GTHREADS 1
36 
37 #define NKS_NO_INLINE_FUNCS
38 #include <nksapi.h>
39 #include <string.h>
40 
41 typedef NXKey_t __gthread_key_t;
42 typedef NXMutex_t *__gthread_mutex_t;
43 typedef NXMutex_t *__gthread_recursive_mutex_t;
44 
45 #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
46 #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
47 
48 static inline int
__gthread_active_p(void)49 __gthread_active_p (void)
50 {
51   return 1;
52 }
53 
54 #ifdef _LIBOBJC
55 
56 /* This is the config.h file in libobjc/ */
57 #include <config.h>
58 
59 #ifdef HAVE_SCHED_H
60 # include <sched.h>
61 #endif
62 
63 /* Key structure for maintaining thread specific storage */
64 static NXKey_t _objc_thread_storage;
65 
66 /* Backend initialization functions */
67 
68 /* Initialize the threads subsystem.  */
69 static inline int
__gthread_objc_init_thread_system(void)70 __gthread_objc_init_thread_system (void)
71 {
72   /* Initialize the thread storage key.  */
73   if (NXKeyCreate (NULL, NULL, &_objc_thread_storage) == 0)
74     return 0;
75   return -1;
76 }
77 
78 /* Close the threads subsystem.  */
79 static inline int
__gthread_objc_close_thread_system(void)80 __gthread_objc_close_thread_system (void)
81 {
82   if (NXKeyDelete (_objc_thread_storage) == 0)
83     return 0;
84   return -1;
85 }
86 
87 /* Backend thread functions */
88 
89 /* Create a new thread of execution.  */
90 static inline objc_thread_t
__gthread_objc_thread_detach(void (* func)(void *),void * arg)91 __gthread_objc_thread_detach (void (*func)(void *), void *arg)
92 {
93   objc_thread_t thread_id;
94   NXContext_t context;
95   NXThreadId_t new_thread_handle;
96   int err;
97 
98   if ((context = NXContextAlloc (func, arg, NX_PRIO_MED, 0, 0, 0, &err)) == NULL)
99     thread_id = NULL;
100   else if (NXThreadCreate (context, NX_THR_DETACHED, &new_thread_handle) == 0)
101     thread_id = (objc_thread_t) new_thread_handle;
102   else {
103     NXContextFree (context);
104     thread_id = NULL;
105   }
106 
107   return thread_id;
108 }
109 
110 /* Set the current thread's priority.  */
111 static inline int
__gthread_objc_thread_set_priority(int priority)112 __gthread_objc_thread_set_priority (int priority)
113 {
114   if (NXThreadSetPriority (NXThreadGetId (), priority) == 0)
115     return 0;
116   return -1;
117 }
118 
119 /* Return the current thread's priority.  */
120 static inline int
__gthread_objc_thread_get_priority(void)121 __gthread_objc_thread_get_priority (void)
122 {
123   int priority;
124 
125   if (NXThreadGetPriority (NXThreadGetId (), &priority) == 0)
126     return priority;
127   return -1;
128 }
129 
130 /* Yield our process time to another thread.  */
131 static inline void
__gthread_objc_thread_yield(void)132 __gthread_objc_thread_yield (void)
133 {
134   NXThreadYield ();
135 }
136 
137 /* Terminate the current thread.  */
138 static inline int
__gthread_objc_thread_exit(void)139 __gthread_objc_thread_exit (void)
140 {
141   /* exit the thread */
142   NXThreadExit (&__objc_thread_exit_status);
143 
144   /* Failed if we reached here */
145   return -1;
146 }
147 
148 /* Returns an integer value which uniquely describes a thread.  */
149 static inline objc_thread_t
__gthread_objc_thread_id(void)150 __gthread_objc_thread_id (void)
151 {
152   (objc_thread_t) NXThreadGetId ();
153 }
154 
155 /* Sets the thread's local storage pointer.  */
156 static inline int
__gthread_objc_thread_set_data(void * value)157 __gthread_objc_thread_set_data (void *value)
158 {
159   return NXKeySetValue (_objc_thread_storage, value);
160 }
161 
162 /* Returns the thread's local storage pointer.  */
163 static inline void *
__gthread_objc_thread_get_data(void)164 __gthread_objc_thread_get_data (void)
165 {
166   void *value;
167 
168   if (NXKeyGetValue (_objc_thread_storage, &value) == 0)
169     return value;
170   return NULL;
171 }
172 
173 /* Backend mutex functions */
174 
175 /* Allocate a mutex.  */
176 static inline int
__gthread_objc_mutex_allocate(objc_mutex_t mutex)177 __gthread_objc_mutex_allocate (objc_mutex_t mutex)
178 {
179   static const NX_LOCK_INFO_ALLOC (info, "GNU ObjC", 0);
180 
181   if ((mutex->backend = NXMutexAlloc (0, 0, &info)) == NULL)
182     return 0;
183   return -1;
184 }
185 
186 /* Deallocate a mutex.  */
187 static inline int
__gthread_objc_mutex_deallocate(objc_mutex_t mutex)188 __gthread_objc_mutex_deallocate (objc_mutex_t mutex)
189 {
190   while (NXMutexIsOwned ((NXMutex_t *)mutex->backend))
191     NXUnlock ((NXMutex_t *)mutex->backend);
192   if (NXMutexFree ((NXMutex_t *)mutex->backend) != 0)
193     return -1;
194   mutex->backend = NULL;
195   return 0;
196 }
197 
198 /* Grab a lock on a mutex.  */
199 static inline int
__gthread_objc_mutex_lock(objc_mutex_t mutex)200 __gthread_objc_mutex_lock (objc_mutex_t mutex)
201 {
202   return NXLock ((NXMutex_t *)mutex->backend);
203 }
204 
205 /* Try to grab a lock on a mutex.  */
206 static inline int
__gthread_objc_mutex_trylock(objc_mutex_t mutex)207 __gthread_objc_mutex_trylock (objc_mutex_t mutex)
208 {
209   if (!NXTryLock ((NXMutex_t *)mutex->backend))
210     return -1;
211   return 0;
212 }
213 
214 /* Unlock the mutex */
215 static inline int
__gthread_objc_mutex_unlock(objc_mutex_t mutex)216 __gthread_objc_mutex_unlock (objc_mutex_t mutex)
217 {
218   return NXUnlock ((NXMutex_t *)mutex->backend);
219 }
220 
221 /* Backend condition mutex functions */
222 
223 /* Allocate a condition.  */
224 static inline int
__gthread_objc_condition_allocate(objc_condition_t condition)225 __gthread_objc_condition_allocate (objc_condition_t condition)
226 {
227   condition->backend = NXCondAlloc (NULL);
228   if (condition->backend == NULL)
229     return -1;
230 
231   return 0;
232 }
233 
234 /* Deallocate a condition.  */
235 static inline int
__gthread_objc_condition_deallocate(objc_condition_t condition)236 __gthread_objc_condition_deallocate (objc_condition_t condition)
237 {
238    if (NXCondFree ((NXCond_t *)condition->backend) != 0)
239      return -1;
240    condition->backend = NULL;
241    return 0;
242 }
243 
244 /* Wait on the condition */
245 static inline int
__gthread_objc_condition_wait(objc_condition_t condition,objc_mutex_t mutex)246 __gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
247 {
248   return NXCondWait ((NXCond_t *)condition->backend, (NXMutex_t *)mutex->backend);
249 }
250 
251 /* Wake up all threads waiting on this condition.  */
252 static inline int
__gthread_objc_condition_broadcast(objc_condition_t condition)253 __gthread_objc_condition_broadcast (objc_condition_t condition)
254 {
255   return NXCondBroadcast ((NXCond_t *)condition->backend);
256 }
257 
258 /* Wake up one thread waiting on this condition.  */
259 static inline int
__gthread_objc_condition_signal(objc_condition_t condition)260 __gthread_objc_condition_signal (objc_condition_t condition)
261 {
262   return NXCondSignal ((NXCond_t *)condition->backend);
263 }
264 
265 #else /* _LIBOBJC */
266 
267 #if defined(__cplusplus)
268 # include <bits/atomicity.h>
269 /* The remaining conditions here are temporary until there is
270    an application accessible atomic operations API set... */
271 #elif defined(_M_IA64) || defined(__ia64__)
272 # include <../libstdc++-v3/config/cpu/ia64/bits/atomicity.h>
273 #elif defined(_M_IX86) || defined(__i486__)
274 # include <../libstdc++-v3/config/cpu/i486/bits/atomicity.h>
275 #elif defined(_M_AMD64) || defined(__x86_64__)
276 # include <../libstdc++-v3/config/cpu/x86-64/bits/atomicity.h>
277 #endif
278 
279 typedef volatile long __gthread_once_t;
280 
281 #define __GTHREAD_ONCE_INIT 0
282 
283 static inline int
__gthread_once(__gthread_once_t * once,void (* func)(void))284 __gthread_once (__gthread_once_t *once, void (*func) (void))
285 {
286   if (__compare_and_swap (once, 0, 1))
287   {
288     func();
289     *once |= 2;
290   }
291   else
292   {
293     while (!(*once & 2))
294       NXThreadYield ();
295   }
296   return 0;
297 }
298 
299 static inline int
__gthread_key_create(__gthread_key_t * key,void (* dtor)(void *))300 __gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
301 {
302   return NXKeyCreate (dtor, NULL, key);
303 }
304 
305 static inline int
__gthread_key_dtor(__gthread_key_t key,void * ptr)306 __gthread_key_dtor (__gthread_key_t key, void *ptr)
307 {
308   /* Just reset the key value to zero. */
309   if (ptr)
310     return NXKeySetValue (key, NULL);
311   return 0;
312 }
313 
314 static inline int
__gthread_key_delete(__gthread_key_t key)315 __gthread_key_delete (__gthread_key_t key)
316 {
317   return NXKeyDelete (key);
318 }
319 
320 static inline void *
__gthread_getspecific(__gthread_key_t key)321 __gthread_getspecific (__gthread_key_t key)
322 {
323   void *value;
324 
325   if (NXKeyGetValue (key, &value) == 0)
326     return value;
327   return NULL;
328 }
329 
330 static inline int
__gthread_setspecific(__gthread_key_t key,const void * ptr)331 __gthread_setspecific (__gthread_key_t key, const void *ptr)
332 {
333   return NXKeySetValue (key, (void *)ptr);
334 }
335 
336 static inline void
__gthread_mutex_init_function(__gthread_mutex_t * mutex)337 __gthread_mutex_init_function (__gthread_mutex_t *mutex)
338 {
339   static const NX_LOCK_INFO_ALLOC (info, "GTHREADS", 0);
340 
341   *mutex = NXMutexAlloc (0, 0, &info);
342 }
343 
344 static inline int
__gthread_mutex_lock(__gthread_mutex_t * mutex)345 __gthread_mutex_lock (__gthread_mutex_t *mutex)
346 {
347   return NXLock (*mutex);
348 }
349 
350 static inline int
__gthread_mutex_trylock(__gthread_mutex_t * mutex)351 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
352 {
353   if (NXTryLock (*mutex))
354     return 0;
355   return -1;
356 }
357 
358 static inline int
__gthread_mutex_unlock(__gthread_mutex_t * mutex)359 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
360 {
361   return NXUnlock (*mutex);
362 }
363 
364 static inline void
__gthread_recursive_mutex_init_function(__gthread_recursive_mutex_t * mutex)365 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
366 {
367   static const NX_LOCK_INFO_ALLOC (info, "GTHREADS", 0);
368 
369   *mutex = NXMutexAlloc (NX_MUTEX_RECURSIVE, 0, &info);
370 }
371 
372 static inline int
__gthread_recursive_mutex_lock(__gthread_recursive_mutex_t * mutex)373 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
374 {
375   return NXLock (*mutex);
376 }
377 
378 static inline int
__gthread_recursive_mutex_trylock(__gthread_recursive_mutex_t * mutex)379 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
380 {
381   if (NXTryLock (*mutex))
382     return 0;
383   return -1;
384 }
385 
386 static inline int
__gthread_recursive_mutex_unlock(__gthread_recursive_mutex_t * mutex)387 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
388 {
389   return NXUnlock (*mutex);
390 }
391 
392 #endif /* _LIBOBJC */
393 
394 #endif /* not GCC_GTHR_NKS_H */
395