Changed API for fetching StackFrames in bulk on multiple threads ThreadMirror.FetchFr...
[mono.git] / mono / utils / mono-semaphore.c
1 /*
2  * mono-semaphore.c: mono-semaphore functions
3  *
4  * Author:
5  *      Gonzalo Paniagua Javier  <gonzalo@novell.com>
6  *
7  * (C) 2010 Novell, Inc.
8  */
9
10 #include <config.h>
11 #include <errno.h>
12 #include "utils/mono-semaphore.h"
13 #ifdef HAVE_SYS_TIME_H
14 #include <sys/time.h>
15 #endif
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif
19
20 #if (defined (HAVE_SEMAPHORE_H) || defined (USE_MACH_SEMA)) && !defined(HOST_WIN32)
21 /* sem_* or semaphore_* functions in use */
22 #  ifdef USE_MACH_SEMA
23 #    define TIMESPEC mach_timespec_t
24 #    define WAIT_BLOCK(a,b) semaphore_timedwait (*(a), *(b))
25 #  elif defined(__native_client__) && defined(USE_NEWLIB)
26 #    define TIMESPEC struct timespec
27 #    define WAIT_BLOCK(a, b) sem_trywait(a)
28 #  elif defined(__OpenBSD__)
29 #    define TIMESPEC struct timespec
30 #    define WAIT_BLOCK(a) sem_trywait(a)
31 #  else
32 #    define TIMESPEC struct timespec
33 #    define WAIT_BLOCK(a,b) sem_timedwait (a, b)
34 #  endif
35
36 #ifndef NSEC_PER_SEC
37 #define NSEC_PER_SEC 1000000000
38 #endif
39
40 int
41 mono_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, gboolean alertable)
42 {
43         TIMESPEC ts, copy;
44         struct timeval t;
45         int res = 0;
46 #if defined(__OpenBSD__)
47         int timeout;
48 #endif
49
50 #ifndef USE_MACH_SEMA
51         if (timeout_ms == 0)
52                 return sem_trywait (sem);
53 #endif
54         if (timeout_ms == (guint32) 0xFFFFFFFF)
55                 return mono_sem_wait (sem, alertable);
56
57 #ifdef USE_MACH_SEMA
58         memset (&t, 0, sizeof (t));
59 #else
60         gettimeofday (&t, NULL);
61 #endif
62         ts.tv_sec = timeout_ms / 1000 + t.tv_sec;
63         ts.tv_nsec = (timeout_ms % 1000) * 1000000 + t.tv_usec * 1000;
64         while (ts.tv_nsec > NSEC_PER_SEC) {
65                 ts.tv_nsec -= NSEC_PER_SEC;
66                 ts.tv_sec++;
67         }
68 #if defined(__OpenBSD__)
69         timeout = ts.tv_sec;
70         while (timeout) {
71                 if ((res = WAIT_BLOCK (sem)) == 0)
72                         return res;
73
74                 if (alertable)
75                         return -1;
76
77                 usleep (ts.tv_nsec / 1000);
78                 timeout--;
79         }
80 #else
81         copy = ts;
82         while ((res = WAIT_BLOCK (sem, &ts)) == -1 && errno == EINTR) {
83                 struct timeval current;
84                 if (alertable)
85                         return -1;
86 #ifdef USE_MACH_SEMA
87                 memset (&current, 0, sizeof (current));
88 #else
89                 gettimeofday (&current, NULL);
90 #endif
91                 ts = copy;
92                 ts.tv_sec -= (current.tv_sec - t.tv_sec);
93                 ts.tv_nsec -= (current.tv_usec - t.tv_usec) * 1000;
94                 if (ts.tv_nsec < 0) {
95                         if (ts.tv_sec <= 0) {
96                                 ts.tv_nsec = 0;
97                         } else {
98                                 ts.tv_sec--;
99                                 ts.tv_nsec += NSEC_PER_SEC;
100                         }
101                 }
102                 if (ts.tv_sec < 0) {
103                         ts.tv_sec = 0;
104                         ts.tv_nsec = 0;
105                 }
106         }
107 #endif
108         /* OSX might return > 0 for error */
109         if (res != 0)
110                 res = -1;
111         return res;
112 }
113
114 int
115 mono_sem_wait (MonoSemType *sem, gboolean alertable)
116 {
117         int res;
118 #ifndef USE_MACH_SEMA
119         while ((res = sem_wait (sem)) == -1 && errno == EINTR)
120 #else
121         while ((res = semaphore_wait (*sem)) == KERN_ABORTED)
122 #endif
123         {
124                 if (alertable)
125                         return -1;
126         }
127         /* OSX might return > 0 for error */
128         if (res != 0)
129                 res = -1;
130         return res;
131 }
132
133 int
134 mono_sem_post (MonoSemType *sem)
135 {
136         int res;
137 #ifndef USE_MACH_SEMA
138         while ((res = sem_post (sem)) == -1 && errno == EINTR);
139 #else
140         res = semaphore_signal (*sem);
141         /* OSX might return > 0 for error */
142         if (res != KERN_SUCCESS)
143                 res = -1;
144 #endif
145         return res;
146 }
147
148 #else
149 /* Windows or io-layer functions in use */
150 int
151 mono_sem_wait (MonoSemType *sem, gboolean alertable)
152 {
153         return mono_sem_timedwait (sem, INFINITE, alertable);
154 }
155
156 int
157 mono_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, gboolean alertable)
158 {
159         gboolean res;
160
161         while ((res = WaitForSingleObjectEx (*sem, timeout_ms, alertable)) == WAIT_IO_COMPLETION) {
162                 if (alertable) {
163                         errno = EINTR;
164                         return -1;
165                 }
166         }
167         switch (res) {
168         case WAIT_OBJECT_0:
169                 return 0;    
170         // WAIT_TIMEOUT and WAIT_FAILED
171         default:
172                 return -1;
173         }
174 }
175
176 int
177 mono_sem_post (MonoSemType *sem)
178 {
179         if (!ReleaseSemaphore (*sem, 1, NULL))
180                 return -1;
181         return 0;
182 }
183 #endif
184