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
)
361 handle
->signalled
= FALSE
;
364 mono_os_cond_init (&handle
->signal_cond
);
365 mono_os_mutex_init (&handle
->signal_mutex
);
368 handle
->specific
= g_memdup (handle_specific
, mono_w32handle_ops_typesize (type
));
372 * mono_w32handle_new_internal:
373 * @type: Init handle to this type
375 * Search for a free handle and initialize it. Return the handle on
376 * success and 0 on failure. This is only called from
377 * mono_w32handle_new, and scan_mutex must be held.
379 static guint32
mono_w32handle_new_internal (MonoW32HandleType type
,
380 gpointer handle_specific
)
383 static guint32 last
= 0;
384 gboolean retry
= FALSE
;
386 /* A linear scan should be fast enough. Start from the last
387 * allocation, assuming that handles are allocated more often
388 * than they're freed. Leave the space reserved for file
392 if (last
< mono_w32handle_fd_reserve
) {
393 last
= mono_w32handle_fd_reserve
;
400 for(i
= SLOT_INDEX (count
); i
< private_handles_slots_count
; i
++) {
401 if (private_handles
[i
]) {
402 for (k
= SLOT_OFFSET (count
); k
< HANDLE_PER_SLOT
; k
++) {
403 MonoW32HandleBase
*handle
= &private_handles
[i
][k
];
405 if(handle
->type
== MONO_W32HANDLE_UNUSED
) {
408 mono_w32handle_init_handle (handle
, type
, handle_specific
);
416 if(retry
&& last
> mono_w32handle_fd_reserve
) {
417 /* Try again from the beginning */
418 last
= mono_w32handle_fd_reserve
;
422 /* Will need to expand the array. The caller will sort it out */
428 mono_w32handle_new (MonoW32HandleType type
, gpointer handle_specific
)
430 guint32 handle_idx
= 0;
433 g_assert (!shutting_down
);
435 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Creating new handle of type %s", __func__
,
436 mono_w32handle_ops_typename (type
));
438 g_assert(!type_is_fd(type
));
440 mono_os_mutex_lock (&scan_mutex
);
442 while ((handle_idx
= mono_w32handle_new_internal (type
, handle_specific
)) == 0) {
443 /* Try and expand the array, and have another go */
444 int idx
= SLOT_INDEX (private_handles_count
);
445 if (idx
>= SLOT_MAX
) {
449 private_handles
[idx
] = g_new0 (MonoW32HandleBase
, HANDLE_PER_SLOT
);
451 private_handles_count
+= HANDLE_PER_SLOT
;
452 private_handles_slots_count
++;
455 mono_os_mutex_unlock (&scan_mutex
);
457 if (handle_idx
== 0) {
458 /* We ran out of slots */
459 handle
= INVALID_HANDLE_VALUE
;
463 /* Make sure we left the space for fd mappings */
464 g_assert (handle_idx
>= mono_w32handle_fd_reserve
);
466 handle
= GUINT_TO_POINTER (handle_idx
);
468 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Allocated new handle %p", __func__
, handle
);
474 gpointer
mono_w32handle_new_fd (MonoW32HandleType type
, int fd
,
475 gpointer handle_specific
)
477 MonoW32HandleBase
*handle_data
;
478 int fd_index
, fd_offset
;
480 g_assert (!shutting_down
);
482 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Creating new handle of type %s", __func__
,
483 mono_w32handle_ops_typename (type
));
485 g_assert(type_is_fd(type
));
487 if (fd
>= mono_w32handle_fd_reserve
) {
488 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: fd %d is too big", __func__
, fd
);
490 return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE
));
493 fd_index
= SLOT_INDEX (fd
);
494 fd_offset
= SLOT_OFFSET (fd
);
496 /* Initialize the array entries on demand */
497 if (!private_handles
[fd_index
]) {
498 mono_os_mutex_lock (&scan_mutex
);
500 if (!private_handles
[fd_index
])
501 private_handles
[fd_index
] = g_new0 (MonoW32HandleBase
, HANDLE_PER_SLOT
);
503 mono_os_mutex_unlock (&scan_mutex
);
506 handle_data
= &private_handles
[fd_index
][fd_offset
];
508 if (handle_data
->type
!= MONO_W32HANDLE_UNUSED
) {
509 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: fd %d is already in use!", __func__
, fd
);
510 /* FIXME: clean up this handle? We can't do anything
511 * with the fd, cos thats the new one
515 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Assigning new fd handle %p", __func__
, (gpointer
)(gsize
)fd
);
517 mono_w32handle_init_handle (handle_data
, type
, handle_specific
);
519 return(GUINT_TO_POINTER(fd
));
523 mono_w32handle_lookup (gpointer handle
, MonoW32HandleType type
,
524 gpointer
*handle_specific
)
526 MonoW32HandleBase
*handle_data
;
528 g_assert (handle_specific
);
530 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
534 if (handle_data
->type
!= type
) {
538 *handle_specific
= handle_data
->specific
;
544 mono_w32handle_foreach (gboolean (*on_each
)(gpointer handle
, gpointer data
, gpointer user_data
), gpointer user_data
)
546 MonoW32HandleBase
*handle_data
= NULL
;
550 mono_os_mutex_lock (&scan_mutex
);
552 for (i
= SLOT_INDEX (0); i
< private_handles_slots_count
; i
++) {
553 if (private_handles
[i
]) {
554 for (k
= SLOT_OFFSET (0); k
< HANDLE_PER_SLOT
; k
++) {
555 handle_data
= &private_handles
[i
][k
];
556 if (handle_data
->type
== MONO_W32HANDLE_UNUSED
)
558 handle
= GUINT_TO_POINTER (i
* HANDLE_PER_SLOT
+ k
);
559 if (on_each (handle
, handle_data
->specific
, user_data
) == TRUE
)
566 mono_os_mutex_unlock (&scan_mutex
);
569 /* This might list some shared handles twice if they are already
570 * opened by this process, and the check function returns FALSE the
571 * first time. Shared handles that are created during the search are
572 * unreffed if the check function returns FALSE, so callers must not
573 * rely on the handle persisting (unless the check function returns
575 * The caller owns the returned handle.
577 gpointer
mono_w32handle_search (MonoW32HandleType type
,
578 gboolean (*check
)(gpointer test
, gpointer user
),
580 gpointer
*handle_specific
,
581 gboolean search_shared
)
583 MonoW32HandleBase
*handle_data
= NULL
;
586 gboolean found
= FALSE
;
588 mono_os_mutex_lock (&scan_mutex
);
590 for (i
= SLOT_INDEX (0); !found
&& i
< private_handles_slots_count
; i
++) {
591 if (private_handles
[i
]) {
592 for (k
= SLOT_OFFSET (0); k
< HANDLE_PER_SLOT
; k
++) {
593 handle_data
= &private_handles
[i
][k
];
595 if (handle_data
->type
== type
) {
596 ret
= GUINT_TO_POINTER (i
* HANDLE_PER_SLOT
+ k
);
597 if (check (ret
, user_data
) == TRUE
) {
598 mono_w32handle_ref (ret
);
607 mono_os_mutex_unlock (&scan_mutex
);
614 if(handle_specific
!= NULL
) {
615 *handle_specific
= handle_data
->specific
;
622 void mono_w32handle_ref (gpointer handle
)
624 MonoW32HandleBase
*handle_data
;
626 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
627 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Attempting to ref invalid private handle %p", __func__
, handle
);
631 InterlockedIncrement ((gint32
*)&handle_data
->ref
);
634 g_message ("%s: %s handle %p ref now %d",
635 __func__
, mono_w32handle_ops_typename (handle_data
->type
), handle
, handle_data
->ref
);
639 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type
))(gpointer
, gpointer
);
641 /* The handle must not be locked on entry to this function */
642 static void mono_w32handle_unref_full (gpointer handle
, gboolean ignore_private_busy_handles
)
644 MonoW32HandleBase
*handle_data
;
645 gboolean destroy
= FALSE
, early_exit
= FALSE
;
648 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
649 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Attempting to unref invalid private handle %p",
654 /* Possible race condition here if another thread refs the
655 * handle between here and setting the type to UNUSED. I
656 * could lock a mutex, but I'm not sure that allowing a handle
657 * reference to reach 0 isn't an application bug anyway.
659 destroy
= (InterlockedDecrement ((gint32
*)&handle_data
->ref
) ==0);
662 g_message ("%s: %s handle %p ref now %d (destroy %s)",
663 __func__
, mono_w32handle_ops_typename (handle_data
->type
), handle
, handle_data
->ref
, destroy
?"TRUE":"FALSE");
667 /* Need to copy the handle info, reset the slot in the
668 * array, and _only then_ call the close function to
669 * avoid race conditions (eg file descriptors being
670 * closed, and another file being opened getting the
671 * same fd racing the memset())
673 MonoW32HandleType type
;
674 gpointer handle_specific
;
675 void (*close_func
)(gpointer
, gpointer
);
677 type
= handle_data
->type
;
678 handle_specific
= handle_data
->specific
;
680 mono_os_mutex_lock (&scan_mutex
);
682 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Destroying handle %p", __func__
, handle
);
684 /* Destroy the mutex and cond var. We hope nobody
685 * tried to grab them between the handle unlock and
686 * now, but pthreads doesn't have a
687 * "unlock_and_destroy" atomic function.
689 thr_ret
= mono_os_mutex_destroy (&handle_data
->signal_mutex
);
690 /*WARNING gross hack to make cleanup not crash when exiting without the whole runtime teardown.*/
691 if (thr_ret
== EBUSY
&& ignore_private_busy_handles
) {
695 g_error ("Error destroying handle %p mutex due to %d\n", handle
, thr_ret
);
697 thr_ret
= mono_os_cond_destroy (&handle_data
->signal_cond
);
698 if (thr_ret
== EBUSY
&& ignore_private_busy_handles
)
700 else if (thr_ret
!= 0)
701 g_error ("Error destroying handle %p cond var due to %d\n", handle
, thr_ret
);
704 memset (handle_data
, 0, sizeof (MonoW32HandleBase
));
706 mono_os_mutex_unlock (&scan_mutex
);
711 close_func
= _wapi_handle_ops_get_close_func (type
);
712 if (close_func
!= NULL
) {
713 close_func (handle
, handle_specific
);
716 g_free (handle_specific
);
720 void mono_w32handle_unref (gpointer handle
)
722 mono_w32handle_unref_full (handle
, FALSE
);
726 mono_w32handle_register_ops (MonoW32HandleType type
, MonoW32HandleOps
*ops
)
728 handle_ops
[type
] = ops
;
731 void mono_w32handle_register_capabilities (MonoW32HandleType type
,
732 MonoW32HandleCapability caps
)
734 handle_caps
[type
] = caps
;
737 gboolean
mono_w32handle_test_capabilities (gpointer handle
,
738 MonoW32HandleCapability caps
)
740 MonoW32HandleBase
*handle_data
;
741 MonoW32HandleType type
;
743 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
747 type
= handle_data
->type
;
749 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: testing 0x%x against 0x%x (%d)", __func__
,
750 handle_caps
[type
], caps
, handle_caps
[type
] & caps
);
752 return((handle_caps
[type
] & caps
) != 0);
755 static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type
))(gpointer
, gpointer
)
757 if (handle_ops
[type
] != NULL
&&
758 handle_ops
[type
]->close
!= NULL
) {
759 return (handle_ops
[type
]->close
);
765 void mono_w32handle_ops_close (gpointer handle
, gpointer data
)
767 MonoW32HandleBase
*handle_data
;
768 MonoW32HandleType type
;
770 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
774 type
= handle_data
->type
;
776 if (handle_ops
[type
] != NULL
&&
777 handle_ops
[type
]->close
!= NULL
) {
778 handle_ops
[type
]->close (handle
, data
);
782 void mono_w32handle_ops_details (MonoW32HandleType type
, gpointer data
)
784 if (handle_ops
[type
] != NULL
&&
785 handle_ops
[type
]->details
!= NULL
) {
786 handle_ops
[type
]->details (data
);
790 const gchar
* mono_w32handle_ops_typename (MonoW32HandleType type
)
792 g_assert (handle_ops
[type
]);
793 g_assert (handle_ops
[type
]->typename
);
794 return handle_ops
[type
]->typename ();
797 gsize
mono_w32handle_ops_typesize (MonoW32HandleType type
)
799 g_assert (handle_ops
[type
]);
800 g_assert (handle_ops
[type
]->typesize
);
801 return handle_ops
[type
]->typesize ();
804 void mono_w32handle_ops_signal (gpointer handle
)
806 MonoW32HandleBase
*handle_data
;
807 MonoW32HandleType type
;
809 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
813 type
= handle_data
->type
;
815 if (handle_ops
[type
] != NULL
&& handle_ops
[type
]->signal
!= NULL
) {
816 handle_ops
[type
]->signal (handle
);
820 gboolean
mono_w32handle_ops_own (gpointer handle
)
822 MonoW32HandleBase
*handle_data
;
823 MonoW32HandleType type
;
825 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
829 type
= handle_data
->type
;
831 if (handle_ops
[type
] != NULL
&& handle_ops
[type
]->own_handle
!= NULL
) {
832 return(handle_ops
[type
]->own_handle (handle
));
838 gboolean
mono_w32handle_ops_isowned (gpointer handle
)
840 MonoW32HandleBase
*handle_data
;
841 MonoW32HandleType type
;
843 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
847 type
= handle_data
->type
;
849 if (handle_ops
[type
] != NULL
&& handle_ops
[type
]->is_owned
!= NULL
) {
850 return(handle_ops
[type
]->is_owned (handle
));
856 guint32
mono_w32handle_ops_specialwait (gpointer handle
, guint32 timeout
, gboolean
*alerted
)
858 MonoW32HandleBase
*handle_data
;
859 MonoW32HandleType type
;
861 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
865 type
= handle_data
->type
;
867 if (handle_ops
[type
] != NULL
&&
868 handle_ops
[type
]->special_wait
!= NULL
) {
869 return(handle_ops
[type
]->special_wait (handle
, timeout
, alerted
));
875 void mono_w32handle_ops_prewait (gpointer handle
)
877 MonoW32HandleBase
*handle_data
;
878 MonoW32HandleType type
;
880 if (!mono_w32handle_lookup_data (handle
, &handle_data
)) {
884 type
= handle_data
->type
;
886 if (handle_ops
[type
] != NULL
&&
887 handle_ops
[type
]->prewait
!= NULL
) {
888 handle_ops
[type
]->prewait (handle
);
895 struct timespec sleepytime
;
897 g_assert (ms
< 1000);
899 sleepytime
.tv_sec
= 0;
900 sleepytime
.tv_nsec
= ms
* 1000000;
901 nanosleep (&sleepytime
, NULL
);
905 mono_w32handle_lock_handles (gpointer
*handles
, gsize numhandles
)
910 /* Lock all the handles, with backoff */
912 for(i
=0; i
<numhandles
; i
++) {
913 gpointer handle
= handles
[i
];
915 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: attempting to lock %p", __func__
, handle
);
917 thr_ret
= mono_w32handle_trylock_handle (handle
);
922 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: attempt failed for %p: %s", __func__
,
923 handle
, strerror (thr_ret
));
928 thr_ret
= mono_w32handle_unlock_handle (handle
);
929 g_assert (thr_ret
== 0);
932 /* If iter ever reaches 100 the nanosleep will
933 * return EINVAL immediately, but we have a
934 * design flaw if that happens.
938 g_warning ("%s: iteration overflow!",
943 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Backing off for %d ms", __func__
,
951 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: Locked all handles", __func__
);
955 mono_w32handle_unlock_handles (gpointer
*handles
, gsize numhandles
)
960 for(i
=0; i
<numhandles
; i
++) {
961 gpointer handle
= handles
[i
];
963 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: unlocking handle %p", __func__
, handle
);
965 thr_ret
= mono_w32handle_unlock_handle (handle
);
966 g_assert (thr_ret
== 0);
971 mono_w32handle_timedwait_signal_naked (mono_cond_t
*cond
, mono_mutex_t
*mutex
, guint32 timeout
, gboolean poll
, gboolean
*alerted
)
976 res
= mono_os_cond_timedwait (cond
, mutex
, timeout
);
978 /* This is needed when waiting for process handles */
981 * pthread_cond_(timed)wait() can return 0 even if the condition was not
982 * signalled. This happens at least on Darwin. We surface this, i.e., we
983 * get spurious wake-ups.
985 * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
987 res
= mono_os_cond_timedwait (cond
, mutex
, timeout
);
990 /* Real timeout is less than 100ms time */
991 res
= mono_os_cond_timedwait (cond
, mutex
, timeout
);
993 res
= mono_os_cond_timedwait (cond
, mutex
, 100);
995 /* Mask the fake timeout, this will cause
996 * another poll if the cond was not really signaled
1008 signal_global (gpointer unused
)
1010 /* If we reach here, then interrupt token is set to the flag value, which
1011 * means that the target thread is either
1012 * - before the first CAS in timedwait, which means it won't enter the wait.
1013 * - it is after the first CAS, so it is already waiting, or it will enter
1014 * the wait, and it will be interrupted by the broadcast. */
1015 mono_os_mutex_lock (&global_signal_mutex
);
1016 mono_os_cond_broadcast (&global_signal_cond
);
1017 mono_os_mutex_unlock (&global_signal_mutex
);
1021 mono_w32handle_timedwait_signal (guint32 timeout
, gboolean poll
, gboolean
*alerted
)
1025 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: waiting for global", __func__
);
1031 mono_thread_info_install_interrupt (signal_global
, NULL
, alerted
);
1036 res
= mono_w32handle_timedwait_signal_naked (&global_signal_cond
, &global_signal_mutex
, timeout
, poll
, alerted
);
1039 mono_thread_info_uninstall_interrupt (alerted
);
1045 signal_handle_and_unref (gpointer handle
)
1047 MonoW32HandleBase
*handle_data
;
1049 mono_mutex_t
*mutex
;
1051 if (!mono_w32handle_lookup_data (handle
, &handle_data
))
1052 g_error ("cannot signal unknown handle %p", handle
);
1054 /* If we reach here, then interrupt token is set to the flag value, which
1055 * means that the target thread is either
1056 * - before the first CAS in timedwait, which means it won't enter the wait.
1057 * - it is after the first CAS, so it is already waiting, or it will enter
1058 * the wait, and it will be interrupted by the broadcast. */
1059 cond
= &handle_data
->signal_cond
;
1060 mutex
= &handle_data
->signal_mutex
;
1062 mono_os_mutex_lock (mutex
);
1063 mono_os_cond_broadcast (cond
);
1064 mono_os_mutex_unlock (mutex
);
1066 mono_w32handle_unref (handle
);
1070 mono_w32handle_timedwait_signal_handle (gpointer handle
, guint32 timeout
, gboolean poll
, gboolean
*alerted
)
1072 MonoW32HandleBase
*handle_data
;
1075 if (!mono_w32handle_lookup_data (handle
, &handle_data
))
1076 g_error ("cannot wait on unknown handle %p", handle
);
1078 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: waiting for %p (type %s)", __func__
, handle
,
1079 mono_w32handle_ops_typename (mono_w32handle_get_type (handle
)));
1085 mono_thread_info_install_interrupt (signal_handle_and_unref
, handle
, alerted
);
1088 mono_w32handle_ref (handle
);
1091 res
= mono_w32handle_timedwait_signal_naked (&handle_data
->signal_cond
, &handle_data
->signal_mutex
, timeout
, poll
, alerted
);
1094 mono_thread_info_uninstall_interrupt (alerted
);
1096 /* if it is alerted, then the handle is unref in the interrupt callback */
1097 mono_w32handle_unref (handle
);
1104 void mono_w32handle_dump (void)
1106 MonoW32HandleBase
*handle_data
;
1109 mono_os_mutex_lock (&scan_mutex
);
1111 for(i
= SLOT_INDEX (0); i
< private_handles_slots_count
; i
++) {
1112 if (private_handles
[i
]) {
1113 for (k
= SLOT_OFFSET (0); k
< HANDLE_PER_SLOT
; k
++) {
1114 handle_data
= &private_handles
[i
][k
];
1116 if (handle_data
->type
== MONO_W32HANDLE_UNUSED
) {
1120 g_print ("%3x [%7s] %s %d ",
1121 i
* HANDLE_PER_SLOT
+ k
,
1122 mono_w32handle_ops_typename (handle_data
->type
),
1123 handle_data
->signalled
?"Sg":"Un",
1125 mono_w32handle_ops_details (handle_data
->type
, handle_data
->specific
);
1131 mono_os_mutex_unlock (&scan_mutex
);
1135 own_if_signalled (gpointer handle
)
1137 if (!mono_w32handle_issignalled (handle
))
1140 mono_w32handle_ops_own (handle
);
1145 own_if_owned( gpointer handle
)
1147 if (!mono_w32handle_ops_isowned (handle
))
1150 mono_w32handle_ops_own (handle
);
1154 MonoW32HandleWaitRet
1155 mono_w32handle_wait_one (gpointer handle
, guint32 timeout
, gboolean alertable
)
1157 MonoW32HandleWaitRet ret
;
1164 if (mono_w32handle_test_capabilities (handle
, MONO_W32HANDLE_CAP_SPECIAL_WAIT
)) {
1165 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p has special wait",
1168 switch (mono_w32handle_ops_specialwait (handle
, timeout
, alertable
? &alerted
: NULL
)) {
1170 ret
= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
;
1172 case WAIT_IO_COMPLETION
:
1173 ret
= MONO_W32HANDLE_WAIT_RET_ALERTED
;
1176 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1179 ret
= MONO_W32HANDLE_WAIT_RET_FAILED
;
1182 g_assert_not_reached ();
1186 ret
= MONO_W32HANDLE_WAIT_RET_ALERTED
;
1191 if (!mono_w32handle_test_capabilities (handle
, MONO_W32HANDLE_CAP_WAIT
)) {
1192 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p can't be waited for",
1195 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1198 thr_ret
= mono_w32handle_lock_handle (handle
);
1199 g_assert (thr_ret
== 0);
1201 if (mono_w32handle_test_capabilities (handle
, MONO_W32HANDLE_CAP_OWN
)) {
1202 if (own_if_owned (handle
)) {
1203 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p already owned",
1206 ret
= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
;
1211 if (timeout
!= INFINITE
)
1212 start
= mono_msec_ticks ();
1217 if (own_if_signalled (handle
)) {
1218 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p signalled",
1221 ret
= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
;
1225 mono_w32handle_ops_prewait (handle
);
1227 if (timeout
== INFINITE
) {
1228 waited
= mono_w32handle_timedwait_signal_handle (handle
, INFINITE
, FALSE
, alertable
? &alerted
: NULL
);
1232 elapsed
= mono_msec_ticks () - start
;
1233 if (elapsed
> timeout
) {
1234 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1238 waited
= mono_w32handle_timedwait_signal_handle (handle
, timeout
- elapsed
, FALSE
, alertable
? &alerted
: NULL
);
1242 ret
= MONO_W32HANDLE_WAIT_RET_ALERTED
;
1247 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1253 thr_ret
= mono_w32handle_unlock_handle (handle
);
1254 g_assert (thr_ret
== 0);
1259 MonoW32HandleWaitRet
1260 mono_w32handle_wait_multiple (gpointer
*handles
, gsize nhandles
, gboolean waitall
, guint32 timeout
, gboolean alertable
)
1262 MonoW32HandleWaitRet ret
;
1263 gboolean alerted
, poll
;
1266 gpointer handles_sorted
[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
];
1269 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1272 return mono_w32handle_wait_one (handles
[0], timeout
, alertable
);
1276 if (nhandles
> MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
) {
1277 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: too many handles: %d",
1278 __func__
, nhandles
);
1280 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1283 for (i
= 0; i
< nhandles
; ++i
) {
1284 if (!mono_w32handle_test_capabilities (handles
[i
], MONO_W32HANDLE_CAP_WAIT
)
1285 && !mono_w32handle_test_capabilities (handles
[i
], MONO_W32HANDLE_CAP_SPECIAL_WAIT
))
1287 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p can't be waited for",
1288 __func__
, handles
[i
]);
1290 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1293 handles_sorted
[i
] = handles
[i
];
1296 qsort (handles_sorted
, nhandles
, sizeof (gpointer
), g_direct_equal
);
1297 for (i
= 1; i
< nhandles
; ++i
) {
1298 if (handles_sorted
[i
- 1] == handles_sorted
[i
]) {
1299 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p is duplicated",
1300 __func__
, handles_sorted
[i
]);
1302 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1307 for (i
= 0; i
< nhandles
; ++i
) {
1308 if (mono_w32handle_get_type (handles
[i
]) == MONO_W32HANDLE_PROCESS
) {
1309 /* Can't wait for a process handle + another handle without polling */
1314 if (timeout
!= INFINITE
)
1315 start
= mono_msec_ticks ();
1317 for (i
= 0; i
< nhandles
; ++i
) {
1318 /* Add a reference, as we need to ensure the handle wont
1319 * disappear from under us while we're waiting in the loop
1320 * (not lock, as we don't want exclusive access here) */
1321 mono_w32handle_ref (handles
[i
]);
1325 gsize count
, lowest
;
1332 mono_w32handle_lock_handles (handles
, nhandles
);
1334 for (i
= 0; i
< nhandles
; i
++) {
1335 if ((mono_w32handle_test_capabilities (handles
[i
], MONO_W32HANDLE_CAP_OWN
) && mono_w32handle_ops_isowned (handles
[i
]))
1336 || mono_w32handle_issignalled (handles
[i
]))
1345 signalled
= (waitall
&& count
== nhandles
) || (!waitall
&& count
> 0);
1348 for (i
= 0; i
< nhandles
; i
++)
1349 own_if_signalled (handles
[i
]);
1352 mono_w32handle_unlock_handles (handles
, nhandles
);
1355 ret
= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
+ lowest
;
1359 for (i
= 0; i
< nhandles
; i
++) {
1360 mono_w32handle_ops_prewait (handles
[i
]);
1362 if (mono_w32handle_test_capabilities (handles
[i
], MONO_W32HANDLE_CAP_SPECIAL_WAIT
)
1363 && !mono_w32handle_issignalled (handles
[i
]))
1365 mono_w32handle_ops_specialwait (handles
[i
], 0, alertable
? &alerted
: NULL
);
1369 thr_ret
= mono_w32handle_lock_signal_mutex ();
1370 g_assert (thr_ret
== 0);
1374 for (i
= 0; i
< nhandles
; ++i
) {
1375 if (!mono_w32handle_issignalled (handles
[i
])) {
1382 for (i
= 0; i
< nhandles
; ++i
) {
1383 if (mono_w32handle_issignalled (handles
[i
])) {
1393 if (timeout
== INFINITE
) {
1394 waited
= mono_w32handle_timedwait_signal (INFINITE
, poll
, alertable
? &alerted
: NULL
);
1398 elapsed
= mono_msec_ticks () - start
;
1399 if (elapsed
> timeout
) {
1400 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1402 thr_ret
= mono_w32handle_unlock_signal_mutex ();
1403 g_assert (thr_ret
== 0);
1408 waited
= mono_w32handle_timedwait_signal (timeout
- elapsed
, poll
, alertable
? &alerted
: NULL
);
1412 thr_ret
= mono_w32handle_unlock_signal_mutex ();
1413 g_assert (thr_ret
== 0);
1416 ret
= MONO_W32HANDLE_WAIT_RET_ALERTED
;
1421 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1427 for (i
= 0; i
< nhandles
; i
++) {
1428 /* Unref everything we reffed above */
1429 mono_w32handle_unref (handles
[i
]);
1435 MonoW32HandleWaitRet
1436 mono_w32handle_signal_and_wait (gpointer signal_handle
, gpointer wait_handle
, guint32 timeout
, gboolean alertable
)
1438 MonoW32HandleWaitRet ret
;
1445 if (!mono_w32handle_test_capabilities (signal_handle
, MONO_W32HANDLE_CAP_SIGNAL
))
1446 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1447 if (!mono_w32handle_test_capabilities (wait_handle
, MONO_W32HANDLE_CAP_WAIT
))
1448 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1450 if (mono_w32handle_test_capabilities (wait_handle
, MONO_W32HANDLE_CAP_SPECIAL_WAIT
)) {
1451 g_warning ("%s: handle %p has special wait, implement me!!", __func__
, wait_handle
);
1452 return MONO_W32HANDLE_WAIT_RET_FAILED
;
1455 thr_ret
= mono_w32handle_lock_handle (wait_handle
);
1456 g_assert (thr_ret
== 0);
1458 mono_w32handle_ops_signal (signal_handle
);
1460 if (mono_w32handle_test_capabilities (wait_handle
, MONO_W32HANDLE_CAP_OWN
)) {
1461 if (own_if_owned (wait_handle
)) {
1462 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p already owned",
1463 __func__
, wait_handle
);
1465 ret
= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
;
1470 if (timeout
!= INFINITE
)
1471 start
= mono_msec_ticks ();
1476 if (own_if_signalled (wait_handle
)) {
1477 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_W32HANDLE
, "%s: handle %p signalled",
1478 __func__
, wait_handle
);
1480 ret
= MONO_W32HANDLE_WAIT_RET_SUCCESS_0
;
1484 mono_w32handle_ops_prewait (wait_handle
);
1486 if (timeout
== INFINITE
) {
1487 waited
= mono_w32handle_timedwait_signal_handle (wait_handle
, INFINITE
, FALSE
, alertable
? &alerted
: NULL
);
1491 elapsed
= mono_msec_ticks () - start
;
1492 if (elapsed
> timeout
) {
1493 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1497 waited
= mono_w32handle_timedwait_signal_handle (wait_handle
, timeout
- elapsed
, FALSE
, alertable
? &alerted
: NULL
);
1501 ret
= MONO_W32HANDLE_WAIT_RET_ALERTED
;
1506 ret
= MONO_W32HANDLE_WAIT_RET_TIMEOUT
;
1512 thr_ret
= mono_w32handle_unlock_handle (wait_handle
);
1513 g_assert (thr_ret
== 0);
1518 #endif /* !defined(HOST_WIN32) */