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