[xbuild] Pick the correct base path for target frameworks.
[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(__OpenBSD__)
26 #    define TIMESPEC struct timespec
27 #    define WAIT_BLOCK(a) sem_trywait(a)
28 #  else
29 #    define TIMESPEC struct timespec
30 #    define WAIT_BLOCK(a,b) sem_timedwait (a, b)
31 #  endif
32
33 #define NSEC_PER_SEC 1000000000
34 int
35 mono_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, gboolean alertable)
36 {
37         TIMESPEC ts, copy;
38         struct timeval t;
39         int res = 0;
40 #if defined(__OpenBSD__)
41         int timeout;
42 #endif
43
44 #ifndef USE_MACH_SEMA
45         if (timeout_ms == 0)
46                 return sem_trywait (sem);
47 #endif
48         if (timeout_ms == (guint32) 0xFFFFFFFF)
49                 return mono_sem_wait (sem, alertable);
50
51 #ifdef USE_MACH_SEMA
52         memset (&t, 0, sizeof (TIMESPEC));
53 #else
54         gettimeofday (&t, NULL);
55 #endif
56         ts.tv_sec = timeout_ms / 1000 + t.tv_sec;
57         ts.tv_nsec = (timeout_ms % 1000) * 1000000 + t.tv_usec * 1000;
58         while (ts.tv_nsec > NSEC_PER_SEC) {
59                 ts.tv_nsec -= NSEC_PER_SEC;
60                 ts.tv_sec++;
61         }
62 #if defined(__OpenBSD__)
63         timeout = ts.tv_sec;
64         while (timeout) {
65                 if ((res = WAIT_BLOCK (sem)) == 0)
66                         return res;
67
68                 if (alertable)
69                         return -1;
70
71                 usleep (ts.tv_nsec / 1000);
72                 timeout--;
73         }
74 #else
75         copy = ts;
76         while ((res = WAIT_BLOCK (sem, &ts)) == -1 && errno == EINTR) {
77                 struct timeval current;
78                 if (alertable)
79                         return -1;
80 #ifdef USE_MACH_SEMA
81                 memset (&current, 0, sizeof (TIMESPEC));
82 #else
83                 gettimeofday (&current, NULL);
84 #endif
85                 ts = copy;
86                 ts.tv_sec -= (current.tv_sec - t.tv_sec);
87                 ts.tv_nsec -= (current.tv_usec - t.tv_usec) * 1000;
88                 if (ts.tv_nsec < 0) {
89                         if (ts.tv_sec <= 0) {
90                                 ts.tv_nsec = 0;
91                         } else {
92                                 ts.tv_sec--;
93                                 ts.tv_nsec += NSEC_PER_SEC;
94                         }
95                 }
96                 if (ts.tv_sec < 0) {
97                         ts.tv_sec = 0;
98                         ts.tv_nsec = 0;
99                 }
100         }
101 #endif
102         /* OSX might return > 0 for error */
103         if (res != 0)
104                 res = -1;
105         return res;
106 }
107
108 int
109 mono_sem_wait (MonoSemType *sem, gboolean alertable)
110 {
111         int res;
112 #ifndef USE_MACH_SEMA
113         while ((res = sem_wait (sem)) == -1 && errno == EINTR)
114 #else
115         while ((res = semaphore_wait (*sem)) == -1 && errno == EINTR)
116 #endif
117         {
118                 if (alertable)
119                         return -1;
120         }
121         /* OSX might return > 0 for error */
122         if (res != 0)
123                 res = -1;
124         return res;
125 }
126
127 int
128 mono_sem_post (MonoSemType *sem)
129 {
130         int res;
131 #ifndef USE_MACH_SEMA
132         while ((res = sem_post (sem)) == -1 && errno == EINTR);
133 #else
134         while ((res = semaphore_signal (*sem)) == -1 && errno == EINTR);
135         /* OSX might return > 0 for error */
136         if (res != 0)
137                 res = -1;
138 #endif
139         return res;
140 }
141
142 #else
143 /* Windows or io-layer functions in use */
144 int
145 mono_sem_wait (MonoSemType *sem, gboolean alertable)
146 {
147         return mono_sem_timedwait (sem, INFINITE, alertable);
148 }
149
150 int
151 mono_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, gboolean alertable)
152 {
153         gboolean res;
154
155         while ((res = WaitForSingleObjectEx (*sem, timeout_ms, alertable)) == WAIT_IO_COMPLETION) {
156                 if (alertable) {
157                         errno = EINTR;
158                         return -1;
159                 }
160         }
161         switch (res) {
162         case WAIT_OBJECT_0:
163                 return 0;    
164         // WAIT_TIMEOUT and WAIT_FAILED
165         default:
166                 return -1;
167         }
168 }
169
170 int
171 mono_sem_post (MonoSemType *sem)
172 {
173         if (!ReleaseSemaphore (*sem, 1, NULL))
174                 return -1;
175         return 0;
176 }
177 #endif
178