1169689Skan/* Threads compatibility routines for libgcc2 and libobjc.  */
2169689Skan/* Compile this one with gcc.  */
3169689Skan/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
4169689Skan
5169689SkanThis file is part of GCC.
6169689Skan
7169689SkanGCC is free software; you can redistribute it and/or modify it under
8169689Skanthe terms of the GNU General Public License as published by the Free
9169689SkanSoftware Foundation; either version 2, or (at your option) any later
10169689Skanversion.
11169689Skan
12169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY
13169689SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or
14169689SkanFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15169689Skanfor more details.
16169689Skan
17169689SkanYou should have received a copy of the GNU General Public License
18169689Skanalong with GCC; see the file COPYING.  If not, write to the Free
19169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
20169689Skan02110-1301, USA.  */
21169689Skan
22169689Skan/* As a special exception, if you link this library with other files,
23169689Skan   some of which are compiled with GCC, to produce an executable,
24169689Skan   this library does not by itself cause the resulting executable
25169689Skan   to be covered by the GNU General Public License.
26169689Skan   This exception does not however invalidate any other reasons why
27169689Skan   the executable file might be covered by the GNU General Public License.  */
28169689Skan
29169689Skan#ifndef GCC_GTHR_NKS_H
30169689Skan#define GCC_GTHR_NKS_H
31169689Skan
32169689Skan/* NKS threads specific definitions.
33169689Skan   Easy, since the interface is mostly one-to-one mapping.  */
34169689Skan
35169689Skan#define __GTHREADS 1
36169689Skan
37169689Skan#define NKS_NO_INLINE_FUNCS
38169689Skan#include <nksapi.h>
39169689Skan#include <string.h>
40169689Skan
41169689Skantypedef NXKey_t __gthread_key_t;
42169689Skantypedef NXMutex_t *__gthread_mutex_t;
43169689Skantypedef NXMutex_t *__gthread_recursive_mutex_t;
44169689Skan
45169689Skan#define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
46169689Skan#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
47169689Skan
48169689Skanstatic inline int
49169689Skan__gthread_active_p (void)
50169689Skan{
51169689Skan  return 1;
52169689Skan}
53169689Skan
54169689Skan#ifdef _LIBOBJC
55169689Skan
56169689Skan/* This is the config.h file in libobjc/ */
57169689Skan#include <config.h>
58169689Skan
59169689Skan#ifdef HAVE_SCHED_H
60169689Skan# include <sched.h>
61169689Skan#endif
62169689Skan
63169689Skan/* Key structure for maintaining thread specific storage */
64169689Skanstatic NXKey_t _objc_thread_storage;
65169689Skan
66169689Skan/* Backend initialization functions */
67169689Skan
68169689Skan/* Initialize the threads subsystem.  */
69169689Skanstatic inline int
70169689Skan__gthread_objc_init_thread_system (void)
71169689Skan{
72169689Skan  /* Initialize the thread storage key.  */
73169689Skan  if (NXKeyCreate (NULL, NULL, &_objc_thread_storage) == 0)
74169689Skan    return 0;
75169689Skan  return -1;
76169689Skan}
77169689Skan
78169689Skan/* Close the threads subsystem.  */
79169689Skanstatic inline int
80169689Skan__gthread_objc_close_thread_system (void)
81169689Skan{
82169689Skan  if (NXKeyDelete (_objc_thread_storage) == 0)
83169689Skan    return 0;
84169689Skan  return -1;
85169689Skan}
86169689Skan
87169689Skan/* Backend thread functions */
88169689Skan
89169689Skan/* Create a new thread of execution.  */
90169689Skanstatic inline objc_thread_t
91169689Skan__gthread_objc_thread_detach (void (*func)(void *), void *arg)
92169689Skan{
93169689Skan  objc_thread_t thread_id;
94169689Skan  NXContext_t context;
95169689Skan  NXThreadId_t new_thread_handle;
96169689Skan  int err;
97169689Skan
98169689Skan  if ((context = NXContextAlloc (func, arg, NX_PRIO_MED, 0, 0, 0, &err)) == NULL)
99169689Skan    thread_id = NULL;
100169689Skan  else if (NXThreadCreate (context, NX_THR_DETACHED, &new_thread_handle) == 0)
101169689Skan    thread_id = (objc_thread_t) new_thread_handle;
102169689Skan  else {
103169689Skan    NXContextFree (context);
104169689Skan    thread_id = NULL;
105169689Skan  }
106169689Skan
107169689Skan  return thread_id;
108169689Skan}
109169689Skan
110169689Skan/* Set the current thread's priority.  */
111169689Skanstatic inline int
112169689Skan__gthread_objc_thread_set_priority (int priority)
113169689Skan{
114169689Skan  if (NXThreadSetPriority (NXThreadGetId (), priority) == 0)
115169689Skan    return 0;
116169689Skan  return -1;
117169689Skan}
118169689Skan
119169689Skan/* Return the current thread's priority.  */
120169689Skanstatic inline int
121169689Skan__gthread_objc_thread_get_priority (void)
122169689Skan{
123169689Skan  int priority;
124169689Skan
125169689Skan  if (NXThreadGetPriority (NXThreadGetId (), &priority) == 0)
126169689Skan    return priority;
127169689Skan  return -1;
128169689Skan}
129169689Skan
130169689Skan/* Yield our process time to another thread.  */
131169689Skanstatic inline void
132169689Skan__gthread_objc_thread_yield (void)
133169689Skan{
134169689Skan  NXThreadYield ();
135169689Skan}
136169689Skan
137169689Skan/* Terminate the current thread.  */
138169689Skanstatic inline int
139169689Skan__gthread_objc_thread_exit (void)
140169689Skan{
141169689Skan  /* exit the thread */
142169689Skan  NXThreadExit (&__objc_thread_exit_status);
143169689Skan
144169689Skan  /* Failed if we reached here */
145169689Skan  return -1;
146169689Skan}
147169689Skan
148169689Skan/* Returns an integer value which uniquely describes a thread.  */
149169689Skanstatic inline objc_thread_t
150169689Skan__gthread_objc_thread_id (void)
151169689Skan{
152169689Skan  (objc_thread_t) NXThreadGetId ();
153169689Skan}
154169689Skan
155169689Skan/* Sets the thread's local storage pointer.  */
156169689Skanstatic inline int
157169689Skan__gthread_objc_thread_set_data (void *value)
158169689Skan{
159169689Skan  return NXKeySetValue (_objc_thread_storage, value);
160169689Skan}
161169689Skan
162169689Skan/* Returns the thread's local storage pointer.  */
163169689Skanstatic inline void *
164169689Skan__gthread_objc_thread_get_data (void)
165169689Skan{
166169689Skan  void *value;
167169689Skan
168169689Skan  if (NXKeyGetValue (_objc_thread_storage, &value) == 0)
169169689Skan    return value;
170169689Skan  return NULL;
171169689Skan}
172169689Skan
173169689Skan/* Backend mutex functions */
174169689Skan
175169689Skan/* Allocate a mutex.  */
176169689Skanstatic inline int
177169689Skan__gthread_objc_mutex_allocate (objc_mutex_t mutex)
178169689Skan{
179169689Skan  static const NX_LOCK_INFO_ALLOC (info, "GNU ObjC", 0);
180169689Skan
181169689Skan  if ((mutex->backend = NXMutexAlloc (0, 0, &info)) == NULL)
182169689Skan    return 0;
183169689Skan  return -1;
184169689Skan}
185169689Skan
186169689Skan/* Deallocate a mutex.  */
187169689Skanstatic inline int
188169689Skan__gthread_objc_mutex_deallocate (objc_mutex_t mutex)
189169689Skan{
190169689Skan  while (NXMutexIsOwned ((NXMutex_t *)mutex->backend))
191169689Skan    NXUnlock ((NXMutex_t *)mutex->backend);
192169689Skan  if (NXMutexFree ((NXMutex_t *)mutex->backend) != 0)
193169689Skan    return -1;
194169689Skan  mutex->backend = NULL;
195169689Skan  return 0;
196169689Skan}
197169689Skan
198169689Skan/* Grab a lock on a mutex.  */
199169689Skanstatic inline int
200169689Skan__gthread_objc_mutex_lock (objc_mutex_t mutex)
201169689Skan{
202169689Skan  return NXLock ((NXMutex_t *)mutex->backend);
203169689Skan}
204169689Skan
205169689Skan/* Try to grab a lock on a mutex.  */
206169689Skanstatic inline int
207169689Skan__gthread_objc_mutex_trylock (objc_mutex_t mutex)
208169689Skan{
209169689Skan  if (!NXTryLock ((NXMutex_t *)mutex->backend))
210169689Skan    return -1;
211169689Skan  return 0;
212169689Skan}
213169689Skan
214169689Skan/* Unlock the mutex */
215169689Skanstatic inline int
216169689Skan__gthread_objc_mutex_unlock (objc_mutex_t mutex)
217169689Skan{
218169689Skan  return NXUnlock ((NXMutex_t *)mutex->backend);
219169689Skan}
220169689Skan
221169689Skan/* Backend condition mutex functions */
222169689Skan
223169689Skan/* Allocate a condition.  */
224169689Skanstatic inline int
225169689Skan__gthread_objc_condition_allocate (objc_condition_t condition)
226169689Skan{
227169689Skan  condition->backend = NXCondAlloc (NULL);
228169689Skan  if (condition->backend == NULL)
229169689Skan    return -1;
230169689Skan
231169689Skan  return 0;
232169689Skan}
233169689Skan
234169689Skan/* Deallocate a condition.  */
235169689Skanstatic inline int
236169689Skan__gthread_objc_condition_deallocate (objc_condition_t condition)
237169689Skan{
238169689Skan   if (NXCondFree ((NXCond_t *)condition->backend) != 0)
239169689Skan     return -1;
240169689Skan   condition->backend = NULL;
241169689Skan   return 0;
242169689Skan}
243169689Skan
244169689Skan/* Wait on the condition */
245169689Skanstatic inline int
246169689Skan__gthread_objc_condition_wait (objc_condition_t condition, objc_mutex_t mutex)
247169689Skan{
248169689Skan  return NXCondWait ((NXCond_t *)condition->backend, (NXMutex_t *)mutex->backend);
249169689Skan}
250169689Skan
251169689Skan/* Wake up all threads waiting on this condition.  */
252169689Skanstatic inline int
253169689Skan__gthread_objc_condition_broadcast (objc_condition_t condition)
254169689Skan{
255169689Skan  return NXCondBroadcast ((NXCond_t *)condition->backend);
256169689Skan}
257169689Skan
258169689Skan/* Wake up one thread waiting on this condition.  */
259169689Skanstatic inline int
260169689Skan__gthread_objc_condition_signal (objc_condition_t condition)
261169689Skan{
262169689Skan  return NXCondSignal ((NXCond_t *)condition->backend);
263169689Skan}
264169689Skan
265169689Skan#else /* _LIBOBJC */
266169689Skan
267169689Skan#if defined(__cplusplus)
268169689Skan# include <bits/atomicity.h>
269169689Skan/* The remaining conditions here are temporary until there is
270169689Skan   an application accessible atomic operations API set... */
271169689Skan#elif defined(_M_IA64) || defined(__ia64__)
272169689Skan# include <../libstdc++-v3/config/cpu/ia64/bits/atomicity.h>
273169689Skan#elif defined(_M_IX86) || defined(__i486__)
274169689Skan# include <../libstdc++-v3/config/cpu/i486/bits/atomicity.h>
275169689Skan#elif defined(_M_AMD64) || defined(__x86_64__)
276169689Skan# include <../libstdc++-v3/config/cpu/x86-64/bits/atomicity.h>
277169689Skan#endif
278169689Skan
279169689Skantypedef volatile long __gthread_once_t;
280169689Skan
281169689Skan#define __GTHREAD_ONCE_INIT 0
282169689Skan
283169689Skanstatic inline int
284169689Skan__gthread_once (__gthread_once_t *once, void (*func) (void))
285169689Skan{
286169689Skan  if (__compare_and_swap (once, 0, 1))
287169689Skan  {
288169689Skan    func();
289169689Skan    *once |= 2;
290169689Skan  }
291169689Skan  else
292169689Skan  {
293169689Skan    while (!(*once & 2))
294169689Skan      NXThreadYield ();
295169689Skan  }
296169689Skan  return 0;
297169689Skan}
298169689Skan
299169689Skanstatic inline int
300169689Skan__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
301169689Skan{
302169689Skan  return NXKeyCreate (dtor, NULL, key);
303169689Skan}
304169689Skan
305169689Skanstatic inline int
306169689Skan__gthread_key_dtor (__gthread_key_t key, void *ptr)
307169689Skan{
308169689Skan  /* Just reset the key value to zero. */
309169689Skan  if (ptr)
310169689Skan    return NXKeySetValue (key, NULL);
311169689Skan  return 0;
312169689Skan}
313169689Skan
314169689Skanstatic inline int
315169689Skan__gthread_key_delete (__gthread_key_t key)
316169689Skan{
317169689Skan  return NXKeyDelete (key);
318169689Skan}
319169689Skan
320169689Skanstatic inline void *
321169689Skan__gthread_getspecific (__gthread_key_t key)
322169689Skan{
323169689Skan  void *value;
324169689Skan
325169689Skan  if (NXKeyGetValue (key, &value) == 0)
326169689Skan    return value;
327169689Skan  return NULL;
328169689Skan}
329169689Skan
330169689Skanstatic inline int
331169689Skan__gthread_setspecific (__gthread_key_t key, const void *ptr)
332169689Skan{
333169689Skan  return NXKeySetValue (key, (void *)ptr);
334169689Skan}
335169689Skan
336169689Skanstatic inline void
337169689Skan__gthread_mutex_init_function (__gthread_mutex_t *mutex)
338169689Skan{
339169689Skan  static const NX_LOCK_INFO_ALLOC (info, "GTHREADS", 0);
340169689Skan
341169689Skan  *mutex = NXMutexAlloc (0, 0, &info);
342169689Skan}
343169689Skan
344169689Skanstatic inline int
345169689Skan__gthread_mutex_lock (__gthread_mutex_t *mutex)
346169689Skan{
347169689Skan  return NXLock (*mutex);
348169689Skan}
349169689Skan
350169689Skanstatic inline int
351169689Skan__gthread_mutex_trylock (__gthread_mutex_t *mutex)
352169689Skan{
353169689Skan  if (NXTryLock (*mutex))
354169689Skan    return 0;
355169689Skan  return -1;
356169689Skan}
357169689Skan
358169689Skanstatic inline int
359169689Skan__gthread_mutex_unlock (__gthread_mutex_t *mutex)
360169689Skan{
361169689Skan  return NXUnlock (*mutex);
362169689Skan}
363169689Skan
364169689Skanstatic inline void
365169689Skan__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
366169689Skan{
367169689Skan  static const NX_LOCK_INFO_ALLOC (info, "GTHREADS", 0);
368169689Skan
369169689Skan  *mutex = NXMutexAlloc (NX_MUTEX_RECURSIVE, 0, &info);
370169689Skan}
371169689Skan
372169689Skanstatic inline int
373169689Skan__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
374169689Skan{
375169689Skan  return NXLock (*mutex);
376169689Skan}
377169689Skan
378169689Skanstatic inline int
379169689Skan__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
380169689Skan{
381169689Skan  if (NXTryLock (*mutex))
382169689Skan    return 0;
383169689Skan  return -1;
384169689Skan}
385169689Skan
386169689Skanstatic inline int
387169689Skan__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
388169689Skan{
389169689Skan  return NXUnlock (*mutex);
390169689Skan}
391169689Skan
392169689Skan#endif /* _LIBOBJC */
393169689Skan
394169689Skan#endif /* not GCC_GTHR_NKS_H */
395