2015-05-18 Steven G. Kargl <kargl@gcc.gnu.org>
[official-gcc.git] / libgo / runtime / thread-sema.c
blob18827b025d7e2b642b99d0818318c0019b272bd6
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 #include "config.h"
6 #include "runtime.h"
8 #include <errno.h>
9 #include <stdlib.h>
10 #include <time.h>
11 #include <semaphore.h>
13 /* If we don't have sem_timedwait, use pthread_cond_timedwait instead.
14 We don't always use condition variables because on some systems
15 pthread_mutex_lock and pthread_mutex_unlock must be called by the
16 same thread. That is never true of semaphores. */
18 struct go_sem
20 sem_t sem;
22 #ifndef HAVE_SEM_TIMEDWAIT
23 int timedwait;
24 pthread_mutex_t mutex;
25 pthread_cond_t cond;
26 #endif
29 /* Create a semaphore. */
31 uintptr
32 runtime_semacreate(void)
34 struct go_sem *p;
36 /* Call malloc rather than runtime_malloc. This will allocate space
37 on the C heap. We can't call runtime_malloc here because it
38 could cause a deadlock. */
39 p = malloc (sizeof (struct go_sem));
40 if (sem_init (&p->sem, 0, 0) != 0)
41 runtime_throw ("sem_init");
43 #ifndef HAVE_SEM_TIMEDWAIT
44 if (pthread_mutex_init (&p->mutex, NULL) != 0)
45 runtime_throw ("pthread_mutex_init");
46 if (pthread_cond_init (&p->cond, NULL) != 0)
47 runtime_throw ("pthread_cond_init");
48 #endif
50 return (uintptr) p;
53 /* Acquire m->waitsema. */
55 int32
56 runtime_semasleep (int64 ns)
58 M *m;
59 struct go_sem *sem;
60 int r;
62 m = runtime_m ();
63 sem = (struct go_sem *) m->waitsema;
64 if (ns >= 0)
66 int64 abs;
67 struct timespec ts;
68 int err;
70 abs = ns + runtime_nanotime ();
71 ts.tv_sec = abs / 1000000000LL;
72 ts.tv_nsec = abs % 1000000000LL;
74 err = 0;
76 #ifdef HAVE_SEM_TIMEDWAIT
77 r = sem_timedwait (&sem->sem, &ts);
78 if (r != 0)
79 err = errno;
80 #else
81 if (pthread_mutex_lock (&sem->mutex) != 0)
82 runtime_throw ("pthread_mutex_lock");
84 while ((r = sem_trywait (&sem->sem)) != 0)
86 r = pthread_cond_timedwait (&sem->cond, &sem->mutex, &ts);
87 if (r != 0)
89 err = r;
90 break;
94 if (pthread_mutex_unlock (&sem->mutex) != 0)
95 runtime_throw ("pthread_mutex_unlock");
96 #endif
98 if (err != 0)
100 if (err == ETIMEDOUT || err == EAGAIN || err == EINTR)
101 return -1;
102 runtime_throw ("sema_timedwait");
104 return 0;
107 while (sem_wait (&sem->sem) != 0)
109 if (errno == EINTR)
110 continue;
111 runtime_throw ("sem_wait");
114 return 0;
117 /* Wake up mp->waitsema. */
119 void
120 runtime_semawakeup (M *mp)
122 struct go_sem *sem;
124 sem = (struct go_sem *) mp->waitsema;
125 if (sem_post (&sem->sem) != 0)
126 runtime_throw ("sem_post");
128 #ifndef HAVE_SEM_TIMEDWAIT
129 if (pthread_mutex_lock (&sem->mutex) != 0)
130 runtime_throw ("pthread_mutex_lock");
131 if (pthread_cond_broadcast (&sem->cond) != 0)
132 runtime_throw ("pthread_cond_broadcast");
133 if (pthread_mutex_unlock (&sem->mutex) != 0)
134 runtime_throw ("pthread_mutex_unlock");
135 #endif
138 void
139 runtime_osinit (void)
141 runtime_ncpu = getproccount();
144 void
145 runtime_goenvs (void)
147 runtime_goenvs_unix ();