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