#region Sync with metadata/object-internals.h
int lock_thread_id;
// stores a thread handle
- internal IntPtr system_thread_handle;
+ IntPtr handle;
+ IntPtr native_handle; // used only on Win32
/* Note this is an opaque object (an array), not a CultureInfo */
private object cached_culture_info;
// Closes the system thread handle
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern void Thread_free_internal(IntPtr handle);
+ private extern void Thread_free_internal();
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
~InternalThread() {
- Thread_free_internal(system_thread_handle);
+ Thread_free_internal();
}
}
* of icalls, do not require an increment.
*/
#pragma warning disable 169
- private const int mono_corlib_version = 160;
+ private const int mono_corlib_version = 161;
#pragma warning restore 169
[ComVisible (true)]
#include "mono/io-layer/wapi.h"
#include "mono/io-layer/wapi-private.h"
-#include "mono/utils/mono-once.h"
+#include "mono/utils/mono-lazy-init.h"
static pthread_key_t error_key;
-static mono_once_t error_key_once=MONO_ONCE_INIT;
+static mono_lazy_init_t error_key_once = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
static void error_init(void)
{
g_assert (ret == 0);
}
-void _wapi_error_cleanup (void)
+static void error_cleanup (void)
{
int ret;
g_assert (ret == 0);
}
+void _wapi_error_cleanup (void)
+{
+ mono_lazy_cleanup (&error_key_once, error_cleanup);
+}
+
/**
* GetLastError:
*
if (_wapi_has_shut_down)
return 0;
- mono_once(&error_key_once, error_init);
+ mono_lazy_initialize(&error_key_once, error_init);
errptr=pthread_getspecific(error_key);
err=GPOINTER_TO_UINT(errptr);
if (_wapi_has_shut_down)
return;
/* Set the thread-local error code */
- mono_once(&error_key_once, error_init);
+ mono_lazy_initialize(&error_key_once, error_init);
ret = pthread_setspecific(error_key, GUINT_TO_POINTER(code));
g_assert (ret == 0);
}
#include <mono/utils/strenc.h>
#include <mono/utils/mono-once.h>
#include <mono/utils/mono-logger-internals.h>
-#include <mono/utils/w32handle.h>
+#include <mono/metadata/w32handle.h>
/*
* If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise
#include <mono/io-layer/io-private.h>
#include <mono/io-layer/io-trace.h>
#include <mono/utils/mono-logger-internals.h>
-#include <mono/utils/w32handle.h>
+#include <mono/metadata/w32handle.h>
gboolean
_wapi_lock_file_region (int fd, off_t offset, off_t length)
#include <mono/io-layer/io-private.h>
#include <mono/io-layer/io-trace.h>
#include <mono/utils/mono-logger-internals.h>
-#include <mono/utils/w32handle.h>
+#include <mono/metadata/w32handle.h>
static guint32
convert_from_flags(int flags)
#include <mono/utils/mono-proclib.h>
#include <mono/utils/mono-once.h>
#include <mono/utils/mono-logger-internals.h>
-#include <mono/utils/w32handle.h>
+#include <mono/metadata/w32handle.h>
#define STILL_ACTIVE STATUS_PENDING
#include <mono/utils/mono-poll.h>
#include <mono/utils/mono-once.h>
#include <mono/utils/mono-logger-internals.h>
-#include <mono/utils/w32handle.h>
+#include <mono/metadata/w32handle.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <mono/io-layer/wapi.h>
#include <mono/io-layer/wapi-private.h>
-#include <mono/utils/w32handle.h>
+#include <mono/metadata/w32handle.h>
/**
* WaitForSingleObjectEx:
#define _WAPI_WAIT_H_
#include "mono/io-layer/status.h"
-#include "mono/utils/w32handle.h"
+#include "mono/metadata/w32handle.h"
G_BEGIN_DECLS
#include <mono/io-layer/io-private.h>
#include <mono/io-layer/socket-private.h>
#include <mono/io-layer/process-private.h>
-#include <mono/utils/w32handle.h>
+#include <mono/metadata/w32handle.h>
struct _WapiHandle_shared_ref
{
#include "socket-private.h"
#include "mono/utils/mono-lazy-init.h"
-#include "mono/utils/w32handle.h"
+#include "mono/metadata/w32handle.h"
gboolean _wapi_has_shut_down = FALSE;
w32semaphore.h \
w32event.h \
w32handle-namespace.h \
- w32handle-namespace.c
+ w32handle-namespace.c \
+ w32handle.h \
+ w32handle.c
# These source files have compile time dependencies on GC code
gc_dependent_sources = \
#include <mono/utils/atomic.h>
#include <mono/utils/mono-memory-model.h>
#include <mono/utils/mono-threads.h>
-#include <mono/utils/w32handle.h>
+#include <mono/metadata/w32handle.h>
#ifdef HOST_WIN32
#include <direct.h>
#endif
* Changes which are already detected at runtime, like the addition
* of icalls, do not require an increment.
*/
-#define MONO_CORLIB_VERSION 160
+#define MONO_CORLIB_VERSION 161
typedef struct
{
mono_domain_try_unload (domain, &exc);
}
-static guint32
-guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
+static MonoThreadInfoWaitRet
+guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
{
- guint32 result;
+ MonoThreadInfoWaitRet result;
MONO_ENTER_GC_SAFE;
- result = WaitForSingleObjectEx (handle, timeout, alertable);
+ result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
MONO_EXIT_GC_SAFE;
return result;
mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
{
MonoError error;
- HANDLE thread_handle;
+ MonoThreadHandle *thread_handle;
MonoAppDomainState prev_state;
MonoMethod *method;
unload_data *thread_data;
return;
/* Wait for the thread */
- while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
+ while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
/* The unload thread tries to abort us */
/* The icall wrapper will execute the abort */
static char *server_uri;
-static HANDLE receiver_thread_handle;
+static MonoThreadHandle *receiver_thread_handle;
static gboolean stop_receiver_thread;
/* Wait for the receiver thread to exit */
if (receiver_thread_handle)
- WaitForSingleObjectEx (receiver_thread_handle, 0, FALSE);
+ mono_thread_info_wait_one_handle (receiver_thread_handle, 0, FALSE);
}
static int
#include <mono/metadata/marshal.h>
#include <mono/utils/strenc.h>
#include <utils/mono-io-portability.h>
-#include <mono/utils/w32handle.h>
+#include <mono/metadata/w32handle.h>
#undef DEBUG
static void reference_queue_clear_for_domain (MonoDomain *domain);
-static guint32
-guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
+static MonoThreadInfoWaitRet
+guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
{
- guint32 result;
+ MonoThreadInfoWaitRet result;
MONO_ENTER_GC_SAFE;
- result = WaitForSingleObjectEx (handle, timeout, alertable);
+ result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
MONO_EXIT_GC_SAFE;
return result;
ResetEvent (pending_done_event);
mono_gc_finalize_notify ();
/* g_print ("Waiting for pending finalizers....\n"); */
- guarded_wait (pending_done_event, INFINITE, TRUE);
+ MONO_ENTER_GC_SAFE;
+ WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE);
+ MONO_EXIT_GC_SAFE;
/* g_print ("Done pending....\n"); */
#else
gboolean alerted = FALSE;
if (!gc_disabled) {
finished = TRUE;
if (mono_thread_internal_current () != gc_thread) {
+ int ret;
gint64 start_ticks = mono_msec_ticks ();
gint64 end_ticks = start_ticks + 2000;
}
if (!finalizer_thread_exited) {
- int ret;
-
/* Set a flag which the finalizer thread can check */
suspend_finalizers = TRUE;
mono_gc_suspend_finalizers ();
/* Wait for it to stop */
ret = guarded_wait (gc_thread->handle, 100, TRUE);
- if (ret == WAIT_TIMEOUT) {
+ if (ret == MONO_THREAD_INFO_WAIT_RET_TIMEOUT) {
/*
* The finalizer thread refused to exit. Make it stop.
*/
mono_thread_internal_stop (gc_thread);
ret = guarded_wait (gc_thread->handle, 100, TRUE);
- g_assert (ret != WAIT_TIMEOUT);
+ g_assert (ret != MONO_THREAD_INFO_WAIT_RET_TIMEOUT);
/* The thread can't set this flag */
finalizer_thread_exited = TRUE;
}
}
- int ret;
/* Wait for the thread to actually exit */
ret = guarded_wait (gc_thread->handle, INFINITE, TRUE);
- g_assert (ret == WAIT_OBJECT_0);
+ g_assert (ret == MONO_THREAD_INFO_WAIT_RET_SUCCESS_0);
mono_thread_join (GUINT_TO_POINTER (gc_thread->tid));
g_assert (finalizer_thread_exited);
struct _MonoInternalThread {
MonoObject obj;
volatile int lock_thread_id; /* to be used as the pre-shifted thread id in thin locks. Used for appdomain_ref push/pop */
- HANDLE handle;
+ MonoThreadHandle *handle;
+ HANDLE native_handle;
MonoArray *cached_culture_info;
gunichar2 *name;
guint32 name_len;
#include <mono/io-layer/io-layer.h>
/* FIXME: fix this code to not depend so much on the internals */
#include <mono/metadata/class-internals.h>
-#include <mono/utils/w32handle.h>
+#include <mono/metadata/w32handle.h>
#define LOGDEBUG(...)
/* define LOGDEBUG(...) g_message(__VA_ARGS__) */
#include <mono/utils/mono-threads.h>
#include <mono/utils/mono-memory-model.h>
#include <mono/utils/networking.h>
-#include <mono/utils/w32handle.h>
+#include <mono/metadata/w32handle.h>
#include <time.h>
#ifdef HAVE_SYS_TIME_H
void ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj);
HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this_obj, MonoObject *start);
-void ves_icall_System_Threading_InternalThread_Thread_free_internal(MonoInternalThread *this_obj, HANDLE thread);
+void ves_icall_System_Threading_InternalThread_Thread_free_internal(MonoInternalThread *this_obj);
void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms);
gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms);
gint32 ves_icall_System_Threading_Thread_GetDomainID (void);
#include <mono/utils/mono-memory-model.h>
#include <mono/utils/mono-threads-coop.h>
#include <mono/utils/mono-error-internals.h>
-#include <mono/utils/w32handle.h>
+#include <mono/metadata/w32handle.h>
#include <mono/metadata/w32event.h>
#include <mono/metadata/w32mutex.h>
static gint32 thread_interruption_requested = 0;
/* Event signaled when a thread changes its background mode */
-static HANDLE background_change_event;
+static MonoOSEvent background_change_event;
static gboolean shutting_down = FALSE;
mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPriority priority)
{
g_assert (internal);
- g_assert (internal->handle);
g_assert (priority >= MONO_THREAD_PRIORITY_LOWEST);
g_assert (priority <= MONO_THREAD_PRIORITY_HIGHEST);
#ifdef HOST_WIN32
BOOL res;
- res = SetThreadPriority (internal->handle, priority - 2);
+ g_assert (internal->native_handle);
+
+ res = SetThreadPriority (internal->native_handle, priority - 2);
if (!res)
g_error ("%s: SetThreadPriority failed, error %d", __func__, GetLastError ());
#else /* HOST_WIN32 */
info = mono_thread_info_current ();
internal = thread->internal_thread;
- internal->handle = mono_thread_info_duplicate_handle (info);
+ internal->handle = mono_threads_open_thread_handle (info->handle);
+#ifdef HOST_WIN32
+ internal->native_handle = OpenThread (THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId ());
+#endif
internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
internal->thread_info = info;
internal->small_id = info->small_id;
gboolean threadpool_thread, guint32 stack_size, MonoError *error)
{
StartInfo *start_info = NULL;
- HANDLE thread_handle;
+ MonoThreadHandle *thread_handle;
MonoNativeThreadId tid;
gboolean ret;
gsize stack_set_size;
if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
exit (mono_environment_exitcode_get ());
- mono_thread_info_exit ();
+ mono_thread_info_exit (0);
}
void
* This is called from the finalizer of the internal thread object.
*/
void
-ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
+ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj)
{
- THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
+ THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, this_obj->handle));
/*
* Since threads keep a reference to their thread object while running, by the time this function is called,
* the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
* when thread_cleanup () can be called after this.
*/
- if (thread)
- mono_threads_close_thread_handle (thread);
+ if (this_obj->handle) {
+ mono_threads_close_thread_handle (this_obj->handle);
+ this_obj->handle = NULL;
+ }
+
+#if HOST_WIN32
+ CloseHandle (this_obj->native_handle);
+#endif
if (this_obj->synch_cs) {
MonoCoopMutex *synch_cs = this_obj->synch_cs;
LOCK_THREAD (internal);
internal->priority = priority;
- if (internal->handle != NULL)
+ if (internal->thread_info != NULL)
mono_thread_internal_set_priority (internal, priority);
UNLOCK_THREAD (internal);
}
ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
{
MonoInternalThread *thread = this_obj->internal_thread;
- HANDLE handle = thread->handle;
+ MonoThreadHandle *handle = thread->handle;
MonoInternalThread *cur_thread = mono_thread_internal_current ();
gboolean ret;
mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
MONO_ENTER_GC_SAFE;
- ret=WaitForSingleObjectEx (handle, ms, TRUE);
+ ret=mono_thread_info_wait_one_handle (handle, ms, TRUE);
MONO_EXIT_GC_SAFE;
mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
- if(ret==WAIT_OBJECT_0) {
+ if(ret==MONO_THREAD_INFO_WAIT_RET_SUCCESS_0) {
THREAD_DEBUG (g_message ("%s: join successful", __func__));
return(TRUE);
* be notified, since it has to rebuild the list of threads to
* wait for.
*/
- mono_w32event_set (background_change_event);
+ mono_os_event_set (&background_change_event);
}
}
* be notified, since it has to rebuild the list of threads to
* wait for.
*/
- mono_w32event_set (background_change_event);
+ mono_os_event_set (&background_change_event);
}
}
mono_os_mutex_init_recursive(&interlocked_mutex);
mono_os_mutex_init_recursive(&joinable_threads_mutex);
- background_change_event = mono_w32event_create (TRUE, FALSE);
- g_assert(background_change_event != NULL);
+ mono_os_event_init (&background_change_event, TRUE, FALSE);
mono_init_static_data_info (&thread_static_info);
mono_init_static_data_info (&context_static_info);
void mono_thread_cleanup (void)
{
-#if !defined(RUN_IN_SUBTHREAD)
+#if !defined(RUN_IN_SUBTHREAD) && !defined(HOST_WIN32)
/* The main thread must abandon any held mutexes (particularly
* important for named mutexes as they are shared across
* processes, see bug 74680.) This will happen when the
* thread exits, but if it's not running in a subthread it
* won't exit in time.
*/
- mono_thread_info_set_exited (mono_thread_info_current ());
+ mono_w32mutex_abandon ();
#endif
#if 0
mono_os_mutex_destroy (&interlocked_mutex);
mono_os_mutex_destroy (&delayed_free_table_mutex);
mono_os_mutex_destroy (&small_id_mutex);
- CloseHandle (background_change_event);
+ mono_os_event_destroy (&background_change_event);
#endif
mono_native_tls_free (current_object_key);
struct wait_data
{
- HANDLE handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
+ MonoThreadHandle *handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
guint32 num;
};
static void
wait_for_tids (struct wait_data *wait, guint32 timeout)
{
- guint32 i, ret;
+ guint32 i;
+ MonoThreadInfoWaitRet ret;
THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
MONO_ENTER_GC_SAFE;
- ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
+ ret = mono_thread_info_wait_multiple_handle(wait->handles, wait->num, NULL, TRUE, timeout, TRUE);
MONO_EXIT_GC_SAFE;
- if(ret==WAIT_FAILED) {
+ if(ret==MONO_THREAD_INFO_WAIT_RET_FAILED) {
/* See the comment in build_wait_tids() */
THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
return;
for(i=0; i<wait->num; i++)
mono_threads_close_thread_handle (wait->handles [i]);
- if (ret == WAIT_TIMEOUT)
+ if (ret == MONO_THREAD_INFO_WAIT_RET_TIMEOUT)
return;
for(i=0; i<wait->num; i++) {
static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
{
- guint32 i, ret, count;
+ guint32 i;
+ MonoThreadInfoWaitRet ret;
THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
- /* Add the thread state change event, so it wakes up if a thread changes
- * to background mode.
- */
- count = wait->num;
- if (count < MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
- wait->handles [count] = background_change_event;
- count++;
- }
+ /* Add the thread state change event, so it wakes
+ * up if a thread changes to background mode. */
MONO_ENTER_GC_SAFE;
- ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
+ ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, &background_change_event, FALSE, timeout, TRUE);
MONO_EXIT_GC_SAFE;
- if(ret==WAIT_FAILED) {
+ if(ret==MONO_THREAD_INFO_WAIT_RET_FAILED) {
/* See the comment in build_wait_tids() */
THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
return;
for(i=0; i<wait->num; i++)
mono_threads_close_thread_handle (wait->handles [i]);
- if (ret == WAIT_TIMEOUT)
+ if (ret == MONO_THREAD_INFO_WAIT_RET_TIMEOUT)
return;
if (ret < wait->num) {
{
struct wait_data *wait=(struct wait_data *)user;
- if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
- HANDLE handle;
+ if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS - 1) {
MonoInternalThread *thread=(MonoInternalThread *)value;
/* Ignore background threads, we abort them later */
return;
}
- handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
- if (handle == NULL) {
- THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
- return;
- }
-
THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
- wait->handles[wait->num]=handle;
+ wait->handles[wait->num]=mono_threads_open_thread_handle (thread->handle);
wait->threads[wait->num]=thread;
wait->num++;
struct wait_data *wait=(struct wait_data *)user;
MonoNativeThreadId self = mono_native_thread_id_get ();
MonoInternalThread *thread = (MonoInternalThread *)value;
- HANDLE handle;
if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
return FALSE;
&& (thread->state & ThreadState_Background) != 0
&& (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
) {
- handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
- if (handle == NULL)
- return FALSE;
-
- wait->handles[wait->num] = handle;
+ wait->handles[wait->num] = mono_threads_open_thread_handle (thread->handle);
wait->threads[wait->num] = thread;
wait->num++;
mono_thread_detach_internal (current_thread);
/* Wake up other threads potentially waiting for us */
- mono_thread_info_exit ();
+ mono_thread_info_exit (0);
} else {
shutting_down = TRUE;
* interrupt the main thread if it is waiting for all
* the other threads.
*/
- mono_w32event_set (background_change_event);
+ mono_os_event_set (&background_change_event);
mono_threads_unlock ();
}
THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
mono_g_hash_table_foreach (threads, print_tids, NULL));
- mono_w32event_reset (background_change_event);
+ mono_os_event_reset (&background_change_event);
wait->num=0;
/*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
{
MonoInternalThread *thread = (MonoInternalThread*)value;
struct wait_data *wait = (struct wait_data*)user_data;
- HANDLE handle;
/*
* We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
return;
if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
- handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
- if (handle == NULL)
- return;
-
- wait->handles [wait->num] = handle;
+ wait->handles [wait->num] = mono_threads_open_thread_handle (thread->handle);
wait->threads [wait->num] = thread;
wait->num++;
}
/* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
- HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
- if (handle == NULL)
- return;
- data->wait.handles [data->wait.num] = handle;
+ data->wait.handles [data->wait.num] = mono_threads_open_thread_handle (thread->handle);
data->wait.threads [data->wait.num] = thread;
data->wait.num++;
} else {
or similar */
/* Our implementation of this function ignores the func argument */
#ifdef HOST_WIN32
- QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
+ QueueUserAPC ((PAPCFUNC)dummy_apc, thread->native_handle, (ULONG_PTR)NULL);
#else
mono_thread_info_self_interrupt ();
#endif
#include "w32handle-namespace.h"
#include "mono/io-layer/io-layer.h"
#include "mono/utils/mono-logger-internals.h"
-#include "mono/utils/w32handle.h"
+#include "mono/metadata/w32handle.h"
typedef struct {
gboolean manual;
#include <config.h>
#include <glib.h>
-#include "mono/utils/w32handle.h"
+#include "mono/metadata/w32handle.h"
#define MONO_W32HANDLE_NAMESPACE_MAX_PATH 260
--- /dev/null
+/*
+ * w32handle.c: Generic and internal operations on handles
+ *
+ * Author:
+ * Dick Porter (dick@ximian.com)
+ * Ludovic Henry (luhenry@microsoft.com)
+ *
+ * (C) 2002-2011 Novell, Inc.
+ * Copyright 2011 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
+#include <config.h>
+
+#if !defined(HOST_WIN32)
+
+#include <glib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <unistd.h>
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#include <string.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#endif
+#include <sys/stat.h>
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif
+
+#include "w32handle.h"
+
+#include "utils/atomic.h"
+#include "utils/mono-logger-internals.h"
+#include "utils/mono-os-mutex.h"
+#include "utils/mono-proclib.h"
+#include "utils/mono-threads.h"
+#include "utils/mono-time.h"
+
+#undef DEBUG_REFS
+
+#define SLOT_MAX (1024 * 16)
+
+/* must be a power of 2 */
+#define HANDLE_PER_SLOT (256)
+
+#define INFINITE 0xFFFFFFFF
+
+typedef struct {
+ MonoW32HandleType type;
+ guint ref;
+ gboolean signalled;
+ mono_mutex_t signal_mutex;
+ mono_cond_t signal_cond;
+ gpointer specific;
+} MonoW32HandleBase;
+
+static MonoW32HandleCapability handle_caps [MONO_W32HANDLE_COUNT];
+static MonoW32HandleOps *handle_ops [MONO_W32HANDLE_COUNT];
+
+/*
+ * We can hold SLOT_MAX * HANDLE_PER_SLOT handles.
+ * If 4M handles are not enough... Oh, well... we will crash.
+ */
+#define SLOT_INDEX(x) (x / HANDLE_PER_SLOT)
+#define SLOT_OFFSET(x) (x % HANDLE_PER_SLOT)
+
+static MonoW32HandleBase *private_handles [SLOT_MAX];
+static guint32 private_handles_count = 0;
+static guint32 private_handles_slots_count = 0;
+
+guint32 mono_w32handle_fd_reserve;
+
+/*
+ * This is an internal handle which is used for handling waiting for multiple handles.
+ * Threads which wait for multiple handles wait on this one handle, and when a handle
+ * is signalled, this handle is signalled too.
+ */
+static mono_mutex_t global_signal_mutex;
+static mono_cond_t global_signal_cond;
+
+static mono_mutex_t scan_mutex;
+
+static gboolean shutting_down = FALSE;
+
+static gboolean
+type_is_fd (MonoW32HandleType type)
+{
+ switch (type) {
+ case MONO_W32HANDLE_FILE:
+ case MONO_W32HANDLE_CONSOLE:
+ case MONO_W32HANDLE_SOCKET:
+ case MONO_W32HANDLE_PIPE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static gboolean
+mono_w32handle_lookup_data (gpointer handle, MonoW32HandleBase **handle_data)
+{
+ gsize index, offset;
+
+ g_assert (handle_data);
+
+ index = SLOT_INDEX ((gsize) handle);
+ if (index >= SLOT_MAX)
+ return FALSE;
+ if (!private_handles [index])
+ return FALSE;
+
+ offset = SLOT_OFFSET ((gsize) handle);
+ if (private_handles [index][offset].type == MONO_W32HANDLE_UNUSED)
+ return FALSE;
+
+ *handle_data = &private_handles [index][offset];
+ return TRUE;
+}
+
+MonoW32HandleType
+mono_w32handle_get_type (gpointer handle)
+{
+ MonoW32HandleBase *handle_data;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data))
+ return MONO_W32HANDLE_UNUSED; /* An impossible type */
+
+ return handle_data->type;
+}
+
+void
+mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast)
+{
+ MonoW32HandleBase *handle_data;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ return;
+ }
+
+#ifdef DEBUG
+ g_message ("%s: setting state of %p to %s (broadcast %s)", __func__,
+ handle, state?"TRUE":"FALSE", broadcast?"TRUE":"FALSE");
+#endif
+
+ if (state == TRUE) {
+ /* Tell everyone blocking on a single handle */
+
+ /* The condition the global signal cond is waiting on is the signalling of
+ * _any_ handle. So lock it before setting the signalled state.
+ */
+ mono_os_mutex_lock (&global_signal_mutex);
+
+ /* This function _must_ be called with
+ * handle->signal_mutex locked
+ */
+ handle_data->signalled=state;
+
+ if (broadcast == TRUE) {
+ mono_os_cond_broadcast (&handle_data->signal_cond);
+ } else {
+ mono_os_cond_signal (&handle_data->signal_cond);
+ }
+
+ /* Tell everyone blocking on multiple handles that something
+ * was signalled
+ */
+ mono_os_cond_broadcast (&global_signal_cond);
+
+ mono_os_mutex_unlock (&global_signal_mutex);
+ } else {
+ handle_data->signalled=state;
+ }
+}
+
+gboolean
+mono_w32handle_issignalled (gpointer handle)
+{
+ MonoW32HandleBase *handle_data;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ return(FALSE);
+ }
+
+ return handle_data->signalled;
+}
+
+static int
+mono_w32handle_lock_signal_mutex (void)
+{
+#ifdef DEBUG
+ g_message ("%s: lock global signal mutex", __func__);
+#endif
+
+ mono_os_mutex_lock (&global_signal_mutex);
+
+ return 0;
+}
+
+static int
+mono_w32handle_unlock_signal_mutex (void)
+{
+#ifdef DEBUG
+ g_message ("%s: unlock global signal mutex", __func__);
+#endif
+
+ mono_os_mutex_unlock (&global_signal_mutex);
+
+ return 0;
+}
+
+int
+mono_w32handle_lock_handle (gpointer handle)
+{
+ MonoW32HandleBase *handle_data;
+
+#ifdef DEBUG
+ g_message ("%s: locking handle %p", __func__, handle);
+#endif
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ return(0);
+ }
+
+ mono_w32handle_ref (handle);
+
+ mono_os_mutex_lock (&handle_data->signal_mutex);
+
+ return 0;
+}
+
+int
+mono_w32handle_trylock_handle (gpointer handle)
+{
+ MonoW32HandleBase *handle_data;
+ int ret;
+
+#ifdef DEBUG
+ g_message ("%s: locking handle %p", __func__, handle);
+#endif
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ return(0);
+ }
+
+ mono_w32handle_ref (handle);
+
+ ret = mono_os_mutex_trylock (&handle_data->signal_mutex);
+ if (ret != 0) {
+ mono_w32handle_unref (handle);
+ }
+
+ return(ret);
+}
+
+int
+mono_w32handle_unlock_handle (gpointer handle)
+{
+ MonoW32HandleBase *handle_data;
+
+#ifdef DEBUG
+ g_message ("%s: unlocking handle %p", __func__, handle);
+#endif
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ return(0);
+ }
+
+ mono_os_mutex_unlock (&handle_data->signal_mutex);
+
+ mono_w32handle_unref (handle);
+
+ return 0;
+}
+
+/*
+ * wapi_init:
+ *
+ * Initialize the io-layer.
+ */
+void
+mono_w32handle_init (void)
+{
+ static gboolean initialized = FALSE;
+
+ if (initialized)
+ return;
+
+ g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
+ == MONO_W32HANDLE_COUNT);
+
+ /* This is needed by the code in mono_w32handle_new_internal */
+ mono_w32handle_fd_reserve = (eg_getdtablesize () + (HANDLE_PER_SLOT - 1)) & ~(HANDLE_PER_SLOT - 1);
+
+ do {
+ /*
+ * The entries in private_handles reserved for fds are allocated lazily to
+ * save memory.
+ */
+
+ private_handles_count += HANDLE_PER_SLOT;
+ private_handles_slots_count ++;
+ } while(mono_w32handle_fd_reserve > private_handles_count);
+
+ mono_os_mutex_init (&scan_mutex);
+
+ mono_os_cond_init (&global_signal_cond);
+ mono_os_mutex_init (&global_signal_mutex);
+
+ initialized = TRUE;
+}
+
+void
+mono_w32handle_cleanup (void)
+{
+ int i, j, k;
+
+ g_assert (!shutting_down);
+ shutting_down = TRUE;
+
+ /* Every shared handle we were using ought really to be closed
+ * by now, but to make sure just blow them all away. The
+ * exiting finalizer thread in particular races us to the
+ * program exit and doesn't always win, so it can be left
+ * cluttering up the shared file. Anything else left over is
+ * really a bug.
+ */
+ for(i = SLOT_INDEX (0); private_handles[i] != NULL; i++) {
+ for(j = SLOT_OFFSET (0); j < HANDLE_PER_SLOT; j++) {
+ MonoW32HandleBase *handle_data = &private_handles[i][j];
+ gpointer handle = GINT_TO_POINTER (i*HANDLE_PER_SLOT+j);
+
+ for(k = handle_data->ref; k > 0; k--) {
+ mono_w32handle_unref (handle);
+ }
+ }
+ }
+
+ for (i = 0; i < SLOT_MAX; ++i)
+ g_free (private_handles [i]);
+}
+
+static void mono_w32handle_init_handle (MonoW32HandleBase *handle,
+ MonoW32HandleType type, gpointer handle_specific)
+{
+ g_assert (handle->ref == 0);
+
+ handle->type = type;
+ handle->signalled = FALSE;
+ handle->ref = 1;
+
+ mono_os_cond_init (&handle->signal_cond);
+ mono_os_mutex_init (&handle->signal_mutex);
+
+ if (handle_specific)
+ handle->specific = g_memdup (handle_specific, mono_w32handle_ops_typesize (type));
+}
+
+/*
+ * mono_w32handle_new_internal:
+ * @type: Init handle to this type
+ *
+ * Search for a free handle and initialize it. Return the handle on
+ * success and 0 on failure. This is only called from
+ * mono_w32handle_new, and scan_mutex must be held.
+ */
+static guint32 mono_w32handle_new_internal (MonoW32HandleType type,
+ gpointer handle_specific)
+{
+ guint32 i, k, count;
+ static guint32 last = 0;
+ gboolean retry = FALSE;
+
+ /* A linear scan should be fast enough. Start from the last
+ * allocation, assuming that handles are allocated more often
+ * than they're freed. Leave the space reserved for file
+ * descriptors
+ */
+
+ if (last < mono_w32handle_fd_reserve) {
+ last = mono_w32handle_fd_reserve;
+ } else {
+ retry = TRUE;
+ }
+
+again:
+ count = last;
+ for(i = SLOT_INDEX (count); i < private_handles_slots_count; i++) {
+ if (private_handles [i]) {
+ for (k = SLOT_OFFSET (count); k < HANDLE_PER_SLOT; k++) {
+ MonoW32HandleBase *handle = &private_handles [i][k];
+
+ if(handle->type == MONO_W32HANDLE_UNUSED) {
+ last = count + 1;
+
+ mono_w32handle_init_handle (handle, type, handle_specific);
+ return (count);
+ }
+ count++;
+ }
+ }
+ }
+
+ if(retry && last > mono_w32handle_fd_reserve) {
+ /* Try again from the beginning */
+ last = mono_w32handle_fd_reserve;
+ goto again;
+ }
+
+ /* Will need to expand the array. The caller will sort it out */
+
+ return(0);
+}
+
+gpointer
+mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific)
+{
+ guint32 handle_idx = 0;
+ gpointer handle;
+
+ g_assert (!shutting_down);
+
+ g_assert(!type_is_fd(type));
+
+ mono_os_mutex_lock (&scan_mutex);
+
+ while ((handle_idx = mono_w32handle_new_internal (type, handle_specific)) == 0) {
+ /* Try and expand the array, and have another go */
+ int idx = SLOT_INDEX (private_handles_count);
+ if (idx >= SLOT_MAX) {
+ break;
+ }
+
+ private_handles [idx] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT);
+
+ private_handles_count += HANDLE_PER_SLOT;
+ private_handles_slots_count ++;
+ }
+
+ mono_os_mutex_unlock (&scan_mutex);
+
+ if (handle_idx == 0) {
+ /* We ran out of slots */
+ handle = INVALID_HANDLE_VALUE;
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle", __func__, mono_w32handle_ops_typename (type));
+ goto done;
+ }
+
+ /* Make sure we left the space for fd mappings */
+ g_assert (handle_idx >= mono_w32handle_fd_reserve);
+
+ handle = GUINT_TO_POINTER (handle_idx);
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), handle);
+
+done:
+ return(handle);
+}
+
+gpointer mono_w32handle_new_fd (MonoW32HandleType type, int fd,
+ gpointer handle_specific)
+{
+ MonoW32HandleBase *handle_data;
+ int fd_index, fd_offset;
+
+ g_assert (!shutting_down);
+
+ g_assert(type_is_fd(type));
+
+ if (fd >= mono_w32handle_fd_reserve) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle, fd is too big", __func__, mono_w32handle_ops_typename (type));
+
+ return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE));
+ }
+
+ fd_index = SLOT_INDEX (fd);
+ fd_offset = SLOT_OFFSET (fd);
+
+ /* Initialize the array entries on demand */
+ if (!private_handles [fd_index]) {
+ mono_os_mutex_lock (&scan_mutex);
+
+ if (!private_handles [fd_index])
+ private_handles [fd_index] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT);
+
+ mono_os_mutex_unlock (&scan_mutex);
+ }
+
+ handle_data = &private_handles [fd_index][fd_offset];
+
+ if (handle_data->type != MONO_W32HANDLE_UNUSED) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle, fd is already in use", __func__, mono_w32handle_ops_typename (type));
+ /* FIXME: clean up this handle? We can't do anything
+ * with the fd, cos thats the new one
+ */
+ return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE));
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), GUINT_TO_POINTER(fd));
+
+ mono_w32handle_init_handle (handle_data, type, handle_specific);
+
+ return(GUINT_TO_POINTER(fd));
+}
+
+gboolean
+mono_w32handle_lookup (gpointer handle, MonoW32HandleType type,
+ gpointer *handle_specific)
+{
+ MonoW32HandleBase *handle_data;
+
+ g_assert (handle_specific);
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ return(FALSE);
+ }
+
+ if (handle_data->type != type) {
+ return(FALSE);
+ }
+
+ *handle_specific = handle_data->specific;
+
+ return(TRUE);
+}
+
+static gboolean
+mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data);
+
+static gboolean
+mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data, guint minimum);
+
+void
+mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data)
+{
+ guint32 i, k;
+
+ mono_os_mutex_lock (&scan_mutex);
+
+ for (i = SLOT_INDEX (0); i < private_handles_slots_count; i++) {
+ if (!private_handles [i])
+ continue;
+ for (k = SLOT_OFFSET (0); k < HANDLE_PER_SLOT; k++) {
+ MonoW32HandleBase *handle_data = NULL;
+ gpointer handle;
+ gboolean destroy, finished;
+
+ handle_data = &private_handles [i][k];
+ if (handle_data->type == MONO_W32HANDLE_UNUSED)
+ continue;
+
+ handle = GUINT_TO_POINTER (i * HANDLE_PER_SLOT + k);
+
+ if (!mono_w32handle_ref_core (handle, handle_data)) {
+ /* we are racing with mono_w32handle_unref:
+ * the handle ref has been decremented, but it
+ * hasn't yet been destroyed. */
+ continue;
+ }
+
+ finished = on_each (handle, handle_data->specific, user_data);
+
+ /* we do not want to have to destroy the handle here,
+ * as it would means the ref/unref are unbalanced */
+ destroy = mono_w32handle_unref_core (handle, handle_data, 2);
+ g_assert (!destroy);
+
+ if (finished)
+ goto done;
+ }
+ }
+
+done:
+ mono_os_mutex_unlock (&scan_mutex);
+}
+
+typedef struct {
+ MonoW32HandleType type;
+ gboolean (*search_user_callback)(gpointer handle, gpointer data);
+ gpointer search_user_data;
+ gpointer handle;
+ gpointer handle_specific;
+} SearchData;
+
+static gboolean
+search_callback (gpointer handle, gpointer handle_specific, gpointer user_data)
+{
+ SearchData *search_data = (SearchData*) user_data;
+
+ if (search_data->type != mono_w32handle_get_type (handle))
+ return FALSE;
+
+ if (!search_data->search_user_callback (handle, search_data->search_user_data))
+ return FALSE;
+
+ mono_w32handle_ref (handle);
+ search_data->handle = handle;
+ search_data->handle_specific = handle_specific;
+ return TRUE;
+}
+
+/* This might list some shared handles twice if they are already
+ * opened by this process, and the check function returns FALSE the
+ * first time. Shared handles that are created during the search are
+ * unreffed if the check function returns FALSE, so callers must not
+ * rely on the handle persisting (unless the check function returns
+ * TRUE)
+ * The caller owns the returned handle.
+ */
+gpointer mono_w32handle_search (MonoW32HandleType type,
+ gboolean (*check)(gpointer test, gpointer user),
+ gpointer user_data,
+ gpointer *handle_specific,
+ gboolean search_shared)
+{
+ SearchData search_data;
+
+ memset (&search_data, 0, sizeof (search_data));
+ search_data.type = type;
+ search_data.search_user_callback = check;
+ search_data.search_user_data = user_data;
+ mono_w32handle_foreach (search_callback, &search_data);
+ if (handle_specific)
+ *handle_specific = search_data.handle_specific;
+ return search_data.handle;
+}
+
+static gboolean
+mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data)
+{
+ guint old, new;
+
+ do {
+ old = handle_data->ref;
+ if (old == 0)
+ return FALSE;
+
+ new = old + 1;
+ } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old);
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: ref %s handle %p, ref: %d -> %d",
+ __func__, mono_w32handle_ops_typename (handle_data->type), handle, old, new);
+
+ return TRUE;
+}
+
+static gboolean
+mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data, guint minimum)
+{
+ MonoW32HandleType type;
+ guint old, new;
+
+ type = handle_data->type;
+
+ do {
+ old = handle_data->ref;
+ if (!(old >= minimum))
+ g_error ("%s: handle %p has ref %d, it should be >= %d", __func__, handle, old, minimum);
+
+ new = old - 1;
+ } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old);
+
+ /* handle_data might contain invalid data from now on, if
+ * another thread is unref'ing this handle at the same time */
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unref %s handle %p, ref: %d -> %d destroy: %s",
+ __func__, mono_w32handle_ops_typename (type), handle, old, new, new == 0 ? "true" : "false");
+
+ return new == 0;
+}
+
+void mono_w32handle_ref (gpointer handle)
+{
+ MonoW32HandleBase *handle_data;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to ref handle %p, unknown handle", __func__, handle);
+ return;
+ }
+
+ if (!mono_w32handle_ref_core (handle, handle_data))
+ g_error ("%s: failed to ref handle %p", __func__, handle);
+}
+
+static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer);
+
+/* The handle must not be locked on entry to this function */
+void
+mono_w32handle_unref (gpointer handle)
+{
+ MonoW32HandleBase *handle_data;
+ gboolean destroy;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to unref handle %p, unknown handle",
+ __func__, handle);
+ return;
+ }
+
+ destroy = mono_w32handle_unref_core (handle, handle_data, 1);
+
+ if (destroy) {
+ /* Need to copy the handle info, reset the slot in the
+ * array, and _only then_ call the close function to
+ * avoid race conditions (eg file descriptors being
+ * closed, and another file being opened getting the
+ * same fd racing the memset())
+ */
+ MonoW32HandleType type;
+ gpointer handle_specific;
+ void (*close_func)(gpointer, gpointer);
+
+ type = handle_data->type;
+ handle_specific = handle_data->specific;
+
+ mono_os_mutex_lock (&scan_mutex);
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: destroy %s handle %p", __func__, mono_w32handle_ops_typename (type), handle);
+
+ mono_os_mutex_destroy (&handle_data->signal_mutex);
+ mono_os_cond_destroy (&handle_data->signal_cond);
+
+ memset (handle_data, 0, sizeof (MonoW32HandleBase));
+
+ mono_os_mutex_unlock (&scan_mutex);
+
+ close_func = _wapi_handle_ops_get_close_func (type);
+ if (close_func != NULL) {
+ close_func (handle, handle_specific);
+ }
+
+ g_free (handle_specific);
+ }
+}
+
+void
+mono_w32handle_register_ops (MonoW32HandleType type, MonoW32HandleOps *ops)
+{
+ handle_ops [type] = ops;
+}
+
+void mono_w32handle_register_capabilities (MonoW32HandleType type,
+ MonoW32HandleCapability caps)
+{
+ handle_caps[type] = caps;
+}
+
+gboolean mono_w32handle_test_capabilities (gpointer handle,
+ MonoW32HandleCapability caps)
+{
+ MonoW32HandleBase *handle_data;
+ MonoW32HandleType type;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ return(FALSE);
+ }
+
+ type = handle_data->type;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: testing 0x%x against 0x%x (%d)", __func__,
+ handle_caps[type], caps, handle_caps[type] & caps);
+
+ return((handle_caps[type] & caps) != 0);
+}
+
+static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer)
+{
+ if (handle_ops[type] != NULL &&
+ handle_ops[type]->close != NULL) {
+ return (handle_ops[type]->close);
+ }
+
+ return (NULL);
+}
+
+void mono_w32handle_ops_close (gpointer handle, gpointer data)
+{
+ MonoW32HandleBase *handle_data;
+ MonoW32HandleType type;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ return;
+ }
+
+ type = handle_data->type;
+
+ if (handle_ops[type] != NULL &&
+ handle_ops[type]->close != NULL) {
+ handle_ops[type]->close (handle, data);
+ }
+}
+
+void mono_w32handle_ops_details (MonoW32HandleType type, gpointer data)
+{
+ if (handle_ops[type] != NULL &&
+ handle_ops[type]->details != NULL) {
+ handle_ops[type]->details (data);
+ }
+}
+
+const gchar* mono_w32handle_ops_typename (MonoW32HandleType type)
+{
+ g_assert (handle_ops [type]);
+ g_assert (handle_ops [type]->typename);
+ return handle_ops [type]->typename ();
+}
+
+gsize mono_w32handle_ops_typesize (MonoW32HandleType type)
+{
+ g_assert (handle_ops [type]);
+ g_assert (handle_ops [type]->typesize);
+ return handle_ops [type]->typesize ();
+}
+
+void mono_w32handle_ops_signal (gpointer handle)
+{
+ MonoW32HandleBase *handle_data;
+ MonoW32HandleType type;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ return;
+ }
+
+ type = handle_data->type;
+
+ if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
+ handle_ops[type]->signal (handle);
+ }
+}
+
+gboolean mono_w32handle_ops_own (gpointer handle, guint32 *statuscode)
+{
+ MonoW32HandleBase *handle_data;
+ MonoW32HandleType type;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ return(FALSE);
+ }
+
+ type = handle_data->type;
+
+ if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
+ return(handle_ops[type]->own_handle (handle, statuscode));
+ } else {
+ return(FALSE);
+ }
+}
+
+gboolean mono_w32handle_ops_isowned (gpointer handle)
+{
+ MonoW32HandleBase *handle_data;
+ MonoW32HandleType type;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ return(FALSE);
+ }
+
+ type = handle_data->type;
+
+ if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
+ return(handle_ops[type]->is_owned (handle));
+ } else {
+ return(FALSE);
+ }
+}
+
+guint32 mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *alerted)
+{
+ MonoW32HandleBase *handle_data;
+ MonoW32HandleType type;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ return(WAIT_FAILED);
+ }
+
+ type = handle_data->type;
+
+ if (handle_ops[type] != NULL &&
+ handle_ops[type]->special_wait != NULL) {
+ return(handle_ops[type]->special_wait (handle, timeout, alerted));
+ } else {
+ return(WAIT_FAILED);
+ }
+}
+
+void mono_w32handle_ops_prewait (gpointer handle)
+{
+ MonoW32HandleBase *handle_data;
+ MonoW32HandleType type;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data)) {
+ return;
+ }
+
+ type = handle_data->type;
+
+ if (handle_ops[type] != NULL &&
+ handle_ops[type]->prewait != NULL) {
+ handle_ops[type]->prewait (handle);
+ }
+}
+
+static void
+spin (guint32 ms)
+{
+ struct timespec sleepytime;
+
+ g_assert (ms < 1000);
+
+ sleepytime.tv_sec = 0;
+ sleepytime.tv_nsec = ms * 1000000;
+ nanosleep (&sleepytime, NULL);
+}
+
+static void
+mono_w32handle_lock_handles (gpointer *handles, gsize numhandles)
+{
+ guint32 i, iter=0;
+ int thr_ret;
+
+ /* Lock all the handles, with backoff */
+again:
+ for(i=0; i<numhandles; i++) {
+ gpointer handle = handles[i];
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempting to lock %p", __func__, handle);
+
+ thr_ret = mono_w32handle_trylock_handle (handle);
+
+ if (thr_ret != 0) {
+ /* Bummer */
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempt failed for %p: %s", __func__,
+ handle, strerror (thr_ret));
+
+ while (i--) {
+ handle = handles[i];
+
+ thr_ret = mono_w32handle_unlock_handle (handle);
+ g_assert (thr_ret == 0);
+ }
+
+ /* If iter ever reaches 100 the nanosleep will
+ * return EINVAL immediately, but we have a
+ * design flaw if that happens.
+ */
+ iter++;
+ if(iter==100) {
+ g_warning ("%s: iteration overflow!",
+ __func__);
+ iter=1;
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Backing off for %d ms", __func__,
+ iter*10);
+ spin (10 * iter);
+
+ goto again;
+ }
+ }
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Locked all handles", __func__);
+}
+
+static void
+mono_w32handle_unlock_handles (gpointer *handles, gsize numhandles)
+{
+ guint32 i;
+ int thr_ret;
+
+ for(i=0; i<numhandles; i++) {
+ gpointer handle = handles[i];
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unlocking handle %p", __func__, handle);
+
+ thr_ret = mono_w32handle_unlock_handle (handle);
+ g_assert (thr_ret == 0);
+ }
+}
+
+static int
+mono_w32handle_timedwait_signal_naked (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout, gboolean poll, gboolean *alerted)
+{
+ int res;
+
+ if (!poll) {
+ res = mono_os_cond_timedwait (cond, mutex, timeout);
+ } else {
+ /* This is needed when waiting for process handles */
+ if (!alerted) {
+ /*
+ * pthread_cond_(timed)wait() can return 0 even if the condition was not
+ * signalled. This happens at least on Darwin. We surface this, i.e., we
+ * get spurious wake-ups.
+ *
+ * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
+ */
+ res = mono_os_cond_timedwait (cond, mutex, timeout);
+ } else {
+ if (timeout < 100) {
+ /* Real timeout is less than 100ms time */
+ res = mono_os_cond_timedwait (cond, mutex, timeout);
+ } else {
+ res = mono_os_cond_timedwait (cond, mutex, 100);
+
+ /* Mask the fake timeout, this will cause
+ * another poll if the cond was not really signaled
+ */
+ if (res == -1)
+ res = 0;
+ }
+ }
+ }
+
+ return res;
+}
+
+static void
+signal_global (gpointer unused)
+{
+ /* If we reach here, then interrupt token is set to the flag value, which
+ * means that the target thread is either
+ * - before the first CAS in timedwait, which means it won't enter the wait.
+ * - it is after the first CAS, so it is already waiting, or it will enter
+ * the wait, and it will be interrupted by the broadcast. */
+ mono_os_mutex_lock (&global_signal_mutex);
+ mono_os_cond_broadcast (&global_signal_cond);
+ mono_os_mutex_unlock (&global_signal_mutex);
+}
+
+static int
+mono_w32handle_timedwait_signal (guint32 timeout, gboolean poll, gboolean *alerted)
+{
+ int res;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for global", __func__);
+
+ if (alerted)
+ *alerted = FALSE;
+
+ if (alerted) {
+ mono_thread_info_install_interrupt (signal_global, NULL, alerted);
+ if (*alerted)
+ return 0;
+ }
+
+ res = mono_w32handle_timedwait_signal_naked (&global_signal_cond, &global_signal_mutex, timeout, poll, alerted);
+
+ if (alerted)
+ mono_thread_info_uninstall_interrupt (alerted);
+
+ return res;
+}
+
+static void
+signal_handle_and_unref (gpointer handle)
+{
+ MonoW32HandleBase *handle_data;
+ mono_cond_t *cond;
+ mono_mutex_t *mutex;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data))
+ g_error ("cannot signal unknown handle %p", handle);
+
+ /* If we reach here, then interrupt token is set to the flag value, which
+ * means that the target thread is either
+ * - before the first CAS in timedwait, which means it won't enter the wait.
+ * - it is after the first CAS, so it is already waiting, or it will enter
+ * the wait, and it will be interrupted by the broadcast. */
+ cond = &handle_data->signal_cond;
+ mutex = &handle_data->signal_mutex;
+
+ mono_os_mutex_lock (mutex);
+ mono_os_cond_broadcast (cond);
+ mono_os_mutex_unlock (mutex);
+
+ mono_w32handle_unref (handle);
+}
+
+static int
+mono_w32handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean poll, gboolean *alerted)
+{
+ MonoW32HandleBase *handle_data;
+ int res;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data))
+ g_error ("cannot wait on unknown handle %p", handle);
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for %p (type %s)", __func__, handle,
+ mono_w32handle_ops_typename (mono_w32handle_get_type (handle)));
+
+ if (alerted)
+ *alerted = FALSE;
+
+ if (alerted) {
+ mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
+ if (*alerted)
+ return 0;
+ mono_w32handle_ref (handle);
+ }
+
+ res = mono_w32handle_timedwait_signal_naked (&handle_data->signal_cond, &handle_data->signal_mutex, timeout, poll, alerted);
+
+ if (alerted) {
+ mono_thread_info_uninstall_interrupt (alerted);
+ if (!*alerted) {
+ /* if it is alerted, then the handle is unref in the interrupt callback */
+ mono_w32handle_unref (handle);
+ }
+ }
+
+ return res;
+}
+
+static gboolean
+dump_callback (gpointer handle, gpointer handle_specific, gpointer user_data)
+{
+ MonoW32HandleBase *handle_data;
+
+ if (!mono_w32handle_lookup_data (handle, &handle_data))
+ g_error ("cannot dump unknown handle %p", handle);
+
+ g_print ("%p [%7s] signalled: %5s ref: %3d ",
+ handle, mono_w32handle_ops_typename (handle_data->type), handle_data->signalled ? "true" : "false", handle_data->ref);
+ mono_w32handle_ops_details (handle_data->type, handle_data->specific);
+ g_print ("\n");
+
+ return FALSE;
+}
+
+void mono_w32handle_dump (void)
+{
+ mono_w32handle_foreach (dump_callback, NULL);
+}
+
+static gboolean
+own_if_signalled (gpointer handle, guint32 *statuscode)
+{
+ if (!mono_w32handle_issignalled (handle))
+ return FALSE;
+
+ *statuscode = WAIT_OBJECT_0;
+ mono_w32handle_ops_own (handle, statuscode);
+ return TRUE;
+}
+
+static gboolean
+own_if_owned( gpointer handle, guint32 *statuscode)
+{
+ if (!mono_w32handle_ops_isowned (handle))
+ return FALSE;
+
+ *statuscode = WAIT_OBJECT_0;
+ mono_w32handle_ops_own (handle, statuscode);
+ return TRUE;
+}
+
+MonoW32HandleWaitRet
+mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable)
+{
+ MonoW32HandleWaitRet ret;
+ gboolean alerted;
+ gint64 start;
+ gint thr_ret;
+ guint32 statuscode = 0;
+
+ alerted = FALSE;
+
+ if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p has special wait",
+ __func__, handle);
+
+ switch (mono_w32handle_ops_specialwait (handle, timeout, alertable ? &alerted : NULL)) {
+ case WAIT_OBJECT_0:
+ ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
+ break;
+ case WAIT_ABANDONED_0:
+ ret = MONO_W32HANDLE_WAIT_RET_ABANDONED_0;
+ break;
+ case WAIT_IO_COMPLETION:
+ ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
+ break;
+ case WAIT_TIMEOUT:
+ ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
+ break;
+ case WAIT_FAILED:
+ ret = MONO_W32HANDLE_WAIT_RET_FAILED;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (alerted)
+ ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
+
+ return ret;
+ }
+
+ if (!mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_WAIT)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for",
+ __func__, handle);
+
+ return MONO_W32HANDLE_WAIT_RET_FAILED;
+ }
+
+ thr_ret = mono_w32handle_lock_handle (handle);
+ g_assert (thr_ret == 0);
+
+ if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_OWN)) {
+ if (own_if_owned (handle, &statuscode)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned",
+ __func__, handle);
+
+ ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
+ goto done;
+ }
+ }
+
+ if (timeout != INFINITE)
+ start = mono_msec_ticks ();
+
+ for (;;) {
+ gint waited;
+
+ if (own_if_signalled (handle, &statuscode)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled",
+ __func__, handle);
+
+ ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
+ goto done;
+ }
+
+ mono_w32handle_ops_prewait (handle);
+
+ if (timeout == INFINITE) {
+ waited = mono_w32handle_timedwait_signal_handle (handle, INFINITE, FALSE, alertable ? &alerted : NULL);
+ } else {
+ gint64 elapsed;
+
+ elapsed = mono_msec_ticks () - start;
+ if (elapsed > timeout) {
+ ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
+ goto done;
+ }
+
+ waited = mono_w32handle_timedwait_signal_handle (handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL);
+ }
+
+ if (alerted) {
+ ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
+ goto done;
+ }
+
+ if (waited != 0) {
+ ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
+ goto done;
+ }
+ }
+
+done:
+ thr_ret = mono_w32handle_unlock_handle (handle);
+ g_assert (thr_ret == 0);
+
+ return ret;
+}
+
+MonoW32HandleWaitRet
+mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable)
+{
+ MonoW32HandleWaitRet ret;
+ gboolean alerted, poll;
+ gint i, thr_ret;
+ gint64 start;
+ gpointer handles_sorted [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
+ guint32 statuscodes [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS] = {0};
+
+ if (nhandles == 0)
+ return MONO_W32HANDLE_WAIT_RET_FAILED;
+
+ if (nhandles == 1)
+ return mono_w32handle_wait_one (handles [0], timeout, alertable);
+
+ alerted = FALSE;
+
+ if (nhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: too many handles: %zd",
+ __func__, nhandles);
+
+ return MONO_W32HANDLE_WAIT_RET_FAILED;
+ }
+
+ for (i = 0; i < nhandles; ++i) {
+ if (!mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_WAIT)
+ && !mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_SPECIAL_WAIT))
+ {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for",
+ __func__, handles [i]);
+
+ return MONO_W32HANDLE_WAIT_RET_FAILED;
+ }
+
+ handles_sorted [i] = handles [i];
+ }
+
+ qsort (handles_sorted, nhandles, sizeof (gpointer), g_direct_equal);
+ for (i = 1; i < nhandles; ++i) {
+ if (handles_sorted [i - 1] == handles_sorted [i]) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p is duplicated",
+ __func__, handles_sorted [i]);
+
+ return MONO_W32HANDLE_WAIT_RET_FAILED;
+ }
+ }
+
+ poll = FALSE;
+ for (i = 0; i < nhandles; ++i) {
+ if (mono_w32handle_get_type (handles [i]) == MONO_W32HANDLE_PROCESS) {
+ /* Can't wait for a process handle + another handle without polling */
+ poll = TRUE;
+ }
+ }
+
+ if (timeout != INFINITE)
+ start = mono_msec_ticks ();
+
+ for (i = 0; i < nhandles; ++i) {
+ /* Add a reference, as we need to ensure the handle wont
+ * disappear from under us while we're waiting in the loop
+ * (not lock, as we don't want exclusive access here) */
+ mono_w32handle_ref (handles [i]);
+ }
+
+ for (;;) {
+ gsize count, lowest;
+ gboolean signalled;
+ gint waited;
+
+ count = 0;
+ lowest = nhandles;
+
+ mono_w32handle_lock_handles (handles, nhandles);
+
+ for (i = 0; i < nhandles; i++) {
+ if ((mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_OWN) && mono_w32handle_ops_isowned (handles [i]))
+ || mono_w32handle_issignalled (handles [i]))
+ {
+ count ++;
+
+ if (i < lowest)
+ lowest = i;
+ }
+ }
+
+ signalled = (waitall && count == nhandles) || (!waitall && count > 0);
+
+ if (signalled) {
+ for (i = 0; i < nhandles; i++)
+ own_if_signalled (handles [i], &statuscodes [i]);
+ }
+
+ mono_w32handle_unlock_handles (handles, nhandles);
+
+ if (signalled) {
+ ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + lowest;
+ for (i = lowest; i < nhandles; i++) {
+ if (statuscodes [i] == WAIT_ABANDONED_0) {
+ ret = MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + lowest;
+ break;
+ }
+ }
+ goto done;
+ }
+
+ for (i = 0; i < nhandles; i++) {
+ mono_w32handle_ops_prewait (handles[i]);
+
+ if (mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_SPECIAL_WAIT)
+ && !mono_w32handle_issignalled (handles [i]))
+ {
+ mono_w32handle_ops_specialwait (handles [i], 0, alertable ? &alerted : NULL);
+ }
+ }
+
+ thr_ret = mono_w32handle_lock_signal_mutex ();
+ g_assert (thr_ret == 0);
+
+ if (waitall) {
+ signalled = TRUE;
+ for (i = 0; i < nhandles; ++i) {
+ if (!mono_w32handle_issignalled (handles [i])) {
+ signalled = FALSE;
+ break;
+ }
+ }
+ } else {
+ signalled = FALSE;
+ for (i = 0; i < nhandles; ++i) {
+ if (mono_w32handle_issignalled (handles [i])) {
+ signalled = TRUE;
+ break;
+ }
+ }
+ }
+
+ waited = 0;
+
+ if (!signalled) {
+ if (timeout == INFINITE) {
+ waited = mono_w32handle_timedwait_signal (INFINITE, poll, alertable ? &alerted : NULL);
+ } else {
+ gint64 elapsed;
+
+ elapsed = mono_msec_ticks () - start;
+ if (elapsed > timeout) {
+ ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
+
+ thr_ret = mono_w32handle_unlock_signal_mutex ();
+ g_assert (thr_ret == 0);
+
+ goto done;
+ }
+
+ waited = mono_w32handle_timedwait_signal (timeout - elapsed, poll, alertable ? &alerted : NULL);
+ }
+ }
+
+ thr_ret = mono_w32handle_unlock_signal_mutex ();
+ g_assert (thr_ret == 0);
+
+ if (alerted) {
+ ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
+ goto done;
+ }
+
+ if (waited != 0) {
+ ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
+ goto done;
+ }
+ }
+
+done:
+ for (i = 0; i < nhandles; i++) {
+ /* Unref everything we reffed above */
+ mono_w32handle_unref (handles [i]);
+ }
+
+ return ret;
+}
+
+MonoW32HandleWaitRet
+mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable)
+{
+ MonoW32HandleWaitRet ret;
+ gint64 start;
+ gboolean alerted;
+ gint thr_ret;
+ guint32 statuscode = 0;
+
+ alerted = FALSE;
+
+ if (!mono_w32handle_test_capabilities (signal_handle, MONO_W32HANDLE_CAP_SIGNAL))
+ return MONO_W32HANDLE_WAIT_RET_FAILED;
+ if (!mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_WAIT))
+ return MONO_W32HANDLE_WAIT_RET_FAILED;
+
+ if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) {
+ g_warning ("%s: handle %p has special wait, implement me!!", __func__, wait_handle);
+ return MONO_W32HANDLE_WAIT_RET_FAILED;
+ }
+
+ thr_ret = mono_w32handle_lock_handle (wait_handle);
+ g_assert (thr_ret == 0);
+
+ mono_w32handle_ops_signal (signal_handle);
+
+ if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_OWN)) {
+ if (own_if_owned (wait_handle, &statuscode)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned",
+ __func__, wait_handle);
+
+ ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
+ goto done;
+ }
+ }
+
+ if (timeout != INFINITE)
+ start = mono_msec_ticks ();
+
+ for (;;) {
+ gint waited;
+
+ if (own_if_signalled (wait_handle, &statuscode)) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled",
+ __func__, wait_handle);
+
+ ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
+ goto done;
+ }
+
+ mono_w32handle_ops_prewait (wait_handle);
+
+ if (timeout == INFINITE) {
+ waited = mono_w32handle_timedwait_signal_handle (wait_handle, INFINITE, FALSE, alertable ? &alerted : NULL);
+ } else {
+ gint64 elapsed;
+
+ elapsed = mono_msec_ticks () - start;
+ if (elapsed > timeout) {
+ ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
+ goto done;
+ }
+
+ waited = mono_w32handle_timedwait_signal_handle (wait_handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL);
+ }
+
+ if (alerted) {
+ ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
+ goto done;
+ }
+
+ if (waited != 0) {
+ ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
+ goto done;
+ }
+ }
+
+done:
+ thr_ret = mono_w32handle_unlock_handle (wait_handle);
+ g_assert (thr_ret == 0);
+
+ return ret;
+}
+
+#endif /* !defined(HOST_WIN32) */
--- /dev/null
+
+#ifndef _MONO_METADATA_W32HANDLE_H_
+#define _MONO_METADATA_W32HANDLE_H_
+
+#include <config.h>
+#include <glib.h>
+
+#ifndef INVALID_HANDLE_VALUE
+#define INVALID_HANDLE_VALUE (gpointer)-1
+#endif
+
+#define MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS 64
+
+typedef enum {
+ MONO_W32HANDLE_UNUSED = 0,
+ MONO_W32HANDLE_FILE,
+ MONO_W32HANDLE_CONSOLE,
+ MONO_W32HANDLE_THREAD,
+ MONO_W32HANDLE_SEM,
+ MONO_W32HANDLE_MUTEX,
+ MONO_W32HANDLE_EVENT,
+ MONO_W32HANDLE_SOCKET,
+ MONO_W32HANDLE_FIND,
+ MONO_W32HANDLE_PROCESS,
+ MONO_W32HANDLE_PIPE,
+ MONO_W32HANDLE_NAMEDMUTEX,
+ MONO_W32HANDLE_NAMEDSEM,
+ MONO_W32HANDLE_NAMEDEVENT,
+ MONO_W32HANDLE_COUNT
+} MonoW32HandleType;
+
+typedef struct
+{
+ void (*close)(gpointer handle, gpointer data);
+
+ /* SignalObjectAndWait */
+ void (*signal)(gpointer signal);
+
+ /* Called by WaitForSingleObject and WaitForMultipleObjects,
+ * with the handle locked (shared handles aren't locked.)
+ * Returns TRUE if ownership was established, false otherwise.
+ * If TRUE, *statuscode contains a status code such as
+ * WAIT_OBJECT_0 or WAIT_ABANDONED_0.
+ */
+ gboolean (*own_handle)(gpointer handle, guint32 *statuscode);
+
+ /* Called by WaitForSingleObject and WaitForMultipleObjects, if the
+ * handle in question is "ownable" (ie mutexes), to see if the current
+ * thread already owns this handle
+ */
+ gboolean (*is_owned)(gpointer handle);
+
+ /* Called by WaitForSingleObject and WaitForMultipleObjects,
+ * if the handle in question needs a special wait function
+ * instead of using the normal handle signal mechanism.
+ * Returns the WaitForSingleObject return code.
+ */
+ guint32 (*special_wait)(gpointer handle, guint32 timeout, gboolean *alerted);
+
+ /* Called by WaitForSingleObject and WaitForMultipleObjects,
+ * if the handle in question needs some preprocessing before the
+ * signal wait.
+ */
+ void (*prewait)(gpointer handle);
+
+ /* Called when dumping the handles */
+ void (*details)(gpointer data);
+
+ /* Called to get the name of the handle type */
+ const gchar* (*typename) (void);
+
+ /* Called to get the size of the handle type */
+ gsize (*typesize) (void);
+} MonoW32HandleOps;
+
+typedef enum {
+ MONO_W32HANDLE_CAP_WAIT = 0x01,
+ MONO_W32HANDLE_CAP_SIGNAL = 0x02,
+ MONO_W32HANDLE_CAP_OWN = 0x04,
+ MONO_W32HANDLE_CAP_SPECIAL_WAIT = 0x08,
+} MonoW32HandleCapability;
+
+extern guint32 mono_w32handle_fd_reserve;
+
+void
+mono_w32handle_init (void);
+
+void
+mono_w32handle_cleanup (void);
+
+void
+mono_w32handle_register_ops (MonoW32HandleType type, MonoW32HandleOps *ops);
+
+gpointer
+mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific);
+
+gpointer
+mono_w32handle_new_fd (MonoW32HandleType type, int fd, gpointer handle_specific);
+
+MonoW32HandleType
+mono_w32handle_get_type (gpointer handle);
+
+gboolean
+mono_w32handle_lookup (gpointer handle, MonoW32HandleType type, gpointer *handle_specific);
+
+gpointer
+mono_w32handle_search (MonoW32HandleType type, gboolean (*check)(gpointer, gpointer), gpointer user_data, gpointer *handle_specific, gboolean search_shared);
+
+void
+mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data);
+
+void
+mono_w32handle_dump (void);
+
+void
+mono_w32handle_ref (gpointer handle);
+
+void
+mono_w32handle_unref (gpointer handle);
+
+void
+mono_w32handle_register_capabilities (MonoW32HandleType type, MonoW32HandleCapability caps);
+
+gboolean
+mono_w32handle_test_capabilities (gpointer handle, MonoW32HandleCapability caps);
+
+void
+mono_w32handle_ops_close (gpointer handle, gpointer data);
+
+void
+mono_w32handle_ops_signal (gpointer handle);
+
+gboolean
+mono_w32handle_ops_own (gpointer handle, guint32 *statuscode);
+
+gboolean
+mono_w32handle_ops_isowned (gpointer handle);
+
+guint32
+mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *alerted);
+
+void
+mono_w32handle_ops_prewait (gpointer handle);
+
+void
+mono_w32handle_ops_details (MonoW32HandleType type, gpointer data);
+
+const gchar*
+mono_w32handle_ops_typename (MonoW32HandleType type);
+
+gsize
+mono_w32handle_ops_typesize (MonoW32HandleType type);
+
+void
+mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast);
+
+gboolean
+mono_w32handle_issignalled (gpointer handle);
+
+int
+mono_w32handle_lock_handle (gpointer handle);
+
+int
+mono_w32handle_trylock_handle (gpointer handle);
+
+int
+mono_w32handle_unlock_handle (gpointer handle);
+
+typedef enum {
+ MONO_W32HANDLE_WAIT_RET_SUCCESS_0 = 0,
+ MONO_W32HANDLE_WAIT_RET_ABANDONED_0 = MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS,
+ MONO_W32HANDLE_WAIT_RET_ALERTED = -1,
+ MONO_W32HANDLE_WAIT_RET_TIMEOUT = -2,
+ MONO_W32HANDLE_WAIT_RET_FAILED = -3,
+} MonoW32HandleWaitRet;
+
+MonoW32HandleWaitRet
+mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable);
+
+MonoW32HandleWaitRet
+mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable);
+
+MonoW32HandleWaitRet
+mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable);
+
+#endif /* _MONO_METADATA_W32HANDLE_H_ */
#include "mono/metadata/object-internals.h"
#include "mono/utils/mono-logger-internals.h"
#include "mono/utils/mono-threads.h"
-#include "mono/utils/w32handle.h"
+#include "mono/metadata/w32handle.h"
typedef struct {
MonoNativeThreadId tid;
#include "w32handle-namespace.h"
#include "mono/io-layer/io-layer.h"
#include "mono/utils/mono-logger-internals.h"
-#include "mono/utils/w32handle.h"
+#include "mono/metadata/w32handle.h"
typedef struct {
guint32 val;
GPtrArray *frag;
int len, j;
GPtrArray *threads;
- HANDLE handle;
+ MonoThreadHandle *thread_handle;
gpointer *user_data;
MonoMethod **methods;
user_data [1] = acfg;
user_data [2] = frag;
- handle = mono_threads_create_thread (compile_thread_main, (gpointer) user_data, NULL, NULL);
- g_ptr_array_add (threads, handle);
+ thread_handle = mono_threads_create_thread (compile_thread_main, (gpointer) user_data, NULL, NULL);
+ g_ptr_array_add (threads, thread_handle);
}
g_free (methods);
for (i = 0; i < threads->len; ++i) {
- WaitForSingleObjectEx (g_ptr_array_index (threads, i), INFINITE, FALSE);
+ mono_thread_info_wait_one_handle (g_ptr_array_index (threads, i), INFINITE, FALSE);
mono_threads_close_thread_handle (g_ptr_array_index (threads, i));
}
} else {
static MonoNativeThreadId debugger_thread_id;
-static HANDLE debugger_thread_handle;
+static MonoThreadHandle *debugger_thread_handle;
static int log_level;
#include "mono/utils/mono-counters.h"
#include "mono/utils/mono-hwcap.h"
#include "mono/utils/mono-logger-internals.h"
-#include "mono/utils/w32handle.h"
+#include "mono/metadata/w32handle.h"
#include "mini.h"
#include "jit.h"
#include <mono/utils/mono-threads.h>
#include <mono/utils/mono-threads-coop.h>
#include <mono/utils/checked-build.h>
-#include <mono/utils/w32handle.h>
+#include <mono/metadata/w32handle.h>
#include <mono/io-layer/io-layer.h>
#include "mini.h"
#include "utils/mono-threads.h"
#include "utils/mono-conc-hashtable.h"
#include "utils/checked-build.h"
-#include "utils/w32handle.h"
+#include "metadata/w32handle.h"
#include <stdlib.h>
#include <string.h>
parse.h \
checked-build.c \
checked-build.h \
- w32handle.c \
- w32handle.h \
os-event.h
arch_sources =
#include <mono/utils/mono-threads.h>
#include <mono/utils/mono-coop-semaphore.h>
#include <mono/metadata/gc-internals.h>
-#include <mono/utils/w32handle.h>
#include <mono/utils/mono-threads-debug.h>
#include <errno.h>
#include <sys/resource.h>
-#if defined(__native_client__)
-void nacl_shutdown_gc_thread(void);
-#endif
-
-void
-mono_threads_platform_register (MonoThreadInfo *info)
-{
- gpointer thread_handle;
-
- thread_handle = mono_w32handle_new (MONO_W32HANDLE_THREAD, NULL);
- if (thread_handle == INVALID_HANDLE_VALUE)
- g_error ("%s: failed to create handle", __func__);
-
- g_assert (!info->handle);
- info->handle = thread_handle;
-}
-
int
mono_threads_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize* const stack_size, MonoNativeThreadId *out_tid)
{
}
void
-mono_threads_platform_exit (int exit_code)
-{
-#if defined(__native_client__)
- nacl_shutdown_gc_thread();
-#endif
-
- mono_thread_info_detach ();
-
- pthread_exit (NULL);
-}
-
-void
-mono_threads_platform_unregister (MonoThreadInfo *info)
+mono_threads_platform_exit (gsize exit_code)
{
- g_assert (info->handle);
-
- /* The thread is no longer active, so unref it */
- mono_w32handle_unref (info->handle);
- info->handle = NULL;
+ pthread_exit ((gpointer) exit_code);
}
int
return (int)lim.rlim_max;
}
-gpointer
-mono_threads_platform_duplicate_handle (MonoThreadInfo *info)
-{
- g_assert (info->handle);
- mono_w32handle_ref (info->handle);
- return info->handle;
-}
-
-HANDLE
-mono_threads_platform_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
-{
- mono_w32handle_ref (handle);
-
- return handle;
-}
-
-void
-mono_threads_platform_close_thread_handle (HANDLE handle)
-{
- mono_w32handle_unref (handle);
-}
-
int
mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
{
return !pthread_join (tid, &res);
}
-void
-mono_threads_platform_set_exited (gpointer handle)
-{
- int thr_ret;
-
- g_assert (handle);
- if (mono_w32handle_issignalled (handle))
- g_error ("%s: handle %p thread %p has already exited, it's handle is signalled", __func__, handle, mono_native_thread_id_get ());
- if (mono_w32handle_get_type (handle) == MONO_W32HANDLE_UNUSED)
- g_error ("%s: handle %p thread %p has already exited, it's handle type is 'unused'", __func__, handle, mono_native_thread_id_get ());
-
- thr_ret = mono_w32handle_lock_handle (handle);
- g_assert (thr_ret == 0);
-
- mono_w32handle_set_signal_state (handle, TRUE, TRUE);
-
- thr_ret = mono_w32handle_unlock_handle (handle);
- g_assert (thr_ret == 0);
-}
-
-static const gchar* thread_typename (void)
-{
- return "Thread";
-}
-
-static gsize thread_typesize (void)
-{
- return 0;
-}
-
-static MonoW32HandleOps thread_ops = {
- NULL, /* close */
- NULL, /* signal */
- NULL, /* own */
- NULL, /* is_owned */
- NULL, /* special_wait */
- NULL, /* prewait */
- NULL, /* details */
- thread_typename, /* typename */
- thread_typesize, /* typesize */
-};
-
-void
-mono_threads_platform_init (void)
-{
- mono_w32handle_register_ops (MONO_W32HANDLE_THREAD, &thread_ops);
-
- mono_w32handle_register_capabilities (MONO_W32HANDLE_THREAD, MONO_W32HANDLE_CAP_WAIT);
-}
-
#endif /* defined(_POSIX_VERSION) || defined(__native_client__) */
#if defined(USE_POSIX_BACKEND)
#if defined (HOST_WIN32)
-void
-mono_threads_platform_register (MonoThreadInfo *info)
-{
- HANDLE thread_handle;
-
- thread_handle = GetCurrentThread ();
- g_assert (thread_handle);
-
- /* The handle returned by GetCurrentThread () is a pseudo handle, so it can't
- * be used to refer to the thread from other threads for things like aborting. */
- DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle, THREAD_ALL_ACCESS, TRUE, 0);
-
- g_assert (!info->handle);
- info->handle = thread_handle;
-}
-
int
mono_threads_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize* const stack_size, MonoNativeThreadId *out_tid)
{
}
void
-mono_threads_platform_exit (int exit_code)
+mono_threads_platform_exit (gsize exit_code)
{
- mono_thread_info_detach ();
ExitThread (exit_code);
}
-void
-mono_threads_platform_unregister (MonoThreadInfo *info)
-{
- g_assert (info->handle);
-
- CloseHandle (info->handle);
- info->handle = NULL;
-}
-
int
mono_threads_get_max_stack_size (void)
{
return INT_MAX;
}
-gpointer
-mono_threads_platform_duplicate_handle (MonoThreadInfo *info)
-{
- HANDLE thread_handle;
-
- g_assert (info->handle);
- DuplicateHandle (GetCurrentProcess (), info->handle, GetCurrentProcess (), &thread_handle, THREAD_ALL_ACCESS, TRUE, 0);
-
- return thread_handle;
-}
-
-HANDLE
-mono_threads_platform_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
-{
- return OpenThread (THREAD_ALL_ACCESS, TRUE, tid);
-}
-
-void
-mono_threads_platform_close_thread_handle (HANDLE handle)
-{
- CloseHandle (handle);
-}
-
#if defined(_MSC_VER)
const DWORD MS_VC_EXCEPTION=0x406D1388;
#pragma pack(push,8)
#endif
}
-void
-mono_threads_platform_set_exited (gpointer handle)
-{
-}
-
-void
-mono_threads_platform_init (void)
-{
-}
-
#endif
#include <mono/utils/mono-coop-semaphore.h>
#include <mono/utils/mono-threads-coop.h>
#include <mono/utils/mono-threads-debug.h>
+#include <mono/utils/os-event.h>
#include <errno.h>
mono_thread_info_set_tid (info, mono_native_thread_id_get ());
info->small_id = small_id;
+ info->handle = g_new0 (MonoThreadHandle, 1);
+ info->handle->ref = 1;
+ mono_os_event_init (&info->handle->event, TRUE, FALSE);
+
mono_os_sem_init (&info->resume_semaphore, 0);
/*set TLS early so SMR works */
info->stackdata = g_byte_array_new ();
- mono_threads_platform_register (info);
mono_threads_suspend_register (info);
/*
static void
mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info);
+static void
+mono_threads_signal_thread_handle (MonoThreadHandle* thread_handle);
+
static void
unregister_thread (void *arg)
{
/* we need to duplicate it, as the info->handle is going
* to be closed when unregistering from the platform */
- handle = mono_threads_platform_duplicate_handle (info);
+ handle = mono_threads_open_thread_handle (info->handle);
/*
First perform the callback that requires no locks.
if (threads_callbacks.thread_unregister)
threads_callbacks.thread_unregister (info);
- mono_threads_platform_unregister (info);
+ /* The thread is no longer active, so unref its handle */
+ mono_threads_close_thread_handle (info->handle);
+ info->handle = NULL;
+
result = mono_thread_info_remove (info);
g_assert (result);
mono_threads_transition_detach (info);
mono_thread_small_id_free (small_id);
- /* Signal the w32handle. It can be done as late as here
- * because w32handle does not access the current MonoThreadInfo,
- * neither does it switch state to BLOCKING. */
- mono_threads_platform_set_exited (handle);
+ mono_threads_signal_thread_handle (handle);
- mono_threads_platform_close_thread_handle (handle);
+ mono_threads_close_thread_handle (handle);
}
static void
mono_lls_init (&thread_list, NULL);
mono_thread_smr_init ();
- mono_threads_platform_init ();
mono_threads_suspend_init ();
mono_threads_suspend_init_signals ();
mono_threads_coop_init ();
gpointer start_routine_arg;
gint32 priority;
MonoCoopSem registered;
- gpointer handle;
+ MonoThreadHandle *handle;
} CreateThreadData;
static gsize WINAPI
MonoThreadInfo *info;
MonoThreadStart start_routine;
gpointer start_routine_arg;
- guint32 start_routine_res;
+ gsize start_routine_res;
gsize dummy;
thread_data = (CreateThreadData*) data;
info = mono_thread_info_attach (&dummy);
info->runtime_thread = TRUE;
- thread_data->handle = mono_thread_info_duplicate_handle (info);
+ thread_data->handle = mono_threads_open_thread_handle (info->handle);
mono_coop_sem_post (&thread_data->registered);
/* Run the actual main function of the thread */
start_routine_res = start_routine (start_routine_arg);
- mono_threads_platform_exit (start_routine_res);
+ mono_thread_info_exit (start_routine_res);
g_assert_not_reached ();
}
* Create a new thread executing START with argument ARG. Store its id into OUT_TID.
* Returns: a windows or io-layer handle for the thread.
*/
-HANDLE
+MonoThreadHandle*
mono_threads_create_thread (MonoThreadStart start, gpointer arg, gsize * const stack_size, MonoNativeThreadId *out_tid)
{
CreateThreadData *thread_data;
gint res;
- gpointer ret;
+ MonoThreadHandle *ret;
thread_data = g_new0 (CreateThreadData, 1);
thread_data->ref = 2;
((MonoThreadInfo*)info)->tls [key] = value;
}
+#if defined(__native_client__)
+void nacl_shutdown_gc_thread(void);
+#endif
+
/*
* mono_thread_info_exit:
*
* This function doesn't return.
*/
void
-mono_thread_info_exit (void)
+mono_thread_info_exit (gsize exit_code)
{
+#if defined(__native_client__)
+ nacl_shutdown_gc_thread();
+#endif
+
+ mono_thread_info_detach ();
+
mono_threads_platform_exit (0);
}
/*
* mono_threads_open_thread_handle:
*
- * Return a io-layer/win32 handle for the thread identified by HANDLE/TID.
- * The handle need to be closed by calling CloseHandle () when it is no
- * longer needed.
+ * Duplicate the handle. The handle needs to be closed by calling
+ * mono_threads_close_thread_handle () when it is no longer needed.
*/
-HANDLE
-mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
+MonoThreadHandle*
+mono_threads_open_thread_handle (MonoThreadHandle *thread_handle)
{
- return mono_threads_platform_open_thread_handle (handle, tid);
+ guint32 oldref, newref;
+
+ g_assert (thread_handle);
+
+ do {
+ oldref = thread_handle->ref;
+ if (!(oldref >= 1))
+ g_error ("%s: thread_handle %p has ref %u, it should be >= 1", __func__, thread_handle, oldref);
+
+ newref = oldref + 1;
+ } while (InterlockedCompareExchange ((gint32*) &thread_handle->ref, newref, oldref) != oldref);
+
+ return thread_handle;
}
void
-mono_threads_close_thread_handle (HANDLE handle)
+mono_threads_close_thread_handle (MonoThreadHandle *thread_handle)
{
- return mono_threads_platform_close_thread_handle (handle);
+ guint32 oldref, newref;
+
+ g_assert (thread_handle);
+
+ do {
+ oldref = thread_handle->ref;
+ if (!(oldref >= 1))
+ g_error ("%s: thread_handle %p has ref %u, it should be >= 1", __func__, thread_handle, oldref);
+
+ newref = oldref - 1;
+ } while (InterlockedCompareExchange ((gint32*) &thread_handle->ref, newref, oldref) != oldref);
+
+ if (newref == 0) {
+ mono_os_event_destroy (&thread_handle->event);
+ g_free (thread_handle);
+ }
+}
+
+static void
+mono_threads_signal_thread_handle (MonoThreadHandle* thread_handle)
+{
+ mono_os_event_set (&thread_handle->event);
}
#define INTERRUPT_STATE ((MonoThreadInfoInterruptToken*) (size_t) -1)
return mono_thread_info_get_tid (info) == mono_native_thread_id_get ();
}
-void
-mono_thread_info_set_exited (THREAD_INFO_TYPE *info)
+MonoThreadInfoWaitRet
+mono_thread_info_wait_one_handle (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
{
- g_assert (mono_thread_info_is_current (info));
+ MonoOSEventWaitRet res;
- g_assert (info->handle);
- mono_threads_platform_set_exited (info->handle);
+ res = mono_os_event_wait_one (&thread_handle->event, timeout);
+ if (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0)
+ return MONO_THREAD_INFO_WAIT_RET_SUCCESS_0;
+ else if (res == MONO_OS_EVENT_WAIT_RET_ALERTED)
+ return MONO_THREAD_INFO_WAIT_RET_ALERTED;
+ else if (res == MONO_OS_EVENT_WAIT_RET_TIMEOUT)
+ return MONO_THREAD_INFO_WAIT_RET_TIMEOUT;
+ else
+ g_error ("%s: unknown res value %d", __func__, res);
}
-gpointer
-mono_thread_info_duplicate_handle (MonoThreadInfo *info)
+MonoThreadInfoWaitRet
+mono_thread_info_wait_multiple_handle (MonoThreadHandle **thread_handles, gsize nhandles, MonoOSEvent *background_change_event, gboolean waitall, guint32 timeout, gboolean alertable)
{
- g_assert (mono_thread_info_is_current (info));
- return mono_threads_platform_duplicate_handle (info);
+ MonoOSEventWaitRet res;
+ MonoOSEvent *thread_events [MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS];
+ gint i;
+
+ g_assert (nhandles <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS);
+ if (background_change_event)
+ g_assert (nhandles <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS - 1);
+
+ for (i = 0; i < nhandles; ++i)
+ thread_events [i] = &thread_handles [i]->event;
+
+ if (background_change_event)
+ thread_events [nhandles ++] = background_change_event;
+
+ res = mono_os_event_wait_multiple (thread_events, nhandles, waitall, timeout);
+ if (res >= MONO_OS_EVENT_WAIT_RET_SUCCESS_0 && res <= MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + nhandles - 1)
+ return MONO_THREAD_INFO_WAIT_RET_SUCCESS_0 + (res - MONO_OS_EVENT_WAIT_RET_SUCCESS_0);
+ else if (res == MONO_OS_EVENT_WAIT_RET_ALERTED)
+ return MONO_THREAD_INFO_WAIT_RET_ALERTED;
+ else if (res == MONO_OS_EVENT_WAIT_RET_TIMEOUT)
+ return MONO_THREAD_INFO_WAIT_RET_TIMEOUT;
+ else
+ g_error ("%s: unknown res value %d", __func__, res);
}
#include <mono/utils/mono-linked-list-set.h>
#include <mono/utils/mono-tls.h>
#include <mono/utils/mono-coop-semaphore.h>
+#include <mono/utils/os-event.h>
#include <mono/io-layer/io-layer.h>
#endif /* #ifdef HOST_WIN32 */
+typedef struct {
+ guint32 ref;
+ MonoOSEvent event;
+} MonoThreadHandle;
+
/*
THREAD_INFO_TYPE is a way to make the mono-threads module parametric - or sort of.
The GC using mono-threads might extend the MonoThreadInfo struct to add its own
/* IO layer handle for this thread */
/* Set when the thread is started, or in _wapi_thread_duplicate () */
- HANDLE handle;
+ MonoThreadHandle *handle;
void *jit_data;
mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value);
void
-mono_thread_info_exit (void);
-
-void
-mono_thread_info_set_exited (THREAD_INFO_TYPE *info);
+mono_thread_info_exit (gsize exit_code);
void
mono_thread_info_install_interrupt (void (*callback) (gpointer data), gpointer data, gboolean *interrupted);
gboolean
mono_thread_info_is_live (THREAD_INFO_TYPE *info);
-HANDLE
+MonoThreadHandle*
mono_threads_create_thread (MonoThreadStart start, gpointer arg, gsize * const stack_size, MonoNativeThreadId *out_tid);
int
mono_threads_get_max_stack_size (void);
-HANDLE
-mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid);
+MonoThreadHandle*
+mono_threads_open_thread_handle (MonoThreadHandle *handle);
void
-mono_threads_close_thread_handle (HANDLE handle);
+mono_threads_close_thread_handle (MonoThreadHandle *handle);
MONO_API void
mono_threads_attach_tools_thread (void);
void mono_threads_suspend_init_signals (void);
-void mono_threads_platform_init (void);
-
void mono_threads_coop_init (void);
/*
gint mono_threads_suspend_get_restart_signal (void);
gint mono_threads_suspend_get_abort_signal (void);
-void mono_threads_platform_register (THREAD_INFO_TYPE *info);
-void mono_threads_platform_unregister (THREAD_INFO_TYPE *info);
int mono_threads_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize* const stack_size, MonoNativeThreadId *out_tid);
void mono_threads_platform_get_stack_bounds (guint8 **staddr, size_t *stsize);
gboolean mono_threads_platform_yield (void);
-void mono_threads_platform_exit (int exit_code);
-HANDLE mono_threads_platform_open_thread_handle (HANDLE handle, MonoNativeThreadId tid);
-void mono_threads_platform_close_thread_handle (HANDLE handle);
-void mono_threads_platform_set_exited (gpointer handle);
-gpointer mono_threads_platform_duplicate_handle (THREAD_INFO_TYPE *info);
+void mono_threads_platform_exit (gsize exit_code);
void mono_threads_coop_begin_global_suspend (void);
void mono_threads_coop_end_global_suspend (void);
gboolean
mono_thread_info_is_current (THREAD_INFO_TYPE *info);
-gpointer
-mono_thread_info_duplicate_handle (THREAD_INFO_TYPE *info);
+typedef enum {
+ MONO_THREAD_INFO_WAIT_RET_SUCCESS_0 = 0,
+ MONO_THREAD_INFO_WAIT_RET_ALERTED = -1,
+ MONO_THREAD_INFO_WAIT_RET_TIMEOUT = -2,
+ MONO_THREAD_INFO_WAIT_RET_FAILED = -3,
+} MonoThreadInfoWaitRet;
+
+MonoThreadInfoWaitRet
+mono_thread_info_wait_one_handle (MonoThreadHandle *handle, guint32 timeout, gboolean alertable);
+
+MonoThreadInfoWaitRet
+mono_thread_info_wait_multiple_handle (MonoThreadHandle **thread_handles, gsize nhandles, MonoOSEvent *background_change_event, gboolean waitall, guint32 timeout, gboolean alertable);
#endif /* __MONO_THREADS_H__ */
+++ /dev/null
-/*
- * w32handle.c: Generic and internal operations on handles
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- * Ludovic Henry (luhenry@microsoft.com)
- *
- * (C) 2002-2011 Novell, Inc.
- * Copyright 2011 Xamarin Inc
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-
-#include <config.h>
-
-#if !defined(HOST_WIN32)
-
-#include <glib.h>
-#include <pthread.h>
-#include <errno.h>
-#include <unistd.h>
-#ifdef HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-#include <string.h>
-#include <sys/types.h>
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
-#ifdef HAVE_SYS_UN_H
-# include <sys/un.h>
-#endif
-#ifdef HAVE_SYS_MMAN_H
-# include <sys/mman.h>
-#endif
-#ifdef HAVE_DIRENT_H
-# include <dirent.h>
-#endif
-#include <sys/stat.h>
-#ifdef HAVE_SYS_RESOURCE_H
-# include <sys/resource.h>
-#endif
-
-#include "w32handle.h"
-
-#include "atomic.h"
-#include "mono-logger-internals.h"
-#include "mono-os-mutex.h"
-#include "mono-proclib.h"
-#include "mono-threads.h"
-#include "mono-time.h"
-
-#undef DEBUG_REFS
-
-#define SLOT_MAX (1024 * 16)
-
-/* must be a power of 2 */
-#define HANDLE_PER_SLOT (256)
-
-#define INFINITE 0xFFFFFFFF
-
-typedef struct {
- MonoW32HandleType type;
- guint ref;
- gboolean signalled;
- mono_mutex_t signal_mutex;
- mono_cond_t signal_cond;
- gpointer specific;
-} MonoW32HandleBase;
-
-static MonoW32HandleCapability handle_caps [MONO_W32HANDLE_COUNT];
-static MonoW32HandleOps *handle_ops [MONO_W32HANDLE_COUNT];
-
-/*
- * We can hold SLOT_MAX * HANDLE_PER_SLOT handles.
- * If 4M handles are not enough... Oh, well... we will crash.
- */
-#define SLOT_INDEX(x) (x / HANDLE_PER_SLOT)
-#define SLOT_OFFSET(x) (x % HANDLE_PER_SLOT)
-
-static MonoW32HandleBase *private_handles [SLOT_MAX];
-static guint32 private_handles_count = 0;
-static guint32 private_handles_slots_count = 0;
-
-guint32 mono_w32handle_fd_reserve;
-
-/*
- * This is an internal handle which is used for handling waiting for multiple handles.
- * Threads which wait for multiple handles wait on this one handle, and when a handle
- * is signalled, this handle is signalled too.
- */
-static mono_mutex_t global_signal_mutex;
-static mono_cond_t global_signal_cond;
-
-static mono_mutex_t scan_mutex;
-
-static gboolean shutting_down = FALSE;
-
-static gboolean
-type_is_fd (MonoW32HandleType type)
-{
- switch (type) {
- case MONO_W32HANDLE_FILE:
- case MONO_W32HANDLE_CONSOLE:
- case MONO_W32HANDLE_SOCKET:
- case MONO_W32HANDLE_PIPE:
- return TRUE;
- default:
- return FALSE;
- }
-}
-
-static gboolean
-mono_w32handle_lookup_data (gpointer handle, MonoW32HandleBase **handle_data)
-{
- gsize index, offset;
-
- g_assert (handle_data);
-
- index = SLOT_INDEX ((gsize) handle);
- if (index >= SLOT_MAX)
- return FALSE;
- if (!private_handles [index])
- return FALSE;
-
- offset = SLOT_OFFSET ((gsize) handle);
- if (private_handles [index][offset].type == MONO_W32HANDLE_UNUSED)
- return FALSE;
-
- *handle_data = &private_handles [index][offset];
- return TRUE;
-}
-
-MonoW32HandleType
-mono_w32handle_get_type (gpointer handle)
-{
- MonoW32HandleBase *handle_data;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data))
- return MONO_W32HANDLE_UNUSED; /* An impossible type */
-
- return handle_data->type;
-}
-
-void
-mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast)
-{
- MonoW32HandleBase *handle_data;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return;
- }
-
-#ifdef DEBUG
- g_message ("%s: setting state of %p to %s (broadcast %s)", __func__,
- handle, state?"TRUE":"FALSE", broadcast?"TRUE":"FALSE");
-#endif
-
- if (state == TRUE) {
- /* Tell everyone blocking on a single handle */
-
- /* The condition the global signal cond is waiting on is the signalling of
- * _any_ handle. So lock it before setting the signalled state.
- */
- mono_os_mutex_lock (&global_signal_mutex);
-
- /* This function _must_ be called with
- * handle->signal_mutex locked
- */
- handle_data->signalled=state;
-
- if (broadcast == TRUE) {
- mono_os_cond_broadcast (&handle_data->signal_cond);
- } else {
- mono_os_cond_signal (&handle_data->signal_cond);
- }
-
- /* Tell everyone blocking on multiple handles that something
- * was signalled
- */
- mono_os_cond_broadcast (&global_signal_cond);
-
- mono_os_mutex_unlock (&global_signal_mutex);
- } else {
- handle_data->signalled=state;
- }
-}
-
-gboolean
-mono_w32handle_issignalled (gpointer handle)
-{
- MonoW32HandleBase *handle_data;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return(FALSE);
- }
-
- return handle_data->signalled;
-}
-
-static int
-mono_w32handle_lock_signal_mutex (void)
-{
-#ifdef DEBUG
- g_message ("%s: lock global signal mutex", __func__);
-#endif
-
- mono_os_mutex_lock (&global_signal_mutex);
-
- return 0;
-}
-
-static int
-mono_w32handle_unlock_signal_mutex (void)
-{
-#ifdef DEBUG
- g_message ("%s: unlock global signal mutex", __func__);
-#endif
-
- mono_os_mutex_unlock (&global_signal_mutex);
-
- return 0;
-}
-
-int
-mono_w32handle_lock_handle (gpointer handle)
-{
- MonoW32HandleBase *handle_data;
-
-#ifdef DEBUG
- g_message ("%s: locking handle %p", __func__, handle);
-#endif
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return(0);
- }
-
- mono_w32handle_ref (handle);
-
- mono_os_mutex_lock (&handle_data->signal_mutex);
-
- return 0;
-}
-
-int
-mono_w32handle_trylock_handle (gpointer handle)
-{
- MonoW32HandleBase *handle_data;
- int ret;
-
-#ifdef DEBUG
- g_message ("%s: locking handle %p", __func__, handle);
-#endif
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return(0);
- }
-
- mono_w32handle_ref (handle);
-
- ret = mono_os_mutex_trylock (&handle_data->signal_mutex);
- if (ret != 0) {
- mono_w32handle_unref (handle);
- }
-
- return(ret);
-}
-
-int
-mono_w32handle_unlock_handle (gpointer handle)
-{
- MonoW32HandleBase *handle_data;
-
-#ifdef DEBUG
- g_message ("%s: unlocking handle %p", __func__, handle);
-#endif
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return(0);
- }
-
- mono_os_mutex_unlock (&handle_data->signal_mutex);
-
- mono_w32handle_unref (handle);
-
- return 0;
-}
-
-/*
- * wapi_init:
- *
- * Initialize the io-layer.
- */
-void
-mono_w32handle_init (void)
-{
- static gboolean initialized = FALSE;
-
- if (initialized)
- return;
-
- g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
- == MONO_W32HANDLE_COUNT);
-
- /* This is needed by the code in mono_w32handle_new_internal */
- mono_w32handle_fd_reserve = (eg_getdtablesize () + (HANDLE_PER_SLOT - 1)) & ~(HANDLE_PER_SLOT - 1);
-
- do {
- /*
- * The entries in private_handles reserved for fds are allocated lazily to
- * save memory.
- */
-
- private_handles_count += HANDLE_PER_SLOT;
- private_handles_slots_count ++;
- } while(mono_w32handle_fd_reserve > private_handles_count);
-
- mono_os_mutex_init (&scan_mutex);
-
- mono_os_cond_init (&global_signal_cond);
- mono_os_mutex_init (&global_signal_mutex);
-
- initialized = TRUE;
-}
-
-void
-mono_w32handle_cleanup (void)
-{
- int i, j, k;
-
- g_assert (!shutting_down);
- shutting_down = TRUE;
-
- /* Every shared handle we were using ought really to be closed
- * by now, but to make sure just blow them all away. The
- * exiting finalizer thread in particular races us to the
- * program exit and doesn't always win, so it can be left
- * cluttering up the shared file. Anything else left over is
- * really a bug.
- */
- for(i = SLOT_INDEX (0); private_handles[i] != NULL; i++) {
- for(j = SLOT_OFFSET (0); j < HANDLE_PER_SLOT; j++) {
- MonoW32HandleBase *handle_data = &private_handles[i][j];
- gpointer handle = GINT_TO_POINTER (i*HANDLE_PER_SLOT+j);
-
- for(k = handle_data->ref; k > 0; k--) {
- mono_w32handle_unref (handle);
- }
- }
- }
-
- for (i = 0; i < SLOT_MAX; ++i)
- g_free (private_handles [i]);
-}
-
-static void mono_w32handle_init_handle (MonoW32HandleBase *handle,
- MonoW32HandleType type, gpointer handle_specific)
-{
- g_assert (handle->ref == 0);
-
- handle->type = type;
- handle->signalled = FALSE;
- handle->ref = 1;
-
- mono_os_cond_init (&handle->signal_cond);
- mono_os_mutex_init (&handle->signal_mutex);
-
- if (handle_specific)
- handle->specific = g_memdup (handle_specific, mono_w32handle_ops_typesize (type));
-}
-
-/*
- * mono_w32handle_new_internal:
- * @type: Init handle to this type
- *
- * Search for a free handle and initialize it. Return the handle on
- * success and 0 on failure. This is only called from
- * mono_w32handle_new, and scan_mutex must be held.
- */
-static guint32 mono_w32handle_new_internal (MonoW32HandleType type,
- gpointer handle_specific)
-{
- guint32 i, k, count;
- static guint32 last = 0;
- gboolean retry = FALSE;
-
- /* A linear scan should be fast enough. Start from the last
- * allocation, assuming that handles are allocated more often
- * than they're freed. Leave the space reserved for file
- * descriptors
- */
-
- if (last < mono_w32handle_fd_reserve) {
- last = mono_w32handle_fd_reserve;
- } else {
- retry = TRUE;
- }
-
-again:
- count = last;
- for(i = SLOT_INDEX (count); i < private_handles_slots_count; i++) {
- if (private_handles [i]) {
- for (k = SLOT_OFFSET (count); k < HANDLE_PER_SLOT; k++) {
- MonoW32HandleBase *handle = &private_handles [i][k];
-
- if(handle->type == MONO_W32HANDLE_UNUSED) {
- last = count + 1;
-
- mono_w32handle_init_handle (handle, type, handle_specific);
- return (count);
- }
- count++;
- }
- }
- }
-
- if(retry && last > mono_w32handle_fd_reserve) {
- /* Try again from the beginning */
- last = mono_w32handle_fd_reserve;
- goto again;
- }
-
- /* Will need to expand the array. The caller will sort it out */
-
- return(0);
-}
-
-gpointer
-mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific)
-{
- guint32 handle_idx = 0;
- gpointer handle;
-
- g_assert (!shutting_down);
-
- g_assert(!type_is_fd(type));
-
- mono_os_mutex_lock (&scan_mutex);
-
- while ((handle_idx = mono_w32handle_new_internal (type, handle_specific)) == 0) {
- /* Try and expand the array, and have another go */
- int idx = SLOT_INDEX (private_handles_count);
- if (idx >= SLOT_MAX) {
- break;
- }
-
- private_handles [idx] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT);
-
- private_handles_count += HANDLE_PER_SLOT;
- private_handles_slots_count ++;
- }
-
- mono_os_mutex_unlock (&scan_mutex);
-
- if (handle_idx == 0) {
- /* We ran out of slots */
- handle = INVALID_HANDLE_VALUE;
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle", __func__, mono_w32handle_ops_typename (type));
- goto done;
- }
-
- /* Make sure we left the space for fd mappings */
- g_assert (handle_idx >= mono_w32handle_fd_reserve);
-
- handle = GUINT_TO_POINTER (handle_idx);
-
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), handle);
-
-done:
- return(handle);
-}
-
-gpointer mono_w32handle_new_fd (MonoW32HandleType type, int fd,
- gpointer handle_specific)
-{
- MonoW32HandleBase *handle_data;
- int fd_index, fd_offset;
-
- g_assert (!shutting_down);
-
- g_assert(type_is_fd(type));
-
- if (fd >= mono_w32handle_fd_reserve) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle, fd is too big", __func__, mono_w32handle_ops_typename (type));
-
- return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE));
- }
-
- fd_index = SLOT_INDEX (fd);
- fd_offset = SLOT_OFFSET (fd);
-
- /* Initialize the array entries on demand */
- if (!private_handles [fd_index]) {
- mono_os_mutex_lock (&scan_mutex);
-
- if (!private_handles [fd_index])
- private_handles [fd_index] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT);
-
- mono_os_mutex_unlock (&scan_mutex);
- }
-
- handle_data = &private_handles [fd_index][fd_offset];
-
- if (handle_data->type != MONO_W32HANDLE_UNUSED) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle, fd is already in use", __func__, mono_w32handle_ops_typename (type));
- /* FIXME: clean up this handle? We can't do anything
- * with the fd, cos thats the new one
- */
- return(GUINT_TO_POINTER (INVALID_HANDLE_VALUE));
- }
-
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: create %s handle %p", __func__, mono_w32handle_ops_typename (type), GUINT_TO_POINTER(fd));
-
- mono_w32handle_init_handle (handle_data, type, handle_specific);
-
- return(GUINT_TO_POINTER(fd));
-}
-
-gboolean
-mono_w32handle_lookup (gpointer handle, MonoW32HandleType type,
- gpointer *handle_specific)
-{
- MonoW32HandleBase *handle_data;
-
- g_assert (handle_specific);
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return(FALSE);
- }
-
- if (handle_data->type != type) {
- return(FALSE);
- }
-
- *handle_specific = handle_data->specific;
-
- return(TRUE);
-}
-
-static gboolean
-mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data);
-
-static gboolean
-mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data, guint minimum);
-
-void
-mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data)
-{
- guint32 i, k;
-
- mono_os_mutex_lock (&scan_mutex);
-
- for (i = SLOT_INDEX (0); i < private_handles_slots_count; i++) {
- if (!private_handles [i])
- continue;
- for (k = SLOT_OFFSET (0); k < HANDLE_PER_SLOT; k++) {
- MonoW32HandleBase *handle_data = NULL;
- gpointer handle;
- gboolean destroy, finished;
-
- handle_data = &private_handles [i][k];
- if (handle_data->type == MONO_W32HANDLE_UNUSED)
- continue;
-
- handle = GUINT_TO_POINTER (i * HANDLE_PER_SLOT + k);
-
- if (!mono_w32handle_ref_core (handle, handle_data)) {
- /* we are racing with mono_w32handle_unref:
- * the handle ref has been decremented, but it
- * hasn't yet been destroyed. */
- continue;
- }
-
- finished = on_each (handle, handle_data->specific, user_data);
-
- /* we do not want to have to destroy the handle here,
- * as it would means the ref/unref are unbalanced */
- destroy = mono_w32handle_unref_core (handle, handle_data, 2);
- g_assert (!destroy);
-
- if (finished)
- goto done;
- }
- }
-
-done:
- mono_os_mutex_unlock (&scan_mutex);
-}
-
-typedef struct {
- MonoW32HandleType type;
- gboolean (*search_user_callback)(gpointer handle, gpointer data);
- gpointer search_user_data;
- gpointer handle;
- gpointer handle_specific;
-} SearchData;
-
-static gboolean
-search_callback (gpointer handle, gpointer handle_specific, gpointer user_data)
-{
- SearchData *search_data = (SearchData*) user_data;
-
- if (search_data->type != mono_w32handle_get_type (handle))
- return FALSE;
-
- if (!search_data->search_user_callback (handle, search_data->search_user_data))
- return FALSE;
-
- mono_w32handle_ref (handle);
- search_data->handle = handle;
- search_data->handle_specific = handle_specific;
- return TRUE;
-}
-
-/* This might list some shared handles twice if they are already
- * opened by this process, and the check function returns FALSE the
- * first time. Shared handles that are created during the search are
- * unreffed if the check function returns FALSE, so callers must not
- * rely on the handle persisting (unless the check function returns
- * TRUE)
- * The caller owns the returned handle.
- */
-gpointer mono_w32handle_search (MonoW32HandleType type,
- gboolean (*check)(gpointer test, gpointer user),
- gpointer user_data,
- gpointer *handle_specific,
- gboolean search_shared)
-{
- SearchData search_data;
-
- memset (&search_data, 0, sizeof (search_data));
- search_data.type = type;
- search_data.search_user_callback = check;
- search_data.search_user_data = user_data;
- mono_w32handle_foreach (search_callback, &search_data);
- if (handle_specific)
- *handle_specific = search_data.handle_specific;
- return search_data.handle;
-}
-
-static gboolean
-mono_w32handle_ref_core (gpointer handle, MonoW32HandleBase *handle_data)
-{
- guint old, new;
-
- do {
- old = handle_data->ref;
- if (old == 0)
- return FALSE;
-
- new = old + 1;
- } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old);
-
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: ref %s handle %p, ref: %d -> %d",
- __func__, mono_w32handle_ops_typename (handle_data->type), handle, old, new);
-
- return TRUE;
-}
-
-static gboolean
-mono_w32handle_unref_core (gpointer handle, MonoW32HandleBase *handle_data, guint minimum)
-{
- MonoW32HandleType type;
- guint old, new;
-
- type = handle_data->type;
-
- do {
- old = handle_data->ref;
- if (!(old >= minimum))
- g_error ("%s: handle %p has ref %d, it should be >= %d", __func__, handle, old, minimum);
-
- new = old - 1;
- } while (InterlockedCompareExchange ((gint32*) &handle_data->ref, new, old) != old);
-
- /* handle_data might contain invalid data from now on, if
- * another thread is unref'ing this handle at the same time */
-
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unref %s handle %p, ref: %d -> %d destroy: %s",
- __func__, mono_w32handle_ops_typename (type), handle, old, new, new == 0 ? "true" : "false");
-
- return new == 0;
-}
-
-void mono_w32handle_ref (gpointer handle)
-{
- MonoW32HandleBase *handle_data;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to ref handle %p, unknown handle", __func__, handle);
- return;
- }
-
- if (!mono_w32handle_ref_core (handle, handle_data))
- g_error ("%s: failed to ref handle %p", __func__, handle);
-}
-
-static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer);
-
-/* The handle must not be locked on entry to this function */
-void
-mono_w32handle_unref (gpointer handle)
-{
- MonoW32HandleBase *handle_data;
- gboolean destroy;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to unref handle %p, unknown handle",
- __func__, handle);
- return;
- }
-
- destroy = mono_w32handle_unref_core (handle, handle_data, 1);
-
- if (destroy) {
- /* Need to copy the handle info, reset the slot in the
- * array, and _only then_ call the close function to
- * avoid race conditions (eg file descriptors being
- * closed, and another file being opened getting the
- * same fd racing the memset())
- */
- MonoW32HandleType type;
- gpointer handle_specific;
- void (*close_func)(gpointer, gpointer);
-
- type = handle_data->type;
- handle_specific = handle_data->specific;
-
- mono_os_mutex_lock (&scan_mutex);
-
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: destroy %s handle %p", __func__, mono_w32handle_ops_typename (type), handle);
-
- mono_os_mutex_destroy (&handle_data->signal_mutex);
- mono_os_cond_destroy (&handle_data->signal_cond);
-
- memset (handle_data, 0, sizeof (MonoW32HandleBase));
-
- mono_os_mutex_unlock (&scan_mutex);
-
- close_func = _wapi_handle_ops_get_close_func (type);
- if (close_func != NULL) {
- close_func (handle, handle_specific);
- }
-
- g_free (handle_specific);
- }
-}
-
-void
-mono_w32handle_register_ops (MonoW32HandleType type, MonoW32HandleOps *ops)
-{
- handle_ops [type] = ops;
-}
-
-void mono_w32handle_register_capabilities (MonoW32HandleType type,
- MonoW32HandleCapability caps)
-{
- handle_caps[type] = caps;
-}
-
-gboolean mono_w32handle_test_capabilities (gpointer handle,
- MonoW32HandleCapability caps)
-{
- MonoW32HandleBase *handle_data;
- MonoW32HandleType type;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return(FALSE);
- }
-
- type = handle_data->type;
-
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: testing 0x%x against 0x%x (%d)", __func__,
- handle_caps[type], caps, handle_caps[type] & caps);
-
- return((handle_caps[type] & caps) != 0);
-}
-
-static void (*_wapi_handle_ops_get_close_func (MonoW32HandleType type))(gpointer, gpointer)
-{
- if (handle_ops[type] != NULL &&
- handle_ops[type]->close != NULL) {
- return (handle_ops[type]->close);
- }
-
- return (NULL);
-}
-
-void mono_w32handle_ops_close (gpointer handle, gpointer data)
-{
- MonoW32HandleBase *handle_data;
- MonoW32HandleType type;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return;
- }
-
- type = handle_data->type;
-
- if (handle_ops[type] != NULL &&
- handle_ops[type]->close != NULL) {
- handle_ops[type]->close (handle, data);
- }
-}
-
-void mono_w32handle_ops_details (MonoW32HandleType type, gpointer data)
-{
- if (handle_ops[type] != NULL &&
- handle_ops[type]->details != NULL) {
- handle_ops[type]->details (data);
- }
-}
-
-const gchar* mono_w32handle_ops_typename (MonoW32HandleType type)
-{
- g_assert (handle_ops [type]);
- g_assert (handle_ops [type]->typename);
- return handle_ops [type]->typename ();
-}
-
-gsize mono_w32handle_ops_typesize (MonoW32HandleType type)
-{
- g_assert (handle_ops [type]);
- g_assert (handle_ops [type]->typesize);
- return handle_ops [type]->typesize ();
-}
-
-void mono_w32handle_ops_signal (gpointer handle)
-{
- MonoW32HandleBase *handle_data;
- MonoW32HandleType type;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return;
- }
-
- type = handle_data->type;
-
- if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
- handle_ops[type]->signal (handle);
- }
-}
-
-gboolean mono_w32handle_ops_own (gpointer handle, guint32 *statuscode)
-{
- MonoW32HandleBase *handle_data;
- MonoW32HandleType type;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return(FALSE);
- }
-
- type = handle_data->type;
-
- if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
- return(handle_ops[type]->own_handle (handle, statuscode));
- } else {
- return(FALSE);
- }
-}
-
-gboolean mono_w32handle_ops_isowned (gpointer handle)
-{
- MonoW32HandleBase *handle_data;
- MonoW32HandleType type;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return(FALSE);
- }
-
- type = handle_data->type;
-
- if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
- return(handle_ops[type]->is_owned (handle));
- } else {
- return(FALSE);
- }
-}
-
-guint32 mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *alerted)
-{
- MonoW32HandleBase *handle_data;
- MonoW32HandleType type;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return(WAIT_FAILED);
- }
-
- type = handle_data->type;
-
- if (handle_ops[type] != NULL &&
- handle_ops[type]->special_wait != NULL) {
- return(handle_ops[type]->special_wait (handle, timeout, alerted));
- } else {
- return(WAIT_FAILED);
- }
-}
-
-void mono_w32handle_ops_prewait (gpointer handle)
-{
- MonoW32HandleBase *handle_data;
- MonoW32HandleType type;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data)) {
- return;
- }
-
- type = handle_data->type;
-
- if (handle_ops[type] != NULL &&
- handle_ops[type]->prewait != NULL) {
- handle_ops[type]->prewait (handle);
- }
-}
-
-static void
-spin (guint32 ms)
-{
- struct timespec sleepytime;
-
- g_assert (ms < 1000);
-
- sleepytime.tv_sec = 0;
- sleepytime.tv_nsec = ms * 1000000;
- nanosleep (&sleepytime, NULL);
-}
-
-static void
-mono_w32handle_lock_handles (gpointer *handles, gsize numhandles)
-{
- guint32 i, iter=0;
- int thr_ret;
-
- /* Lock all the handles, with backoff */
-again:
- for(i=0; i<numhandles; i++) {
- gpointer handle = handles[i];
-
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempting to lock %p", __func__, handle);
-
- thr_ret = mono_w32handle_trylock_handle (handle);
-
- if (thr_ret != 0) {
- /* Bummer */
-
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: attempt failed for %p: %s", __func__,
- handle, strerror (thr_ret));
-
- while (i--) {
- handle = handles[i];
-
- thr_ret = mono_w32handle_unlock_handle (handle);
- g_assert (thr_ret == 0);
- }
-
- /* If iter ever reaches 100 the nanosleep will
- * return EINVAL immediately, but we have a
- * design flaw if that happens.
- */
- iter++;
- if(iter==100) {
- g_warning ("%s: iteration overflow!",
- __func__);
- iter=1;
- }
-
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Backing off for %d ms", __func__,
- iter*10);
- spin (10 * iter);
-
- goto again;
- }
- }
-
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: Locked all handles", __func__);
-}
-
-static void
-mono_w32handle_unlock_handles (gpointer *handles, gsize numhandles)
-{
- guint32 i;
- int thr_ret;
-
- for(i=0; i<numhandles; i++) {
- gpointer handle = handles[i];
-
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: unlocking handle %p", __func__, handle);
-
- thr_ret = mono_w32handle_unlock_handle (handle);
- g_assert (thr_ret == 0);
- }
-}
-
-static int
-mono_w32handle_timedwait_signal_naked (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout, gboolean poll, gboolean *alerted)
-{
- int res;
-
- if (!poll) {
- res = mono_os_cond_timedwait (cond, mutex, timeout);
- } else {
- /* This is needed when waiting for process handles */
- if (!alerted) {
- /*
- * pthread_cond_(timed)wait() can return 0 even if the condition was not
- * signalled. This happens at least on Darwin. We surface this, i.e., we
- * get spurious wake-ups.
- *
- * http://pubs.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_wait.html
- */
- res = mono_os_cond_timedwait (cond, mutex, timeout);
- } else {
- if (timeout < 100) {
- /* Real timeout is less than 100ms time */
- res = mono_os_cond_timedwait (cond, mutex, timeout);
- } else {
- res = mono_os_cond_timedwait (cond, mutex, 100);
-
- /* Mask the fake timeout, this will cause
- * another poll if the cond was not really signaled
- */
- if (res == -1)
- res = 0;
- }
- }
- }
-
- return res;
-}
-
-static void
-signal_global (gpointer unused)
-{
- /* If we reach here, then interrupt token is set to the flag value, which
- * means that the target thread is either
- * - before the first CAS in timedwait, which means it won't enter the wait.
- * - it is after the first CAS, so it is already waiting, or it will enter
- * the wait, and it will be interrupted by the broadcast. */
- mono_os_mutex_lock (&global_signal_mutex);
- mono_os_cond_broadcast (&global_signal_cond);
- mono_os_mutex_unlock (&global_signal_mutex);
-}
-
-static int
-mono_w32handle_timedwait_signal (guint32 timeout, gboolean poll, gboolean *alerted)
-{
- int res;
-
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for global", __func__);
-
- if (alerted)
- *alerted = FALSE;
-
- if (alerted) {
- mono_thread_info_install_interrupt (signal_global, NULL, alerted);
- if (*alerted)
- return 0;
- }
-
- res = mono_w32handle_timedwait_signal_naked (&global_signal_cond, &global_signal_mutex, timeout, poll, alerted);
-
- if (alerted)
- mono_thread_info_uninstall_interrupt (alerted);
-
- return res;
-}
-
-static void
-signal_handle_and_unref (gpointer handle)
-{
- MonoW32HandleBase *handle_data;
- mono_cond_t *cond;
- mono_mutex_t *mutex;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data))
- g_error ("cannot signal unknown handle %p", handle);
-
- /* If we reach here, then interrupt token is set to the flag value, which
- * means that the target thread is either
- * - before the first CAS in timedwait, which means it won't enter the wait.
- * - it is after the first CAS, so it is already waiting, or it will enter
- * the wait, and it will be interrupted by the broadcast. */
- cond = &handle_data->signal_cond;
- mutex = &handle_data->signal_mutex;
-
- mono_os_mutex_lock (mutex);
- mono_os_cond_broadcast (cond);
- mono_os_mutex_unlock (mutex);
-
- mono_w32handle_unref (handle);
-}
-
-static int
-mono_w32handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboolean poll, gboolean *alerted)
-{
- MonoW32HandleBase *handle_data;
- int res;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data))
- g_error ("cannot wait on unknown handle %p", handle);
-
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: waiting for %p (type %s)", __func__, handle,
- mono_w32handle_ops_typename (mono_w32handle_get_type (handle)));
-
- if (alerted)
- *alerted = FALSE;
-
- if (alerted) {
- mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
- if (*alerted)
- return 0;
- mono_w32handle_ref (handle);
- }
-
- res = mono_w32handle_timedwait_signal_naked (&handle_data->signal_cond, &handle_data->signal_mutex, timeout, poll, alerted);
-
- if (alerted) {
- mono_thread_info_uninstall_interrupt (alerted);
- if (!*alerted) {
- /* if it is alerted, then the handle is unref in the interrupt callback */
- mono_w32handle_unref (handle);
- }
- }
-
- return res;
-}
-
-static gboolean
-dump_callback (gpointer handle, gpointer handle_specific, gpointer user_data)
-{
- MonoW32HandleBase *handle_data;
-
- if (!mono_w32handle_lookup_data (handle, &handle_data))
- g_error ("cannot dump unknown handle %p", handle);
-
- g_print ("%p [%7s] signalled: %5s ref: %3d ",
- handle, mono_w32handle_ops_typename (handle_data->type), handle_data->signalled ? "true" : "false", handle_data->ref);
- mono_w32handle_ops_details (handle_data->type, handle_data->specific);
- g_print ("\n");
-
- return FALSE;
-}
-
-void mono_w32handle_dump (void)
-{
- mono_w32handle_foreach (dump_callback, NULL);
-}
-
-static gboolean
-own_if_signalled (gpointer handle, guint32 *statuscode)
-{
- if (!mono_w32handle_issignalled (handle))
- return FALSE;
-
- *statuscode = WAIT_OBJECT_0;
- mono_w32handle_ops_own (handle, statuscode);
- return TRUE;
-}
-
-static gboolean
-own_if_owned( gpointer handle, guint32 *statuscode)
-{
- if (!mono_w32handle_ops_isowned (handle))
- return FALSE;
-
- *statuscode = WAIT_OBJECT_0;
- mono_w32handle_ops_own (handle, statuscode);
- return TRUE;
-}
-
-MonoW32HandleWaitRet
-mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable)
-{
- MonoW32HandleWaitRet ret;
- gboolean alerted;
- gint64 start;
- gint thr_ret;
- guint32 statuscode = 0;
-
- alerted = FALSE;
-
- if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p has special wait",
- __func__, handle);
-
- switch (mono_w32handle_ops_specialwait (handle, timeout, alertable ? &alerted : NULL)) {
- case WAIT_OBJECT_0:
- ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
- break;
- case WAIT_ABANDONED_0:
- ret = MONO_W32HANDLE_WAIT_RET_ABANDONED_0;
- break;
- case WAIT_IO_COMPLETION:
- ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
- break;
- case WAIT_TIMEOUT:
- ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
- break;
- case WAIT_FAILED:
- ret = MONO_W32HANDLE_WAIT_RET_FAILED;
- break;
- default:
- g_assert_not_reached ();
- }
-
- if (alerted)
- ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
-
- return ret;
- }
-
- if (!mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_WAIT)) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for",
- __func__, handle);
-
- return MONO_W32HANDLE_WAIT_RET_FAILED;
- }
-
- thr_ret = mono_w32handle_lock_handle (handle);
- g_assert (thr_ret == 0);
-
- if (mono_w32handle_test_capabilities (handle, MONO_W32HANDLE_CAP_OWN)) {
- if (own_if_owned (handle, &statuscode)) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned",
- __func__, handle);
-
- ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
- goto done;
- }
- }
-
- if (timeout != INFINITE)
- start = mono_msec_ticks ();
-
- for (;;) {
- gint waited;
-
- if (own_if_signalled (handle, &statuscode)) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled",
- __func__, handle);
-
- ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
- goto done;
- }
-
- mono_w32handle_ops_prewait (handle);
-
- if (timeout == INFINITE) {
- waited = mono_w32handle_timedwait_signal_handle (handle, INFINITE, FALSE, alertable ? &alerted : NULL);
- } else {
- gint64 elapsed;
-
- elapsed = mono_msec_ticks () - start;
- if (elapsed > timeout) {
- ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
- goto done;
- }
-
- waited = mono_w32handle_timedwait_signal_handle (handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL);
- }
-
- if (alerted) {
- ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
- goto done;
- }
-
- if (waited != 0) {
- ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
- goto done;
- }
- }
-
-done:
- thr_ret = mono_w32handle_unlock_handle (handle);
- g_assert (thr_ret == 0);
-
- return ret;
-}
-
-MonoW32HandleWaitRet
-mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable)
-{
- MonoW32HandleWaitRet ret;
- gboolean alerted, poll;
- gint i, thr_ret;
- gint64 start;
- gpointer handles_sorted [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
- guint32 statuscodes [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS] = {0};
-
- if (nhandles == 0)
- return MONO_W32HANDLE_WAIT_RET_FAILED;
-
- if (nhandles == 1)
- return mono_w32handle_wait_one (handles [0], timeout, alertable);
-
- alerted = FALSE;
-
- if (nhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: too many handles: %zd",
- __func__, nhandles);
-
- return MONO_W32HANDLE_WAIT_RET_FAILED;
- }
-
- for (i = 0; i < nhandles; ++i) {
- if (!mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_WAIT)
- && !mono_w32handle_test_capabilities (handles[i], MONO_W32HANDLE_CAP_SPECIAL_WAIT))
- {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p can't be waited for",
- __func__, handles [i]);
-
- return MONO_W32HANDLE_WAIT_RET_FAILED;
- }
-
- handles_sorted [i] = handles [i];
- }
-
- qsort (handles_sorted, nhandles, sizeof (gpointer), g_direct_equal);
- for (i = 1; i < nhandles; ++i) {
- if (handles_sorted [i - 1] == handles_sorted [i]) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p is duplicated",
- __func__, handles_sorted [i]);
-
- return MONO_W32HANDLE_WAIT_RET_FAILED;
- }
- }
-
- poll = FALSE;
- for (i = 0; i < nhandles; ++i) {
- if (mono_w32handle_get_type (handles [i]) == MONO_W32HANDLE_PROCESS) {
- /* Can't wait for a process handle + another handle without polling */
- poll = TRUE;
- }
- }
-
- if (timeout != INFINITE)
- start = mono_msec_ticks ();
-
- for (i = 0; i < nhandles; ++i) {
- /* Add a reference, as we need to ensure the handle wont
- * disappear from under us while we're waiting in the loop
- * (not lock, as we don't want exclusive access here) */
- mono_w32handle_ref (handles [i]);
- }
-
- for (;;) {
- gsize count, lowest;
- gboolean signalled;
- gint waited;
-
- count = 0;
- lowest = nhandles;
-
- mono_w32handle_lock_handles (handles, nhandles);
-
- for (i = 0; i < nhandles; i++) {
- if ((mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_OWN) && mono_w32handle_ops_isowned (handles [i]))
- || mono_w32handle_issignalled (handles [i]))
- {
- count ++;
-
- if (i < lowest)
- lowest = i;
- }
- }
-
- signalled = (waitall && count == nhandles) || (!waitall && count > 0);
-
- if (signalled) {
- for (i = 0; i < nhandles; i++)
- own_if_signalled (handles [i], &statuscodes [i]);
- }
-
- mono_w32handle_unlock_handles (handles, nhandles);
-
- if (signalled) {
- ret = MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + lowest;
- for (i = lowest; i < nhandles; i++) {
- if (statuscodes [i] == WAIT_ABANDONED_0) {
- ret = MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + lowest;
- break;
- }
- }
- goto done;
- }
-
- for (i = 0; i < nhandles; i++) {
- mono_w32handle_ops_prewait (handles[i]);
-
- if (mono_w32handle_test_capabilities (handles [i], MONO_W32HANDLE_CAP_SPECIAL_WAIT)
- && !mono_w32handle_issignalled (handles [i]))
- {
- mono_w32handle_ops_specialwait (handles [i], 0, alertable ? &alerted : NULL);
- }
- }
-
- thr_ret = mono_w32handle_lock_signal_mutex ();
- g_assert (thr_ret == 0);
-
- if (waitall) {
- signalled = TRUE;
- for (i = 0; i < nhandles; ++i) {
- if (!mono_w32handle_issignalled (handles [i])) {
- signalled = FALSE;
- break;
- }
- }
- } else {
- signalled = FALSE;
- for (i = 0; i < nhandles; ++i) {
- if (mono_w32handle_issignalled (handles [i])) {
- signalled = TRUE;
- break;
- }
- }
- }
-
- waited = 0;
-
- if (!signalled) {
- if (timeout == INFINITE) {
- waited = mono_w32handle_timedwait_signal (INFINITE, poll, alertable ? &alerted : NULL);
- } else {
- gint64 elapsed;
-
- elapsed = mono_msec_ticks () - start;
- if (elapsed > timeout) {
- ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
-
- thr_ret = mono_w32handle_unlock_signal_mutex ();
- g_assert (thr_ret == 0);
-
- goto done;
- }
-
- waited = mono_w32handle_timedwait_signal (timeout - elapsed, poll, alertable ? &alerted : NULL);
- }
- }
-
- thr_ret = mono_w32handle_unlock_signal_mutex ();
- g_assert (thr_ret == 0);
-
- if (alerted) {
- ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
- goto done;
- }
-
- if (waited != 0) {
- ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
- goto done;
- }
- }
-
-done:
- for (i = 0; i < nhandles; i++) {
- /* Unref everything we reffed above */
- mono_w32handle_unref (handles [i]);
- }
-
- return ret;
-}
-
-MonoW32HandleWaitRet
-mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable)
-{
- MonoW32HandleWaitRet ret;
- gint64 start;
- gboolean alerted;
- gint thr_ret;
- guint32 statuscode = 0;
-
- alerted = FALSE;
-
- if (!mono_w32handle_test_capabilities (signal_handle, MONO_W32HANDLE_CAP_SIGNAL))
- return MONO_W32HANDLE_WAIT_RET_FAILED;
- if (!mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_WAIT))
- return MONO_W32HANDLE_WAIT_RET_FAILED;
-
- if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) {
- g_warning ("%s: handle %p has special wait, implement me!!", __func__, wait_handle);
- return MONO_W32HANDLE_WAIT_RET_FAILED;
- }
-
- thr_ret = mono_w32handle_lock_handle (wait_handle);
- g_assert (thr_ret == 0);
-
- mono_w32handle_ops_signal (signal_handle);
-
- if (mono_w32handle_test_capabilities (wait_handle, MONO_W32HANDLE_CAP_OWN)) {
- if (own_if_owned (wait_handle, &statuscode)) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p already owned",
- __func__, wait_handle);
-
- ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
- goto done;
- }
- }
-
- if (timeout != INFINITE)
- start = mono_msec_ticks ();
-
- for (;;) {
- gint waited;
-
- if (own_if_signalled (wait_handle, &statuscode)) {
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: handle %p signalled",
- __func__, wait_handle);
-
- ret = statuscode == WAIT_ABANDONED_0 ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
- goto done;
- }
-
- mono_w32handle_ops_prewait (wait_handle);
-
- if (timeout == INFINITE) {
- waited = mono_w32handle_timedwait_signal_handle (wait_handle, INFINITE, FALSE, alertable ? &alerted : NULL);
- } else {
- gint64 elapsed;
-
- elapsed = mono_msec_ticks () - start;
- if (elapsed > timeout) {
- ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
- goto done;
- }
-
- waited = mono_w32handle_timedwait_signal_handle (wait_handle, timeout - elapsed, FALSE, alertable ? &alerted : NULL);
- }
-
- if (alerted) {
- ret = MONO_W32HANDLE_WAIT_RET_ALERTED;
- goto done;
- }
-
- if (waited != 0) {
- ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
- goto done;
- }
- }
-
-done:
- thr_ret = mono_w32handle_unlock_handle (wait_handle);
- g_assert (thr_ret == 0);
-
- return ret;
-}
-
-#endif /* !defined(HOST_WIN32) */
+++ /dev/null
-
-#ifndef _MONO_UTILS_W32HANDLE_H_
-#define _MONO_UTILS_W32HANDLE_H_
-
-#include <config.h>
-#include <glib.h>
-
-#ifndef INVALID_HANDLE_VALUE
-#define INVALID_HANDLE_VALUE (gpointer)-1
-#endif
-
-#define MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS 64
-
-typedef enum {
- MONO_W32HANDLE_UNUSED = 0,
- MONO_W32HANDLE_FILE,
- MONO_W32HANDLE_CONSOLE,
- MONO_W32HANDLE_THREAD,
- MONO_W32HANDLE_SEM,
- MONO_W32HANDLE_MUTEX,
- MONO_W32HANDLE_EVENT,
- MONO_W32HANDLE_SOCKET,
- MONO_W32HANDLE_FIND,
- MONO_W32HANDLE_PROCESS,
- MONO_W32HANDLE_PIPE,
- MONO_W32HANDLE_NAMEDMUTEX,
- MONO_W32HANDLE_NAMEDSEM,
- MONO_W32HANDLE_NAMEDEVENT,
- MONO_W32HANDLE_COUNT
-} MonoW32HandleType;
-
-typedef struct
-{
- void (*close)(gpointer handle, gpointer data);
-
- /* SignalObjectAndWait */
- void (*signal)(gpointer signal);
-
- /* Called by WaitForSingleObject and WaitForMultipleObjects,
- * with the handle locked (shared handles aren't locked.)
- * Returns TRUE if ownership was established, false otherwise.
- * If TRUE, *statuscode contains a status code such as
- * WAIT_OBJECT_0 or WAIT_ABANDONED_0.
- */
- gboolean (*own_handle)(gpointer handle, guint32 *statuscode);
-
- /* Called by WaitForSingleObject and WaitForMultipleObjects, if the
- * handle in question is "ownable" (ie mutexes), to see if the current
- * thread already owns this handle
- */
- gboolean (*is_owned)(gpointer handle);
-
- /* Called by WaitForSingleObject and WaitForMultipleObjects,
- * if the handle in question needs a special wait function
- * instead of using the normal handle signal mechanism.
- * Returns the WaitForSingleObject return code.
- */
- guint32 (*special_wait)(gpointer handle, guint32 timeout, gboolean *alerted);
-
- /* Called by WaitForSingleObject and WaitForMultipleObjects,
- * if the handle in question needs some preprocessing before the
- * signal wait.
- */
- void (*prewait)(gpointer handle);
-
- /* Called when dumping the handles */
- void (*details)(gpointer data);
-
- /* Called to get the name of the handle type */
- const gchar* (*typename) (void);
-
- /* Called to get the size of the handle type */
- gsize (*typesize) (void);
-} MonoW32HandleOps;
-
-typedef enum {
- MONO_W32HANDLE_CAP_WAIT = 0x01,
- MONO_W32HANDLE_CAP_SIGNAL = 0x02,
- MONO_W32HANDLE_CAP_OWN = 0x04,
- MONO_W32HANDLE_CAP_SPECIAL_WAIT = 0x08,
-} MonoW32HandleCapability;
-
-extern guint32 mono_w32handle_fd_reserve;
-
-void
-mono_w32handle_init (void);
-
-void
-mono_w32handle_cleanup (void);
-
-void
-mono_w32handle_register_ops (MonoW32HandleType type, MonoW32HandleOps *ops);
-
-gpointer
-mono_w32handle_new (MonoW32HandleType type, gpointer handle_specific);
-
-gpointer
-mono_w32handle_new_fd (MonoW32HandleType type, int fd, gpointer handle_specific);
-
-MonoW32HandleType
-mono_w32handle_get_type (gpointer handle);
-
-gboolean
-mono_w32handle_lookup (gpointer handle, MonoW32HandleType type, gpointer *handle_specific);
-
-gpointer
-mono_w32handle_search (MonoW32HandleType type, gboolean (*check)(gpointer, gpointer), gpointer user_data, gpointer *handle_specific, gboolean search_shared);
-
-void
-mono_w32handle_foreach (gboolean (*on_each)(gpointer handle, gpointer data, gpointer user_data), gpointer user_data);
-
-void
-mono_w32handle_dump (void);
-
-void
-mono_w32handle_ref (gpointer handle);
-
-void
-mono_w32handle_unref (gpointer handle);
-
-void
-mono_w32handle_register_capabilities (MonoW32HandleType type, MonoW32HandleCapability caps);
-
-gboolean
-mono_w32handle_test_capabilities (gpointer handle, MonoW32HandleCapability caps);
-
-void
-mono_w32handle_ops_close (gpointer handle, gpointer data);
-
-void
-mono_w32handle_ops_signal (gpointer handle);
-
-gboolean
-mono_w32handle_ops_own (gpointer handle, guint32 *statuscode);
-
-gboolean
-mono_w32handle_ops_isowned (gpointer handle);
-
-guint32
-mono_w32handle_ops_specialwait (gpointer handle, guint32 timeout, gboolean *alerted);
-
-void
-mono_w32handle_ops_prewait (gpointer handle);
-
-void
-mono_w32handle_ops_details (MonoW32HandleType type, gpointer data);
-
-const gchar*
-mono_w32handle_ops_typename (MonoW32HandleType type);
-
-gsize
-mono_w32handle_ops_typesize (MonoW32HandleType type);
-
-void
-mono_w32handle_set_signal_state (gpointer handle, gboolean state, gboolean broadcast);
-
-gboolean
-mono_w32handle_issignalled (gpointer handle);
-
-int
-mono_w32handle_lock_handle (gpointer handle);
-
-int
-mono_w32handle_trylock_handle (gpointer handle);
-
-int
-mono_w32handle_unlock_handle (gpointer handle);
-
-typedef enum {
- MONO_W32HANDLE_WAIT_RET_SUCCESS_0 = 0,
- MONO_W32HANDLE_WAIT_RET_ABANDONED_0 = MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS,
- MONO_W32HANDLE_WAIT_RET_ALERTED = -1,
- MONO_W32HANDLE_WAIT_RET_TIMEOUT = -2,
- MONO_W32HANDLE_WAIT_RET_FAILED = -3,
-} MonoW32HandleWaitRet;
-
-MonoW32HandleWaitRet
-mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable);
-
-MonoW32HandleWaitRet
-mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable);
-
-MonoW32HandleWaitRet
-mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable);
-
-#endif /* _MONO_UTILS_W32HANDLE_H_ */