1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * mono-mutex.h: Portability wrappers around POSIX Mutexes
5 * Authors: Jeffrey Stedfast <fejj@ximian.com>
7 * Copyright 2002 Ximian, Inc. (www.ximian.com)
21 #include "mono-mutex.h"
24 #ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
25 /* Android does not implement pthread_mutex_timedlock(), but does provide an
26 * unusual declaration: http://code.google.com/p/android/issues/detail?id=7807
28 #ifdef PLATFORM_ANDROID
31 #define CONST_NEEDED const
34 int pthread_mutex_timedlock (pthread_mutex_t
*mutex
,
35 CONST_NEEDED
struct timespec
*timeout
);
37 pthread_mutex_timedlock (pthread_mutex_t
*mutex
, CONST_NEEDED
struct timespec
*timeout
)
39 struct timeval timenow
;
40 struct timespec sleepytime
;
43 /* This is just to avoid a completely busy wait */
44 sleepytime
.tv_sec
= 0;
45 sleepytime
.tv_nsec
= 10000000; /* 10ms */
47 while ((retcode
= pthread_mutex_trylock (mutex
)) == EBUSY
) {
48 gettimeofday (&timenow
, NULL
);
50 if (timenow
.tv_sec
>= timeout
->tv_sec
&&
51 (timenow
.tv_usec
* 1000) >= timeout
->tv_nsec
) {
55 nanosleep (&sleepytime
, NULL
);
60 #endif /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */
64 mono_once (mono_once_t
*once
, void (*once_init
) (void))
68 if (!once
->complete
) {
69 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock
,
70 (void *)&once
->mutex
);
71 thr_ret
= pthread_mutex_lock (&once
->mutex
);
72 g_assert (thr_ret
== 0);
74 if (!once
->complete
) {
76 once
->complete
= TRUE
;
78 thr_ret
= pthread_mutex_unlock (&once
->mutex
);
79 g_assert (thr_ret
== 0);
81 pthread_cleanup_pop (0);
91 mono_mutexattr_init (mono_mutexattr_t
*attr
)
93 memset (attr
, 0, sizeof (mono_mutexattr_t
));
98 mono_mutexattr_settype (mono_mutexattr_t
*attr
, int type
)
105 mono_mutexattr_gettype (mono_mutexattr_t
*attr
, int *type
)
112 mono_mutexattr_setpshared (mono_mutexattr_t
*attr
, int pshared
)
114 attr
->shared
= pshared
;
119 mono_mutexattr_getpshared (mono_mutexattr_t
*attr
, int *pshared
)
121 *pshared
= attr
->shared
;
126 mono_mutexattr_setprotocol (mono_mutexattr_t
*attr
, int protocol
)
128 attr
->protocol
= protocol
;
133 mono_mutexattr_getprotocol (mono_mutexattr_t
*attr
, int *protocol
)
135 *protocol
= attr
->protocol
;
140 mono_mutexattr_setprioceiling (mono_mutexattr_t
*attr
, int prioceiling
)
142 attr
->priority
= prioceiling
;
147 mono_mutexattr_getprioceiling (mono_mutexattr_t
*attr
, int *prioceiling
)
149 *prioceiling
= attr
->priority
;
154 mono_mutexattr_destroy (mono_mutexattr_t
*attr
)
161 mono_mutex_init (mono_mutex_t
*mutex
, const mono_mutexattr_t
*attr
)
168 mutex
->owner
= MONO_THREAD_NONE
;
170 if (!attr
|| attr
->type
== MONO_MUTEX_NORMAL
) {
171 mutex
->type
= MONO_MUTEX_NORMAL
;
172 ret
= pthread_mutex_init (&mutex
->mutex
, NULL
);
174 mutex
->type
= MONO_MUTEX_RECURSIVE
;
175 ret
= pthread_mutex_init (&mutex
->mutex
, NULL
);
176 thr_ret
= pthread_cond_init (&mutex
->cond
, NULL
);
177 g_assert (thr_ret
== 0);
184 mono_mutex_lock (mono_mutex_t
*mutex
)
188 switch (mutex
->type
) {
189 case MONO_MUTEX_NORMAL
:
190 return pthread_mutex_lock (&mutex
->mutex
);
191 case MONO_MUTEX_RECURSIVE
:
192 id
= pthread_self ();
193 if (pthread_mutex_lock (&mutex
->mutex
) != 0)
197 if (pthread_equal (mutex
->owner
, MONO_THREAD_NONE
)) {
201 } else if (pthread_equal (mutex
->owner
, id
)) {
206 if (pthread_cond_wait (&mutex
->cond
, &mutex
->mutex
) != 0)
212 return pthread_mutex_unlock (&mutex
->mutex
);
219 mono_mutex_trylock (mono_mutex_t
*mutex
)
223 switch (mutex
->type
) {
224 case MONO_MUTEX_NORMAL
:
225 return pthread_mutex_trylock (&mutex
->mutex
);
226 case MONO_MUTEX_RECURSIVE
:
227 id
= pthread_self ();
229 if (pthread_mutex_lock (&mutex
->mutex
) != 0)
232 if (!pthread_equal (mutex
->owner
, MONO_THREAD_NONE
) &&
233 !pthread_equal (mutex
->owner
, id
)) {
234 pthread_mutex_unlock (&mutex
->mutex
);
239 if (pthread_equal (mutex
->owner
, MONO_THREAD_NONE
)) {
249 return pthread_mutex_unlock (&mutex
->mutex
);
256 mono_mutex_timedlock (mono_mutex_t
*mutex
, const struct timespec
*timeout
)
260 switch (mutex
->type
) {
261 case MONO_MUTEX_NORMAL
:
262 return pthread_mutex_timedlock (&mutex
->mutex
, timeout
);
263 case MONO_MUTEX_RECURSIVE
:
264 id
= pthread_self ();
266 if (pthread_mutex_timedlock (&mutex
->mutex
, timeout
) != 0)
270 if (pthread_equal (mutex
->owner
, MONO_THREAD_NONE
)) {
274 } else if (pthread_equal (mutex
->owner
, id
)) {
279 if (pthread_cond_timedwait (&mutex
->cond
, &mutex
->mutex
, timeout
) != 0)
285 return pthread_mutex_unlock (&mutex
->mutex
);
292 mono_mutex_unlock (mono_mutex_t
*mutex
)
296 switch (mutex
->type
) {
297 case MONO_MUTEX_NORMAL
:
298 return pthread_mutex_unlock (&mutex
->mutex
);
299 case MONO_MUTEX_RECURSIVE
:
300 if (pthread_mutex_lock (&mutex
->mutex
) != 0)
303 if (pthread_equal (mutex
->owner
, pthread_self())) {
304 /* Not owned by this thread */
305 pthread_mutex_unlock (&mutex
->mutex
);
310 if (mutex
->depth
== 0) {
311 mutex
->owner
= MONO_THREAD_NONE
;
312 if (mutex
->waiters
> 0) {
313 thr_ret
= pthread_cond_signal (&mutex
->cond
);
314 g_assert (thr_ret
== 0);
318 return pthread_mutex_unlock (&mutex
->mutex
);
325 mono_mutex_destroy (mono_mutex_t
*mutex
)
330 switch (mutex
->type
) {
331 case MONO_MUTEX_NORMAL
:
332 ret
= pthread_mutex_destroy (&mutex
->mutex
);
334 case MONO_MUTEX_RECURSIVE
:
335 if ((ret
= pthread_mutex_destroy (&mutex
->mutex
)) == 0) {
336 thr_ret
= pthread_cond_destroy (&mutex
->cond
);
337 g_assert (thr_ret
== 0);
346 mono_cond_wait (pthread_cond_t
*cond
, mono_mutex_t
*mutex
)
348 return pthread_cond_wait (cond
, &mutex
->mutex
);
352 mono_cond_timedwait (pthread_cond_t
*cond
, mono_mutex_t
*mutex
, const struct timespec
*timeout
)
354 return pthread_cond_timedwait (cond
, &mutex
->mutex
, timeout
);
357 #endif /* USE_MONO_MUTEX */