2003-01-12 Alp Toker <alp@atoker.com>
[mono.git] / mono / io-layer / mono-mutex.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Authors: Jeffrey Stedfast <fejj@ximian.com>
4  *
5  *  Copyright 2002 Ximain, Inc. (www.ximian.com)
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
20  *
21  */
22
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <assert.h>
32 #include <sys/time.h>
33
34 #include "mono-mutex.h"
35
36
37 #ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
38 int
39 pthread_mutex_timedlock (pthread_mutex_t *mutex, const struct timespec *timeout)
40 {
41         struct timeval timenow;
42         struct timespec sleepytime;
43         int retcode;
44         
45         /* This is just to avoid a completely busy wait */
46         sleepytime.tv_sec = 0;
47         sleepytime.tv_nsec = 10000000;  /* 10ms */
48         
49         while ((retcode = pthread_mutex_trylock (mutex)) == EBUSY) {
50                 gettimeofday (&timenow, NULL);
51                 
52                 if (timenow.tv_sec >= timeout->tv_sec &&
53                     (timenow.tv_usec * 1000) >= timeout->tv_nsec) {
54                         return ETIMEDOUT;
55                 }
56                 
57                 nanosleep (&sleepytime, NULL);
58         }
59         
60         return retcode;
61 }
62 #endif /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */
63
64
65 int
66 mono_once (mono_once_t *once, void (*once_init) (void))
67 {
68         if (!once->complete) {
69                 pthread_mutex_lock (&once->mutex);
70                 if (!once->complete) {
71                         once_init ();
72                         once->complete = TRUE;
73                 }
74                 pthread_mutex_unlock (&once->mutex);
75         }
76         
77         return 0;
78 }
79
80
81 #ifdef USE_MONO_MUTEX
82
83 int
84 mono_mutexattr_init (mono_mutexattr_t *attr)
85 {
86         memset (attr, 0, sizeof (mono_mutexattr_t));
87         return 0;
88 }
89
90 int
91 mono_mutexattr_settype (mono_mutexattr_t *attr, int type)
92 {
93         attr->type = type;
94         return 0;
95 }
96
97 int
98 mono_mutexattr_gettype (mono_mutexattr_t *attr, int *type)
99 {
100         *type = attr->type;
101         return 0;
102 }
103
104 int
105 mono_mutexattr_setpshared (mono_mutexattr_t *attr, int pshared)
106 {
107         attr->shared = pshared;
108         return 0;
109 }
110
111 int
112 mono_mutexattr_getpshared (mono_mutexattr_t *attr, int *pshared)
113 {
114         *pshared = attr->shared;
115         return 0;
116 }
117
118 int
119 mono_mutexattr_setprotocol (mono_mutexattr_t *attr, int protocol)
120 {
121         attr->protocol = protocol;
122         return 0;
123 }
124
125 int
126 mono_mutexattr_getprotocol (mono_mutexattr_t *attr, int *protocol)
127 {
128         *protocol = attr->protocol;
129         return 0;
130 }
131
132 int
133 mono_mutexattr_setprioceiling (mono_mutexattr_t *attr, int prioceiling)
134 {
135         attr->priority = prioceiling;
136         return 0;
137 }
138
139 int
140 mono_mutexattr_getprioceiling (mono_mutexattr_t *attr, int *prioceiling)
141 {
142         *prioceiling = attr->priority;
143         return 0;
144 }
145
146 int
147 mono_mutexattr_destroy (mono_mutexattr_t *attr)
148 {
149         return 0;
150 }
151
152
153 int
154 mono_mutex_init (mono_mutex_t *mutex, const mono_mutexattr_t *attr)
155 {
156         mutex->waiters = 0;
157         mutex->depth = 0;
158         mutex->owner = MONO_THREAD_NONE;
159         
160         if (!attr || attr->type == MONO_MUTEX_NORMAL) {
161                 mutex->type = MONO_MUTEX_NORMAL;
162                 pthread_mutex_init (&mutex->mutex, NULL);
163         } else {
164                 mutex->type = MONO_MUTEX_RECURSIVE;
165                 pthread_mutex_init (&mutex->mutex, NULL);
166                 pthread_cond_init (&mutex->cond, NULL);
167         }
168         
169         return 0;
170 }
171
172 int
173 mono_mutex_lock (mono_mutex_t *mutex)
174 {
175         pthread_t id;
176         
177         switch (mutex->type) {
178         case MONO_MUTEX_NORMAL:
179                 return pthread_mutex_lock (&mutex->mutex);
180         case MONO_MUTEX_RECURSIVE:
181                 id = pthread_self ();
182                 if (pthread_mutex_lock (&mutex->mutex) != 0)
183                         return EINVAL;
184                 
185                 while (1) {
186                         if (mutex->owner == MONO_THREAD_NONE) {
187                                 mutex->owner = id;
188                                 mutex->depth = 1;
189                                 break;
190                         } else if (mutex->owner == id) {
191                                 mutex->depth++;
192                                 break;
193                         } else {
194                                 mutex->waiters++;
195                                 if (pthread_cond_wait (&mutex->cond, &mutex->mutex) == -1)
196                                         return EINVAL;
197                                 mutex->waiters--;
198                         }
199                 }
200                 
201                 return pthread_mutex_unlock (&mutex->mutex);
202         }
203         
204         return EINVAL;
205 }
206
207 int
208 mono_mutex_trylock (mono_mutex_t *mutex)
209 {
210         pthread_t id;
211         
212         switch (mutex->type) {
213         case MONO_MUTEX_NORMAL:
214                 return pthread_mutex_trylock (&mutex->mutex);
215         case MONO_MUTEX_RECURSIVE:
216                 id = pthread_self ();
217                 
218                 if (pthread_mutex_lock (&mutex->mutex) != 0)
219                         return EINVAL;
220                 
221                 if (mutex->owner != MONO_THREAD_NONE && mutex->owner != id) {
222                         pthread_mutex_unlock (&mutex->mutex);
223                         return EBUSY;
224                 }
225                 
226                 while (1) {
227                         if (mutex->owner == MONO_THREAD_NONE) {
228                                 mutex->owner = id;
229                                 mutex->depth = 1;
230                                 break;
231                         } else {
232                                 mutex->depth++;
233                                 break;
234                         }
235                 }
236                 
237                 return pthread_mutex_unlock (&mutex->mutex);
238         }
239         
240         return EINVAL;
241 }
242
243 int
244 mono_mutex_timedlock (mono_mutex_t *mutex, const struct timespec *timeout)
245 {
246         pthread_t id;
247         
248         switch (mutex->type) {
249         case MONO_MUTEX_NORMAL:
250                 return pthread_mutex_timedlock (&mutex->mutex, timeout);
251         case MONO_MUTEX_RECURSIVE:
252                 id = pthread_self ();
253                 
254                 if (pthread_mutex_timedlock (&mutex->mutex, timeout) != 0)
255                         return ETIMEDOUT;
256                 
257                 while (1) {
258                         if (mutex->owner == MONO_THREAD_NONE) {
259                                 mutex->owner = id;
260                                 mutex->depth = 1;
261                                 break;
262                         } else if (mutex->owner == id) {
263                                 mutex->depth++;
264                                 break;
265                         } else {
266                                 mutex->waiters++;
267                                 if (pthread_cond_timedwait (&mutex->cond, &mutex->mutex, timeout) != 0)
268                                         return ETIMEDOUT;
269                                 mutex->waiters--;
270                         }
271                 }
272                 
273                 return pthread_mutex_unlock (&mutex->mutex);
274         }
275         
276         return EINVAL;
277 }
278
279 int
280 mono_mutex_unlock (mono_mutex_t *mutex)
281 {
282         switch (mutex->type) {
283         case MONO_MUTEX_NORMAL:
284                 return pthread_mutex_unlock (&mutex->mutex);
285         case MONO_MUTEX_RECURSIVE:
286                 if (pthread_mutex_lock (&mutex->mutex) != 0)
287                         return EINVAL;
288                 
289                 assert (mutex->owner == pthread_self ());
290                 
291                 mutex->depth--;
292                 if (mutex->depth == 0) {
293                         mutex->owner = MONO_THREAD_NONE;
294                         if (mutex->waiters > 0)
295                                 pthread_cond_signal (&mutex->cond);
296                 }
297                 
298                 return pthread_mutex_unlock (&mutex->mutex);
299         }
300         
301         return EINVAL;
302 }
303
304 int
305 mono_mutex_destroy (mono_mutex_t *mutex)
306 {
307         int ret = 0;
308         
309         switch (mutex->type) {
310         case MONO_MUTEX_NORMAL:
311                 ret = pthread_mutex_destroy (&mutex->mutex);
312                 break;
313         case MONO_MUTEX_RECURSIVE:
314                 if ((ret = pthread_mutex_destroy (&mutex->mutex)) == 0) {
315                         pthread_cond_destroy (&mutex->cond);
316                 }
317         }
318         
319         return ret;
320 }
321
322
323 int
324 mono_cond_wait (pthread_cond_t *cond, mono_mutex_t *mutex)
325 {
326         return pthread_cond_wait (cond, &mutex->mutex);
327 }
328
329 int
330 mono_cond_timedwait (pthread_cond_t *cond, mono_mutex_t *mutex, const struct timespec *timeout)
331 {
332         return pthread_cond_timedwait (cond, &mutex->mutex, timeout);
333 }
334
335 #endif /* USE_MONO_MUTEX */