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
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING.  If not, write to the Free
19Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2002110-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
41typedef NXKey_t __gthread_key_t;
42typedef NXMutex_t *__gthread_mutex_t;
43typedef 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
48static inline int
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 */
64static NXKey_t _objc_thread_storage;
65
66/* Backend initialization functions */
67
68/* Initialize the threads subsystem.  */
69static inline int
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.  */
79static inline int
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.  */
90static inline objc_thread_t
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.  */
111static inline int
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.  */
120static inline int
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.  */
131static inline void
132__gthread_objc_thread_yield (void)
133{
134  NXThreadYield ();
135}
136
137/* Terminate the current thread.  */
138static inline int
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.  */
149static inline objc_thread_t
150__gthread_objc_thread_id (void)
151{
152  (objc_thread_t) NXThreadGetId ();
153}
154
155/* Sets the thread's local storage pointer.  */
156static inline int
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.  */
163static inline 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.  */
176static inline int
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.  */
187static inline int
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.  */
199static inline int
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.  */
206static inline int
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 */
215static inline int
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.  */
224static inline int
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.  */
235static inline int
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 */
245static inline int
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.  */
252static inline int
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.  */
259static inline int
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
279typedef volatile long __gthread_once_t;
280
281#define __GTHREAD_ONCE_INIT 0
282
283static inline int
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
299static inline int
300__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
301{
302  return NXKeyCreate (dtor, NULL, key);
303}
304
305static inline int
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
314static inline int
315__gthread_key_delete (__gthread_key_t key)
316{
317  return NXKeyDelete (key);
318}
319
320static inline void *
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
330static inline int
331__gthread_setspecific (__gthread_key_t key, const void *ptr)
332{
333  return NXKeySetValue (key, (void *)ptr);
334}
335
336static inline void
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
344static inline int
345__gthread_mutex_lock (__gthread_mutex_t *mutex)
346{
347  return NXLock (*mutex);
348}
349
350static inline int
351__gthread_mutex_trylock (__gthread_mutex_t *mutex)
352{
353  if (NXTryLock (*mutex))
354    return 0;
355  return -1;
356}
357
358static inline int
359__gthread_mutex_unlock (__gthread_mutex_t *mutex)
360{
361  return NXUnlock (*mutex);
362}
363
364static inline void
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
372static inline int
373__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
374{
375  return NXLock (*mutex);
376}
377
378static inline int
379__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
380{
381  if (NXTryLock (*mutex))
382    return 0;
383  return -1;
384}
385
386static inline int
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