Merge pull request #2961 from schani/fix-sgen-refactoring
[mono.git] / mono / utils / w32handle.c
1 /*
2  * w32handle.c:  Generic and internal operations on handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *      Ludovic Henry (luhenry@microsoft.com)
7  *
8  * (C) 2002-2011 Novell, Inc.
9  * Copyright 2011 Xamarin Inc
10  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11  */
12
13 #include <config.h>
14
15 #if !defined(HOST_WIN32)
16
17 #include <glib.h>
18 #include <pthread.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #ifdef HAVE_SIGNAL_H
22 #include <signal.h>
23 #endif
24 #include <string.h>
25 #include <sys/types.h>
26 #ifdef HAVE_SYS_SOCKET_H
27 #  include <sys/socket.h>
28 #endif
29 #ifdef HAVE_SYS_UN_H
30 #  include <sys/un.h>
31 #endif
32 #ifdef HAVE_SYS_MMAN_H
33 #  include <sys/mman.h>
34 #endif
35 #ifdef HAVE_DIRENT_H
36 #  include <dirent.h>
37 #endif
38 #include <sys/stat.h>
39 #ifdef HAVE_SYS_RESOURCE_H
40 #  include <sys/resource.h>
41 #endif
42
43 #include "w32handle.h"
44
45 #include "atomic.h"
46 #include "mono-logger-internals.h"
47 #include "mono-os-mutex.h"
48 #include "mono-proclib.h"
49 #include "mono-threads.h"
50
51 #undef DEBUG_REFS
52
53 #define SLOT_MAX                (1024 * 16)
54
55 /* must be a power of 2 */
56 #define HANDLE_PER_SLOT (256)
57
58 typedef struct {
59         MonoW32HandleType type;
60         guint ref;
61         gboolean signalled;
62         mono_mutex_t signal_mutex;
63         mono_cond_t signal_cond;
64         gpointer specific;
65 } MonoW32HandleBase;
66
67 static MonoW32HandleCapability handle_caps [MONO_W32HANDLE_COUNT];
68 static MonoW32HandleOps *handle_ops [MONO_W32HANDLE_COUNT];
69
70 /*
71  * We can hold SLOT_MAX * HANDLE_PER_SLOT handles.
72  * If 4M handles are not enough... Oh, well... we will crash.
73  */
74 #define SLOT_INDEX(x)   (x / HANDLE_PER_SLOT)
75 #define SLOT_OFFSET(x)  (x % HANDLE_PER_SLOT)
76
77 static MonoW32HandleBase *private_handles [SLOT_MAX];
78 static guint32 private_handles_count = 0;
79 static guint32 private_handles_slots_count = 0;
80
81 guint32 mono_w32handle_fd_reserve;
82
83 /*
84  * This is an internal handle which is used for handling waiting for multiple handles.
85  * Threads which wait for multiple handles wait on this one handle, and when a handle
86  * is signalled, this handle is signalled too.
87  */
88 static mono_mutex_t global_signal_mutex;
89 static mono_cond_t global_signal_cond;
90
91 static mono_mutex_t scan_mutex;
92
93 static gboolean shutting_down = FALSE;
94
95 static gboolean
96 type_is_fd (MonoW32HandleType type)
97 {
98         switch (type) {
99         case MONO_W32HANDLE_FILE:
100         case MONO_W32HANDLE_CONSOLE:
101         case MONO_W32HANDLE_SOCKET:
102         case MONO_W32HANDLE_PIPE:
103                 return TRUE;
104         default:
105                 return FALSE;
106         }
107 }
108
109 static gboolean
110 mono_w32handle_lookup_data (gpointer handle, MonoW32HandleBase **handle_data)
111 {
112         gsize index, offset;
113
114         g_assert (handle_data);
115
116         index = SLOT_INDEX ((gsize) handle);
117         if (index >= SLOT_MAX)
118                 return FALSE;
119         if (!private_handles [index])
120                 return FALSE;
121
122         offset = SLOT_OFFSET ((gsize) handle);
123         if (private_handles [index][offset].type == MONO_W32HANDLE_UNUSED)
124                 return FALSE;
125
126         *handle_data = &private_handles [index][offset];
127         return TRUE;
128 }
129
130 MonoW32HandleType
131 mono_w32handle_get_type (gpointer handle)
132 {
133         MonoW32HandleBase *handle_data;
134
135         if (!mono_w32handle_lookup_data (handle, &handle_data))
136                 return MONO_W32HANDLE_UNUSED;   /* An impossible type */
137
138         return handle_data->type;
139 }
140
141 void
142 mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast)
143 {
144         MonoW32HandleBase *handle_data;
145
146         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
147                 return;
148         }
149
150 #ifdef DEBUG
151         g_message ("%s: setting state of %p to %s (broadcast %s)", __func__,
152                    handle, state?"TRUE":"FALSE", broadcast?"TRUE":"FALSE");
153 #endif
154
155         if (state == TRUE) {
156                 /* Tell everyone blocking on a single handle */
157
158                 /* The condition the global signal cond is waiting on is the signalling of
159                  * _any_ handle. So lock it before setting the signalled state.
160                  */
161                 mono_os_mutex_lock (&global_signal_mutex);
162
163                 /* This function _must_ be called with
164                  * handle->signal_mutex locked
165                  */
166                 handle_data->signalled=state;
167
168                 if (broadcast == TRUE) {
169                         mono_os_cond_broadcast (&handle_data->signal_cond);
170                 } else {
171                         mono_os_cond_signal (&handle_data->signal_cond);
172                 }
173
174                 /* Tell everyone blocking on multiple handles that something
175                  * was signalled
176                  */
177                 mono_os_cond_broadcast (&global_signal_cond);
178
179                 mono_os_mutex_unlock (&global_signal_mutex);
180         } else {
181                 handle_data->signalled=state;
182         }
183 }
184
185 gboolean
186 mono_w32handle_issignalled (gpointer handle)
187 {
188         MonoW32HandleBase *handle_data;
189
190         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
191                 return(FALSE);
192         }
193
194         return handle_data->signalled;
195 }
196
197 int
198 mono_w32handle_lock_signal_mutex (void)
199 {
200 #ifdef DEBUG
201         g_message ("%s: lock global signal mutex", __func__);
202 #endif
203
204         mono_os_mutex_lock (&global_signal_mutex);
205
206         return 0;
207 }
208
209 int
210 mono_w32handle_unlock_signal_mutex (void)
211 {
212 #ifdef DEBUG
213         g_message ("%s: unlock global signal mutex", __func__);
214 #endif
215
216         mono_os_mutex_unlock (&global_signal_mutex);
217
218         return 0;
219 }
220
221 int
222 mono_w32handle_lock_handle (gpointer handle)
223 {
224         MonoW32HandleBase *handle_data;
225
226 #ifdef DEBUG
227         g_message ("%s: locking handle %p", __func__, handle);
228 #endif
229
230         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
231                 return(0);
232         }
233
234         mono_w32handle_ref (handle);
235
236         mono_os_mutex_lock (&handle_data->signal_mutex);
237
238         return 0;
239 }
240
241 int
242 mono_w32handle_trylock_handle (gpointer handle)
243 {
244         MonoW32HandleBase *handle_data;
245         int ret;
246
247 #ifdef DEBUG
248         g_message ("%s: locking handle %p", __func__, handle);
249 #endif
250
251         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
252                 return(0);
253         }
254
255         mono_w32handle_ref (handle);
256
257         ret = mono_os_mutex_trylock (&handle_data->signal_mutex);
258         if (ret != 0) {
259                 mono_w32handle_unref (handle);
260         }
261
262         return(ret);
263 }
264
265 int
266 mono_w32handle_unlock_handle (gpointer handle)
267 {
268         MonoW32HandleBase *handle_data;
269
270 #ifdef DEBUG
271         g_message ("%s: unlocking handle %p", __func__, handle);
272 #endif
273
274         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
275                 return(0);
276         }
277
278         mono_os_mutex_unlock (&handle_data->signal_mutex);
279
280         mono_w32handle_unref (handle);
281
282         return 0;
283 }
284
285 /*
286  * wapi_init:
287  *
288  *   Initialize the io-layer.
289  */
290 void
291 mono_w32handle_init (void)
292 {
293         g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
294                   == MONO_W32HANDLE_COUNT);
295
296         /* This is needed by the code in mono_w32handle_new_internal */
297         mono_w32handle_fd_reserve = (eg_getdtablesize () + (HANDLE_PER_SLOT - 1)) & ~(HANDLE_PER_SLOT - 1);
298
299         do {
300                 /*
301                  * The entries in private_handles reserved for fds are allocated lazily to
302                  * save memory.
303                  */
304
305                 private_handles_count += HANDLE_PER_SLOT;
306                 private_handles_slots_count ++;
307         } while(mono_w32handle_fd_reserve > private_handles_count);
308
309         mono_os_mutex_init (&scan_mutex);
310
311         mono_os_cond_init (&global_signal_cond);
312         mono_os_mutex_init (&global_signal_mutex);
313 }
314
315 static void mono_w32handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles);
316
317 void
318 mono_w32handle_cleanup (void)
319 {
320         int i, j, k;
321
322         g_assert (!shutting_down);
323         shutting_down = TRUE;
324
325         /* Every shared handle we were using ought really to be closed
326          * by now, but to make sure just blow them all away.  The
327          * exiting finalizer thread in particular races us to the
328          * program exit and doesn't always win, so it can be left
329          * cluttering up the shared file.  Anything else left over is
330          * really a bug.
331          */
332         for(i = SLOT_INDEX (0); private_handles[i] != NULL; i++) {
333                 for(j = SLOT_OFFSET (0); j < HANDLE_PER_SLOT; j++) {
334                         MonoW32HandleBase *handle_data = &private_handles[i][j];
335                         gpointer handle = GINT_TO_POINTER (i*HANDLE_PER_SLOT+j);
336
337                         for(k = handle_data->ref; k > 0; k--) {
338                                 mono_w32handle_unref_full (handle, TRUE);
339                         }
340                 }
341         }
342
343         for (i = 0; i < SLOT_MAX; ++i)
344                 g_free (private_handles [i]);
345 }
346
347 static void mono_w32handle_init_handle (MonoW32HandleBase *handle,
348                                MonoW32HandleType type, gpointer handle_specific)
349 {
350         g_assert (!shutting_down);
351         
352         handle->type = type;
353         handle->signalled = FALSE;
354         handle->ref = 1;
355
356         mono_os_cond_init (&handle->signal_cond);
357         mono_os_mutex_init (&handle->signal_mutex);
358
359         if (handle_specific)
360                 handle->specific = g_memdup (handle_specific, mono_w32handle_ops_typesize (type));
361 }
362
363 /*
364  * mono_w32handle_new_internal:
365  * @type: Init handle to this type
366  *
367  * Search for a free handle and initialize it. Return the handle on
368  * success and 0 on failure.  This is only called from
369  * mono_w32handle_new, and scan_mutex must be held.
370  */
371 static guint32 mono_w32handle_new_internal (MonoW32HandleType type,
372                                           gpointer handle_specific)
373 {
374         guint32 i, k, count;
375         static guint32 last = 0;
376         gboolean retry = FALSE;
377         
378         g_assert (!shutting_down);
379         
380         /* A linear scan should be fast enough.  Start from the last
381          * allocation, assuming that handles are allocated more often
382          * than they're freed. Leave the space reserved for file
383          * descriptors
384          */
385
386         if (last < mono_w32handle_fd_reserve) {
387                 last = mono_w32handle_fd_reserve;
388         } else {
389                 retry = TRUE;
390         }
391
392 again:
393         count = last;
394         for(i = SLOT_INDEX (count); i < private_handles_slots_count; i++) {
395                 if (private_handles [i]) {
396                         for (k = SLOT_OFFSET (count); k < HANDLE_PER_SLOT; k++) {
397                                 MonoW32HandleBase *handle = &private_handles [i][k];
398
399                                 if(handle->type == MONO_W32HANDLE_UNUSED) {
400                                         last = count + 1;
401
402                                         mono_w32handle_init_handle (handle, type, handle_specific);
403                                         return (count);
404                                 }
405                                 count++;
406                         }
407                 }
408         }
409
410         if(retry && last > mono_w32handle_fd_reserve) {
411                 /* Try again from the beginning */
412                 last = mono_w32handle_fd_reserve;
413                 goto again;
414         }
415
416         /* Will need to expand the array.  The caller will sort it out */
417
418         return(0);
419 }
420
421 gpointer
422 mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific)
423 {
424         guint32 handle_idx = 0;
425         gpointer handle;
426
427         g_assert (!shutting_down);
428
429         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Creating new handle of type %s", __func__,
430                    mono_w32handle_ops_typename (type));
431
432         g_assert(!type_is_fd(type));
433
434         mono_os_mutex_lock (&scan_mutex);
435
436         while ((handle_idx = mono_w32handle_new_internal (type, handle_specific)) == 0) {
437                 /* Try and expand the array, and have another go */
438                 int idx = SLOT_INDEX (private_handles_count);
439                 if (idx >= SLOT_MAX) {
440                         break;
441                 }
442
443                 private_handles [idx] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT);
444
445                 private_handles_count += HANDLE_PER_SLOT;
446                 private_handles_slots_count ++;
447         }
448
449         mono_os_mutex_unlock (&scan_mutex);
450
451         if (handle_idx == 0) {
452                 /* We ran out of slots */
453                 handle = INVALID_HANDLE_VALUE;
454                 goto done;
455         }
456
457         /* Make sure we left the space for fd mappings */
458         g_assert (handle_idx >= mono_w32handle_fd_reserve);
459
460         handle = GUINT_TO_POINTER (handle_idx);
461
462         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Allocated new handle %p", __func__, handle);
463
464 done:
465         return(handle);
466 }
467
468 gpointer mono_w32handle_new_fd (MonoW32HandleType type, int fd,
469                               gpointer handle_specific)
470 {
471         MonoW32HandleBase *handle_data;
472         int fd_index, fd_offset;
473
474         g_assert (!shutting_down);
475
476         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Creating new handle of type %s", __func__,
477                    mono_w32handle_ops_typename (type));
478
479         g_assert(type_is_fd(type));
480
481         if (fd >= mono_w32handle_fd_reserve) {
482                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: fd %d is too big", __func__, fd);
483
484                 return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE));
485         }
486
487         fd_index = SLOT_INDEX (fd);
488         fd_offset = SLOT_OFFSET (fd);
489
490         /* Initialize the array entries on demand */
491         if (!private_handles [fd_index]) {
492                 mono_os_mutex_lock (&scan_mutex);
493
494                 if (!private_handles [fd_index])
495                         private_handles [fd_index] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT);
496
497                 mono_os_mutex_unlock (&scan_mutex);
498         }
499
500         handle_data = &private_handles [fd_index][fd_offset];
501
502         if (handle_data->type != MONO_W32HANDLE_UNUSED) {
503                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: fd %d is already in use!", __func__, fd);
504                 /* FIXME: clean up this handle?  We can't do anything
505                  * with the fd, cos thats the new one
506                  */
507         }
508
509         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Assigning new fd handle %p", __func__, (gpointer)(gsize)fd);
510
511         mono_w32handle_init_handle (handle_data, type, handle_specific);
512
513         return(GUINT_TO_POINTER(fd));
514 }
515
516 gboolean
517 mono_w32handle_lookup (gpointer handle, MonoW32HandleType type,
518                               gpointer *handle_specific)
519 {
520         MonoW32HandleBase *handle_data;
521
522         g_assert (handle_specific);
523
524         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
525                 return(FALSE);
526         }
527
528         if (handle_data->type != type) {
529                 return(FALSE);
530         }
531
532         *handle_specific = handle_data->specific;
533
534         return(TRUE);
535 }
536
537 void
538 mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data)
539 {
540         MonoW32HandleBase *handle_data = NULL;
541         gpointer handle;
542         guint32 i, k;
543
544         mono_os_mutex_lock (&scan_mutex);
545
546         for (i = SLOT_INDEX (0); i < private_handles_slots_count; i++) {
547                 if (private_handles [i]) {
548                         for (k = SLOT_OFFSET (0); k < HANDLE_PER_SLOT; k++) {
549                                 handle_data = &private_handles [i][k];
550                                 if (handle_data->type == MONO_W32HANDLE_UNUSED)
551                                         continue;
552                                 handle = GUINT_TO_POINTER (i * HANDLE_PER_SLOT + k);
553                                 if (on_each (handle, handle_data->specific, user_data) == TRUE)
554                                         goto done;
555                         }
556                 }
557         }
558
559 done:
560         mono_os_mutex_unlock (&scan_mutex);
561 }
562
563 /* This might list some shared handles twice if they are already
564  * opened by this process, and the check function returns FALSE the
565  * first time.  Shared handles that are created during the search are
566  * unreffed if the check function returns FALSE, so callers must not
567  * rely on the handle persisting (unless the check function returns
568  * TRUE)
569  * The caller owns the returned handle.
570  */
571 gpointer mono_w32handle_search (MonoW32HandleType type,
572                               gboolean (*check)(gpointer test, gpointer user),
573                               gpointer user_data,
574                               gpointer *handle_specific,
575                               gboolean search_shared)
576 {
577         MonoW32HandleBase *handle_data = NULL;
578         gpointer ret = NULL;
579         guint32 i, k;
580         gboolean found = FALSE;
581
582         mono_os_mutex_lock (&scan_mutex);
583
584         for (i = SLOT_INDEX (0); !found && i < private_handles_slots_count; i++) {
585                 if (private_handles [i]) {
586                         for (k = SLOT_OFFSET (0); k < HANDLE_PER_SLOT; k++) {
587                                 handle_data = &private_handles [i][k];
588
589                                 if (handle_data->type == type) {
590                                         ret = GUINT_TO_POINTER (i * HANDLE_PER_SLOT + k);
591                                         if (check (ret, user_data) == TRUE) {
592                                                 mono_w32handle_ref (ret);
593                                                 found = TRUE;
594                                                 break;
595                                         }
596                                 }
597                         }
598                 }
599         }
600
601         mono_os_mutex_unlock (&scan_mutex);
602
603         if (!found) {
604                 ret = NULL;
605                 goto done;
606         }
607
608         if(handle_specific != NULL) {
609                 *handle_specific = handle_data->specific;
610         }
611
612 done:
613         return(ret);
614 }
615
616 void mono_w32handle_ref (gpointer handle)
617 {
618         MonoW32HandleBase *handle_data;
619
620         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
621                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Attempting to ref invalid private handle %p", __func__, handle);
622                 return;
623         }
624
625         InterlockedIncrement ((gint32 *)&handle_data->ref);
626
627 #ifdef DEBUG_REFS
628         g_message ("%s: %s handle %p ref now %d",
629                 __func__, mono_w32handle_ops_typename (handle_data->type), handle, handle_data->ref);
630 #endif
631 }
632
633 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer);
634
635 /* The handle must not be locked on entry to this function */
636 static void mono_w32handle_unref_full (gpointer handle, gboolean ignore_private_busy_handles)
637 {
638         MonoW32HandleBase *handle_data;
639         gboolean destroy = FALSE, early_exit = FALSE;
640         int thr_ret;
641
642         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
643                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Attempting to unref invalid private handle %p",
644                         __func__, handle);
645                 return;
646         }
647
648         /* Possible race condition here if another thread refs the
649          * handle between here and setting the type to UNUSED.  I
650          * could lock a mutex, but I'm not sure that allowing a handle
651          * reference to reach 0 isn't an application bug anyway.
652          */
653         destroy = (InterlockedDecrement ((gint32 *)&handle_data->ref) ==0);
654
655 #ifdef DEBUG_REFS
656         g_message ("%s: %s handle %p ref now %d (destroy %s)",
657                 __func__, mono_w32handle_ops_typename (handle_data->type), handle, handle_data->ref, destroy?"TRUE":"FALSE");
658 #endif
659
660         if(destroy==TRUE) {
661                 /* Need to copy the handle info, reset the slot in the
662                  * array, and _only then_ call the close function to
663                  * avoid race conditions (eg file descriptors being
664                  * closed, and another file being opened getting the
665                  * same fd racing the memset())
666                  */
667                 MonoW32HandleType type;
668                 gpointer handle_specific;
669                 void (*close_func)(gpointer, gpointer);
670
671                 type = handle_data->type;
672                 handle_specific = handle_data->specific;
673
674                 mono_os_mutex_lock (&scan_mutex);
675
676                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Destroying handle %p", __func__, handle);
677
678                 /* Destroy the mutex and cond var.  We hope nobody
679                  * tried to grab them between the handle unlock and
680                  * now, but pthreads doesn't have a
681                  * "unlock_and_destroy" atomic function.
682                  */
683                 thr_ret = mono_os_mutex_destroy (&handle_data->signal_mutex);
684                 /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
685                 if (thr_ret == EBUSY && ignore_private_busy_handles) {
686                         early_exit = TRUE;
687                 } else {
688                         if (thr_ret != 0)
689                                 g_error ("Error destroying handle %p mutex due to %d\n", handle, thr_ret);
690
691                         thr_ret = mono_os_cond_destroy (&handle_data->signal_cond);
692                         if (thr_ret == EBUSY && ignore_private_busy_handles)
693                                 early_exit = TRUE;
694                         else if (thr_ret != 0)
695                                 g_error ("Error destroying handle %p cond var due to %d\n", handle, thr_ret);
696                 }
697
698                 memset (handle_data, 0, sizeof (MonoW32HandleBase));
699
700                 mono_os_mutex_unlock (&scan_mutex);
701
702                 if (early_exit)
703                         return;
704
705                 close_func = _wapi_handle_ops_get_close_func (type);
706                 if (close_func != NULL) {
707                         close_func (handle, handle_specific);
708                 }
709
710                 g_free (handle_specific);
711         }
712 }
713
714 void mono_w32handle_unref (gpointer handle)
715 {
716         mono_w32handle_unref_full (handle, FALSE);
717 }
718
719 void
720 mono_w32handle_register_ops (MonoW32HandleType type, MonoW32HandleOps *ops)
721 {
722         handle_ops [type] = ops;
723 }
724
725 void mono_w32handle_register_capabilities (MonoW32HandleType type,
726                                          MonoW32HandleCapability caps)
727 {
728         handle_caps[type] = caps;
729 }
730
731 gboolean mono_w32handle_test_capabilities (gpointer handle,
732                                          MonoW32HandleCapability caps)
733 {
734         MonoW32HandleBase *handle_data;
735         MonoW32HandleType type;
736
737         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
738                 return(FALSE);
739         }
740
741         type = handle_data->type;
742
743         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: testing 0x%x against 0x%x (%d)", __func__,
744                    handle_caps[type], caps, handle_caps[type] & caps);
745
746         return((handle_caps[type] & caps) != 0);
747 }
748
749 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer)
750 {
751         if (handle_ops[type] != NULL &&
752             handle_ops[type]->close != NULL) {
753                 return (handle_ops[type]->close);
754         }
755
756         return (NULL);
757 }
758
759 void mono_w32handle_ops_close (gpointer handle, gpointer data)
760 {
761         MonoW32HandleBase *handle_data;
762         MonoW32HandleType type;
763
764         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
765                 return;
766         }
767
768         type = handle_data->type;
769
770         if (handle_ops[type] != NULL &&
771             handle_ops[type]->close != NULL) {
772                 handle_ops[type]->close (handle, data);
773         }
774 }
775
776 void mono_w32handle_ops_details (MonoW32HandleType type, gpointer data)
777 {
778         if (handle_ops[type] != NULL &&
779             handle_ops[type]->details != NULL) {
780                 handle_ops[type]->details (data);
781         }
782 }
783
784 const gchar* mono_w32handle_ops_typename (MonoW32HandleType type)
785 {
786         g_assert (handle_ops [type]);
787         g_assert (handle_ops [type]->typename);
788         return handle_ops [type]->typename ();
789 }
790
791 gsize mono_w32handle_ops_typesize (MonoW32HandleType type)
792 {
793         g_assert (handle_ops [type]);
794         g_assert (handle_ops [type]->typesize);
795         return handle_ops [type]->typesize ();
796 }
797
798 void mono_w32handle_ops_signal (gpointer handle)
799 {
800         MonoW32HandleBase *handle_data;
801         MonoW32HandleType type;
802
803         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
804                 return;
805         }
806
807         type = handle_data->type;
808
809         if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
810                 handle_ops[type]->signal (handle);
811         }
812 }
813
814 gboolean mono_w32handle_ops_own (gpointer handle)
815 {
816         MonoW32HandleBase *handle_data;
817         MonoW32HandleType type;
818
819         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
820                 return(FALSE);
821         }
822
823         type = handle_data->type;
824
825         if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
826                 return(handle_ops[type]->own_handle (handle));
827         } else {
828                 return(FALSE);
829         }
830 }
831
832 gboolean mono_w32handle_ops_isowned (gpointer handle)
833 {
834         MonoW32HandleBase *handle_data;
835         MonoW32HandleType type;
836
837         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
838                 return(FALSE);
839         }
840
841         type = handle_data->type;
842
843         if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
844                 return(handle_ops[type]->is_owned (handle));
845         } else {
846                 return(FALSE);
847         }
848 }
849
850 guint32 mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean alertable)
851 {
852         MonoW32HandleBase *handle_data;
853         MonoW32HandleType type;
854
855         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
856                 return(WAIT_FAILED);
857         }
858
859         type = handle_data->type;
860
861         if (handle_ops[type] != NULL &&
862             handle_ops[type]->special_wait != NULL) {
863                 return(handle_ops[type]->special_wait (handle, timeout, alertable));
864         } else {
865                 return(WAIT_FAILED);
866         }
867 }
868
869 void mono_w32handle_ops_prewait (gpointer handle)
870 {
871         MonoW32HandleBase *handle_data;
872         MonoW32HandleType type;
873
874         if (!mono_w32handle_lookup_data (handle, &handle_data)) {
875                 return;
876         }
877
878         type = handle_data->type;
879
880         if (handle_ops[type] != NULL &&
881             handle_ops[type]->prewait != NULL) {
882                 handle_ops[type]->prewait (handle);
883         }
884 }
885
886 static void
887 spin (guint32 ms)
888 {
889         struct timespec sleepytime;
890
891         g_assert (ms < 1000);
892
893         sleepytime.tv_sec = 0;
894         sleepytime.tv_nsec = ms * 1000000;
895         nanosleep (&sleepytime, NULL);
896 }
897
898 gboolean
899 mono_w32handle_count_signalled_handles (guint32 numhandles, gpointer *handles,
900         gboolean waitall, guint32 *retcount, guint32 *lowest)
901 {
902         guint32 count, i, iter=0;
903         gboolean ret;
904         int thr_ret;
905
906         /* Lock all the handles, with backoff */
907 again:
908         for(i=0; i<numhandles; i++) {
909                 gpointer handle = handles[i];
910
911                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempting to lock %p", __func__, handle);
912
913                 thr_ret = mono_w32handle_trylock_handle (handle);
914
915                 if (thr_ret != 0) {
916                         /* Bummer */
917
918                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempt failed for %p: %s", __func__,
919                                    handle, strerror (thr_ret));
920
921                         while (i--) {
922                                 handle = handles[i];
923
924                                 thr_ret = mono_w32handle_unlock_handle (handle);
925                                 g_assert (thr_ret == 0);
926                         }
927
928                         /* If iter ever reaches 100 the nanosleep will
929                          * return EINVAL immediately, but we have a
930                          * design flaw if that happens.
931                          */
932                         iter++;
933                         if(iter==100) {
934                                 g_warning ("%s: iteration overflow!",
935                                            __func__);
936                                 iter=1;
937                         }
938
939                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Backing off for %d ms", __func__,
940                                    iter*10);
941                         spin (10 * iter);
942
943                         goto again;
944                 }
945         }
946
947         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Locked all handles", __func__);
948
949         count=0;
950         *lowest=numhandles;
951
952         for(i=0; i<numhandles; i++) {
953                 gpointer handle = handles[i];
954
955                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Checking handle %p", __func__, handle);
956
957                 if(((mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_OWN)==TRUE) &&
958                     (mono_w32handle_ops_isowned (handle) == TRUE)) ||
959                    (mono_w32handle_issignalled (handle))) {
960                         count++;
961
962                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Handle %p signalled", __func__,
963                                    handle);
964                         if(*lowest>i) {
965                                 *lowest=i;
966                         }
967                 }
968         }
969
970         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: %d event handles signalled", __func__, count);
971
972         if ((waitall == TRUE && count == numhandles) ||
973             (waitall == FALSE && count > 0)) {
974                 ret=TRUE;
975         } else {
976                 ret=FALSE;
977         }
978
979         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Returning %d", __func__, ret);
980
981         *retcount=count;
982
983         return(ret);
984 }
985
986 void mono_w32handle_unlock_handles (guint32 numhandles, gpointer *handles)
987 {
988         guint32 i;
989         int thr_ret;
990
991         for(i=0; i<numhandles; i++) {
992                 gpointer handle = handles[i];
993
994                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unlocking handle %p", __func__, handle);
995
996                 thr_ret = mono_w32handle_unlock_handle (handle);
997                 g_assert (thr_ret == 0);
998         }
999 }
1000
1001 static int
1002 mono_w32handle_timedwait_signal_naked (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout, gboolean poll, gboolean *alerted)
1003 {
1004         int res;
1005
1006         if (!poll) {
1007                 res = mono_os_cond_timedwait (cond, mutex, timeout);
1008         } else {
1009                 /* This is needed when waiting for process handles */
1010                 if (!alerted) {
1011                         /*
1012                          * pthread_cond_(timed)wait() can return 0 even if the condition was not
1013                          * signalled.  This happens at least on Darwin.  We surface this, i.e., we
1014                          * get spurious wake-ups.
1015                          *
1016                          * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
1017                          */
1018                         res = mono_os_cond_timedwait (cond, mutex, timeout);
1019                 } else {
1020                         if (timeout < 100) {
1021                                 /* Real timeout is less than 100ms time */
1022                                 res = mono_os_cond_timedwait (cond, mutex, timeout);
1023                         } else {
1024                                 res = mono_os_cond_timedwait (cond, mutex, 100);
1025
1026                                 /* Mask the fake timeout, this will cause
1027                                  * another poll if the cond was not really signaled
1028                                  */
1029                                 if (res == ETIMEDOUT)
1030                                         res = 0;
1031                         }
1032                 }
1033         }
1034
1035         return res;
1036 }
1037
1038 static void
1039 signal_global (gpointer unused)
1040 {
1041         /* If we reach here, then interrupt token is set to the flag value, which
1042          * means that the target thread is either
1043          * - before the first CAS in timedwait, which means it won't enter the wait.
1044          * - it is after the first CAS, so it is already waiting, or it will enter
1045          *    the wait, and it will be interrupted by the broadcast. */
1046         mono_os_mutex_lock (&global_signal_mutex);
1047         mono_os_cond_broadcast (&global_signal_cond);
1048         mono_os_mutex_unlock (&global_signal_mutex);
1049 }
1050
1051 int
1052 mono_w32handle_timedwait_signal (guint32 timeout, gboolean poll, gboolean *alerted)
1053 {
1054         int res;
1055
1056         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for global", __func__);
1057
1058         if (alerted)
1059                 *alerted = FALSE;
1060
1061         if (alerted) {
1062                 mono_thread_info_install_interrupt (signal_global, NULL, alerted);
1063                 if (*alerted)
1064                         return 0;
1065         }
1066
1067         res = mono_w32handle_timedwait_signal_naked (&global_signal_cond, &global_signal_mutex, timeout, poll, alerted);
1068
1069         if (alerted)
1070                 mono_thread_info_uninstall_interrupt (alerted);
1071
1072         return res;
1073 }
1074
1075 static void
1076 signal_handle_and_unref (gpointer handle)
1077 {
1078         MonoW32HandleBase *handle_data;
1079         mono_cond_t *cond;
1080         mono_mutex_t *mutex;
1081
1082         if (!mono_w32handle_lookup_data (handle, &handle_data))
1083                 g_error ("cannot signal unknown handle %p", handle);
1084
1085         /* If we reach here, then interrupt token is set to the flag value, which
1086          * means that the target thread is either
1087          * - before the first CAS in timedwait, which means it won't enter the wait.
1088          * - it is after the first CAS, so it is already waiting, or it will enter
1089          *    the wait, and it will be interrupted by the broadcast. */
1090         cond = &handle_data->signal_cond;
1091         mutex = &handle_data->signal_mutex;
1092
1093         mono_os_mutex_lock (mutex);
1094         mono_os_cond_broadcast (cond);
1095         mono_os_mutex_unlock (mutex);
1096
1097         mono_w32handle_unref (handle);
1098 }
1099
1100 int
1101 mono_w32handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean poll, gboolean *alerted)
1102 {
1103         MonoW32HandleBase *handle_data;
1104         int res;
1105
1106         if (!mono_w32handle_lookup_data (handle, &handle_data))
1107                 g_error ("cannot wait on unknown handle %p", handle);
1108
1109         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for %p (type %s)", __func__, handle,
1110                    mono_w32handle_ops_typename (mono_w32handle_get_type (handle)));
1111
1112         if (alerted)
1113                 *alerted = FALSE;
1114
1115         if (alerted) {
1116                 mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
1117                 if (*alerted)
1118                         return 0;
1119                 mono_w32handle_ref (handle);
1120         }
1121
1122         res = mono_w32handle_timedwait_signal_naked (&handle_data->signal_cond, &handle_data->signal_mutex, timeout, poll, alerted);
1123
1124         if (alerted) {
1125                 mono_thread_info_uninstall_interrupt (alerted);
1126                 if (!*alerted) {
1127                         /* if it is alerted, then the handle is unref in the interrupt callback */
1128                         mono_w32handle_unref (handle);
1129                 }
1130         }
1131
1132         return res;
1133 }
1134
1135 void mono_w32handle_dump (void)
1136 {
1137         MonoW32HandleBase *handle_data;
1138         guint32 i, k;
1139
1140         mono_os_mutex_lock (&scan_mutex);
1141
1142         for(i = SLOT_INDEX (0); i < private_handles_slots_count; i++) {
1143                 if (private_handles [i]) {
1144                         for (k = SLOT_OFFSET (0); k < HANDLE_PER_SLOT; k++) {
1145                                 handle_data = &private_handles [i][k];
1146
1147                                 if (handle_data->type == MONO_W32HANDLE_UNUSED) {
1148                                         continue;
1149                                 }
1150
1151                                 g_print ("%3x [%7s] %s %d ",
1152                                                  i * HANDLE_PER_SLOT + k,
1153                                                  mono_w32handle_ops_typename (handle_data->type),
1154                                                  handle_data->signalled?"Sg":"Un",
1155                                                  handle_data->ref);
1156                                 mono_w32handle_ops_details (handle_data->type, handle_data->specific);
1157                                 g_print ("\n");
1158                         }
1159                 }
1160         }
1161
1162         mono_os_mutex_unlock (&scan_mutex);
1163 }
1164
1165 #endif /* !defined(HOST_WIN32) */