2 * w32handle.c: Generic and internal operations on handles
5 * Dick Porter (dick@ximian.com)
6 * Ludovic Henry (luhenry@microsoft.com)
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.
15 #if !defined(HOST_WIN32)
25 #include <sys/types.h>
26 #ifdef HAVE_SYS_SOCKET_H
27 # include <sys/socket.h>
32 #ifdef HAVE_SYS_MMAN_H
33 # include <sys/mman.h>
39 #ifdef HAVE_SYS_RESOURCE_H
40 # include <sys/resource.h>
43 #include "w32handle.h"
46 #include "mono-logger-internals.h"
47 #include "mono-os-mutex.h"
48 #include "mono-proclib.h"
49 #include "mono-threads.h"
53 #define SLOT_MAX (1024 * 16)
55 /* must be a power of 2 */
56 #define HANDLE_PER_SLOT (256)
59 MonoW32HandleType type
;
62 mono_mutex_t signal_mutex
;
63 mono_cond_t signal_cond
;
67 static MonoW32HandleCapability handle_caps
[MONO_W32HANDLE_COUNT
];
68 static MonoW32HandleOps
*handle_ops
[MONO_W32HANDLE_COUNT
];
71 * We can hold SLOT_MAX * HANDLE_PER_SLOT handles.
72 * If 4M handles are not enough... Oh, well... we will crash.
74 #define SLOT_INDEX(x) (x / HANDLE_PER_SLOT)
75 #define SLOT_OFFSET(x) (x % HANDLE_PER_SLOT)
77 static MonoW32HandleBase
*private_handles
[SLOT_MAX
];
78 static guint32 private_handles_count
= 0;
79 static guint32 private_handles_slots_count
= 0;
81 guint32 mono_w32handle_fd_reserve
;
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.
88 static mono_mutex_t global_signal_mutex
;
89 static mono_cond_t global_signal_cond
;
91 static mono_mutex_t scan_mutex
;
93 static gboolean shutting_down
= FALSE
;
96 type_is_fd (MonoW32HandleType type
)
99 case MONO_W32HANDLE_FILE
:
100 case MONO_W32HANDLE_CONSOLE
:
101 case MONO_W32HANDLE_SOCKET
:
102 case MONO_W32HANDLE_PIPE
:
110 mono_w32handle_lookup_data (gpointer handle
, MonoW32HandleBase
**handle_data
)
114 g_assert (handle_data
);
116 index
= SLOT_INDEX ((gsize
) handle
);
117 if (index
>= SLOT_MAX
)
119 if (!private_handles
[index
])
122 offset
= SLOT_OFFSET ((gsize
) handle
);
123 if (private_handles
[index
][offset
].type
== MONO_W32HANDLE_UNUSED
)
126 *handle_data
= &private_handles
[index
][offset
];
131 mono_w32handle_get_type (gpointer handle
)
133 MonoW32HandleBase
*handle_data
;
135 if (!mono_w32handle_lookup_data (handle
, &handle_data
))
136 return MONO_W32HANDLE_UNUSED
; /* An impossible type */
138 return handle_data
->type
;
142 mono_w32handle_set_signal_state (gpointer handle
, gboolean state
, gboolean broadcast
)
144 MonoW32HandleBase
*handle_data
;
146 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
151 g_message ("%s: setting state of %p to %s (broadcast %s)", __func__
,
152 handle
, state
?"TRUE":"FALSE", broadcast
?"TRUE":"FALSE");
156 /* Tell everyone blocking on a single handle */
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.
161 mono_os_mutex_lock (&global_signal_mutex
);
163 /* This function _must_ be called with
164 * handle->signal_mutex locked
166 handle_data
->signalled
=state
;
168 if (broadcast
== TRUE
) {
169 mono_os_cond_broadcast (&handle_data
->signal_cond
);
171 mono_os_cond_signal (&handle_data
->signal_cond
);
174 /* Tell everyone blocking on multiple handles that something
177 mono_os_cond_broadcast (&global_signal_cond
);
179 mono_os_mutex_unlock (&global_signal_mutex
);
181 handle_data
->signalled
=state
;
186 mono_w32handle_issignalled (gpointer handle
)
188 MonoW32HandleBase
*handle_data
;
190 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
194 return handle_data
->signalled
;
198 mono_w32handle_lock_signal_mutex (void)
201 g_message ("%s: lock global signal mutex", __func__
);
204 mono_os_mutex_lock (&global_signal_mutex
);
210 mono_w32handle_unlock_signal_mutex (void)
213 g_message ("%s: unlock global signal mutex", __func__
);
216 mono_os_mutex_unlock (&global_signal_mutex
);
222 mono_w32handle_lock_handle (gpointer handle
)
224 MonoW32HandleBase
*handle_data
;
227 g_message ("%s: locking handle %p", __func__
, handle
);
230 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
234 mono_w32handle_ref (handle
);
236 mono_os_mutex_lock (&handle_data
->signal_mutex
);
242 mono_w32handle_trylock_handle (gpointer handle
)
244 MonoW32HandleBase
*handle_data
;
248 g_message ("%s: locking handle %p", __func__
, handle
);
251 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
255 mono_w32handle_ref (handle
);
257 ret
= mono_os_mutex_trylock (&handle_data
->signal_mutex
);
259 mono_w32handle_unref (handle
);
266 mono_w32handle_unlock_handle (gpointer handle
)
268 MonoW32HandleBase
*handle_data
;
271 g_message ("%s: unlocking handle %p", __func__
, handle
);
274 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
278 mono_os_mutex_unlock (&handle_data
->signal_mutex
);
280 mono_w32handle_unref (handle
);
288 * Initialize the io-layer.
291 mono_w32handle_init (void)
293 g_assert ((sizeof (handle_ops
) / sizeof (handle_ops
[0]))
294 == MONO_W32HANDLE_COUNT
);
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);
301 * The entries in private_handles reserved for fds are allocated lazily to
305 private_handles_count
+= HANDLE_PER_SLOT
;
306 private_handles_slots_count
++;
307 } while(mono_w32handle_fd_reserve
> private_handles_count
);
309 mono_os_mutex_init (&scan_mutex
);
311 mono_os_cond_init (&global_signal_cond
);
312 mono_os_mutex_init (&global_signal_mutex
);
315 static void mono_w32handle_unref_full (gpointer handle
, gboolean ignore_private_busy_handles
);
318 mono_w32handle_cleanup (void)
322 g_assert (!shutting_down
);
323 shutting_down
= TRUE
;
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
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
);
337 for(k
= handle_data
->ref
; k
> 0; k
--) {
338 mono_w32handle_unref_full (handle
, TRUE
);
343 for (i
= 0; i
< SLOT_MAX
; ++i
)
344 g_free (private_handles
[i
]);
347 static void mono_w32handle_init_handle (MonoW32HandleBase
*handle
,
348 MonoW32HandleType type
, gpointer handle_specific
)
350 g_assert (!shutting_down
);
353 handle
->signalled
= FALSE
;
356 mono_os_cond_init (&handle
->signal_cond
);
357 mono_os_mutex_init (&handle
->signal_mutex
);
360 handle
->specific
= g_memdup (handle_specific
, mono_w32handle_ops_typesize (type
));
364 * mono_w32handle_new_internal:
365 * @type: Init handle to this type
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.
371 static guint32
mono_w32handle_new_internal (MonoW32HandleType type
,
372 gpointer handle_specific
)
375 static guint32 last
= 0;
376 gboolean retry
= FALSE
;
378 g_assert (!shutting_down
);
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
386 if (last
< mono_w32handle_fd_reserve
) {
387 last
= mono_w32handle_fd_reserve
;
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
];
399 if(handle
->type
== MONO_W32HANDLE_UNUSED
) {
402 mono_w32handle_init_handle (handle
, type
, handle_specific
);
410 if(retry
&& last
> mono_w32handle_fd_reserve
) {
411 /* Try again from the beginning */
412 last
= mono_w32handle_fd_reserve
;
416 /* Will need to expand the array. The caller will sort it out */
422 mono_w32handle_new (MonoW32HandleType type
, gpointer handle_specific
)
424 guint32 handle_idx
= 0;
427 g_assert (!shutting_down
);
429 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Creating new handle of type %s", __func__
,
430 mono_w32handle_ops_typename (type
));
432 g_assert(!type_is_fd(type
));
434 mono_os_mutex_lock (&scan_mutex
);
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
) {
443 private_handles
[idx
] = g_new0 (MonoW32HandleBase
, HANDLE_PER_SLOT
);
445 private_handles_count
+= HANDLE_PER_SLOT
;
446 private_handles_slots_count
++;
449 mono_os_mutex_unlock (&scan_mutex
);
451 if (handle_idx
== 0) {
452 /* We ran out of slots */
453 handle
= INVALID_HANDLE_VALUE
;
457 /* Make sure we left the space for fd mappings */
458 g_assert (handle_idx
>= mono_w32handle_fd_reserve
);
460 handle
= GUINT_TO_POINTER (handle_idx
);
462 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Allocated new handle %p", __func__
, handle
);
468 gpointer
mono_w32handle_new_fd (MonoW32HandleType type
, int fd
,
469 gpointer handle_specific
)
471 MonoW32HandleBase
*handle_data
;
472 int fd_index
, fd_offset
;
474 g_assert (!shutting_down
);
476 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Creating new handle of type %s", __func__
,
477 mono_w32handle_ops_typename (type
));
479 g_assert(type_is_fd(type
));
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
);
484 return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE
));
487 fd_index
= SLOT_INDEX (fd
);
488 fd_offset
= SLOT_OFFSET (fd
);
490 /* Initialize the array entries on demand */
491 if (!private_handles
[fd_index
]) {
492 mono_os_mutex_lock (&scan_mutex
);
494 if (!private_handles
[fd_index
])
495 private_handles
[fd_index
] = g_new0 (MonoW32HandleBase
, HANDLE_PER_SLOT
);
497 mono_os_mutex_unlock (&scan_mutex
);
500 handle_data
= &private_handles
[fd_index
][fd_offset
];
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
509 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Assigning new fd handle %p", __func__
, (gpointer
)(gsize
)fd
);
511 mono_w32handle_init_handle (handle_data
, type
, handle_specific
);
513 return(GUINT_TO_POINTER(fd
));
517 mono_w32handle_lookup (gpointer handle
, MonoW32HandleType type
,
518 gpointer
*handle_specific
)
520 MonoW32HandleBase
*handle_data
;
522 g_assert (handle_specific
);
524 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
528 if (handle_data
->type
!= type
) {
532 *handle_specific
= handle_data
->specific
;
538 mono_w32handle_foreach (gboolean (*on_each
)(gpointer handle
, gpointer data
, gpointer user_data
), gpointer user_data
)
540 MonoW32HandleBase
*handle_data
= NULL
;
544 mono_os_mutex_lock (&scan_mutex
);
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
)
552 handle
= GUINT_TO_POINTER (i
* HANDLE_PER_SLOT
+ k
);
553 if (on_each (handle
, handle_data
->specific
, user_data
) == TRUE
)
560 mono_os_mutex_unlock (&scan_mutex
);
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
569 * The caller owns the returned handle.
571 gpointer
mono_w32handle_search (MonoW32HandleType type
,
572 gboolean (*check
)(gpointer test
, gpointer user
),
574 gpointer
*handle_specific
,
575 gboolean search_shared
)
577 MonoW32HandleBase
*handle_data
= NULL
;
580 gboolean found
= FALSE
;
582 mono_os_mutex_lock (&scan_mutex
);
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
];
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
);
601 mono_os_mutex_unlock (&scan_mutex
);
608 if(handle_specific
!= NULL
) {
609 *handle_specific
= handle_data
->specific
;
616 void mono_w32handle_ref (gpointer handle
)
618 MonoW32HandleBase
*handle_data
;
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
);
625 InterlockedIncrement ((gint32
*)&handle_data
->ref
);
628 g_message ("%s: %s handle %p ref now %d",
629 __func__
, mono_w32handle_ops_typename (handle_data
->type
), handle
, handle_data
->ref
);
633 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type
))(gpointer
, gpointer
);
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
)
638 MonoW32HandleBase
*handle_data
;
639 gboolean destroy
= FALSE
, early_exit
= FALSE
;
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",
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.
653 destroy
= (InterlockedDecrement ((gint32
*)&handle_data
->ref
) ==0);
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");
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())
667 MonoW32HandleType type
;
668 gpointer handle_specific
;
669 void (*close_func
)(gpointer
, gpointer
);
671 type
= handle_data
->type
;
672 handle_specific
= handle_data
->specific
;
674 mono_os_mutex_lock (&scan_mutex
);
676 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Destroying handle %p", __func__
, handle
);
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.
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
) {
689 g_error ("Error destroying handle %p mutex due to %d\n", handle
, thr_ret
);
691 thr_ret
= mono_os_cond_destroy (&handle_data
->signal_cond
);
692 if (thr_ret
== EBUSY
&& ignore_private_busy_handles
)
694 else if (thr_ret
!= 0)
695 g_error ("Error destroying handle %p cond var due to %d\n", handle
, thr_ret
);
698 memset (handle_data
, 0, sizeof (MonoW32HandleBase
));
700 mono_os_mutex_unlock (&scan_mutex
);
705 close_func
= _wapi_handle_ops_get_close_func (type
);
706 if (close_func
!= NULL
) {
707 close_func (handle
, handle_specific
);
710 g_free (handle_specific
);
714 void mono_w32handle_unref (gpointer handle
)
716 mono_w32handle_unref_full (handle
, FALSE
);
720 mono_w32handle_register_ops (MonoW32HandleType type
, MonoW32HandleOps
*ops
)
722 handle_ops
[type
] = ops
;
725 void mono_w32handle_register_capabilities (MonoW32HandleType type
,
726 MonoW32HandleCapability caps
)
728 handle_caps
[type
] = caps
;
731 gboolean
mono_w32handle_test_capabilities (gpointer handle
,
732 MonoW32HandleCapability caps
)
734 MonoW32HandleBase
*handle_data
;
735 MonoW32HandleType type
;
737 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
741 type
= handle_data
->type
;
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
);
746 return((handle_caps
[type
] & caps
) != 0);
749 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type
))(gpointer
, gpointer
)
751 if (handle_ops
[type
] != NULL
&&
752 handle_ops
[type
]->close
!= NULL
) {
753 return (handle_ops
[type
]->close
);
759 void mono_w32handle_ops_close (gpointer handle
, gpointer data
)
761 MonoW32HandleBase
*handle_data
;
762 MonoW32HandleType type
;
764 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
768 type
= handle_data
->type
;
770 if (handle_ops
[type
] != NULL
&&
771 handle_ops
[type
]->close
!= NULL
) {
772 handle_ops
[type
]->close (handle
, data
);
776 void mono_w32handle_ops_details (MonoW32HandleType type
, gpointer data
)
778 if (handle_ops
[type
] != NULL
&&
779 handle_ops
[type
]->details
!= NULL
) {
780 handle_ops
[type
]->details (data
);
784 const gchar
* mono_w32handle_ops_typename (MonoW32HandleType type
)
786 g_assert (handle_ops
[type
]);
787 g_assert (handle_ops
[type
]->typename
);
788 return handle_ops
[type
]->typename ();
791 gsize
mono_w32handle_ops_typesize (MonoW32HandleType type
)
793 g_assert (handle_ops
[type
]);
794 g_assert (handle_ops
[type
]->typesize
);
795 return handle_ops
[type
]->typesize ();
798 void mono_w32handle_ops_signal (gpointer handle
)
800 MonoW32HandleBase
*handle_data
;
801 MonoW32HandleType type
;
803 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
807 type
= handle_data
->type
;
809 if (handle_ops
[type
] != NULL
&& handle_ops
[type
]->signal
!= NULL
) {
810 handle_ops
[type
]->signal (handle
);
814 gboolean
mono_w32handle_ops_own (gpointer handle
)
816 MonoW32HandleBase
*handle_data
;
817 MonoW32HandleType type
;
819 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
823 type
= handle_data
->type
;
825 if (handle_ops
[type
] != NULL
&& handle_ops
[type
]->own_handle
!= NULL
) {
826 return(handle_ops
[type
]->own_handle (handle
));
832 gboolean
mono_w32handle_ops_isowned (gpointer handle
)
834 MonoW32HandleBase
*handle_data
;
835 MonoW32HandleType type
;
837 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
841 type
= handle_data
->type
;
843 if (handle_ops
[type
] != NULL
&& handle_ops
[type
]->is_owned
!= NULL
) {
844 return(handle_ops
[type
]->is_owned (handle
));
850 guint32
mono_w32handle_ops_specialwait (gpointer handle
, guint32 timeout
, gboolean alertable
)
852 MonoW32HandleBase
*handle_data
;
853 MonoW32HandleType type
;
855 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
859 type
= handle_data
->type
;
861 if (handle_ops
[type
] != NULL
&&
862 handle_ops
[type
]->special_wait
!= NULL
) {
863 return(handle_ops
[type
]->special_wait (handle
, timeout
, alertable
));
869 void mono_w32handle_ops_prewait (gpointer handle
)
871 MonoW32HandleBase
*handle_data
;
872 MonoW32HandleType type
;
874 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
878 type
= handle_data
->type
;
880 if (handle_ops
[type
] != NULL
&&
881 handle_ops
[type
]->prewait
!= NULL
) {
882 handle_ops
[type
]->prewait (handle
);
889 struct timespec sleepytime
;
891 g_assert (ms
< 1000);
893 sleepytime
.tv_sec
= 0;
894 sleepytime
.tv_nsec
= ms
* 1000000;
895 nanosleep (&sleepytime
, NULL
);
899 mono_w32handle_count_signalled_handles (guint32 numhandles
, gpointer
*handles
,
900 gboolean waitall
, guint32
*retcount
, guint32
*lowest
)
902 guint32 count
, i
, iter
=0;
906 /* Lock all the handles, with backoff */
908 for(i
=0; i
<numhandles
; i
++) {
909 gpointer handle
= handles
[i
];
911 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: attempting to lock %p", __func__
, handle
);
913 thr_ret
= mono_w32handle_trylock_handle (handle
);
918 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: attempt failed for %p: %s", __func__
,
919 handle
, strerror (thr_ret
));
924 thr_ret
= mono_w32handle_unlock_handle (handle
);
925 g_assert (thr_ret
== 0);
928 /* If iter ever reaches 100 the nanosleep will
929 * return EINVAL immediately, but we have a
930 * design flaw if that happens.
934 g_warning ("%s: iteration overflow!",
939 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Backing off for %d ms", __func__
,
947 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Locked all handles", __func__
);
952 for(i
=0; i
<numhandles
; i
++) {
953 gpointer handle
= handles
[i
];
955 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Checking handle %p", __func__
, handle
);
957 if(((mono_w32handle_test_capabilities (handle
, MONO_W32HANDLE_CAP_OWN
)==TRUE
) &&
958 (mono_w32handle_ops_isowned (handle
) == TRUE
)) ||
959 (mono_w32handle_issignalled (handle
))) {
962 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Handle %p signalled", __func__
,
970 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: %d event handles signalled", __func__
, count
);
972 if ((waitall
== TRUE
&& count
== numhandles
) ||
973 (waitall
== FALSE
&& count
> 0)) {
979 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Returning %d", __func__
, ret
);
986 void mono_w32handle_unlock_handles (guint32 numhandles
, gpointer
*handles
)
991 for(i
=0; i
<numhandles
; i
++) {
992 gpointer handle
= handles
[i
];
994 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: unlocking handle %p", __func__
, handle
);
996 thr_ret
= mono_w32handle_unlock_handle (handle
);
997 g_assert (thr_ret
== 0);
1002 mono_w32handle_timedwait_signal_naked (mono_cond_t
*cond
, mono_mutex_t
*mutex
, guint32 timeout
, gboolean poll
, gboolean
*alerted
)
1007 res
= mono_os_cond_timedwait (cond
, mutex
, timeout
);
1009 /* This is needed when waiting for process handles */
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.
1016 * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
1018 res
= mono_os_cond_timedwait (cond
, mutex
, timeout
);
1020 if (timeout
< 100) {
1021 /* Real timeout is less than 100ms time */
1022 res
= mono_os_cond_timedwait (cond
, mutex
, timeout
);
1024 res
= mono_os_cond_timedwait (cond
, mutex
, 100);
1026 /* Mask the fake timeout, this will cause
1027 * another poll if the cond was not really signaled
1039 signal_global (gpointer unused
)
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
);
1052 mono_w32handle_timedwait_signal (guint32 timeout
, gboolean poll
, gboolean
*alerted
)
1056 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: waiting for global", __func__
);
1062 mono_thread_info_install_interrupt (signal_global
, NULL
, alerted
);
1067 res
= mono_w32handle_timedwait_signal_naked (&global_signal_cond
, &global_signal_mutex
, timeout
, poll
, alerted
);
1070 mono_thread_info_uninstall_interrupt (alerted
);
1076 signal_handle_and_unref (gpointer handle
)
1078 MonoW32HandleBase
*handle_data
;
1080 mono_mutex_t
*mutex
;
1082 if (!mono_w32handle_lookup_data (handle
, &handle_data
))
1083 g_error ("cannot signal unknown handle %p", handle
);
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
;
1093 mono_os_mutex_lock (mutex
);
1094 mono_os_cond_broadcast (cond
);
1095 mono_os_mutex_unlock (mutex
);
1097 mono_w32handle_unref (handle
);
1101 mono_w32handle_timedwait_signal_handle (gpointer handle
, guint32 timeout
, gboolean poll
, gboolean
*alerted
)
1103 MonoW32HandleBase
*handle_data
;
1106 if (!mono_w32handle_lookup_data (handle
, &handle_data
))
1107 g_error ("cannot wait on unknown handle %p", handle
);
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
)));
1116 mono_thread_info_install_interrupt (signal_handle_and_unref
, handle
, alerted
);
1119 mono_w32handle_ref (handle
);
1122 res
= mono_w32handle_timedwait_signal_naked (&handle_data
->signal_cond
, &handle_data
->signal_mutex
, timeout
, poll
, alerted
);
1125 mono_thread_info_uninstall_interrupt (alerted
);
1127 /* if it is alerted, then the handle is unref in the interrupt callback */
1128 mono_w32handle_unref (handle
);
1135 void mono_w32handle_dump (void)
1137 MonoW32HandleBase
*handle_data
;
1140 mono_os_mutex_lock (&scan_mutex
);
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
];
1147 if (handle_data
->type
== MONO_W32HANDLE_UNUSED
) {
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",
1156 mono_w32handle_ops_details (handle_data
->type
, handle_data
->specific
);
1162 mono_os_mutex_unlock (&scan_mutex
);
1165 #endif /* !defined(HOST_WIN32) */