merge -r 53370:58178
[mono.git] / mono / io-layer / mutexes.c
1 /*
2  * mutexes.c:  Mutex handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #include <string.h>
14 #include <unistd.h>
15
16 #include <mono/io-layer/wapi.h>
17 #include <mono/io-layer/wapi-private.h>
18 #include <mono/io-layer/misc-private.h>
19 #include <mono/io-layer/handles-private.h>
20 #include <mono/io-layer/mono-mutex.h>
21 #include <mono/io-layer/mutex-private.h>
22
23 #undef DEBUG
24
25 static void mutex_signal(gpointer handle);
26 static gboolean mutex_own (gpointer handle);
27 static gboolean mutex_is_owned (gpointer handle);
28
29 static void namedmutex_signal (gpointer handle);
30 static gboolean namedmutex_own (gpointer handle);
31 static gboolean namedmutex_is_owned (gpointer handle);
32
33 struct _WapiHandleOps _wapi_mutex_ops = {
34         NULL,                   /* close */
35         mutex_signal,           /* signal */
36         mutex_own,              /* own */
37         mutex_is_owned,         /* is_owned */
38 };
39
40 void _wapi_mutex_details (gpointer handle_info)
41 {
42         struct _WapiHandle_mutex *mut = (struct _WapiHandle_mutex *)handle_info;
43         
44 #ifdef PTHREAD_POINTER_ID
45         g_print ("own: %5d:%5p, count: %5u", mut->pid, mut->tid,
46                  mut->recursion);
47 #else
48         g_print ("own: %5d:%5ld, count: %5u", mut->pid, mut->tid,
49                  mut->recursion);
50 #endif
51 }
52
53 struct _WapiHandleOps _wapi_namedmutex_ops = {
54         NULL,                   /* close */
55         namedmutex_signal,      /* signal */
56         namedmutex_own,         /* own */
57         namedmutex_is_owned,    /* is_owned */
58 };
59
60 static gboolean mutex_release (gpointer handle);
61 static gboolean namedmutex_release (gpointer handle);
62
63 static struct 
64 {
65         gboolean (*release)(gpointer handle);
66 } mutex_ops[WAPI_HANDLE_COUNT] = {
67         {NULL},
68         {NULL},
69         {NULL},
70         {NULL},
71         {NULL},
72         {mutex_release},
73         {NULL},
74         {NULL},
75         {NULL},
76         {NULL},
77         {NULL},
78         {namedmutex_release},
79 };
80
81 static mono_once_t mutex_ops_once=MONO_ONCE_INIT;
82
83 static void mutex_ops_init (void)
84 {
85         _wapi_handle_register_capabilities (WAPI_HANDLE_MUTEX,
86                                             WAPI_HANDLE_CAP_WAIT |
87                                             WAPI_HANDLE_CAP_SIGNAL |
88                                             WAPI_HANDLE_CAP_OWN);
89         _wapi_handle_register_capabilities (WAPI_HANDLE_NAMEDMUTEX,
90                                             WAPI_HANDLE_CAP_WAIT |
91                                             WAPI_HANDLE_CAP_SIGNAL |
92                                             WAPI_HANDLE_CAP_OWN);
93 }
94
95 static void mutex_signal(gpointer handle)
96 {
97         ReleaseMutex(handle);
98 }
99
100 static gboolean mutex_own (gpointer handle)
101 {
102         struct _WapiHandle_mutex *mutex_handle;
103         gboolean ok;
104         
105         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
106                                   (gpointer *)&mutex_handle);
107         if (ok == FALSE) {
108                 g_warning ("%s: error looking up mutex handle %p", __func__,
109                            handle);
110                 return(FALSE);
111         }
112
113         _wapi_thread_own_mutex (pthread_self (), handle);
114         
115 #ifdef DEBUG
116         g_message("%s: owning mutex handle %p", __func__, handle);
117 #endif
118
119         _wapi_handle_set_signal_state (handle, FALSE, FALSE);
120         
121         mutex_handle->pid = getpid ();
122         mutex_handle->tid = pthread_self ();
123         mutex_handle->recursion++;
124
125 #ifdef DEBUG
126         g_message ("%s: mutex handle %p locked %d times by %d:%ld", __func__,
127                    handle, mutex_handle->recursion, mutex_handle->pid,
128                    mutex_handle->tid);
129 #endif
130
131         return(TRUE);
132 }
133
134 static gboolean mutex_is_owned (gpointer handle)
135 {
136         struct _WapiHandle_mutex *mutex_handle;
137         gboolean ok;
138         
139         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
140                                 (gpointer *)&mutex_handle);
141         if(ok==FALSE) {
142                 g_warning ("%s: error looking up mutex handle %p", __func__,
143                            handle);
144                 return(FALSE);
145         }
146         
147 #ifdef DEBUG
148         g_message("%s: testing ownership mutex handle %p", __func__, handle);
149 #endif
150
151         if (mutex_handle->recursion > 0 &&
152             mutex_handle->pid == getpid () &&
153             mutex_handle->tid == pthread_self ()) {
154 #ifdef DEBUG
155                 g_message ("%s: mutex handle %p owned by %d:%ld", __func__,
156                            handle, getpid (), pthread_self ());
157 #endif
158
159                 return(TRUE);
160         } else {
161 #ifdef DEBUG
162                 g_message ("%s: mutex handle %p not owned by %d:%ld, but locked %d times by %d:%ld", __func__, handle, getpid (), pthread_self (), mutex_handle->recursion, mutex_handle->pid, mutex_handle->tid);
163 #endif
164
165                 return(FALSE);
166         }
167 }
168
169 static void namedmutex_signal (gpointer handle)
170 {
171         ReleaseMutex(handle);
172 }
173
174 /* NB, always called with the shared handle lock held */
175 static gboolean namedmutex_own (gpointer handle)
176 {
177         struct _WapiHandle_namedmutex *namedmutex_handle;
178         gboolean ok;
179         
180 #ifdef DEBUG
181         g_message ("%s: owning named mutex handle %p", __func__, handle);
182 #endif
183         
184         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
185                                   (gpointer *)&namedmutex_handle);
186         if (ok == FALSE) {
187                 g_warning ("%s: error looking up named mutex handle %p",
188                            __func__, handle);
189                 return(FALSE);
190         }
191
192         _wapi_thread_own_mutex (pthread_self (), handle);
193
194         namedmutex_handle->pid = getpid ();
195         namedmutex_handle->tid = pthread_self ();
196         namedmutex_handle->recursion++;
197
198         _wapi_shared_handle_set_signal_state (handle, FALSE);
199
200 #ifdef DEBUG
201         g_message ("%s: mutex handle %p locked %d times by %d:%ld", __func__,
202                    handle, namedmutex_handle->recursion,
203                    namedmutex_handle->pid, namedmutex_handle->tid);
204 #endif
205         
206         return(TRUE);
207 }
208
209 static gboolean namedmutex_is_owned (gpointer handle)
210 {
211         struct _WapiHandle_namedmutex *namedmutex_handle;
212         gboolean ok;
213         
214         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
215                                   (gpointer *)&namedmutex_handle);
216         if (ok == FALSE) {
217                 g_warning ("%s: error looking up mutex handle %p", __func__,
218                            handle);
219                 return(FALSE);
220         }
221         
222 #ifdef DEBUG
223         g_message ("%s: testing ownership mutex handle %p", __func__, handle);
224 #endif
225
226         if (namedmutex_handle->recursion > 0 &&
227             namedmutex_handle->pid == getpid () &&
228             namedmutex_handle->tid == pthread_self ()) {
229 #ifdef DEBUG
230                 g_message ("%s: mutex handle %p owned by %d:%ld", __func__,
231                            handle, getpid (), pthread_self ());
232 #endif
233
234                 return(TRUE);
235         } else {
236 #ifdef DEBUG
237                 g_message ("%s: mutex handle %p not owned by %d:%ld, but locked %d times by %d:%ld", __func__, handle, getpid (), pthread_self (), namedmutex_handle->recursion, namedmutex_handle->pid, namedmutex_handle->tid);
238 #endif
239
240                 return(FALSE);
241         }
242 }
243
244 static void mutex_abandon (gpointer handle, pid_t pid, pthread_t tid)
245 {
246         struct _WapiHandle_mutex *mutex_handle;
247         gboolean ok;
248         int thr_ret;
249         
250         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
251                                   (gpointer *)&mutex_handle);
252         if (ok == FALSE) {
253                 g_warning ("%s: error looking up mutex handle %p", __func__,
254                            handle);
255                 return;
256         }
257
258         pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
259                               handle);
260         thr_ret = _wapi_handle_lock_handle (handle);
261         g_assert (thr_ret == 0);
262         
263         if (mutex_handle->pid == pid &&
264             mutex_handle->tid == tid) {
265 #ifdef DEBUG
266                 g_message ("%s: Mutex handle %p abandoned!", __func__, handle);
267 #endif
268
269                 mutex_handle->recursion = 0;
270                 mutex_handle->pid = 0;
271                 mutex_handle->tid = 0;
272                 
273                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
274         }
275
276         thr_ret = _wapi_handle_unlock_handle (handle);
277         g_assert (thr_ret == 0);
278         pthread_cleanup_pop (0);
279 }
280
281 static void namedmutex_abandon (gpointer handle, pid_t pid, pthread_t tid)
282 {
283         struct _WapiHandle_namedmutex *mutex_handle;
284         gboolean ok;
285         int thr_ret;
286         
287         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
288                                   (gpointer *)&mutex_handle);
289         if (ok == FALSE) {
290                 g_warning ("%s: error looking up named mutex handle %p",
291                            __func__, handle);
292                 return;
293         }
294
295         thr_ret = _wapi_handle_lock_shared_handles ();
296         g_assert (thr_ret == 0);
297         
298         if (mutex_handle->pid == pid &&
299             mutex_handle->tid == tid) {
300 #ifdef DEBUG
301                 g_message ("%s: Mutex handle %p abandoned!", __func__, handle);
302 #endif
303
304                 mutex_handle->recursion = 0;
305                 mutex_handle->pid = 0;
306                 mutex_handle->tid = 0;
307                 
308                 _wapi_shared_handle_set_signal_state (handle, TRUE);
309         }
310
311         _wapi_handle_unlock_shared_handles ();
312 }
313
314 /* When a thread exits, any mutexes it still holds need to be
315  * signalled.  This function must not be called with the shared handle
316  * lock held, as namedmutex_abandon () will try to acquire it
317  */
318 void _wapi_mutex_abandon (gpointer data, pid_t pid, pthread_t tid)
319 {
320         WapiHandleType type = _wapi_handle_type (data);
321
322         if (type == WAPI_HANDLE_MUTEX) {
323                 mutex_abandon (data, pid, tid);
324         } else if (type == WAPI_HANDLE_NAMEDMUTEX) {
325                 namedmutex_abandon (data, pid, tid);
326         } else {
327                 g_assert_not_reached ();
328         }
329 }
330
331 static gpointer mutex_create (WapiSecurityAttributes *security G_GNUC_UNUSED,
332                               gboolean owned)
333 {
334         struct _WapiHandle_mutex mutex_handle = {0};
335         gpointer handle;
336         int thr_ret;
337         
338         /* Need to blow away any old errors here, because code tests
339          * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex
340          * was freshly created
341          */
342         SetLastError (ERROR_SUCCESS);
343         
344 #ifdef DEBUG
345         g_message ("%s: Creating unnamed mutex", __func__);
346 #endif
347         
348         handle = _wapi_handle_new (WAPI_HANDLE_MUTEX, &mutex_handle);
349         if (handle == _WAPI_HANDLE_INVALID) {
350                 g_warning ("%s: error creating mutex handle", __func__);
351                 SetLastError (ERROR_GEN_FAILURE);
352                 return(NULL);
353         }
354
355         pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
356                               handle);
357         thr_ret = _wapi_handle_lock_handle (handle);
358         g_assert (thr_ret == 0);
359         
360         if(owned==TRUE) {
361                 mutex_own (handle);
362         } else {
363                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
364         }
365         
366 #ifdef DEBUG
367         g_message ("%s: returning mutex handle %p", __func__, handle);
368 #endif
369
370         thr_ret = _wapi_handle_unlock_handle (handle);
371         g_assert (thr_ret == 0);
372         pthread_cleanup_pop (0);
373         
374         return(handle);
375 }
376
377 static gpointer namedmutex_create (WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned,
378                         const gunichar2 *name)
379 {
380         struct _WapiHandle_namedmutex namedmutex_handle = {{{0}}, 0};
381         gpointer handle;
382         gchar *utf8_name;
383         int thr_ret;
384         gpointer ret = NULL;
385         guint32 namelen;
386         gint32 offset;
387
388         /* w32 seems to guarantee that opening named mutexes can't
389          * race each other
390          */
391         pthread_cleanup_push ((void(*)(void *))_wapi_namespace_unlock, NULL);
392         thr_ret = _wapi_namespace_lock ();
393         g_assert (thr_ret == 0);
394
395         /* Need to blow away any old errors here, because code tests
396          * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex
397          * was freshly created
398          */
399         SetLastError (ERROR_SUCCESS);
400         
401         utf8_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
402         
403 #ifdef DEBUG
404         g_message ("%s: Creating named mutex [%s]", __func__, utf8_name);
405 #endif
406         
407         offset = _wapi_search_handle_namespace (WAPI_HANDLE_NAMEDMUTEX,
408                                                 utf8_name);
409         if (offset == -1) {
410                 /* The name has already been used for a different
411                  * object.
412                  */
413                 SetLastError (ERROR_INVALID_HANDLE);
414                 goto cleanup;
415         } else if (offset != 0) {
416                 /* Not an error, but this is how the caller is
417                  * informed that the mutex wasn't freshly created
418                  */
419                 SetLastError (ERROR_ALREADY_EXISTS);
420         }
421         /* Fall through to create the mutex handle. */
422         
423         if (strlen (utf8_name) < MAX_PATH) {
424                 namelen = strlen (utf8_name);
425         } else {
426                 namelen = MAX_PATH;
427         }
428         
429         memcpy (&namedmutex_handle.sharedns.name, utf8_name, namelen);
430
431         if (offset == 0) {
432                 /* A new named mutex, so create both the private and
433                  * shared parts
434                  */
435                 handle = _wapi_handle_new (WAPI_HANDLE_NAMEDMUTEX,
436                                            &namedmutex_handle);
437         } else {
438                 /* A new reference to an existing named mutex, so just
439                  * create the private part
440                  */
441                 handle = _wapi_handle_new_from_offset (WAPI_HANDLE_NAMEDMUTEX,
442                                                        offset, TRUE);
443         }
444         
445         if (handle == _WAPI_HANDLE_INVALID) {
446                 g_warning ("%s: error creating mutex handle", __func__);
447                 SetLastError (ERROR_GEN_FAILURE);
448                 goto cleanup;
449         }
450         ret = handle;
451
452         if (offset == 0) {
453                 /* Set the initial state, as this is a completely new
454                  * handle
455                  */
456                 thr_ret = _wapi_handle_lock_shared_handles ();
457                 g_assert (thr_ret == 0);
458         
459                 if (owned == TRUE) {
460                         namedmutex_own (handle);
461                 } else {
462                         _wapi_shared_handle_set_signal_state (handle, TRUE);
463                 }
464
465                 _wapi_handle_unlock_shared_handles ();
466         }
467         
468 #ifdef DEBUG
469         g_message ("%s: returning mutex handle %p", __func__, handle);
470 #endif
471
472 cleanup:
473         g_free (utf8_name);
474
475         _wapi_namespace_unlock (NULL);
476         pthread_cleanup_pop (0);
477         
478         return(ret);
479 }
480
481 /**
482  * CreateMutex:
483  * @security: Ignored for now.
484  * @owned: If %TRUE, the mutex is created with the calling thread
485  * already owning the mutex.
486  * @name:Pointer to a string specifying the name of this mutex, or
487  * %NULL.
488  *
489  * Creates a new mutex handle.  A mutex is signalled when no thread
490  * owns it.  A thread acquires ownership of the mutex by waiting for
491  * it with WaitForSingleObject() or WaitForMultipleObjects().  A
492  * thread relinquishes ownership with ReleaseMutex().
493  *
494  * A thread that owns a mutex can specify the same mutex in repeated
495  * wait function calls without blocking.  The thread must call
496  * ReleaseMutex() an equal number of times to release the mutex.
497  *
498  * Return value: A new handle, or %NULL on error.
499  */
500 gpointer CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned,
501                         const gunichar2 *name)
502 {
503         mono_once (&mutex_ops_once, mutex_ops_init);
504
505         if (name == NULL) {
506                 return(mutex_create (security, owned));
507         } else {
508                 return(namedmutex_create (security, owned, name));
509         }
510 }
511
512 static gboolean mutex_release (gpointer handle)
513 {
514         struct _WapiHandle_mutex *mutex_handle;
515         gboolean ok;
516         pthread_t tid=pthread_self();
517         pid_t pid=getpid ();
518         int thr_ret;
519         gboolean ret = FALSE;
520         
521         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_MUTEX,
522                                   (gpointer *)&mutex_handle);
523         if (ok == FALSE) {
524                 g_warning ("%s: error looking up mutex handle %p", __func__,
525                            handle);
526                 return(FALSE);
527         }
528
529         pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle,
530                               handle);
531         thr_ret = _wapi_handle_lock_handle (handle);
532         g_assert (thr_ret == 0);
533         
534 #ifdef DEBUG
535         g_message("%s: Releasing mutex handle %p", __func__, handle);
536 #endif
537
538         if(mutex_handle->tid!=tid || mutex_handle->pid!=pid) {
539 #ifdef DEBUG
540                 g_message("%s: We don't own mutex handle %p (owned by %d:%ld, me %d:%ld)", __func__, handle, mutex_handle->pid, mutex_handle->tid, pid, tid);
541 #endif
542
543                 goto cleanup;
544         }
545         ret = TRUE;
546         
547         /* OK, we own this mutex */
548         mutex_handle->recursion--;
549         
550         if(mutex_handle->recursion==0) {
551                 _wapi_thread_disown_mutex (tid, handle);
552
553 #ifdef DEBUG
554                 g_message("%s: Unlocking mutex handle %p", __func__, handle);
555 #endif
556
557                 mutex_handle->pid=0;
558                 mutex_handle->tid=0;
559                 _wapi_handle_set_signal_state (handle, TRUE, FALSE);
560         }
561
562 cleanup:
563         thr_ret = _wapi_handle_unlock_handle (handle);
564         g_assert (thr_ret == 0);
565         pthread_cleanup_pop (0);
566         
567         return(ret);
568 }
569
570 static gboolean namedmutex_release (gpointer handle)
571 {
572         struct _WapiHandle_namedmutex *mutex_handle;
573         gboolean ok;
574         pthread_t tid=pthread_self();
575         pid_t pid=getpid ();
576         int thr_ret;
577         gboolean ret = FALSE;
578         
579         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_NAMEDMUTEX,
580                                 (gpointer *)&mutex_handle);
581         if(ok==FALSE) {
582                 g_warning ("%s: error looking up named mutex handle %p",
583                            __func__, handle);
584                 return(FALSE);
585         }
586
587         thr_ret = _wapi_handle_lock_shared_handles ();
588         g_assert (thr_ret == 0);
589         
590 #ifdef DEBUG
591         g_message("%s: Releasing mutex handle %p", __func__, handle);
592 #endif
593
594         if(mutex_handle->tid!=tid || mutex_handle->pid!=pid) {
595 #ifdef DEBUG
596                 g_message("%s: We don't own mutex handle %p (owned by %d:%ld, me %d:%ld)", __func__, handle, mutex_handle->pid, mutex_handle->tid, pid, tid);
597 #endif
598
599                 goto cleanup;
600         }
601         ret = TRUE;
602         
603         /* OK, we own this mutex */
604         mutex_handle->recursion--;
605         
606         if(mutex_handle->recursion==0) {
607                 _wapi_thread_disown_mutex (tid, handle);
608
609 #ifdef DEBUG
610                 g_message("%s: Unlocking mutex handle %p", __func__, handle);
611 #endif
612
613                 mutex_handle->pid=0;
614                 mutex_handle->tid=0;
615                 _wapi_shared_handle_set_signal_state (handle, TRUE);
616         }
617
618 cleanup:
619         _wapi_handle_unlock_shared_handles ();
620         
621         return(ret);
622 }
623
624 /**
625  * ReleaseMutex:
626  * @handle: The mutex handle.
627  *
628  * Releases ownership if the mutex handle @handle.
629  *
630  * Return value: %TRUE on success, %FALSE otherwise.  This function
631  * fails if the calling thread does not own the mutex @handle.
632  */
633 gboolean ReleaseMutex(gpointer handle)
634 {
635         WapiHandleType type;
636
637         if (handle == NULL) {
638                 SetLastError (ERROR_INVALID_HANDLE);
639                 return(FALSE);
640         }
641         
642         type = _wapi_handle_type (handle);
643         
644         if (mutex_ops[type].release == NULL) {
645                 SetLastError (ERROR_INVALID_HANDLE);
646                 return(FALSE);
647         }
648         
649         return(mutex_ops[type].release (handle));
650 }