OSDN Git Service

runtime: If no sem_timedwait, use pthread_cond_timedwait.
[pf3gnuchains/gcc-fork.git] / libgo / runtime / thread-sema.c
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.
4
5 #include "config.h"
6 #include "runtime.h"
7
8 #include <errno.h>
9 #include <stdlib.h>
10 #include <time.h>
11 #include <semaphore.h>
12
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.  */
17
18 struct go_sem
19 {
20   sem_t sem;
21
22 #ifndef HAVE_SEM_TIMEDWAIT
23   int timedwait;
24   pthread_mutex_t mutex;
25   pthread_cond_t cond;
26 #endif
27 };
28
29 /* Create a semaphore.  */
30
31 uintptr
32 runtime_semacreate(void)
33 {
34   struct go_sem *p;
35
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");
42
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
49
50   return (uintptr) p;
51 }
52
53 /* Acquire m->waitsema.  */
54
55 int32
56 runtime_semasleep (int64 ns)
57 {
58   M *m;
59   struct go_sem *sem;
60   int r;
61
62   m = runtime_m ();
63   sem = (struct go_sem *) m->waitsema;
64   if (ns >= 0)
65     {
66       int64 abs;
67       struct timespec ts;
68       int err;
69
70       abs = ns + runtime_nanotime ();
71       ts.tv_sec = abs / 1000000000LL;
72       ts.tv_nsec = abs % 1000000000LL;
73
74       err = 0;
75
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");
83
84       while ((r = sem_trywait (&sem->sem)) != 0)
85         {
86           r = pthread_cond_timedwait (&sem->cond, &sem->mutex, &ts);
87           if (r != 0)
88             {
89               err = r;
90               break;
91             }
92         }
93
94       if (pthread_mutex_unlock (&sem->mutex) != 0)
95         runtime_throw ("pthread_mutex_unlock");
96 #endif
97
98       if (err != 0)
99         {
100           if (err == ETIMEDOUT || err == EAGAIN || err == EINTR)
101             return -1;
102           runtime_throw ("sema_timedwait");
103         }
104       return 0;
105     }
106
107   while (sem_wait (&sem->sem) != 0)
108     {
109       if (errno == EINTR)
110         continue;
111       runtime_throw ("sem_wait");
112     }
113
114   return 0;
115 }
116
117 /* Wake up mp->waitsema.  */
118
119 void
120 runtime_semawakeup (M *mp)
121 {
122   struct go_sem *sem;
123
124   sem = (struct go_sem *) mp->waitsema;
125   if (sem_post (&sem->sem) != 0)
126     runtime_throw ("sem_post");
127
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
136 }
137
138 void
139 runtime_osinit(void)
140 {
141 }