[man] Add entries for sgen modes and new major/minor types
[mono.git] / mono / metadata / w32mutex-unix.c
1 /**
2  * \file
3  * Runtime support for managed Mutex on Unix
4  *
5  * Author:
6  *      Ludovic Henry (luhenry@microsoft.com)
7  *
8  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
9  */
10
11 #include "w32mutex.h"
12
13 #include <pthread.h>
14
15 #include "w32error.h"
16 #include "w32handle-namespace.h"
17 #include "mono/metadata/object-internals.h"
18 #include "mono/utils/mono-logger-internals.h"
19 #include "mono/utils/mono-threads.h"
20 #include "mono/metadata/w32handle.h"
21
22 #define MAX_PATH 260
23
24 typedef struct {
25         MonoNativeThreadId tid;
26         guint32 recursion;
27         gboolean abandoned;
28 } MonoW32HandleMutex;
29
30 struct MonoW32HandleNamedMutex {
31         MonoW32HandleMutex m;
32         MonoW32HandleNamespace sharedns;
33 };
34
35 static void
36 thread_own_mutex (MonoInternalThread *internal, gpointer handle)
37 {
38         mono_w32handle_ref (handle);
39
40         /* if we are not on the current thread, there is a
41          * race condition when allocating internal->owned_mutexes */
42         g_assert (mono_thread_internal_is_current (internal));
43
44         if (!internal->owned_mutexes)
45                 internal->owned_mutexes = g_ptr_array_new ();
46
47         g_ptr_array_add (internal->owned_mutexes, handle);
48 }
49
50 static void
51 thread_disown_mutex (MonoInternalThread *internal, gpointer handle)
52 {
53         gboolean removed;
54
55         g_assert (mono_thread_internal_is_current (internal));
56
57         g_assert (internal->owned_mutexes);
58         removed = g_ptr_array_remove (internal->owned_mutexes, handle);
59         g_assert (removed);
60
61         mono_w32handle_unref (handle);
62 }
63
64 static gboolean
65 mutex_handle_own (gpointer handle, MonoW32HandleType type, gboolean *abandoned)
66 {
67         MonoW32HandleMutex *mutex_handle;
68
69         *abandoned = FALSE;
70
71         if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
72                 g_warning ("%s: error looking up %s handle %p", __func__, mono_w32handle_get_typename (type), handle);
73                 return FALSE;
74         }
75
76         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: owning %s handle %p, before: [tid: %p, recursion: %d], after: [tid: %p, recursion: %d], abandoned: %s",
77                 __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion, (gpointer) pthread_self (), mutex_handle->recursion + 1, mutex_handle->abandoned ? "true" : "false");
78
79         if (mutex_handle->recursion != 0) {
80                 g_assert (pthread_equal (pthread_self (), mutex_handle->tid));
81                 mutex_handle->recursion++;
82         } else {
83                 mutex_handle->tid = pthread_self ();
84                 mutex_handle->recursion = 1;
85
86                 thread_own_mutex (mono_thread_internal_current (), handle);
87         }
88
89         if (mutex_handle->abandoned) {
90                 mutex_handle->abandoned = FALSE;
91                 *abandoned = TRUE;
92         }
93
94         mono_w32handle_set_signal_state (handle, FALSE, FALSE);
95
96         return TRUE;
97 }
98
99 static gboolean
100 mutex_handle_is_owned (gpointer handle, MonoW32HandleType type)
101 {
102         MonoW32HandleMutex *mutex_handle;
103
104         if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
105                 g_warning ("%s: error looking up %s handle %p", __func__, mono_w32handle_get_typename (type), handle);
106                 return FALSE;
107         }
108
109         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing ownership %s handle %p",
110                 __func__, mono_w32handle_get_typename (type), handle);
111
112         if (mutex_handle->recursion > 0 && pthread_equal (mutex_handle->tid, pthread_self ())) {
113                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p owned by %p",
114                         __func__, mono_w32handle_get_typename (type), handle, (gpointer) pthread_self ());
115                 return TRUE;
116         } else {
117                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p not owned by %p, tid: %p recursion: %d",
118                         __func__, mono_w32handle_get_typename (type), handle, (gpointer) pthread_self (), (gpointer) mutex_handle->tid, mutex_handle->recursion);
119                 return FALSE;
120         }
121 }
122
123 static void mutex_signal(gpointer handle)
124 {
125         ves_icall_System_Threading_Mutex_ReleaseMutex_internal (handle);
126 }
127
128 static gboolean mutex_own (gpointer handle, gboolean *abandoned)
129 {
130         return mutex_handle_own (handle, MONO_W32HANDLE_MUTEX, abandoned);
131 }
132
133 static gboolean mutex_is_owned (gpointer handle)
134 {
135         
136         return mutex_handle_is_owned (handle, MONO_W32HANDLE_MUTEX);
137 }
138
139 static void namedmutex_signal (gpointer handle)
140 {
141         ves_icall_System_Threading_Mutex_ReleaseMutex_internal (handle);
142 }
143
144 /* NB, always called with the shared handle lock held */
145 static gboolean namedmutex_own (gpointer handle, gboolean *abandoned)
146 {
147         return mutex_handle_own (handle, MONO_W32HANDLE_NAMEDMUTEX, abandoned);
148 }
149
150 static gboolean namedmutex_is_owned (gpointer handle)
151 {
152         return mutex_handle_is_owned (handle, MONO_W32HANDLE_NAMEDMUTEX);
153 }
154
155 static void mutex_handle_prewait (gpointer handle, MonoW32HandleType type)
156 {
157         /* If the mutex is not currently owned, do nothing and let the
158          * usual wait carry on.  If it is owned, check that the owner
159          * is still alive; if it isn't we override the previous owner
160          * and assume that process exited abnormally and failed to
161          * clean up.
162          */
163         MonoW32HandleMutex *mutex_handle;
164
165         if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
166                 g_warning ("%s: error looking up %s handle %p",
167                         __func__, mono_w32handle_get_typename (type), handle);
168                 return;
169         }
170
171         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: pre-waiting %s handle %p, owned? %s",
172                 __func__, mono_w32handle_get_typename (type), handle, mutex_handle->recursion != 0 ? "true" : "false");
173 }
174
175 /* The shared state is not locked when prewait methods are called */
176 static void mutex_prewait (gpointer handle)
177 {
178         mutex_handle_prewait (handle, MONO_W32HANDLE_MUTEX);
179 }
180
181 /* The shared state is not locked when prewait methods are called */
182 static void namedmutex_prewait (gpointer handle)
183 {
184         mutex_handle_prewait (handle, MONO_W32HANDLE_NAMEDMUTEX);
185 }
186
187 static void mutex_details (gpointer data)
188 {
189         MonoW32HandleMutex *mut = (MonoW32HandleMutex *)data;
190         
191 #ifdef PTHREAD_POINTER_ID
192         g_print ("own: %5p, count: %5u", mut->tid, mut->recursion);
193 #else
194         g_print ("own: %5ld, count: %5u", mut->tid, mut->recursion);
195 #endif
196 }
197
198 static void namedmutex_details (gpointer data)
199 {
200         MonoW32HandleNamedMutex *namedmut = (MonoW32HandleNamedMutex *)data;
201         
202 #ifdef PTHREAD_POINTER_ID
203         g_print ("own: %5p, count: %5u, name: \"%s\"",
204                 namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name);
205 #else
206         g_print ("own: %5ld, count: %5u, name: \"%s\"",
207                 namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name);
208 #endif
209 }
210
211 static const gchar* mutex_typename (void)
212 {
213         return "Mutex";
214 }
215
216 static gsize mutex_typesize (void)
217 {
218         return sizeof (MonoW32HandleMutex);
219 }
220
221 static const gchar* namedmutex_typename (void)
222 {
223         return "N.Mutex";
224 }
225
226 static gsize namedmutex_typesize (void)
227 {
228         return sizeof (MonoW32HandleNamedMutex);
229 }
230
231 void
232 mono_w32mutex_init (void)
233 {
234         static MonoW32HandleOps mutex_ops = {
235                 NULL,                   /* close */
236                 mutex_signal,           /* signal */
237                 mutex_own,              /* own */
238                 mutex_is_owned,         /* is_owned */
239                 NULL,                   /* special_wait */
240                 mutex_prewait,                  /* prewait */
241                 mutex_details,  /* details */
242                 mutex_typename, /* typename */
243                 mutex_typesize, /* typesize */
244         };
245
246         static MonoW32HandleOps namedmutex_ops = {
247                 NULL,                   /* close */
248                 namedmutex_signal,      /* signal */
249                 namedmutex_own,         /* own */
250                 namedmutex_is_owned,    /* is_owned */
251                 NULL,                   /* special_wait */
252                 namedmutex_prewait,     /* prewait */
253                 namedmutex_details,     /* details */
254                 namedmutex_typename,    /* typename */
255                 namedmutex_typesize,    /* typesize */
256         };
257
258         mono_w32handle_register_ops (MONO_W32HANDLE_MUTEX,      &mutex_ops);
259         mono_w32handle_register_ops (MONO_W32HANDLE_NAMEDMUTEX, &namedmutex_ops);
260
261         mono_w32handle_register_capabilities (MONO_W32HANDLE_MUTEX,
262                 (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN));
263         mono_w32handle_register_capabilities (MONO_W32HANDLE_NAMEDMUTEX,
264                 (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN));
265 }
266
267 static gpointer mutex_handle_create (MonoW32HandleMutex *mutex_handle, MonoW32HandleType type, gboolean owned)
268 {
269         gpointer handle;
270         gboolean abandoned;
271
272         mutex_handle->tid = 0;
273         mutex_handle->recursion = 0;
274         mutex_handle->abandoned = FALSE;
275
276         handle = mono_w32handle_new (type, mutex_handle);
277         if (handle == INVALID_HANDLE_VALUE) {
278                 g_warning ("%s: error creating %s handle",
279                         __func__, mono_w32handle_get_typename (type));
280                 mono_w32error_set_last (ERROR_GEN_FAILURE);
281                 return NULL;
282         }
283
284         mono_w32handle_lock_handle (handle);
285
286         if (owned)
287                 mutex_handle_own (handle, type, &abandoned);
288         else
289                 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
290
291         mono_w32handle_unlock_handle (handle);
292
293         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: created %s handle %p",
294                 __func__, mono_w32handle_get_typename (type), handle);
295
296         return handle;
297 }
298
299 static gpointer mutex_create (gboolean owned)
300 {
301         MonoW32HandleMutex mutex_handle;
302         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
303                 __func__, mono_w32handle_get_typename (MONO_W32HANDLE_MUTEX));
304         return mutex_handle_create (&mutex_handle, MONO_W32HANDLE_MUTEX, owned);
305 }
306
307 static gpointer namedmutex_create (gboolean owned, const gunichar2 *name)
308 {
309         gpointer handle;
310         gchar *utf8_name;
311
312         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: creating %s handle",
313                 __func__, mono_w32handle_get_typename (MONO_W32HANDLE_NAMEDMUTEX));
314
315         /* w32 seems to guarantee that opening named objects can't race each other */
316         mono_w32handle_namespace_lock ();
317
318         glong utf8_len = 0;
319         utf8_name = g_utf16_to_utf8 (name, -1, NULL, &utf8_len, NULL);
320
321         handle = mono_w32handle_namespace_search_handle (MONO_W32HANDLE_NAMEDMUTEX, utf8_name);
322         if (handle == INVALID_HANDLE_VALUE) {
323                 /* The name has already been used for a different object. */
324                 handle = NULL;
325                 mono_w32error_set_last (ERROR_INVALID_HANDLE);
326         } else if (handle) {
327                 /* Not an error, but this is how the caller is informed that the mutex wasn't freshly created */
328                 mono_w32error_set_last (ERROR_ALREADY_EXISTS);
329
330                 /* mono_w32handle_namespace_search_handle already adds a ref to the handle */
331         } else {
332                 /* A new named mutex */
333                 MonoW32HandleNamedMutex namedmutex_handle;
334
335                 size_t len = utf8_len < MAX_PATH ? utf8_len : MAX_PATH;
336                 memcpy (&namedmutex_handle.sharedns.name [0], utf8_name, len);
337                 namedmutex_handle.sharedns.name [len] = '\0';
338
339                 handle = mutex_handle_create ((MonoW32HandleMutex*) &namedmutex_handle, MONO_W32HANDLE_NAMEDMUTEX, owned);
340         }
341
342         g_free (utf8_name);
343
344         mono_w32handle_namespace_unlock ();
345
346         return handle;
347 }
348
349 gpointer
350 ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
351 {
352         gpointer mutex;
353
354         *created = TRUE;
355
356         /* Need to blow away any old errors here, because code tests
357          * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex
358          * was freshly created */
359         mono_w32error_set_last (ERROR_SUCCESS);
360
361         if (!name) {
362                 mutex = mutex_create (owned);
363         } else {
364                 mutex = namedmutex_create (owned, mono_string_chars (name));
365
366                 if (mono_w32error_get_last () == ERROR_ALREADY_EXISTS)
367                         *created = FALSE;
368         }
369
370         return mutex;
371 }
372
373 MonoBoolean
374 ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle)
375 {
376         MonoW32HandleType type;
377         MonoW32HandleMutex *mutex_handle;
378         pthread_t tid;
379         gboolean ret;
380
381         if (handle == NULL) {
382                 mono_w32error_set_last (ERROR_INVALID_HANDLE);
383                 return FALSE;
384         }
385
386         switch (type = mono_w32handle_get_type (handle)) {
387         case MONO_W32HANDLE_MUTEX:
388         case MONO_W32HANDLE_NAMEDMUTEX:
389                 break;
390         default:
391                 mono_w32error_set_last (ERROR_INVALID_HANDLE);
392                 return FALSE;
393         }
394
395         if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
396                 g_warning ("%s: error looking up %s handle %p",
397                         __func__, mono_w32handle_get_typename (type), handle);
398                 return FALSE;
399         }
400
401         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: releasing %s handle %p, tid: %p recursion: %d",
402                 __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion);
403
404         mono_w32handle_lock_handle (handle);
405
406         tid = pthread_self ();
407
408         if (mutex_handle->abandoned) {
409                 // The Win32 ReleaseMutex() function returns TRUE for abandoned mutexes
410                 ret = TRUE;
411         } else if (!pthread_equal (mutex_handle->tid, tid)) {
412                 ret = FALSE;
413
414                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: we don't own %s handle %p (owned by %ld, me %ld)",
415                             __func__, mono_w32handle_get_typename (type), handle, (long)mutex_handle->tid, (long)tid);
416         } else {
417                 ret = TRUE;
418
419                 /* OK, we own this mutex */
420                 mutex_handle->recursion--;
421
422                 if (mutex_handle->recursion == 0) {
423                         thread_disown_mutex (mono_thread_internal_current (), handle);
424
425                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking %s handle %p, tid: %p recusion : %d",
426                                 __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion);
427
428                         mutex_handle->tid = 0;
429                         mono_w32handle_set_signal_state (handle, TRUE, FALSE);
430                 }
431         }
432
433         mono_w32handle_unlock_handle (handle);
434
435         return ret;
436 }
437
438 gpointer
439 ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name, gint32 rights G_GNUC_UNUSED, gint32 *error)
440 {
441         gpointer handle;
442         gchar *utf8_name;
443
444         *error = ERROR_SUCCESS;
445
446         /* w32 seems to guarantee that opening named objects can't race each other */
447         mono_w32handle_namespace_lock ();
448
449         utf8_name = g_utf16_to_utf8 (mono_string_chars (name), -1, NULL, NULL, NULL);
450
451         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Opening named mutex [%s]",
452                 __func__, utf8_name);
453
454         handle = mono_w32handle_namespace_search_handle (MONO_W32HANDLE_NAMEDMUTEX, utf8_name);
455         if (handle == INVALID_HANDLE_VALUE) {
456                 /* The name has already been used for a different object. */
457                 *error = ERROR_INVALID_HANDLE;
458                 goto cleanup;
459         } else if (!handle) {
460                 /* This name doesn't exist */
461                 *error = ERROR_FILE_NOT_FOUND;
462                 goto cleanup;
463         }
464
465         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning named mutex handle %p",
466                 __func__, handle);
467
468 cleanup:
469         g_free (utf8_name);
470
471         mono_w32handle_namespace_unlock ();
472
473         return handle;
474 }
475
476 void
477 mono_w32mutex_abandon (void)
478 {
479         MonoInternalThread *internal;
480
481         g_assert (mono_thread_internal_current_is_attached ());
482
483         internal = mono_thread_internal_current ();
484         g_assert (internal);
485
486         if (!internal->owned_mutexes)
487                 return;
488
489         while (internal->owned_mutexes->len) {
490                 MonoW32HandleType type;
491                 MonoW32HandleMutex *mutex_handle;
492                 MonoNativeThreadId tid;
493                 gpointer handle;
494
495                 handle = g_ptr_array_index (internal->owned_mutexes, 0);
496
497                 switch (type = mono_w32handle_get_type (handle)) {
498                 case MONO_W32HANDLE_MUTEX:
499                 case MONO_W32HANDLE_NAMEDMUTEX:
500                         break;
501                 default:
502                         g_assert_not_reached ();
503                 }
504
505                 if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) {
506                         g_error ("%s: error looking up %s handle %p",
507                                 __func__, mono_w32handle_get_typename (type), handle);
508                 }
509
510                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandoning %s handle %p",
511                         __func__, mono_w32handle_get_typename (type), handle);
512
513                 tid = MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid);
514
515                 if (!pthread_equal (mutex_handle->tid, tid))
516                         g_error ("%s: trying to release mutex %p acquired by thread %p from thread %p",
517                                 __func__, handle, (gpointer) mutex_handle->tid, (gpointer) tid);
518
519                 mono_w32handle_lock_handle (handle);
520
521                 mutex_handle->recursion = 0;
522                 mutex_handle->tid = 0;
523                 mutex_handle->abandoned = TRUE;
524
525                 mono_w32handle_set_signal_state (handle, TRUE, FALSE);
526
527                 thread_disown_mutex (internal, handle);
528
529                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandoned %s handle %p",
530                         __func__, mono_w32handle_get_typename (type), handle);
531
532                 mono_w32handle_unlock_handle (handle);
533         }
534
535         g_ptr_array_free (internal->owned_mutexes, TRUE);
536         internal->owned_mutexes = NULL;
537 }
538
539 MonoW32HandleNamespace*
540 mono_w32mutex_get_namespace (MonoW32HandleNamedMutex *mutex)
541 {
542         return &mutex->sharedns;
543 }