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