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"
50 #include "mono-time.h"
54 #define SLOT_MAX (1024 * 16)
56 /* must be a power of 2 */
57 #define HANDLE_PER_SLOT (256)
59 #define INFINITE 0xFFFFFFFF
62 MonoW32HandleType type
;
65 mono_mutex_t signal_mutex
;
66 mono_cond_t signal_cond
;
70 static MonoW32HandleCapability handle_caps
[MONO_W32HANDLE_COUNT
];
71 static MonoW32HandleOps
*handle_ops
[MONO_W32HANDLE_COUNT
];
74 * We can hold SLOT_MAX * HANDLE_PER_SLOT handles.
75 * If 4M handles are not enough... Oh, well... we will crash.
77 #define SLOT_INDEX(x) (x / HANDLE_PER_SLOT)
78 #define SLOT_OFFSET(x) (x % HANDLE_PER_SLOT)
80 static MonoW32HandleBase
*private_handles
[SLOT_MAX
];
81 static guint32 private_handles_count
= 0;
82 static guint32 private_handles_slots_count
= 0;
84 guint32 mono_w32handle_fd_reserve
;
87 * This is an internal handle which is used for handling waiting for multiple handles.
88 * Threads which wait for multiple handles wait on this one handle, and when a handle
89 * is signalled, this handle is signalled too.
91 static mono_mutex_t global_signal_mutex
;
92 static mono_cond_t global_signal_cond
;
94 static mono_mutex_t scan_mutex
;
96 static gboolean shutting_down
= FALSE
;
99 type_is_fd (MonoW32HandleType type
)
102 case MONO_W32HANDLE_FILE
:
103 case MONO_W32HANDLE_CONSOLE
:
104 case MONO_W32HANDLE_SOCKET
:
105 case MONO_W32HANDLE_PIPE
:
113 mono_w32handle_lookup_data (gpointer handle
, MonoW32HandleBase
**handle_data
)
117 g_assert (handle_data
);
119 index
= SLOT_INDEX ((gsize
) handle
);
120 if (index
>= SLOT_MAX
)
122 if (!private_handles
[index
])
125 offset
= SLOT_OFFSET ((gsize
) handle
);
126 if (private_handles
[index
][offset
].type
== MONO_W32HANDLE_UNUSED
)
129 *handle_data
= &private_handles
[index
][offset
];
134 mono_w32handle_get_type (gpointer handle
)
136 MonoW32HandleBase
*handle_data
;
138 if (!mono_w32handle_lookup_data (handle
, &handle_data
))
139 return MONO_W32HANDLE_UNUSED
; /* An impossible type */
141 return handle_data
->type
;
145 mono_w32handle_set_signal_state (gpointer handle
, gboolean state
, gboolean broadcast
)
147 MonoW32HandleBase
*handle_data
;
149 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
154 g_message ("%s: setting state of %p to %s (broadcast %s)", __func__
,
155 handle
, state
?"TRUE":"FALSE", broadcast
?"TRUE":"FALSE");
159 /* Tell everyone blocking on a single handle */
161 /* The condition the global signal cond is waiting on is the signalling of
162 * _any_ handle. So lock it before setting the signalled state.
164 mono_os_mutex_lock (&global_signal_mutex
);
166 /* This function _must_ be called with
167 * handle->signal_mutex locked
169 handle_data
->signalled
=state
;
171 if (broadcast
== TRUE
) {
172 mono_os_cond_broadcast (&handle_data
->signal_cond
);
174 mono_os_cond_signal (&handle_data
->signal_cond
);
177 /* Tell everyone blocking on multiple handles that something
180 mono_os_cond_broadcast (&global_signal_cond
);
182 mono_os_mutex_unlock (&global_signal_mutex
);
184 handle_data
->signalled
=state
;
189 mono_w32handle_issignalled (gpointer handle
)
191 MonoW32HandleBase
*handle_data
;
193 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
197 return handle_data
->signalled
;
201 mono_w32handle_lock_signal_mutex (void)
204 g_message ("%s: lock global signal mutex", __func__
);
207 mono_os_mutex_lock (&global_signal_mutex
);
213 mono_w32handle_unlock_signal_mutex (void)
216 g_message ("%s: unlock global signal mutex", __func__
);
219 mono_os_mutex_unlock (&global_signal_mutex
);
225 mono_w32handle_lock_handle (gpointer handle
)
227 MonoW32HandleBase
*handle_data
;
230 g_message ("%s: locking handle %p", __func__
, handle
);
233 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
237 mono_w32handle_ref (handle
);
239 mono_os_mutex_lock (&handle_data
->signal_mutex
);
245 mono_w32handle_trylock_handle (gpointer handle
)
247 MonoW32HandleBase
*handle_data
;
251 g_message ("%s: locking handle %p", __func__
, handle
);
254 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
258 mono_w32handle_ref (handle
);
260 ret
= mono_os_mutex_trylock (&handle_data
->signal_mutex
);
262 mono_w32handle_unref (handle
);
269 mono_w32handle_unlock_handle (gpointer handle
)
271 MonoW32HandleBase
*handle_data
;
274 g_message ("%s: unlocking handle %p", __func__
, handle
);
277 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
281 mono_os_mutex_unlock (&handle_data
->signal_mutex
);
283 mono_w32handle_unref (handle
);
291 * Initialize the io-layer.
294 mono_w32handle_init (void)
296 static gboolean initialized
= FALSE
;
301 g_assert ((sizeof (handle_ops
) / sizeof (handle_ops
[0]))
302 == MONO_W32HANDLE_COUNT
);
304 /* This is needed by the code in mono_w32handle_new_internal */
305 mono_w32handle_fd_reserve
= (eg_getdtablesize () + (HANDLE_PER_SLOT
- 1)) & ~(HANDLE_PER_SLOT
- 1);
309 * The entries in private_handles reserved for fds are allocated lazily to
313 private_handles_count
+= HANDLE_PER_SLOT
;
314 private_handles_slots_count
++;
315 } while(mono_w32handle_fd_reserve
> private_handles_count
);
317 mono_os_mutex_init (&scan_mutex
);
319 mono_os_cond_init (&global_signal_cond
);
320 mono_os_mutex_init (&global_signal_mutex
);
325 static void mono_w32handle_unref_full (gpointer handle
, gboolean ignore_private_busy_handles
);
328 mono_w32handle_cleanup (void)
332 g_assert (!shutting_down
);
333 shutting_down
= TRUE
;
335 /* Every shared handle we were using ought really to be closed
336 * by now, but to make sure just blow them all away. The
337 * exiting finalizer thread in particular races us to the
338 * program exit and doesn't always win, so it can be left
339 * cluttering up the shared file. Anything else left over is
342 for(i
= SLOT_INDEX (0); private_handles
[i
] != NULL
; i
++) {
343 for(j
= SLOT_OFFSET (0); j
< HANDLE_PER_SLOT
; j
++) {
344 MonoW32HandleBase
*handle_data
= &private_handles
[i
][j
];
345 gpointer handle
= GINT_TO_POINTER (i
*HANDLE_PER_SLOT
+j
);
347 for(k
= handle_data
->ref
; k
> 0; k
--) {
348 mono_w32handle_unref_full (handle
, TRUE
);
353 for (i
= 0; i
< SLOT_MAX
; ++i
)
354 g_free (private_handles
[i
]);
357 static void mono_w32handle_init_handle (MonoW32HandleBase
*handle
,
358 MonoW32HandleType type
, gpointer handle_specific
)
360 g_assert (!shutting_down
);
363 handle
->signalled
= FALSE
;
366 mono_os_cond_init (&handle
->signal_cond
);
367 mono_os_mutex_init (&handle
->signal_mutex
);
370 handle
->specific
= g_memdup (handle_specific
, mono_w32handle_ops_typesize (type
));
374 * mono_w32handle_new_internal:
375 * @type: Init handle to this type
377 * Search for a free handle and initialize it. Return the handle on
378 * success and 0 on failure. This is only called from
379 * mono_w32handle_new, and scan_mutex must be held.
381 static guint32
mono_w32handle_new_internal (MonoW32HandleType type
,
382 gpointer handle_specific
)
385 static guint32 last
= 0;
386 gboolean retry
= FALSE
;
388 g_assert (!shutting_down
);
390 /* A linear scan should be fast enough. Start from the last
391 * allocation, assuming that handles are allocated more often
392 * than they're freed. Leave the space reserved for file
396 if (last
< mono_w32handle_fd_reserve
) {
397 last
= mono_w32handle_fd_reserve
;
404 for(i
= SLOT_INDEX (count
); i
< private_handles_slots_count
; i
++) {
405 if (private_handles
[i
]) {
406 for (k
= SLOT_OFFSET (count
); k
< HANDLE_PER_SLOT
; k
++) {
407 MonoW32HandleBase
*handle
= &private_handles
[i
][k
];
409 if(handle
->type
== MONO_W32HANDLE_UNUSED
) {
412 mono_w32handle_init_handle (handle
, type
, handle_specific
);
420 if(retry
&& last
> mono_w32handle_fd_reserve
) {
421 /* Try again from the beginning */
422 last
= mono_w32handle_fd_reserve
;
426 /* Will need to expand the array. The caller will sort it out */
432 mono_w32handle_new (MonoW32HandleType type
, gpointer handle_specific
)
434 guint32 handle_idx
= 0;
437 g_assert (!shutting_down
);
439 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Creating new handle of type %s", __func__
,
440 mono_w32handle_ops_typename (type
));
442 g_assert(!type_is_fd(type
));
444 mono_os_mutex_lock (&scan_mutex
);
446 while ((handle_idx
= mono_w32handle_new_internal (type
, handle_specific
)) == 0) {
447 /* Try and expand the array, and have another go */
448 int idx
= SLOT_INDEX (private_handles_count
);
449 if (idx
>= SLOT_MAX
) {
453 private_handles
[idx
] = g_new0 (MonoW32HandleBase
, HANDLE_PER_SLOT
);
455 private_handles_count
+= HANDLE_PER_SLOT
;
456 private_handles_slots_count
++;
459 mono_os_mutex_unlock (&scan_mutex
);
461 if (handle_idx
== 0) {
462 /* We ran out of slots */
463 handle
= INVALID_HANDLE_VALUE
;
467 /* Make sure we left the space for fd mappings */
468 g_assert (handle_idx
>= mono_w32handle_fd_reserve
);
470 handle
= GUINT_TO_POINTER (handle_idx
);
472 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Allocated new handle %p", __func__
, handle
);
478 gpointer
mono_w32handle_new_fd (MonoW32HandleType type
, int fd
,
479 gpointer handle_specific
)
481 MonoW32HandleBase
*handle_data
;
482 int fd_index
, fd_offset
;
484 g_assert (!shutting_down
);
486 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Creating new handle of type %s", __func__
,
487 mono_w32handle_ops_typename (type
));
489 g_assert(type_is_fd(type
));
491 if (fd
>= mono_w32handle_fd_reserve
) {
492 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: fd %d is too big", __func__
, fd
);
494 return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE
));
497 fd_index
= SLOT_INDEX (fd
);
498 fd_offset
= SLOT_OFFSET (fd
);
500 /* Initialize the array entries on demand */
501 if (!private_handles
[fd_index
]) {
502 mono_os_mutex_lock (&scan_mutex
);
504 if (!private_handles
[fd_index
])
505 private_handles
[fd_index
] = g_new0 (MonoW32HandleBase
, HANDLE_PER_SLOT
);
507 mono_os_mutex_unlock (&scan_mutex
);
510 handle_data
= &private_handles
[fd_index
][fd_offset
];
512 if (handle_data
->type
!= MONO_W32HANDLE_UNUSED
) {
513 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: fd %d is already in use!", __func__
, fd
);
514 /* FIXME: clean up this handle? We can't do anything
515 * with the fd, cos thats the new one
519 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Assigning new fd handle %p", __func__
, (gpointer
)(gsize
)fd
);
521 mono_w32handle_init_handle (handle_data
, type
, handle_specific
);
523 return(GUINT_TO_POINTER(fd
));
527 mono_w32handle_lookup (gpointer handle
, MonoW32HandleType type
,
528 gpointer
*handle_specific
)
530 MonoW32HandleBase
*handle_data
;
532 g_assert (handle_specific
);
534 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
538 if (handle_data
->type
!= type
) {
542 *handle_specific
= handle_data
->specific
;
548 mono_w32handle_foreach (gboolean (*on_each
)(gpointer handle
, gpointer data
, gpointer user_data
), gpointer user_data
)
550 MonoW32HandleBase
*handle_data
= NULL
;
554 mono_os_mutex_lock (&scan_mutex
);
556 for (i
= SLOT_INDEX (0); i
< private_handles_slots_count
; i
++) {
557 if (private_handles
[i
]) {
558 for (k
= SLOT_OFFSET (0); k
< HANDLE_PER_SLOT
; k
++) {
559 handle_data
= &private_handles
[i
][k
];
560 if (handle_data
->type
== MONO_W32HANDLE_UNUSED
)
562 handle
= GUINT_TO_POINTER (i
* HANDLE_PER_SLOT
+ k
);
563 if (on_each (handle
, handle_data
->specific
, user_data
) == TRUE
)
570 mono_os_mutex_unlock (&scan_mutex
);
573 /* This might list some shared handles twice if they are already
574 * opened by this process, and the check function returns FALSE the
575 * first time. Shared handles that are created during the search are
576 * unreffed if the check function returns FALSE, so callers must not
577 * rely on the handle persisting (unless the check function returns
579 * The caller owns the returned handle.
581 gpointer
mono_w32handle_search (MonoW32HandleType type
,
582 gboolean (*check
)(gpointer test
, gpointer user
),
584 gpointer
*handle_specific
,
585 gboolean search_shared
)
587 MonoW32HandleBase
*handle_data
= NULL
;
590 gboolean found
= FALSE
;
592 mono_os_mutex_lock (&scan_mutex
);
594 for (i
= SLOT_INDEX (0); !found
&& i
< private_handles_slots_count
; i
++) {
595 if (private_handles
[i
]) {
596 for (k
= SLOT_OFFSET (0); k
< HANDLE_PER_SLOT
; k
++) {
597 handle_data
= &private_handles
[i
][k
];
599 if (handle_data
->type
== type
) {
600 ret
= GUINT_TO_POINTER (i
* HANDLE_PER_SLOT
+ k
);
601 if (check (ret
, user_data
) == TRUE
) {
602 mono_w32handle_ref (ret
);
611 mono_os_mutex_unlock (&scan_mutex
);
618 if(handle_specific
!= NULL
) {
619 *handle_specific
= handle_data
->specific
;
626 void mono_w32handle_ref (gpointer handle
)
628 MonoW32HandleBase
*handle_data
;
630 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
631 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Attempting to ref invalid private handle %p", __func__
, handle
);
635 InterlockedIncrement ((gint32
*)&handle_data
->ref
);
638 g_message ("%s: %s handle %p ref now %d",
639 __func__
, mono_w32handle_ops_typename (handle_data
->type
), handle
, handle_data
->ref
);
643 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type
))(gpointer
, gpointer
);
645 /* The handle must not be locked on entry to this function */
646 static void mono_w32handle_unref_full (gpointer handle
, gboolean ignore_private_busy_handles
)
648 MonoW32HandleBase
*handle_data
;
649 gboolean destroy
= FALSE
, early_exit
= FALSE
;
652 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
653 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Attempting to unref invalid private handle %p",
658 /* Possible race condition here if another thread refs the
659 * handle between here and setting the type to UNUSED. I
660 * could lock a mutex, but I'm not sure that allowing a handle
661 * reference to reach 0 isn't an application bug anyway.
663 destroy
= (InterlockedDecrement ((gint32
*)&handle_data
->ref
) ==0);
666 g_message ("%s: %s handle %p ref now %d (destroy %s)",
667 __func__
, mono_w32handle_ops_typename (handle_data
->type
), handle
, handle_data
->ref
, destroy
?"TRUE":"FALSE");
671 /* Need to copy the handle info, reset the slot in the
672 * array, and _only then_ call the close function to
673 * avoid race conditions (eg file descriptors being
674 * closed, and another file being opened getting the
675 * same fd racing the memset())
677 MonoW32HandleType type
;
678 gpointer handle_specific
;
679 void (*close_func
)(gpointer
, gpointer
);
681 type
= handle_data
->type
;
682 handle_specific
= handle_data
->specific
;
684 mono_os_mutex_lock (&scan_mutex
);
686 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Destroying handle %p", __func__
, handle
);
688 /* Destroy the mutex and cond var. We hope nobody
689 * tried to grab them between the handle unlock and
690 * now, but pthreads doesn't have a
691 * "unlock_and_destroy" atomic function.
693 thr_ret
= mono_os_mutex_destroy (&handle_data
->signal_mutex
);
694 /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
695 if (thr_ret
== EBUSY
&& ignore_private_busy_handles
) {
699 g_error ("Error destroying handle %p mutex due to %d\n", handle
, thr_ret
);
701 thr_ret
= mono_os_cond_destroy (&handle_data
->signal_cond
);
702 if (thr_ret
== EBUSY
&& ignore_private_busy_handles
)
704 else if (thr_ret
!= 0)
705 g_error ("Error destroying handle %p cond var due to %d\n", handle
, thr_ret
);
708 memset (handle_data
, 0, sizeof (MonoW32HandleBase
));
710 mono_os_mutex_unlock (&scan_mutex
);
715 close_func
= _wapi_handle_ops_get_close_func (type
);
716 if (close_func
!= NULL
) {
717 close_func (handle
, handle_specific
);
720 g_free (handle_specific
);
724 void mono_w32handle_unref (gpointer handle
)
726 mono_w32handle_unref_full (handle
, FALSE
);
730 mono_w32handle_register_ops (MonoW32HandleType type
, MonoW32HandleOps
*ops
)
732 handle_ops
[type
] = ops
;
735 void mono_w32handle_register_capabilities (MonoW32HandleType type
,
736 MonoW32HandleCapability caps
)
738 handle_caps
[type
] = caps
;
741 gboolean
mono_w32handle_test_capabilities (gpointer handle
,
742 MonoW32HandleCapability caps
)
744 MonoW32HandleBase
*handle_data
;
745 MonoW32HandleType type
;
747 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
751 type
= handle_data
->type
;
753 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: testing 0x%x against 0x%x (%d)", __func__
,
754 handle_caps
[type
], caps
, handle_caps
[type
] & caps
);
756 return((handle_caps
[type
] & caps
) != 0);
759 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type
))(gpointer
, gpointer
)
761 if (handle_ops
[type
] != NULL
&&
762 handle_ops
[type
]->close
!= NULL
) {
763 return (handle_ops
[type
]->close
);
769 void mono_w32handle_ops_close (gpointer handle
, gpointer data
)
771 MonoW32HandleBase
*handle_data
;
772 MonoW32HandleType type
;
774 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
778 type
= handle_data
->type
;
780 if (handle_ops
[type
] != NULL
&&
781 handle_ops
[type
]->close
!= NULL
) {
782 handle_ops
[type
]->close (handle
, data
);
786 void mono_w32handle_ops_details (MonoW32HandleType type
, gpointer data
)
788 if (handle_ops
[type
] != NULL
&&
789 handle_ops
[type
]->details
!= NULL
) {
790 handle_ops
[type
]->details (data
);
794 const gchar
* mono_w32handle_ops_typename (MonoW32HandleType type
)
796 g_assert (handle_ops
[type
]);
797 g_assert (handle_ops
[type
]->typename
);
798 return handle_ops
[type
]->typename ();
801 gsize
mono_w32handle_ops_typesize (MonoW32HandleType type
)
803 g_assert (handle_ops
[type
]);
804 g_assert (handle_ops
[type
]->typesize
);
805 return handle_ops
[type
]->typesize ();
808 void mono_w32handle_ops_signal (gpointer handle
)
810 MonoW32HandleBase
*handle_data
;
811 MonoW32HandleType type
;
813 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
817 type
= handle_data
->type
;
819 if (handle_ops
[type
] != NULL
&& handle_ops
[type
]->signal
!= NULL
) {
820 handle_ops
[type
]->signal (handle
);
824 gboolean
mono_w32handle_ops_own (gpointer handle
)
826 MonoW32HandleBase
*handle_data
;
827 MonoW32HandleType type
;
829 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
833 type
= handle_data
->type
;
835 if (handle_ops
[type
] != NULL
&& handle_ops
[type
]->own_handle
!= NULL
) {
836 return(handle_ops
[type
]->own_handle (handle
));
842 gboolean
mono_w32handle_ops_isowned (gpointer handle
)
844 MonoW32HandleBase
*handle_data
;
845 MonoW32HandleType type
;
847 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
851 type
= handle_data
->type
;
853 if (handle_ops
[type
] != NULL
&& handle_ops
[type
]->is_owned
!= NULL
) {
854 return(handle_ops
[type
]->is_owned (handle
));
860 guint32
mono_w32handle_ops_specialwait (gpointer handle
, guint32 timeout
, gboolean
*alerted
)
862 MonoW32HandleBase
*handle_data
;
863 MonoW32HandleType type
;
865 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
869 type
= handle_data
->type
;
871 if (handle_ops
[type
] != NULL
&&
872 handle_ops
[type
]->special_wait
!= NULL
) {
873 return(handle_ops
[type
]->special_wait (handle
, timeout
, alerted
));
879 void mono_w32handle_ops_prewait (gpointer handle
)
881 MonoW32HandleBase
*handle_data
;
882 MonoW32HandleType type
;
884 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
888 type
= handle_data
->type
;
890 if (handle_ops
[type
] != NULL
&&
891 handle_ops
[type
]->prewait
!= NULL
) {
892 handle_ops
[type
]->prewait (handle
);
899 struct timespec sleepytime
;
901 g_assert (ms
< 1000);
903 sleepytime
.tv_sec
= 0;
904 sleepytime
.tv_nsec
= ms
* 1000000;
905 nanosleep (&sleepytime
, NULL
);
909 mono_w32handle_lock_handles (gpointer
*handles
, gsize numhandles
)
914 /* Lock all the handles, with backoff */
916 for(i
=0; i
<numhandles
; i
++) {
917 gpointer handle
= handles
[i
];
919 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: attempting to lock %p", __func__
, handle
);
921 thr_ret
= mono_w32handle_trylock_handle (handle
);
926 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: attempt failed for %p: %s", __func__
,
927 handle
, strerror (thr_ret
));
932 thr_ret
= mono_w32handle_unlock_handle (handle
);
933 g_assert (thr_ret
== 0);
936 /* If iter ever reaches 100 the nanosleep will
937 * return EINVAL immediately, but we have a
938 * design flaw if that happens.
942 g_warning ("%s: iteration overflow!",
947 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Backing off for %d ms", __func__
,
955 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Locked all handles", __func__
);
959 mono_w32handle_unlock_handles (gpointer
*handles
, gsize numhandles
)
964 for(i
=0; i
<numhandles
; i
++) {
965 gpointer handle
= handles
[i
];
967 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: unlocking handle %p", __func__
, handle
);
969 thr_ret
= mono_w32handle_unlock_handle (handle
);
970 g_assert (thr_ret
== 0);
975 mono_w32handle_timedwait_signal_naked (mono_cond_t
*cond
, mono_mutex_t
*mutex
, guint32 timeout
, gboolean poll
, gboolean
*alerted
)
980 res
= mono_os_cond_timedwait (cond
, mutex
, timeout
);
982 /* This is needed when waiting for process handles */
985 * pthread_cond_(timed)wait() can return 0 even if the condition was not
986 * signalled. This happens at least on Darwin. We surface this, i.e., we
987 * get spurious wake-ups.
989 * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
991 res
= mono_os_cond_timedwait (cond
, mutex
, timeout
);
994 /* Real timeout is less than 100ms time */
995 res
= mono_os_cond_timedwait (cond
, mutex
, timeout
);
997 res
= mono_os_cond_timedwait (cond
, mutex
, 100);
999 /* Mask the fake timeout, this will cause
1000 * another poll if the cond was not really signaled
1012 signal_global (gpointer unused
)
1014 /* If we reach here, then interrupt token is set to the flag value, which
1015 * means that the target thread is either
1016 * - before the first CAS in timedwait, which means it won't enter the wait.
1017 * - it is after the first CAS, so it is already waiting, or it will enter
1018 * the wait, and it will be interrupted by the broadcast. */
1019 mono_os_mutex_lock (&global_signal_mutex
);
1020 mono_os_cond_broadcast (&global_signal_cond
);
1021 mono_os_mutex_unlock (&global_signal_mutex
);
1025 mono_w32handle_timedwait_signal (guint32 timeout
, gboolean poll
, gboolean
*alerted
)
1029 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: waiting for global", __func__
);
1035 mono_thread_info_install_interrupt (signal_global
, NULL
, alerted
);
1040 res
= mono_w32handle_timedwait_signal_naked (&global_signal_cond
, &global_signal_mutex
, timeout
, poll
, alerted
);
1043 mono_thread_info_uninstall_interrupt (alerted
);
1049 signal_handle_and_unref (gpointer handle
)
1051 MonoW32HandleBase
*handle_data
;
1053 mono_mutex_t
*mutex
;
1055 if (!mono_w32handle_lookup_data (handle
, &handle_data
))
1056 g_error ("cannot signal unknown handle %p", handle
);
1058 /* If we reach here, then interrupt token is set to the flag value, which
1059 * means that the target thread is either
1060 * - before the first CAS in timedwait, which means it won't enter the wait.
1061 * - it is after the first CAS, so it is already waiting, or it will enter
1062 * the wait, and it will be interrupted by the broadcast. */
1063 cond
= &handle_data
->signal_cond
;
1064 mutex
= &handle_data
->signal_mutex
;
1066 mono_os_mutex_lock (mutex
);
1067 mono_os_cond_broadcast (cond
);
1068 mono_os_mutex_unlock (mutex
);
1070 mono_w32handle_unref (handle
);
1074 mono_w32handle_timedwait_signal_handle (gpointer handle
, guint32 timeout
, gboolean poll
, gboolean
*alerted
)
1076 MonoW32HandleBase
*handle_data
;
1079 if (!mono_w32handle_lookup_data (handle
, &handle_data
))
1080 g_error ("cannot wait on unknown handle %p", handle
);
1082 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: waiting for %p (type %s)", __func__
, handle
,
1083 mono_w32handle_ops_typename (mono_w32handle_get_type (handle
)));
1089 mono_thread_info_install_interrupt (signal_handle_and_unref
, handle
, alerted
);
1092 mono_w32handle_ref (handle
);
1095 res
= mono_w32handle_timedwait_signal_naked (&handle_data
->signal_cond
, &handle_data
->signal_mutex
, timeout
, poll
, alerted
);
1098 mono_thread_info_uninstall_interrupt (alerted
);
1100 /* if it is alerted, then the handle is unref in the interrupt callback */
1101 mono_w32handle_unref (handle
);
1108 void mono_w32handle_dump (void)
1110 MonoW32HandleBase
*handle_data
;
1113 mono_os_mutex_lock (&scan_mutex
);
1115 for(i
= SLOT_INDEX (0); i
< private_handles_slots_count
; i
++) {
1116 if (private_handles
[i
]) {
1117 for (k
= SLOT_OFFSET (0); k
< HANDLE_PER_SLOT
; k
++) {
1118 handle_data
= &private_handles
[i
][k
];
1120 if (handle_data
->type
== MONO_W32HANDLE_UNUSED
) {
1124 g_print ("%3x [%7s] %s %d ",
1125 i
* HANDLE_PER_SLOT
+ k
,
1126 mono_w32handle_ops_typename (handle_data
->type
),
1127 handle_data
->signalled
?"Sg":"Un",
1129 mono_w32handle_ops_details (handle_data
->type
, handle_data
->specific
);
1135 mono_os_mutex_unlock (&scan_mutex
);
1139 own_if_signalled (gpointer handle
)
1141 if (!mono_w32handle_issignalled (handle
))
1144 mono_w32handle_ops_own (handle
);
1149 own_if_owned( gpointer handle
)
1151 if (!mono_w32handle_ops_isowned (handle
))
1154 mono_w32handle_ops_own (handle
);
1158 MonoW32HandleWaitRet
1159 mono_w32handle_wait_one (gpointer handle
, guint32 timeout
, gboolean alertable
)
1161 MonoW32HandleWaitRet ret
;
1168 if (mono_w32handle_test_capabilities (handle
, MONO_W32HANDLE_CAP_SPECIAL_WAIT
)) {
1169 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p has special wait",
1172 switch (mono_w32handle_ops_specialwait (handle
, timeout
, alertable
? &alerted
: NULL
)) {
1174 ret
= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
;
1176 case WAIT_IO_COMPLETION
:
1177 ret
= MONO_W32HANDLE_WAIT_RET_ALERTED
;
1180 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1183 ret
= MONO_W32HANDLE_WAIT_RET_FAILED
;
1186 g_assert_not_reached ();
1190 ret
= MONO_W32HANDLE_WAIT_RET_ALERTED
;
1195 if (!mono_w32handle_test_capabilities (handle
, MONO_W32HANDLE_CAP_WAIT
)) {
1196 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p can't be waited for",
1199 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1202 thr_ret
= mono_w32handle_lock_handle (handle
);
1203 g_assert (thr_ret
== 0);
1205 if (mono_w32handle_test_capabilities (handle
, MONO_W32HANDLE_CAP_OWN
)) {
1206 if (own_if_owned (handle
)) {
1207 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p already owned",
1210 ret
= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
;
1215 if (timeout
!= INFINITE
)
1216 start
= mono_msec_ticks ();
1221 if (own_if_signalled (handle
)) {
1222 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p signalled",
1225 ret
= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
;
1229 mono_w32handle_ops_prewait (handle
);
1231 if (timeout
== INFINITE
) {
1232 waited
= mono_w32handle_timedwait_signal_handle (handle
, INFINITE
, FALSE
, alertable
? &alerted
: NULL
);
1236 elapsed
= mono_msec_ticks () - start
;
1237 if (elapsed
> timeout
) {
1238 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1242 waited
= mono_w32handle_timedwait_signal_handle (handle
, timeout
- elapsed
, FALSE
, alertable
? &alerted
: NULL
);
1246 ret
= MONO_W32HANDLE_WAIT_RET_ALERTED
;
1251 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1257 thr_ret
= mono_w32handle_unlock_handle (handle
);
1258 g_assert (thr_ret
== 0);
1263 MonoW32HandleWaitRet
1264 mono_w32handle_wait_multiple (gpointer
*handles
, gsize nhandles
, gboolean waitall
, guint32 timeout
, gboolean alertable
)
1266 MonoW32HandleWaitRet ret
;
1267 gboolean alerted
, poll
;
1270 gpointer handles_sorted
[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
];
1273 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1276 return mono_w32handle_wait_one (handles
[0], timeout
, alertable
);
1280 if (nhandles
> MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
) {
1281 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: too many handles: %d",
1282 __func__
, nhandles
);
1284 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1287 for (i
= 0; i
< nhandles
; ++i
) {
1288 if (!mono_w32handle_test_capabilities (handles
[i
], MONO_W32HANDLE_CAP_WAIT
)
1289 && !mono_w32handle_test_capabilities (handles
[i
], MONO_W32HANDLE_CAP_SPECIAL_WAIT
))
1291 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p can't be waited for",
1292 __func__
, handles
[i
]);
1294 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1297 handles_sorted
[i
] = handles
[i
];
1300 qsort (handles_sorted
, nhandles
, sizeof (gpointer
), g_direct_equal
);
1301 for (i
= 1; i
< nhandles
; ++i
) {
1302 if (handles_sorted
[i
- 1] == handles_sorted
[i
]) {
1303 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p is duplicated",
1304 __func__
, handles_sorted
[i
]);
1306 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1311 for (i
= 0; i
< nhandles
; ++i
) {
1312 if (mono_w32handle_get_type (handles
[i
]) == MONO_W32HANDLE_PROCESS
) {
1313 /* Can't wait for a process handle + another handle without polling */
1318 if (timeout
!= INFINITE
)
1319 start
= mono_msec_ticks ();
1321 for (i
= 0; i
< nhandles
; ++i
) {
1322 /* Add a reference, as we need to ensure the handle wont
1323 * disappear from under us while we're waiting in the loop
1324 * (not lock, as we don't want exclusive access here) */
1325 mono_w32handle_ref (handles
[i
]);
1329 gsize count
, lowest
;
1336 mono_w32handle_lock_handles (handles
, nhandles
);
1338 for (i
= 0; i
< nhandles
; i
++) {
1339 if ((mono_w32handle_test_capabilities (handles
[i
], MONO_W32HANDLE_CAP_OWN
) && mono_w32handle_ops_isowned (handles
[i
]))
1340 || mono_w32handle_issignalled (handles
[i
]))
1349 signalled
= (waitall
&& count
== nhandles
) || (!waitall
&& count
> 0);
1352 for (i
= 0; i
< nhandles
; i
++)
1353 own_if_signalled (handles
[i
]);
1356 mono_w32handle_unlock_handles (handles
, nhandles
);
1359 ret
= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
+ lowest
;
1363 for (i
= 0; i
< nhandles
; i
++) {
1364 mono_w32handle_ops_prewait (handles
[i
]);
1366 if (mono_w32handle_test_capabilities (handles
[i
], MONO_W32HANDLE_CAP_SPECIAL_WAIT
)
1367 && !mono_w32handle_issignalled (handles
[i
]))
1369 mono_w32handle_ops_specialwait (handles
[i
], 0, alertable
? &alerted
: NULL
);
1373 thr_ret
= mono_w32handle_lock_signal_mutex ();
1374 g_assert (thr_ret
== 0);
1378 for (i
= 0; i
< nhandles
; ++i
) {
1379 if (!mono_w32handle_issignalled (handles
[i
])) {
1386 for (i
= 0; i
< nhandles
; ++i
) {
1387 if (mono_w32handle_issignalled (handles
[i
])) {
1397 if (timeout
== INFINITE
) {
1398 waited
= mono_w32handle_timedwait_signal (INFINITE
, poll
, alertable
? &alerted
: NULL
);
1402 elapsed
= mono_msec_ticks () - start
;
1403 if (elapsed
> timeout
) {
1404 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1406 thr_ret
= mono_w32handle_unlock_signal_mutex ();
1407 g_assert (thr_ret
== 0);
1412 waited
= mono_w32handle_timedwait_signal (timeout
- elapsed
, poll
, alertable
? &alerted
: NULL
);
1416 thr_ret
= mono_w32handle_unlock_signal_mutex ();
1417 g_assert (thr_ret
== 0);
1420 ret
= MONO_W32HANDLE_WAIT_RET_ALERTED
;
1425 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1431 for (i
= 0; i
< nhandles
; i
++) {
1432 /* Unref everything we reffed above */
1433 mono_w32handle_unref (handles
[i
]);
1439 MonoW32HandleWaitRet
1440 mono_w32handle_signal_and_wait (gpointer signal_handle
, gpointer wait_handle
, guint32 timeout
, gboolean alertable
)
1442 MonoW32HandleWaitRet ret
;
1449 if (!mono_w32handle_test_capabilities (signal_handle
, MONO_W32HANDLE_CAP_SIGNAL
))
1450 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1451 if (!mono_w32handle_test_capabilities (wait_handle
, MONO_W32HANDLE_CAP_WAIT
))
1452 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1454 if (mono_w32handle_test_capabilities (wait_handle
, MONO_W32HANDLE_CAP_SPECIAL_WAIT
)) {
1455 g_warning ("%s: handle %p has special wait, implement me!!", __func__
, wait_handle
);
1456 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1459 thr_ret
= mono_w32handle_lock_handle (wait_handle
);
1460 g_assert (thr_ret
== 0);
1462 mono_w32handle_ops_signal (signal_handle
);
1464 if (mono_w32handle_test_capabilities (wait_handle
, MONO_W32HANDLE_CAP_OWN
)) {
1465 if (own_if_owned (wait_handle
)) {
1466 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p already owned",
1467 __func__
, wait_handle
);
1469 ret
= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
;
1474 if (timeout
!= INFINITE
)
1475 start
= mono_msec_ticks ();
1480 if (own_if_signalled (wait_handle
)) {
1481 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p signalled",
1482 __func__
, wait_handle
);
1484 ret
= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
;
1488 mono_w32handle_ops_prewait (wait_handle
);
1490 if (timeout
== INFINITE
) {
1491 waited
= mono_w32handle_timedwait_signal_handle (wait_handle
, INFINITE
, FALSE
, alertable
? &alerted
: NULL
);
1495 elapsed
= mono_msec_ticks () - start
;
1496 if (elapsed
> timeout
) {
1497 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1501 waited
= mono_w32handle_timedwait_signal_handle (wait_handle
, timeout
- elapsed
, FALSE
, alertable
? &alerted
: NULL
);
1505 ret
= MONO_W32HANDLE_WAIT_RET_ALERTED
;
1510 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1516 thr_ret
= mono_w32handle_unlock_handle (wait_handle
);
1517 g_assert (thr_ret
== 0);
1522 #endif /* !defined(HOST_WIN32) */