Fri May 31 16:21:54 CEST 2002 Paolo Molaro <lupus@ximian.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
66 #ifdef USE_MONO_MUTEX
67
68 int
69 mono_mutexattr_init (mono_mutexattr_t *attr)
70 {
71         memset (attr, 0, sizeof (mono_mutexattr_t));
72         return 0;
73 }
74
75 int
76 mono_mutexattr_settype (mono_mutexattr_t *attr, int type)
77 {
78         attr->type = type;
79         return 0;
80 }
81
82 int
83 mono_mutexattr_gettype (mono_mutexattr_t *attr, int *type)
84 {
85         *type = attr->type;
86         return 0;
87 }
88
89 int
90 mono_mutexattr_setpshared (mono_mutexattr_t *attr, int pshared)
91 {
92         attr->shared = pshared;
93         return 0;
94 }
95
96 int
97 mono_mutexattr_getpshared (mono_mutexattr_t *attr, int *pshared)
98 {
99         *pshared = attr->shared;
100         return 0;
101 }
102
103 int
104 mono_mutexattr_setprotocol (mono_mutexattr_t *attr, int protocol)
105 {
106         attr->protocol = protocol;
107         return 0;
108 }
109
110 int
111 mono_mutexattr_getprotocol (mono_mutexattr_t *attr, int *protocol)
112 {
113         *protocol = attr->protocol;
114         return 0;
115 }
116
117 int
118 mono_mutexattr_setprioceiling (mono_mutexattr_t *attr, int prioceiling)
119 {
120         attr->priority = prioceiling;
121         return 0;
122 }
123
124 int
125 mono_mutexattr_getprioceiling (mono_mutexattr_t *attr, int *prioceiling)
126 {
127         *prioceiling = attr->priority;
128         return 0;
129 }
130
131 int
132 mono_mutexattr_destroy (mono_mutexattr_t *attr)
133 {
134         return 0;
135 }
136
137
138 int
139 mono_mutex_init (mono_mutex_t *mutex, const mono_mutexattr_t *attr)
140 {
141         mutex->waiters = 0;
142         mutex->depth = 0;
143         mutex->owner = MONO_THREAD_NONE;
144         
145         if (!attr || attr->type == MONO_MUTEX_NORMAL) {
146                 mutex->type = MONO_MUTEX_NORMAL;
147                 pthread_mutex_init (&mutex->mutex, NULL);
148         } else {
149                 mutex->type = MONO_MUTEX_RECURSIVE;
150                 pthread_mutex_init (&mutex->mutex, NULL);
151                 pthread_cond_init (&mutex->cond, NULL);
152         }
153         
154         return 0;
155 }
156
157 int
158 mono_mutex_lock (mono_mutex_t *mutex)
159 {
160         pthread_t id;
161         
162         switch (mutex->type) {
163         case MONO_MUTEX_NORMAL:
164                 return pthread_mutex_lock (&mutex->mutex);
165         case MONO_MUTEX_RECURSIVE:
166                 id = pthread_self ();
167                 if (pthread_mutex_lock (&mutex->mutex) != 0)
168                         return EINVAL;
169                 
170                 while (1) {
171                         if (mutex->owner == MONO_THREAD_NONE) {
172                                 mutex->owner = id;
173                                 mutex->depth = 1;
174                                 break;
175                         } else if (mutex->owner == id) {
176                                 mutex->depth++;
177                                 break;
178                         } else {
179                                 mutex->waiters++;
180                                 if (pthread_cond_wait (&mutex->cond, &mutex->mutex) == -1)
181                                         return EINVAL;
182                                 mutex->waiters--;
183                         }
184                 }
185                 
186                 return pthread_mutex_unlock (&mutex->mutex);
187         }
188         
189         return EINVAL;
190 }
191
192 int
193 mono_mutex_trylock (mono_mutex_t *mutex)
194 {
195         pthread_t id;
196         
197         switch (mutex->type) {
198         case MONO_MUTEX_NORMAL:
199                 return pthread_mutex_trylock (&mutex->mutex);
200         case MONO_MUTEX_RECURSIVE:
201                 id = pthread_self ();
202                 
203                 if (pthread_mutex_lock (&mutex->mutex) != 0)
204                         return EINVAL;
205                 
206                 if (mutex->owner != MONO_THREAD_NONE && mutex->owner != id) {
207                         pthread_mutex_unlock (&mutex->mutex);
208                         return EBUSY;
209                 }
210                 
211                 while (1) {
212                         if (mutex->owner == MONO_THREAD_NONE) {
213                                 mutex->owner = id;
214                                 mutex->depth = 1;
215                                 break;
216                         } else {
217                                 mutex->depth++;
218                                 break;
219                         }
220                 }
221                 
222                 return pthread_mutex_unlock (&mutex->mutex);
223         }
224         
225         return EINVAL;
226 }
227
228 int
229 mono_mutex_timedlock (mono_mutex_t *mutex, const struct timespec *timeout)
230 {
231         pthread_t id;
232         
233         switch (mutex->type) {
234         case MONO_MUTEX_NORMAL:
235                 return pthread_mutex_timedlock (&mutex->mutex, timeout);
236         case MONO_MUTEX_RECURSIVE:
237                 id = pthread_self ();
238                 
239                 if (pthread_mutex_timedlock (&mutex->mutex, timeout) != 0)
240                         return ETIMEDOUT;
241                 
242                 while (1) {
243                         if (mutex->owner == MONO_THREAD_NONE) {
244                                 mutex->owner = id;
245                                 mutex->depth = 1;
246                                 break;
247                         } else if (mutex->owner == id) {
248                                 mutex->depth++;
249                                 break;
250                         } else {
251                                 mutex->waiters++;
252                                 if (pthread_cond_timedwait (&mutex->cond, &mutex->mutex, timeout) != 0)
253                                         return ETIMEDOUT;
254                                 mutex->waiters--;
255                         }
256                 }
257                 
258                 return pthread_mutex_unlock (&mutex->mutex);
259         }
260         
261         return EINVAL;
262 }
263
264 int
265 mono_mutex_unlock (mono_mutex_t *mutex)
266 {
267         switch (mutex->type) {
268         case MONO_MUTEX_NORMAL:
269                 return pthread_mutex_unlock (&mutex->mutex);
270         case MONO_MUTEX_RECURSIVE:
271                 if (pthread_mutex_lock (&mutex->mutex) != 0)
272                         return EINVAL;
273                 
274                 assert (mutex->owner == pthread_self ());
275                 
276                 mutex->depth--;
277                 if (mutex->depth == 0) {
278                         mutex->owner = MONO_THREAD_NONE;
279                         if (mutex->waiters > 0)
280                                 pthread_cond_signal (&mutex->cond);
281                 }
282                 
283                 return pthread_mutex_unlock (&mutex->mutex);
284         }
285         
286         return EINVAL;
287 }
288
289 int
290 mono_mutex_destroy (mono_mutex_t *mutex)
291 {
292         int ret = 0;
293         
294         switch (mutex->type) {
295         case MONO_MUTEX_NORMAL:
296                 ret = pthread_mutex_destroy (&mutex->mutex);
297                 break;
298         case MONO_MUTEX_RECURSIVE:
299                 if ((ret = pthread_mutex_destroy (&mutex->mutex)) == 0) {
300                         pthread_cond_destroy (&mutex->cond);
301                 }
302         }
303         
304         return ret;
305 }
306
307
308 int
309 mono_cond_wait (pthread_cond_t *cond, mono_mutex_t *mutex)
310 {
311         return pthread_cond_wait (cond, &mutex->mutex);
312 }
313
314 int
315 mono_cond_timedwait (pthread_cond_t *cond, mono_mutex_t *mutex, const struct timespec *timeout)
316 {
317         return pthread_cond_timedwait (cond, &mutex->mutex, timeout);
318 }
319
320 #endif /* USE_MONO_MUTEX */