2010-04-19 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / utils / mono-semaphore.c
blob755166b00551eb9b4210cc668cca68b9da7d1f94
1 /*
2 * mono-semaphore.c: mono-semaphore functions
4 * Author:
5 * Gonzalo Paniagua Javier <gonzalo@novell.com>
7 * (C) 2010 Novell, Inc.
8 */
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
20 #if (defined(HAVE_SEMAPHORE_H) || defined(USE_MACH_SEMA))
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
33 #define NSEC_PER_SEC 1000000000
34 int
35 mono_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, gboolean alertable)
37 TIMESPEC ts, copy;
38 struct timeval t;
39 int res = 0;
40 #if defined(__OpenBSD__)
41 int timeout;
42 #endif
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);
51 gettimeofday (&t, NULL);
52 ts.tv_sec = timeout_ms / 1000 + t.tv_sec;
53 ts.tv_nsec = (timeout_ms % 1000) * 1000000 + t.tv_usec * 1000;
54 while (ts.tv_nsec > NSEC_PER_SEC) {
55 ts.tv_nsec -= NSEC_PER_SEC;
56 ts.tv_sec++;
58 #if defined(__OpenBSD__)
59 timeout = ts.tv_sec;
60 while (timeout) {
61 if ((res = WAIT_BLOCK (sem)) == 0)
62 return res;
64 if (alertable)
65 return -1;
67 usleep (ts.tv_nsec / 1000);
68 timeout--;
70 #else
71 copy = ts;
72 while ((res = WAIT_BLOCK (sem, &ts) == -1) && errno == EINTR) {
73 struct timeval current;
74 if (alertable)
75 return -1;
76 gettimeofday (&current, NULL);
77 ts = copy;
78 ts.tv_sec -= (current.tv_sec - t.tv_sec);
79 ts.tv_nsec -= (current.tv_usec - t.tv_usec) * 1000;
80 if (ts.tv_nsec < 0) {
81 if (ts.tv_sec <= 0) {
82 ts.tv_nsec = 0;
83 } else {
84 ts.tv_sec--;
85 ts.tv_nsec += NSEC_PER_SEC;
88 if (ts.tv_sec < 0) {
89 ts.tv_sec = 0;
90 ts.tv_nsec = 0;
93 #endif
94 return res;
97 int
98 mono_sem_wait (MonoSemType *sem, gboolean alertable)
100 int res;
101 #ifndef USE_MACH_SEMA
102 while ((res = sem_wait (sem) == -1) && errno == EINTR)
103 #else
104 while ((res = semaphore_wait (*sem) == -1) && errno == EINTR)
105 #endif
107 if (alertable)
108 return -1;
110 return res;
114 mono_sem_post (MonoSemType *sem)
116 int res;
117 #ifndef USE_MACH_SEMA
118 while ((res = sem_post (sem) == -1) && errno == EINTR);
119 #else
120 while ((res = semaphore_signal (*sem) == -1) && errno == EINTR);
121 #endif
122 return res;
125 #else
126 /* Windows or io-layer functions in use */
128 mono_sem_wait (MonoSemType *sem, gboolean alertable)
130 return mono_sem_timedwait (sem, INFINITE, alertable);
134 mono_sem_timedwait (MonoSemType *sem, guint32 timeout_ms, gboolean alertable)
136 gboolean res;
138 res = WaitForSingleObjectEx (*sem, timeout_ms, alertable);
139 switch (res) {
140 case WAIT_OBJECT_0:
141 return 0;
142 case WAIT_IO_COMPLETION:
143 errno = EINTR;
144 return -1;
145 // WAIT_TIMEOUT and WAIT_FAILED
146 default:
147 return -1;
152 mono_sem_post (MonoSemType *sem)
154 if (!ReleaseSemaphore (*sem, 1, NULL))
155 return -1;
156 return 0;
158 #endif