[mini] bump AOT version - WrapperType changed
[mono.git] / mono / io-layer / handles.c
1 /*
2  * handles.c:  Generic and internal operations on handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002-2011 Novell, Inc.
8  * Copyright 2011 Xamarin Inc
9  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
10  */
11
12 #include <config.h>
13 #include <glib.h>
14 #include <pthread.h>
15 #include <errno.h>
16 #include <unistd.h>
17 #ifdef HAVE_SIGNAL_H
18 #include <signal.h>
19 #endif
20 #include <string.h>
21 #include <sys/types.h>
22 #ifdef HAVE_SYS_SOCKET_H
23 #  include <sys/socket.h>
24 #endif
25 #ifdef HAVE_SYS_UN_H
26 #  include <sys/un.h>
27 #endif
28 #ifdef HAVE_SYS_MMAN_H
29 #  include <sys/mman.h>
30 #endif
31 #ifdef HAVE_DIRENT_H
32 #  include <dirent.h>
33 #endif
34 #include <sys/stat.h>
35 #ifdef HAVE_SYS_RESOURCE_H
36 #  include <sys/resource.h>
37 #endif
38
39 #include <mono/io-layer/wapi.h>
40 #include <mono/io-layer/wapi-private.h>
41 #include <mono/io-layer/handles-private.h>
42 #include <mono/io-layer/shared.h>
43 #include <mono/io-layer/process-private.h>
44 #include <mono/io-layer/io-trace.h>
45
46 #include <mono/utils/mono-os-mutex.h>
47 #include <mono/utils/mono-proclib.h>
48 #include <mono/utils/mono-threads.h>
49 #include <mono/utils/mono-once.h>
50 #include <mono/utils/mono-logger-internals.h>
51 #undef DEBUG_REFS
52
53 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
54
55 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT] = { (WapiHandleCapability)0 };
56 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
57         NULL,
58         &_wapi_file_ops,
59         &_wapi_console_ops,
60         &_wapi_thread_ops,
61         &_wapi_sem_ops,
62         &_wapi_mutex_ops,
63         &_wapi_event_ops,
64 #ifndef DISABLE_SOCKETS
65         &_wapi_socket_ops,
66 #endif
67         &_wapi_find_ops,
68         &_wapi_process_ops,
69         &_wapi_pipe_ops,
70         &_wapi_namedmutex_ops,
71         &_wapi_namedsem_ops,
72         &_wapi_namedevent_ops,
73 };
74
75 static void _wapi_shared_details (gpointer handle_info);
76
77 static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
78         NULL,
79         _wapi_file_details,
80         _wapi_console_details,
81         _wapi_shared_details,   /* thread */
82         _wapi_sem_details,
83         _wapi_mutex_details,
84         _wapi_event_details,
85         NULL,                   /* Nothing useful to see in a socket handle */
86         NULL,                   /* Nothing useful to see in a find handle */
87         _wapi_shared_details,   /* process */
88         _wapi_pipe_details,
89         _wapi_shared_details,   /* namedmutex */
90         _wapi_shared_details,   /* namedsem */
91         _wapi_shared_details,   /* namedevent */
92 };
93
94 const char *_wapi_handle_typename[] = {
95         "Unused",
96         "File",
97         "Console",
98         "Thread",
99         "Sem",
100         "Mutex",
101         "Event",
102         "Socket",
103         "Find",
104         "Process",
105         "Pipe",
106         "N.Mutex",
107         "N.Sem",
108         "N.Event",
109         "Error!!"
110 };
111
112 /*
113  * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
114  * If 4M handles are not enough... Oh, well... we will crash.
115  */
116 #define SLOT_INDEX(x)   (x / _WAPI_HANDLE_INITIAL_COUNT)
117 #define SLOT_OFFSET(x)  (x % _WAPI_HANDLE_INITIAL_COUNT)
118
119 struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
120 static guint32 _wapi_private_handle_count = 0;
121 static guint32 _wapi_private_handle_slot_count = 0;
122
123 /*
124  * If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise
125  * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a
126  * 4MB array.
127  */
128 static GHashTable *file_share_hash;
129 static mono_mutex_t file_share_hash_mutex;
130
131 #define file_share_hash_lock() mono_os_mutex_lock (&file_share_hash_mutex)
132 #define file_share_hash_unlock() mono_os_mutex_unlock (&file_share_hash_mutex)
133
134 guint32 _wapi_fd_reserve;
135
136 /* 
137  * This is an internal handle which is used for handling waiting for multiple handles.
138  * Threads which wait for multiple handles wait on this one handle, and when a handle
139  * is signalled, this handle is signalled too.
140  */
141 gpointer _wapi_global_signal_handle;
142
143 /* Point to the mutex/cond inside _wapi_global_signal_handle */
144 mono_mutex_t *_wapi_global_signal_mutex;
145 mono_cond_t *_wapi_global_signal_cond;
146
147 int _wapi_sem_id;
148 gboolean _wapi_has_shut_down = FALSE;
149
150 /* Use this instead of getpid(), to cope with linuxthreads.  It's a
151  * function rather than a variable lookup because we need to get at
152  * this before share_init() might have been called.
153  */
154 static pid_t _wapi_pid;
155 static mono_once_t pid_init_once = MONO_ONCE_INIT;
156
157 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
158
159 static void pid_init (void)
160 {
161         _wapi_pid = getpid ();
162 }
163
164 pid_t _wapi_getpid (void)
165 {
166         mono_once (&pid_init_once, pid_init);
167         
168         return(_wapi_pid);
169 }
170
171
172 static mono_mutex_t scan_mutex;
173
174 static void handle_cleanup (void)
175 {
176         int i, j, k;
177         
178         /* Every shared handle we were using ought really to be closed
179          * by now, but to make sure just blow them all away.  The
180          * exiting finalizer thread in particular races us to the
181          * program exit and doesn't always win, so it can be left
182          * cluttering up the shared file.  Anything else left over is
183          * really a bug.
184          */
185         for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
186                 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
187                         struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
188                         gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
189
190                         for(k = handle_data->ref; k > 0; k--) {
191                                 _wapi_handle_unref_full (handle, TRUE);
192                         }
193                 }
194         }
195         
196         _wapi_shm_semaphores_remove ();
197
198         if (file_share_hash) {
199                 g_hash_table_destroy (file_share_hash);
200                 mono_os_mutex_destroy (&file_share_hash_mutex);
201         }
202
203         for (i = 0; i < _WAPI_PRIVATE_MAX_SLOTS; ++i)
204                 g_free (_wapi_private_handles [i]);
205 }
206
207 int
208 wapi_getdtablesize (void)
209 {
210         return eg_getdtablesize ();
211 }
212
213 /*
214  * wapi_init:
215  *
216  *   Initialize the io-layer.
217  */
218 void
219 wapi_init (void)
220 {
221         g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
222                   == WAPI_HANDLE_COUNT);
223
224         _wapi_fd_reserve = wapi_getdtablesize ();
225
226         /* This is needed by the code in _wapi_handle_new_internal */
227         _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
228
229         do {
230                 /* 
231                  * The entries in _wapi_private_handles reserved for fds are allocated lazily to 
232                  * save memory.
233                  */
234                 /*
235                 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
236                                                         _WAPI_HANDLE_INITIAL_COUNT);
237                 */
238
239                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
240                 _wapi_private_handle_slot_count ++;
241         } while(_wapi_fd_reserve > _wapi_private_handle_count);
242
243         _wapi_shm_semaphores_init ();
244
245         _wapi_io_init ();
246         mono_os_mutex_init (&scan_mutex);
247
248         _wapi_global_signal_handle = _wapi_handle_new (WAPI_HANDLE_EVENT, NULL);
249
250         _wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
251         _wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
252
253         wapi_processes_init ();
254 }
255
256 void
257 wapi_cleanup (void)
258 {
259         g_assert (_wapi_has_shut_down == FALSE);
260         
261         _wapi_has_shut_down = TRUE;
262
263         _wapi_error_cleanup ();
264         _wapi_thread_cleanup ();
265         wapi_processes_cleanup ();
266         handle_cleanup ();
267 }
268
269 static size_t _wapi_handle_struct_size (WapiHandleType type)
270 {
271         size_t type_size;
272
273         switch (type) {
274                 case WAPI_HANDLE_FILE: case WAPI_HANDLE_CONSOLE: case WAPI_HANDLE_PIPE:
275                         type_size = sizeof (struct _WapiHandle_file);
276                         break;
277                 case WAPI_HANDLE_THREAD:
278                         type_size = sizeof (struct _WapiHandle_thread);
279                         break;
280                 case WAPI_HANDLE_SEM:
281                         type_size = sizeof (struct _WapiHandle_sem);
282                         break;
283                 case WAPI_HANDLE_MUTEX:
284                         type_size = sizeof (struct _WapiHandle_mutex);
285                         break;
286                 case WAPI_HANDLE_EVENT:
287                         type_size = sizeof (struct _WapiHandle_event);
288                         break;
289                 case WAPI_HANDLE_SOCKET:
290                         type_size = sizeof (struct _WapiHandle_socket);
291                         break;
292                 case WAPI_HANDLE_FIND:
293                         type_size = sizeof (struct _WapiHandle_find);
294                         break;
295                 case WAPI_HANDLE_PROCESS:
296                         type_size = sizeof (struct _WapiHandle_process);
297                         break;
298                 case WAPI_HANDLE_NAMEDMUTEX:
299                         type_size = sizeof (struct _WapiHandle_namedmutex);
300                         break;
301                 case WAPI_HANDLE_NAMEDSEM:
302                         type_size = sizeof (struct _WapiHandle_namedsem);
303                         break;
304                 case WAPI_HANDLE_NAMEDEVENT:
305                         type_size = sizeof (struct _WapiHandle_namedevent);
306                         break;
307
308                 default:
309                         g_error ("Unknown WapiHandleType: %d\n", type);
310         }
311
312         return type_size;
313 }
314
315 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
316                                WapiHandleType type, gpointer handle_specific)
317 {
318         int thr_ret;
319         int type_size;
320         
321         g_assert (_wapi_has_shut_down == FALSE);
322         
323         handle->type = type;
324         handle->signalled = FALSE;
325         handle->ref = 1;
326         
327         thr_ret = mono_os_cond_init (&handle->signal_cond);
328         g_assert (thr_ret == 0);
329                         
330         thr_ret = mono_os_mutex_init (&handle->signal_mutex);
331         g_assert (thr_ret == 0);
332
333         if (handle_specific != NULL) {
334                 type_size = _wapi_handle_struct_size (type);
335                 memcpy (&handle->u, handle_specific,
336                         type_size);
337         }
338 }
339
340 /*
341  * _wapi_handle_new_internal:
342  * @type: Init handle to this type
343  *
344  * Search for a free handle and initialize it. Return the handle on
345  * success and 0 on failure.  This is only called from
346  * _wapi_handle_new, and scan_mutex must be held.
347  */
348 static guint32 _wapi_handle_new_internal (WapiHandleType type,
349                                           gpointer handle_specific)
350 {
351         guint32 i, k, count;
352         static guint32 last = 0;
353         gboolean retry = FALSE;
354         
355         g_assert (_wapi_has_shut_down == FALSE);
356         
357         /* A linear scan should be fast enough.  Start from the last
358          * allocation, assuming that handles are allocated more often
359          * than they're freed. Leave the space reserved for file
360          * descriptors
361          */
362         
363         if (last < _wapi_fd_reserve) {
364                 last = _wapi_fd_reserve;
365         } else {
366                 retry = TRUE;
367         }
368
369 again:
370         count = last;
371         for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
372                 if (_wapi_private_handles [i]) {
373                         for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
374                                 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
375
376                                 if(handle->type == WAPI_HANDLE_UNUSED) {
377                                         last = count + 1;
378                         
379                                         _wapi_handle_init (handle, type, handle_specific);
380                                         return (count);
381                                 }
382                                 count++;
383                         }
384                 }
385         }
386
387         if(retry && last > _wapi_fd_reserve) {
388                 /* Try again from the beginning */
389                 last = _wapi_fd_reserve;
390                 goto again;
391         }
392
393         /* Will need to expand the array.  The caller will sort it out */
394
395         return(0);
396 }
397
398 gpointer 
399 _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
400 {
401         guint32 handle_idx = 0;
402         gpointer handle;
403         int thr_ret;
404
405         g_assert (_wapi_has_shut_down == FALSE);
406                 
407         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating new handle of type %s", __func__,
408                    _wapi_handle_typename[type]);
409
410         g_assert(!_WAPI_FD_HANDLE(type));
411         
412         thr_ret = mono_os_mutex_lock (&scan_mutex);
413         g_assert (thr_ret == 0);
414                 
415         while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
416                 /* Try and expand the array, and have another go */
417                 int idx = SLOT_INDEX (_wapi_private_handle_count);
418                 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
419                         break;
420                 }
421
422                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
423                                                 _WAPI_HANDLE_INITIAL_COUNT);
424
425                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
426                 _wapi_private_handle_slot_count ++;
427         }
428         
429         thr_ret = mono_os_mutex_unlock (&scan_mutex);
430         g_assert (thr_ret == 0);
431
432         if (handle_idx == 0) {
433                 /* We ran out of slots */
434                 handle = _WAPI_HANDLE_INVALID;
435                 goto done;
436         }
437                 
438         /* Make sure we left the space for fd mappings */
439         g_assert (handle_idx >= _wapi_fd_reserve);
440         
441         handle = GUINT_TO_POINTER (handle_idx);
442
443         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Allocated new handle %p", __func__, handle);
444
445 done:
446         return(handle);
447 }
448
449 static void
450 init_handles_slot (int idx)
451 {
452         int thr_ret;
453
454         thr_ret = mono_os_mutex_lock (&scan_mutex);
455         g_assert (thr_ret == 0);
456
457         if (_wapi_private_handles [idx] == NULL) {
458                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
459                                                                                           _WAPI_HANDLE_INITIAL_COUNT);
460                 g_assert (_wapi_private_handles [idx]);
461         }
462
463         thr_ret = mono_os_mutex_unlock (&scan_mutex);
464         g_assert (thr_ret == 0);
465 }
466
467 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
468                               gpointer handle_specific)
469 {
470         struct _WapiHandleUnshared *handle;
471         int thr_ret;
472         
473         g_assert (_wapi_has_shut_down == FALSE);
474         
475         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Creating new handle of type %s", __func__,
476                    _wapi_handle_typename[type]);
477         
478         g_assert(_WAPI_FD_HANDLE(type));
479
480         if (fd >= _wapi_fd_reserve) {
481                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d is too big", __func__, fd);
482
483                 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
484         }
485
486         /* Initialize the array entries on demand */
487         if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
488                 init_handles_slot (SLOT_INDEX (fd));
489
490         handle = &_WAPI_PRIVATE_HANDLES(fd);
491         
492         if (handle->type != WAPI_HANDLE_UNUSED) {
493                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fd %d is already in use!", __func__, fd);
494                 /* FIXME: clean up this handle?  We can't do anything
495                  * with the fd, cos thats the new one
496                  */
497         }
498
499         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Assigning new fd handle %d", __func__, fd);
500
501         /* Prevent file share entries racing with us, when the file
502          * handle is only half initialised
503          */
504         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
505         g_assert(thr_ret == 0);
506
507         _wapi_handle_init (handle, type, handle_specific);
508
509         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
510
511         return(GUINT_TO_POINTER(fd));
512 }
513
514 gboolean 
515 _wapi_lookup_handle (gpointer handle, WapiHandleType type,
516                               gpointer *handle_specific)
517 {
518         struct _WapiHandleUnshared *handle_data;
519         guint32 handle_idx = GPOINTER_TO_UINT(handle);
520
521         if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
522                 return(FALSE);
523         }
524
525         /* Initialize the array entries on demand */
526         if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
527                 init_handles_slot (SLOT_INDEX (handle_idx));
528         
529         handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
530         
531         if (handle_data->type != type) {
532                 return(FALSE);
533         }
534
535         if (handle_specific == NULL) {
536                 return(FALSE);
537         }
538         
539         *handle_specific = &handle_data->u;
540         
541         return(TRUE);
542 }
543
544 void
545 _wapi_handle_foreach (WapiHandleType type,
546                         gboolean (*on_each)(gpointer test, gpointer user),
547                         gpointer user_data)
548 {
549         struct _WapiHandleUnshared *handle_data = NULL;
550         gpointer ret = NULL;
551         guint32 i, k;
552         int thr_ret;
553
554         thr_ret = mono_os_mutex_lock (&scan_mutex);
555         g_assert (thr_ret == 0);
556
557         for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
558                 if (_wapi_private_handles [i]) {
559                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
560                                 handle_data = &_wapi_private_handles [i][k];
561                         
562                                 if (handle_data->type == type) {
563                                         ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
564                                         if (on_each (ret, user_data) == TRUE)
565                                                 break;
566                                 }
567                         }
568                 }
569         }
570
571         thr_ret = mono_os_mutex_unlock (&scan_mutex);
572         g_assert (thr_ret == 0);
573 }
574
575 /* This might list some shared handles twice if they are already
576  * opened by this process, and the check function returns FALSE the
577  * first time.  Shared handles that are created during the search are
578  * unreffed if the check function returns FALSE, so callers must not
579  * rely on the handle persisting (unless the check function returns
580  * TRUE)
581  * The caller owns the returned handle.
582  */
583 gpointer _wapi_search_handle (WapiHandleType type,
584                               gboolean (*check)(gpointer test, gpointer user),
585                               gpointer user_data,
586                               gpointer *handle_specific,
587                               gboolean search_shared)
588 {
589         struct _WapiHandleUnshared *handle_data = NULL;
590         gpointer ret = NULL;
591         guint32 i, k;
592         gboolean found = FALSE;
593         int thr_ret;
594
595         thr_ret = mono_os_mutex_lock (&scan_mutex);
596         g_assert (thr_ret == 0);
597         
598         for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
599                 if (_wapi_private_handles [i]) {
600                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
601                                 handle_data = &_wapi_private_handles [i][k];
602                 
603                                 if (handle_data->type == type) {
604                                         ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
605                                         if (check (ret, user_data) == TRUE) {
606                                                 _wapi_handle_ref (ret);
607                                                 found = TRUE;
608                                                 break;
609                                         }
610                                 }
611                         }
612                 }
613         }
614
615         thr_ret = mono_os_mutex_unlock (&scan_mutex);
616         g_assert (thr_ret == 0);
617
618         if (!found) {
619                 ret = NULL;
620                 goto done;
621         }
622         
623         if(handle_specific != NULL) {
624                 *handle_specific = &handle_data->u;
625         }
626
627 done:
628         return(ret);
629 }
630
631 /* Returns the offset of the metadata array, or _WAPI_HANDLE_INVALID on error, or NULL for
632  * not found
633  */
634 gpointer _wapi_search_handle_namespace (WapiHandleType type,
635                                       gchar *utf8_name)
636 {
637         struct _WapiHandleUnshared *handle_data;
638         guint32 i, k;
639         gpointer ret = NULL;
640         int thr_ret;
641         
642         g_assert(_WAPI_SHARED_NAMESPACE(type));
643         
644         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Lookup for handle named [%s] type %s", __func__,
645                    utf8_name, _wapi_handle_typename[type]);
646
647         thr_ret = mono_os_mutex_lock (&scan_mutex);
648         g_assert (thr_ret == 0);
649         
650         for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
651                 if (!_wapi_private_handles [i])
652                         continue;
653                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
654                         WapiSharedNamespace *sharedns;
655                         
656                         handle_data = &_wapi_private_handles [i][k];
657
658                         /* Check mutex, event, semaphore, timer, job and
659                          * file-mapping object names.  So far only mutex,
660                          * semaphore and event are implemented.
661                          */
662                         if (!_WAPI_SHARED_NAMESPACE (handle_data->type)) {
663                                 continue;
664                         }
665
666                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[handle_data->type]);
667
668                         sharedns=(WapiSharedNamespace *)&handle_data->u;
669                                 
670                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: name is [%s]", __func__, sharedns->name);
671
672                         if (strcmp (sharedns->name, utf8_name) == 0) {
673                                 if (handle_data->type != type) {
674                                         /* Its the wrong type, so fail now */
675                                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[handle_data->type]);
676                                         ret = _WAPI_HANDLE_INVALID;
677                                         goto done;
678                                 } else {
679                                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle 0x%x matches name and type", __func__, i);
680                                         ret = handle_data;
681                                         goto done;
682                                 }
683                         }
684                 }
685         }
686
687 done:
688         thr_ret = mono_os_mutex_unlock (&scan_mutex);
689         g_assert (thr_ret == 0);
690         
691         return(ret);
692 }
693
694 void _wapi_handle_ref (gpointer handle)
695 {
696         guint32 idx = GPOINTER_TO_UINT(handle);
697         struct _WapiHandleUnshared *handle_data;
698
699         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
700                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Attempting to ref invalid private handle %p", __func__, handle);
701                 return;
702         }
703         
704         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
705                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Attempting to ref unused handle %p", __func__, handle);
706                 return;
707         }
708
709         handle_data = &_WAPI_PRIVATE_HANDLES(idx);
710         
711         InterlockedIncrement ((gint32 *)&handle_data->ref);
712         
713 #ifdef DEBUG_REFS
714         g_message ("%s: %s handle %p ref now %d", __func__, 
715                    _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
716                    handle,
717                    _WAPI_PRIVATE_HANDLES(idx).ref);
718 #endif
719 }
720
721 /* The handle must not be locked on entry to this function */
722 static void _wapi_handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
723 {
724         guint32 idx = GPOINTER_TO_UINT(handle);
725         gboolean destroy = FALSE, early_exit = FALSE;
726         int thr_ret;
727
728         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
729                 return;
730         }
731         
732         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
733                 g_warning ("%s: Attempting to unref unused handle %p",
734                            __func__, handle);
735                 return;
736         }
737
738         /* Possible race condition here if another thread refs the
739          * handle between here and setting the type to UNUSED.  I
740          * could lock a mutex, but I'm not sure that allowing a handle
741          * reference to reach 0 isn't an application bug anyway.
742          */
743         destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
744         
745 #ifdef DEBUG_REFS
746         g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
747                    _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
748                    handle,
749                    _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
750 #endif
751         
752         if(destroy==TRUE) {
753                 /* Need to copy the handle info, reset the slot in the
754                  * array, and _only then_ call the close function to
755                  * avoid race conditions (eg file descriptors being
756                  * closed, and another file being opened getting the
757                  * same fd racing the memset())
758                  */
759                 struct _WapiHandleUnshared handle_data;
760                 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
761                 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
762
763                 thr_ret = mono_os_mutex_lock (&scan_mutex);
764
765                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Destroying handle %p", __func__, handle);
766                 
767                 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
768                         sizeof (struct _WapiHandleUnshared));
769
770                 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
771                         sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
772
773                 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
774
775                 /* Destroy the mutex and cond var.  We hope nobody
776                  * tried to grab them between the handle unlock and
777                  * now, but pthreads doesn't have a
778                  * "unlock_and_destroy" atomic function.
779                  */
780                 thr_ret = mono_os_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
781                 /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
782                 if (thr_ret == EBUSY && ignore_private_busy_handles) {
783                         early_exit = TRUE;
784                 } else {
785                         if (thr_ret != 0)
786                                 g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
787
788                         thr_ret = mono_os_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
789                         if (thr_ret == EBUSY && ignore_private_busy_handles)
790                                 early_exit = TRUE;
791                         else if (thr_ret != 0)
792                                 g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
793                 }
794
795                 thr_ret = mono_os_mutex_unlock (&scan_mutex);
796                 g_assert (thr_ret == 0);
797
798                 if (early_exit)
799                         return;
800                 
801                 if (close_func != NULL) {
802                         close_func (handle, &handle_data.u);
803                 }
804         }
805 }
806
807 void _wapi_handle_unref (gpointer handle)
808 {
809         _wapi_handle_unref_full (handle, FALSE);
810 }
811
812 void _wapi_handle_register_capabilities (WapiHandleType type,
813                                          WapiHandleCapability caps)
814 {
815         handle_caps[type] = caps;
816 }
817
818 gboolean _wapi_handle_test_capabilities (gpointer handle,
819                                          WapiHandleCapability caps)
820 {
821         guint32 idx = GPOINTER_TO_UINT(handle);
822         WapiHandleType type;
823
824         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
825                 return(FALSE);
826         }
827         
828         type = _WAPI_PRIVATE_HANDLES(idx).type;
829
830         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: testing 0x%x against 0x%x (%d)", __func__,
831                    handle_caps[type], caps, handle_caps[type] & caps);
832         
833         return((handle_caps[type] & caps) != 0);
834 }
835
836 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
837 {
838         if (handle_ops[type] != NULL &&
839             handle_ops[type]->close != NULL) {
840                 return (handle_ops[type]->close);
841         }
842
843         return (NULL);
844 }
845
846 void _wapi_handle_ops_close (gpointer handle, gpointer data)
847 {
848         guint32 idx = GPOINTER_TO_UINT(handle);
849         WapiHandleType type;
850
851         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
852                 return;
853         }
854         
855         type = _WAPI_PRIVATE_HANDLES(idx).type;
856
857         if (handle_ops[type] != NULL &&
858             handle_ops[type]->close != NULL) {
859                 handle_ops[type]->close (handle, data);
860         }
861 }
862
863 void _wapi_handle_ops_signal (gpointer handle)
864 {
865         guint32 idx = GPOINTER_TO_UINT(handle);
866         WapiHandleType type;
867
868         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
869                 return;
870         }
871         
872         type = _WAPI_PRIVATE_HANDLES(idx).type;
873
874         if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
875                 handle_ops[type]->signal (handle);
876         }
877 }
878
879 gboolean _wapi_handle_ops_own (gpointer handle)
880 {
881         guint32 idx = GPOINTER_TO_UINT(handle);
882         WapiHandleType type;
883         
884         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
885                 return(FALSE);
886         }
887         
888         type = _WAPI_PRIVATE_HANDLES(idx).type;
889
890         if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
891                 return(handle_ops[type]->own_handle (handle));
892         } else {
893                 return(FALSE);
894         }
895 }
896
897 gboolean _wapi_handle_ops_isowned (gpointer handle)
898 {
899         guint32 idx = GPOINTER_TO_UINT(handle);
900         WapiHandleType type;
901
902         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
903                 return(FALSE);
904         }
905         
906         type = _WAPI_PRIVATE_HANDLES(idx).type;
907
908         if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
909                 return(handle_ops[type]->is_owned (handle));
910         } else {
911                 return(FALSE);
912         }
913 }
914
915 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout, gboolean alertable)
916 {
917         guint32 idx = GPOINTER_TO_UINT(handle);
918         WapiHandleType type;
919         
920         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
921                 return(WAIT_FAILED);
922         }
923         
924         type = _WAPI_PRIVATE_HANDLES(idx).type;
925         
926         if (handle_ops[type] != NULL &&
927             handle_ops[type]->special_wait != NULL) {
928                 return(handle_ops[type]->special_wait (handle, timeout, alertable));
929         } else {
930                 return(WAIT_FAILED);
931         }
932 }
933
934 void _wapi_handle_ops_prewait (gpointer handle)
935 {
936         guint32 idx = GPOINTER_TO_UINT (handle);
937         WapiHandleType type;
938         
939         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
940                 return;
941         }
942         
943         type = _WAPI_PRIVATE_HANDLES (idx).type;
944         
945         if (handle_ops[type] != NULL &&
946             handle_ops[type]->prewait != NULL) {
947                 handle_ops[type]->prewait (handle);
948         }
949 }
950
951
952 /**
953  * CloseHandle:
954  * @handle: The handle to release
955  *
956  * Closes and invalidates @handle, releasing any resources it
957  * consumes.  When the last handle to a temporary or non-persistent
958  * object is closed, that object can be deleted.  Closing the same
959  * handle twice is an error.
960  *
961  * Return value: %TRUE on success, %FALSE otherwise.
962  */
963 gboolean CloseHandle(gpointer handle)
964 {
965         if (handle == NULL) {
966                 /* Problem: because we map file descriptors to the
967                  * same-numbered handle we can't tell the difference
968                  * between a bogus handle and the handle to stdin.
969                  * Assume that it's the console handle if that handle
970                  * exists...
971                  */
972                 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
973                         SetLastError (ERROR_INVALID_PARAMETER);
974                         return(FALSE);
975                 }
976         }
977         if (handle == _WAPI_HANDLE_INVALID){
978                 SetLastError (ERROR_INVALID_PARAMETER);
979                 return(FALSE);
980         }
981         
982         _wapi_handle_unref (handle);
983         
984         return(TRUE);
985 }
986
987 /* Lots more to implement here, but this is all we need at the moment */
988 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
989                           gpointer targetprocess, gpointer *target,
990                           guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
991 {
992         if (srcprocess != _WAPI_PROCESS_CURRENT ||
993             targetprocess != _WAPI_PROCESS_CURRENT) {
994                 /* Duplicating other process's handles is not supported */
995                 SetLastError (ERROR_INVALID_HANDLE);
996                 return(FALSE);
997         }
998         
999         if (src == _WAPI_PROCESS_CURRENT) {
1000                 *target = _wapi_process_duplicate ();
1001         } else if (src == _WAPI_THREAD_CURRENT) {
1002                 g_assert_not_reached ();
1003         } else {
1004                 _wapi_handle_ref (src);
1005                 *target = src;
1006         }
1007         
1008         return(TRUE);
1009 }
1010
1011 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1012                                                gpointer *handles,
1013                                                gboolean waitall,
1014                                                guint32 *retcount,
1015                                                guint32 *lowest)
1016 {
1017         guint32 count, i, iter=0;
1018         gboolean ret;
1019         int thr_ret;
1020         WapiHandleType type;
1021         
1022         /* Lock all the handles, with backoff */
1023 again:
1024         for(i=0; i<numhandles; i++) {
1025                 gpointer handle = handles[i];
1026                 guint32 idx = GPOINTER_TO_UINT(handle);
1027
1028                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempting to lock %p", __func__, handle);
1029
1030                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1031
1032                 thr_ret = _wapi_handle_trylock_handle (handle);
1033                 
1034                 if (thr_ret != 0) {
1035                         /* Bummer */
1036                         
1037                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: attempt failed for %p: %s", __func__,
1038                                    handle, strerror (thr_ret));
1039
1040                         while (i--) {
1041                                 handle = handles[i];
1042                                 idx = GPOINTER_TO_UINT(handle);
1043
1044                                 thr_ret = _wapi_handle_unlock_handle (handle);
1045                                 g_assert (thr_ret == 0);
1046                         }
1047
1048                         /* If iter ever reaches 100 the nanosleep will
1049                          * return EINVAL immediately, but we have a
1050                          * design flaw if that happens.
1051                          */
1052                         iter++;
1053                         if(iter==100) {
1054                                 g_warning ("%s: iteration overflow!",
1055                                            __func__);
1056                                 iter=1;
1057                         }
1058                         
1059                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Backing off for %d ms", __func__,
1060                                    iter*10);
1061                         _wapi_handle_spin (10 * iter);
1062                         
1063                         goto again;
1064                 }
1065         }
1066         
1067         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Locked all handles", __func__);
1068
1069         count=0;
1070         *lowest=numhandles;
1071         
1072         for(i=0; i<numhandles; i++) {
1073                 gpointer handle = handles[i];
1074                 guint32 idx = GPOINTER_TO_UINT(handle);
1075                 
1076                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1077
1078                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Checking handle %p", __func__, handle);
1079
1080                 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1081                     (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1082                    (_wapi_handle_issignalled (handle))) {
1083                         count++;
1084                         
1085                         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %p signalled", __func__,
1086                                    handle);
1087                         if(*lowest>i) {
1088                                 *lowest=i;
1089                         }
1090                 }
1091         }
1092         
1093         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %d event handles signalled", __func__, count);
1094
1095         if ((waitall == TRUE && count == numhandles) ||
1096             (waitall == FALSE && count > 0)) {
1097                 ret=TRUE;
1098         } else {
1099                 ret=FALSE;
1100         }
1101         
1102         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning %d", __func__, ret);
1103
1104         *retcount=count;
1105         
1106         return(ret);
1107 }
1108
1109 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1110 {
1111         guint32 i;
1112         int thr_ret;
1113         
1114         for(i=0; i<numhandles; i++) {
1115                 gpointer handle = handles[i];
1116                 
1117                 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking handle %p", __func__, handle);
1118
1119                 thr_ret = _wapi_handle_unlock_handle (handle);
1120                 g_assert (thr_ret == 0);
1121         }
1122 }
1123
1124 static void
1125 signal_handle_and_unref (gpointer handle)
1126 {
1127         mono_cond_t *cond;
1128         mono_mutex_t *mutex;
1129         guint32 idx;
1130
1131         g_assert (handle);
1132
1133         /* If we reach here, then interrupt token is set to the flag value, which
1134          * means that the target thread is either
1135          * - before the first CAS in timedwait, which means it won't enter the wait.
1136          * - it is after the first CAS, so it is already waiting, or it will enter
1137          *    the wait, and it will be interrupted by the broadcast. */
1138         idx = GPOINTER_TO_UINT (handle);
1139         cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1140         mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1141
1142         mono_os_mutex_lock (mutex);
1143         mono_os_cond_broadcast (cond);
1144         mono_os_mutex_unlock (mutex);
1145
1146         _wapi_handle_unref (handle);
1147 }
1148
1149 int
1150 _wapi_handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean poll, gboolean *alerted)
1151 {
1152         guint32 idx;
1153         int res;
1154         mono_cond_t *cond;
1155         mono_mutex_t *mutex;
1156
1157         MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: waiting for %p (type %s)", __func__, handle,
1158                    _wapi_handle_typename[_wapi_handle_type (handle)]);
1159
1160         if (alerted)
1161                 *alerted = FALSE;
1162
1163         idx = GPOINTER_TO_UINT(handle);
1164
1165         if (alerted) {
1166                 mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
1167                 if (*alerted)
1168                         return 0;
1169                 _wapi_handle_ref (handle);
1170         }
1171
1172         cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1173         mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1174
1175         if (!poll) {
1176                 res = mono_os_cond_timedwait (cond, mutex, timeout);
1177         } else {
1178                 /* This is needed when waiting for process handles */
1179                 if (!alerted) {
1180                         /*
1181                          * pthread_cond_(timed)wait() can return 0 even if the condition was not
1182                          * signalled.  This happens at least on Darwin.  We surface this, i.e., we
1183                          * get spurious wake-ups.
1184                          *
1185                          * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
1186                          */
1187                         res = mono_os_cond_timedwait (cond, mutex, timeout);
1188                 } else {
1189                         if (timeout < 100) {
1190                                 /* Real timeout is less than 100ms time */
1191                                 res = mono_os_cond_timedwait (cond, mutex, timeout);
1192                         } else {
1193                                 res = mono_os_cond_timedwait (cond, mutex, 100);
1194
1195                                 /* Mask the fake timeout, this will cause
1196                                  * another poll if the cond was not really signaled
1197                                  */
1198                                 if (res == ETIMEDOUT)
1199                                         res = 0;
1200                         }
1201                 }
1202         }
1203
1204         if (alerted) {
1205                 mono_thread_info_uninstall_interrupt (alerted);
1206                 if (!*alerted) {
1207                         /* if it is alerted, then the handle is unref in the interrupt callback */
1208                         _wapi_handle_unref (handle);
1209                 }
1210         }
1211
1212         return res;
1213 }
1214
1215 void
1216 _wapi_free_share_info (_WapiFileShare *share_info)
1217 {
1218         file_share_hash_lock ();
1219         g_hash_table_remove (file_share_hash, share_info);
1220         file_share_hash_unlock ();
1221         /* The hashtable dtor frees share_info */
1222 }
1223
1224 static gint
1225 wapi_share_info_equal (gconstpointer ka, gconstpointer kb)
1226 {
1227         const _WapiFileShare *s1 = (const _WapiFileShare *)ka;
1228         const _WapiFileShare *s2 = (const _WapiFileShare *)kb;
1229
1230         return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
1231 }
1232
1233 static guint
1234 wapi_share_info_hash (gconstpointer data)
1235 {
1236         const _WapiFileShare *s = (const _WapiFileShare *)data;
1237
1238         return s->inode;
1239 }
1240
1241 gboolean _wapi_handle_get_or_set_share (guint64 device, guint64 inode,
1242                                         guint32 new_sharemode,
1243                                         guint32 new_access,
1244                                         guint32 *old_sharemode,
1245                                         guint32 *old_access,
1246                                         struct _WapiFileShare **share_info)
1247 {
1248         struct _WapiFileShare *file_share;
1249         int thr_ret;
1250         gboolean exists = FALSE;
1251
1252         /* Prevent new entries racing with us */
1253         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1254         g_assert (thr_ret == 0);
1255
1256         _WapiFileShare tmp;
1257
1258         /*
1259          * Instead of allocating a 4MB array, we use a hash table to keep track of this
1260          * info. This is needed even if SHM is disabled, to track sharing inside
1261          * the current process.
1262          */
1263         if (!file_share_hash) {
1264                 file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
1265                 mono_os_mutex_init_recursive (&file_share_hash_mutex);
1266         }
1267
1268         tmp.device = device;
1269         tmp.inode = inode;
1270
1271         file_share_hash_lock ();
1272
1273         file_share = (_WapiFileShare *)g_hash_table_lookup (file_share_hash, &tmp);
1274         if (file_share) {
1275                 *old_sharemode = file_share->sharemode;
1276                 *old_access = file_share->access;
1277                 *share_info = file_share;
1278
1279                 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1280                 exists = TRUE;
1281         } else {
1282                 file_share = g_new0 (_WapiFileShare, 1);
1283
1284                 file_share->device = device;
1285                 file_share->inode = inode;
1286                 file_share->opened_by_pid = _wapi_getpid ();
1287                 file_share->sharemode = new_sharemode;
1288                 file_share->access = new_access;
1289                 file_share->handle_refs = 1;
1290                 *share_info = file_share;
1291
1292                 g_hash_table_insert (file_share_hash, file_share, file_share);
1293         }
1294
1295         file_share_hash_unlock ();
1296         
1297         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1298
1299         return(exists);
1300 }
1301
1302 void _wapi_handle_dump (void)
1303 {
1304         struct _WapiHandleUnshared *handle_data;
1305         guint32 i, k;
1306         int thr_ret;
1307         
1308         thr_ret = mono_os_mutex_lock (&scan_mutex);
1309         g_assert (thr_ret == 0);
1310         
1311         for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1312                 if (_wapi_private_handles [i]) {
1313                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1314                                 handle_data = &_wapi_private_handles [i][k];
1315
1316                                 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1317                                         continue;
1318                                 }
1319                 
1320                                 g_print ("%3x [%7s] %s %d ",
1321                                                  i * _WAPI_HANDLE_INITIAL_COUNT + k,
1322                                                  _wapi_handle_typename[handle_data->type],
1323                                                  handle_data->signalled?"Sg":"Un",
1324                                                  handle_data->ref);
1325                                 if (handle_details[handle_data->type])
1326                                         handle_details[handle_data->type](&handle_data->u);
1327                                 g_print ("\n");
1328                         }
1329                 }
1330         }
1331
1332         thr_ret = mono_os_mutex_unlock (&scan_mutex);
1333         g_assert (thr_ret == 0);
1334 }
1335
1336 static void _wapi_shared_details (gpointer handle_info)
1337 {
1338         struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1339         
1340         g_print ("offset: 0x%x", shared->offset);
1341 }