From ac37cf0ccbfd06454ac12282384142d12a96b63c Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Thu, 21 Jan 2021 14:19:59 -0500 Subject: [PATCH 01/36] Remove appropriate icalls from Mono --- src/mono/mono/metadata/icall-decl.h | 4 - src/mono/mono/metadata/icall-def-netcore.h | 22 ---- src/mono/mono/metadata/threads.c | 99 --------------- src/mono/mono/metadata/w32event-unix.c | 19 --- src/mono/mono/metadata/w32event-win32.c | 49 -------- src/mono/mono/metadata/w32event.h | 4 - src/mono/mono/metadata/w32mutex-unix.c | 102 ---------------- src/mono/mono/metadata/w32mutex-win32.c | 45 ------- src/mono/mono/metadata/w32semaphore-unix.c | 127 -------------------- src/mono/mono/metadata/w32semaphore-win32.c | 45 ------- 10 files changed, 516 deletions(-) diff --git a/src/mono/mono/metadata/icall-decl.h b/src/mono/mono/metadata/icall-decl.h index 1d233f24600d1a..cbaedb53d73a08 100644 --- a/src/mono/mono/metadata/icall-decl.h +++ b/src/mono/mono/metadata/icall-decl.h @@ -225,10 +225,6 @@ ICALL_EXPORT gpointer ves_icall_System_Runtime_InteropServices_Marshal_ReAlloc ICALL_EXPORT char* ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (const gunichar2*, int); ICALL_EXPORT gunichar2* ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (const gunichar2*, int); -ICALL_EXPORT gpointer ves_icall_System_Threading_Semaphore_CreateSemaphore_icall (gint32 initialCount, gint32 maximumCount, const gunichar2 *name, gint32 name_length, gint32 *win32error); -ICALL_EXPORT gpointer ves_icall_System_Threading_Semaphore_OpenSemaphore_icall (const gunichar2 *name, gint32 name_length, gint32 rights, gint32 *win32error); -ICALL_EXPORT MonoBoolean ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (gpointer handle, gint32 releaseCount, gint32 *prevcount); - ICALL_EXPORT gpointer ves_icall_System_Threading_LowLevelLifoSemaphore_InitInternal (void); ICALL_EXPORT void ves_icall_System_Threading_LowLevelLifoSemaphore_DeleteInternal (gpointer sem_ptr); ICALL_EXPORT gint32 ves_icall_System_Threading_LowLevelLifoSemaphore_TimedWaitInternal (gpointer sem_ptr, gint32 timeout_ms); diff --git a/src/mono/mono/metadata/icall-def-netcore.h b/src/mono/mono/metadata/icall-def-netcore.h index 73c3dfca687c4d..2f2f6192a2b733 100644 --- a/src/mono/mono/metadata/icall-def-netcore.h +++ b/src/mono/mono/metadata/icall-def-netcore.h @@ -1,6 +1,3 @@ -ICALL_TYPE(SAFEWAITHANDLE, "Microsoft.Win32.SafeHandles.SafeWaitHandle", SAFEWAITHANDLE_1) // && UNIX -NOHANDLES(ICALL(SAFEWAITHANDLE_1, "CloseEventInternal", ves_icall_System_Threading_Events_CloseEvent_internal)) - ICALL_TYPE(RUNTIME, "Mono.Runtime", RUNTIME_20) NOHANDLES(ICALL(RUNTIME_20, "AnnotateMicrosoftTelemetry_internal", ves_icall_Mono_Runtime_AnnotateMicrosoftTelemetry)) NOHANDLES(ICALL(RUNTIME_19, "CheckCrashReportLog_internal", ves_icall_Mono_Runtime_CheckCrashReportingLog)) @@ -447,11 +444,6 @@ HANDLES(STRING_9, "FastAllocateString", ves_icall_System_String_FastAllocateStri HANDLES(STRING_10, "InternalIntern", ves_icall_System_String_InternalIntern, MonoString, 1, (MonoString)) HANDLES(STRING_11, "InternalIsInterned", ves_icall_System_String_InternalIsInterned, MonoString, 1, (MonoString)) -ICALL_TYPE(NATIVEC, "System.Threading.EventWaitHandle", EWH_1) // && Unix -HANDLES(EWH_1, "CreateEventInternal", ves_icall_System_Threading_Events_CreateEvent_icall, gpointer, 5, (MonoBoolean, MonoBoolean, const_gunichar2_ptr, gint32, gint32_ref)) -NOHANDLES(ICALL(EWH_2, "ResetEventInternal", ves_icall_System_Threading_Events_ResetEvent_internal)) -NOHANDLES(ICALL(EWH_3, "SetEventInternal", ves_icall_System_Threading_Events_SetEvent_internal)) - ICALL_TYPE(ILOCK, "System.Threading.Interlocked", ILOCK_1) NOHANDLES(ICALL(ILOCK_1, "Add(int&,int)", ves_icall_System_Threading_Interlocked_Add_Int)) NOHANDLES(ICALL(ILOCK_2, "Add(long&,long)", ves_icall_System_Threading_Interlocked_Add_Long)) @@ -490,16 +482,6 @@ HANDLES(MONIT_7, "Monitor_wait", ves_icall_System_Threading_Monitor_Monitor_wait NOHANDLES(ICALL(MONIT_8, "get_LockContentionCount", ves_icall_System_Threading_Monitor_Monitor_LockContentionCount)) HANDLES(MONIT_9, "try_enter_with_atomic_var", ves_icall_System_Threading_Monitor_Monitor_try_enter_with_atomic_var, void, 4, (MonoObject, guint32, MonoBoolean, MonoBoolean_ref)) -ICALL_TYPE(MUTEX, "System.Threading.Mutex", MUTEX_1) -HANDLES(MUTEX_1, "CreateMutex_icall", ves_icall_System_Threading_Mutex_CreateMutex_icall, gpointer, 4, (MonoBoolean, const_gunichar2_ptr, gint32, MonoBoolean_ref)) -HANDLES(MUTEX_2, "OpenMutex_icall", ves_icall_System_Threading_Mutex_OpenMutex_icall, gpointer, 4, (const_gunichar2_ptr, gint32, gint32, gint32_ref)) -NOHANDLES(ICALL(MUTEX_3, "ReleaseMutex_internal", ves_icall_System_Threading_Mutex_ReleaseMutex_internal)) - -ICALL_TYPE(SEMA, "System.Threading.Semaphore", SEMA_1) -NOHANDLES(ICALL(SEMA_1, "CreateSemaphore_icall", ves_icall_System_Threading_Semaphore_CreateSemaphore_icall)) -NOHANDLES(ICALL(SEMA_2, "OpenSemaphore_icall", ves_icall_System_Threading_Semaphore_OpenSemaphore_icall)) -NOHANDLES(ICALL(SEMA_3, "ReleaseSemaphore_internal", ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal)) - ICALL_TYPE(THREAD, "System.Threading.Thread", THREAD_1) HANDLES(THREAD_1, "ClrState", ves_icall_System_Threading_Thread_ClrState, void, 2, (MonoInternalThread, guint32)) HANDLES(ITHREAD_2, "FreeInternal", ves_icall_System_Threading_InternalThread_Thread_free_internal, void, 1, (MonoInternalThread)) @@ -517,10 +499,6 @@ HANDLES(THREAD_11, "SleepInternal", ves_icall_System_Threading_Thread_Sleep_inte HANDLES(THREAD_13, "StartInternal", ves_icall_System_Threading_Thread_StartInternal, void, 1, (MonoThreadObject)) NOHANDLES(ICALL(THREAD_14, "YieldInternal", ves_icall_System_Threading_Thread_YieldInternal)) -ICALL_TYPE(WAITH, "System.Threading.WaitHandle", WAITH_1) -HANDLES(WAITH_1, "SignalAndWait_Internal", ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal, gint32, 3, (gpointer, gpointer, gint32)) -HANDLES(WAITH_2, "Wait_internal", ves_icall_System_Threading_WaitHandle_Wait_internal, gint32, 4, (gpointer_ptr, gint32, MonoBoolean, gint32)) - ICALL_TYPE(TYPE, "System.Type", TYPE_1) HANDLES(TYPE_1, "internal_from_handle", ves_icall_System_Type_internal_from_handle, MonoReflectionType, 1, (MonoType_ref)) diff --git a/src/mono/mono/metadata/threads.c b/src/mono/mono/metadata/threads.c index 36fbfa86c9f750..a2153547992cfa 100644 --- a/src/mono/mono/metadata/threads.c +++ b/src/mono/mono/metadata/threads.c @@ -2066,105 +2066,6 @@ map_native_wait_result_to_managed (MonoW32HandleWaitRet val, gsize numobjects) } } -gint32 -ves_icall_System_Threading_WaitHandle_Wait_internal (gpointer *handles, gint32 numhandles, MonoBoolean waitall, gint32 timeout, MonoError *error) -{ - /* Do this WaitSleepJoin check before creating objects */ - if (mono_thread_current_check_pending_interrupt ()) - return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0); - - MonoInternalThread * const thread = mono_thread_internal_current (); - - mono_thread_set_state (thread, ThreadState_WaitSleepJoin); - - gint64 start = 0; - - if (timeout == -1) - timeout = MONO_INFINITE_WAIT; - if (timeout != MONO_INFINITE_WAIT) - start = mono_msec_ticks (); - - guint32 timeoutLeft = timeout; - - MonoW32HandleWaitRet ret; - -#ifdef DISABLE_THREADS - if (numhandles == 1 && timeout == MONO_INFINITE_WAIT) { - gboolean signalled = FALSE; - for (int i = 0; i < numhandles; ++i) { - if (mono_w32handle_handle_is_owned (handles [i]) || mono_w32handle_handle_is_signalled (handles [i])) { - signalled = TRUE; - break; - } - } - if (!signalled) { - mono_error_set_synchronization_lock (error, "Cannot wait on events on this runtime."); - return 0; - } - } -#endif - - HANDLE_LOOP_PREPARE; - - for (;;) { - - /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */ - ret = mono_w32handle_wait_multiple (handles, numhandles, waitall, timeoutLeft, TRUE, error); - - if (ret != MONO_W32HANDLE_WAIT_RET_ALERTED) - break; - - SETUP_ICALL_FRAME; - - MonoExceptionHandle exc = MONO_HANDLE_NEW (MonoException, NULL); - - const gboolean interrupt = mono_thread_execute_interruption (&exc); - - if (interrupt) - mono_error_set_exception_handle (error, exc); - - CLEAR_ICALL_FRAME; - - if (interrupt) - break; - - if (timeout != MONO_INFINITE_WAIT) { - gint64 const elapsed = mono_msec_ticks () - start; - if (elapsed >= timeout) { - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - break; - } - - timeoutLeft = timeout - elapsed; - } - } - - mono_thread_clr_state (thread, ThreadState_WaitSleepJoin); - - return map_native_wait_result_to_managed (ret, numhandles); -} - -gint32 -ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (gpointer toSignal, gpointer toWait, gint32 ms, MonoError *error) -{ - MonoW32HandleWaitRet ret; - MonoInternalThread *thread = mono_thread_internal_current (); - - if (ms == -1) - ms = MONO_INFINITE_WAIT; - - if (mono_thread_current_check_pending_interrupt ()) - return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0); - - mono_thread_set_state (thread, ThreadState_WaitSleepJoin); - - ret = mono_w32handle_signal_and_wait (toSignal, toWait, ms, TRUE); - - mono_thread_clr_state (thread, ThreadState_WaitSleepJoin); - - return map_native_wait_result_to_managed (ret, 1); -} - gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location) { return mono_atomic_inc_i32 (location); diff --git a/src/mono/mono/metadata/w32event-unix.c b/src/mono/mono/metadata/w32event-unix.c index e55051b991f91b..df8c04237696fa 100644 --- a/src/mono/mono/metadata/w32event-unix.c +++ b/src/mono/mono/metadata/w32event-unix.c @@ -274,19 +274,6 @@ mono_w32event_create_full (MonoBoolean manual, MonoBoolean initial, const char * return event; } -gpointer -ves_icall_System_Threading_Events_CreateEvent_icall (MonoBoolean manual, MonoBoolean initial, - const gunichar2* name, gint32 name_length, gint32 *win32error, MonoError *error) -{ - *win32error = ERROR_SUCCESS; - gsize utf8_name_length = 0; - char *utf8_name = mono_utf16_to_utf8len (name, name_length, &utf8_name_length, error); - return_val_if_nok (error, NULL); - gpointer result = mono_w32event_create_full (manual, initial, utf8_name, utf8_name_length, win32error); - g_free (utf8_name); - return result; -} - gboolean ves_icall_System_Threading_Events_SetEvent_internal (gpointer handle) { @@ -372,12 +359,6 @@ ves_icall_System_Threading_Events_ResetEvent_internal (gpointer handle) return TRUE; } -void -ves_icall_System_Threading_Events_CloseEvent_internal (gpointer handle) -{ - mono_w32handle_close (handle); -} - gpointer mono_w32event_open (const gchar *utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *win32error) { diff --git a/src/mono/mono/metadata/w32event-win32.c b/src/mono/mono/metadata/w32event-win32.c index f51d75ba7ded04..4b3ee206726678 100644 --- a/src/mono/mono/metadata/w32event-win32.c +++ b/src/mono/mono/metadata/w32event-win32.c @@ -44,52 +44,3 @@ mono_w32event_reset (gpointer handle) { ResetEvent (handle); } - -gpointer -ves_icall_System_Threading_Events_CreateEvent_icall (MonoBoolean manual, MonoBoolean initial, - const gunichar2 *name, gint32 name_length, gint32 *win32error, MonoError *error) -{ - gpointer event; - - MONO_ENTER_GC_SAFE; - event = CreateEventW (NULL, manual, initial, name); - *win32error = GetLastError (); - MONO_EXIT_GC_SAFE; - - return event; -} - -gboolean -ves_icall_System_Threading_Events_SetEvent_internal (gpointer handle) -{ - return SetEvent (handle); -} - -gboolean -ves_icall_System_Threading_Events_ResetEvent_internal (gpointer handle) -{ - return ResetEvent (handle); -} - -void -ves_icall_System_Threading_Events_CloseEvent_internal (gpointer handle) -{ - CloseHandle (handle); -} - -gpointer -ves_icall_System_Threading_Events_OpenEvent_icall (const gunichar2 *name, gint32 name_length, - gint32 rights, gint32 *win32error, MonoError *error) -{ - gpointer handle; - - *win32error = ERROR_SUCCESS; - - MONO_ENTER_GC_SAFE; - handle = OpenEventW (rights, FALSE, name); - if (!handle) - *win32error = GetLastError (); - MONO_EXIT_GC_SAFE; - - return handle; -} diff --git a/src/mono/mono/metadata/w32event.h b/src/mono/mono/metadata/w32event.h index 7f6e92e28398bd..ee0102d5de305c 100644 --- a/src/mono/mono/metadata/w32event.h +++ b/src/mono/mono/metadata/w32event.h @@ -36,10 +36,6 @@ ICALL_EXPORT gboolean ves_icall_System_Threading_Events_ResetEvent_internal (gpointer handle); -ICALL_EXPORT -void -ves_icall_System_Threading_Events_CloseEvent_internal (gpointer handle); - typedef struct MonoW32HandleNamedEvent MonoW32HandleNamedEvent; MonoW32HandleNamespace* diff --git a/src/mono/mono/metadata/w32mutex-unix.c b/src/mono/mono/metadata/w32mutex-unix.c index 0e1da775ff9612..32c33c52b811c4 100644 --- a/src/mono/mono/metadata/w32mutex-unix.c +++ b/src/mono/mono/metadata/w32mutex-unix.c @@ -341,108 +341,6 @@ namedmutex_create (gboolean owned, const char *utf8_name, gsize utf8_len) return handle; } -gpointer -ves_icall_System_Threading_Mutex_CreateMutex_icall (MonoBoolean owned, const gunichar2 *name, - gint32 name_length, MonoBoolean *created, MonoError *error) -{ - gpointer mutex; - - *created = TRUE; - - /* Need to blow away any old errors here, because code tests - * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex - * was freshly created */ - mono_w32error_set_last (ERROR_SUCCESS); - - if (!name) { - mutex = mutex_create (owned); - } else { - gsize utf8_name_length = 0; - char *utf8_name = mono_utf16_to_utf8len (name, name_length, &utf8_name_length, error); - return_val_if_nok (error, NULL); - - mutex = namedmutex_create (owned, utf8_name, utf8_name_length); - - if (mono_w32error_get_last () == ERROR_ALREADY_EXISTS) - *created = FALSE; - g_free (utf8_name); - } - - return mutex; -} - -MonoBoolean -ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle) -{ - MonoW32Handle *handle_data; - MonoW32HandleMutex *mutex_handle; - pthread_t tid; - gboolean ret; - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { - g_warning ("%s: unkown handle %p", __func__, handle); - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - if (handle_data->type != MONO_W32TYPE_MUTEX && handle_data->type != MONO_W32TYPE_NAMEDMUTEX) { - g_warning ("%s: unknown mutex handle %p", __func__, handle); - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_w32handle_unref (handle_data); - return FALSE; - } - - mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: releasing %s handle %p, tid: %p recursion: %d", - __func__, mono_w32handle_get_typename (handle_data->type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); - - mono_w32handle_lock (handle_data); - - tid = pthread_self (); - - if (mutex_handle->abandoned) { - // The Win32 ReleaseMutex() function returns TRUE for abandoned mutexes - ret = TRUE; - } else if (!pthread_equal (mutex_handle->tid, tid)) { - ret = FALSE; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: we don't own %s handle %p (owned by %ld, me %ld)", - __func__, mono_w32handle_get_typename (handle_data->type), handle, (long)mutex_handle->tid, (long)tid); - } else { - ret = TRUE; - - /* OK, we own this mutex */ - mutex_handle->recursion--; - - if (mutex_handle->recursion == 0) { - thread_disown_mutex (mono_thread_internal_current (), handle); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: unlocking %s handle %p, tid: %p recusion : %d", - __func__, mono_w32handle_get_typename (handle_data->type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); - - mutex_handle->tid = 0; - mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); - } - } - - mono_w32handle_unlock (handle_data); - mono_w32handle_unref (handle_data); - - return ret; -} - -gpointer -ves_icall_System_Threading_Mutex_OpenMutex_icall (const gunichar2 *name, gint32 name_length, gint32 rights G_GNUC_UNUSED, gint32 *win32error, MonoError *error) -{ - *win32error = ERROR_SUCCESS; - char *utf8_name = mono_utf16_to_utf8 (name, name_length, error); - return_val_if_nok (error, NULL); - gpointer handle = mono_w32mutex_open (utf8_name, rights, win32error); - g_free (utf8_name); - return handle; -} - gpointer mono_w32mutex_open (const char* utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *win32error) { diff --git a/src/mono/mono/metadata/w32mutex-win32.c b/src/mono/mono/metadata/w32mutex-win32.c index 879bfeaa9c131a..3e50e1269d8dec 100644 --- a/src/mono/mono/metadata/w32mutex-win32.c +++ b/src/mono/mono/metadata/w32mutex-win32.c @@ -20,48 +20,3 @@ void mono_w32mutex_init (void) { } - -gpointer -ves_icall_System_Threading_Mutex_CreateMutex_icall (MonoBoolean owned, const gunichar2 *name, - gint32 name_length, MonoBoolean *created, MonoError *error) -{ - HANDLE mutex; - - *created = TRUE; - - /* Need to blow away any old errors here, because code tests - * for ERROR_ALREADY_EXISTS on success (!) to see if a mutex - * was freshly created */ - SetLastError (ERROR_SUCCESS); - - MONO_ENTER_GC_SAFE; - mutex = CreateMutexW (NULL, owned, name); - if (name && GetLastError () == ERROR_ALREADY_EXISTS) - *created = FALSE; - MONO_EXIT_GC_SAFE; - - return mutex; -} - -MonoBoolean -ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle) -{ - return ReleaseMutex (handle); -} - -gpointer -ves_icall_System_Threading_Mutex_OpenMutex_icall (const gunichar2 *name, gint32 name_length, - gint32 rights, gint32 *win32error, MonoError *error) -{ - HANDLE ret; - - *win32error = ERROR_SUCCESS; - - MONO_ENTER_GC_SAFE; - ret = OpenMutexW (rights, FALSE, name); - if (!ret) - *win32error = GetLastError (); - MONO_EXIT_GC_SAFE; - - return ret; -} diff --git a/src/mono/mono/metadata/w32semaphore-unix.c b/src/mono/mono/metadata/w32semaphore-unix.c index fd1138b2b01538..539f3683232ef1 100644 --- a/src/mono/mono/metadata/w32semaphore-unix.c +++ b/src/mono/mono/metadata/w32semaphore-unix.c @@ -233,133 +233,6 @@ namedsem_create (gint32 initial, gint32 max, const gunichar2 *name, gint32 name_ return handle; } -// These functions appear to be using coop-aware locking functions, and so this file does not include explicit -// GC-safe transitions like its corresponding Windows version - -gpointer -ves_icall_System_Threading_Semaphore_CreateSemaphore_icall (gint32 initialCount, gint32 maximumCount, - const gunichar2 *name, gint32 name_length, gint32 *win32error) -{ - if (maximumCount <= 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: maximumCount <= 0", __func__); -invalid_parameter: - *win32error = ERROR_INVALID_PARAMETER; - return NULL; - } - - if (initialCount > maximumCount || initialCount < 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: initialCount > maximumCount or < 0", __func__); - goto invalid_parameter; - } - - /* Need to blow away any old errors here, because code tests - * for ERROR_ALREADY_EXISTS on success (!) to see if a - * semaphore was freshly created - */ - mono_w32error_set_last (ERROR_SUCCESS); - - ERROR_DECL (error); - - gpointer sem = name ? namedsem_create (initialCount, maximumCount, name, name_length, error) - : sem_create (initialCount, maximumCount); - *win32error = mono_w32error_get_last (); - mono_error_set_pending_exception (error); \ - return sem; -} - -MonoBoolean -ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (gpointer handle, gint32 releaseCount, gint32 *prevcount) -{ - MonoW32Handle *handle_data = NULL; - MonoW32HandleSemaphore *sem_handle; - MonoBoolean ret = FALSE; - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { - g_warning ("%s: unkown handle %p", __func__, handle); -invalid_handle: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - goto exit; - } - - if (handle_data->type != MONO_W32TYPE_SEM && handle_data->type != MONO_W32TYPE_NAMEDSEM) { - g_warning ("%s: unknown sem handle %p", __func__, handle); - goto invalid_handle; - } - - sem_handle = (MonoW32HandleSemaphore*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: releasing %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle); - - mono_w32handle_lock (handle_data); - - /* Do this before checking for count overflow, because overflowing - * max is a listed technique for finding the current value */ - if (prevcount) - *prevcount = sem_handle->val; - - /* No idea why max is signed, but thats the spec :-( */ - if (sem_handle->val + releaseCount > (guint32)sem_handle->max) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: %s handle %p val %d count %d max %d, max value would be exceeded", - __func__, mono_w32handle_get_typename (handle_data->type), handle, sem_handle->val, releaseCount, sem_handle->max); - - ret = FALSE; - } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: %s handle %p val %d count %d max %d", - __func__, mono_w32handle_get_typename (handle_data->type), handle, sem_handle->val, releaseCount, sem_handle->max); - - sem_handle->val += releaseCount; - mono_w32handle_set_signal_state (handle_data, TRUE, TRUE); - ret = TRUE; - } - - mono_w32handle_unlock (handle_data); -exit: - if (handle_data) - mono_w32handle_unref (handle_data); - return ret; -} - -gpointer -ves_icall_System_Threading_Semaphore_OpenSemaphore_icall (const gunichar2 *name, gint32 name_length, - gint32 rights, gint32 *win32error) -{ - g_assert (name); - gpointer handle = NULL; - ERROR_DECL (error); - - *win32error = ERROR_SUCCESS; - - char *utf8_name = mono_utf16_to_utf8 (name, name_length, error); - goto_if_nok (error, exit); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: Opening named sem [%s]", __func__, utf8_name); - - // Opening named objects does not race. - mono_w32handle_namespace_lock (); - - handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDSEM, utf8_name); - - mono_w32handle_namespace_unlock (); - - if (handle == INVALID_HANDLE_VALUE) { - /* The name has already been used for a different object. */ - *win32error = ERROR_INVALID_HANDLE; - goto exit; - } else if (!handle) { - /* This name doesn't exist */ - *win32error = ERROR_FILE_NOT_FOUND; - goto exit; - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: returning named sem handle %p", __func__, handle); - -exit: - g_free (utf8_name); - mono_error_set_pending_exception (error); \ - return handle; -} - MonoW32HandleNamespace* mono_w32semaphore_get_namespace (MonoW32HandleNamedSemaphore *semaphore) { diff --git a/src/mono/mono/metadata/w32semaphore-win32.c b/src/mono/mono/metadata/w32semaphore-win32.c index 3856be46aea9f5..677cc79c54c5aa 100644 --- a/src/mono/mono/metadata/w32semaphore-win32.c +++ b/src/mono/mono/metadata/w32semaphore-win32.c @@ -20,48 +20,3 @@ void mono_w32semaphore_init (void) { } - -#if HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE || HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE_EX -gpointer -ves_icall_System_Threading_Semaphore_CreateSemaphore_icall (gint32 initialCount, gint32 maximumCount, - const gunichar2 *name, gint32 name_length, gint32 *win32error) -{ - HANDLE sem; - MONO_ENTER_GC_SAFE; -#if HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE - sem = CreateSemaphoreW (NULL, initialCount, maximumCount, name); -#elif HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE_EX - sem = CreateSemaphoreExW (NULL, initialCount, maximumCount, name, 0, SEMAPHORE_ALL_ACCESS); -#endif - MONO_EXIT_GC_SAFE; - *win32error = GetLastError (); - return sem; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_CREATE_SEMAPHORE && !HAVE_EXTERN_DEFINED_WIN32_CREATE_SEMAPHORE_EX -gpointer -ves_icall_System_Threading_Semaphore_CreateSemaphore_icall (gint32 initialCount, gint32 maximumCount, - const gunichar2 *name, gint32 name_length, gint32 *win32error) -{ - g_unsupported_api ("CreateSemaphore, CreateSemaphoreEx"); - SetLastError (ERROR_NOT_SUPPORTED); - return NULL; -} -#endif /* HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE || HAVE_API_SUPPORT_WIN32_CREATE_SEMAPHORE_EX) */ - -MonoBoolean -ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (gpointer handle, gint32 releaseCount, gint32 *prevcount) -{ - return ReleaseSemaphore (handle, releaseCount, (PLONG)prevcount); -} - -gpointer -ves_icall_System_Threading_Semaphore_OpenSemaphore_icall (const gunichar2 *name, gint32 name_length, - gint32 rights, gint32 *win32error) -{ - HANDLE sem; - MONO_ENTER_GC_SAFE; - sem = OpenSemaphoreW (rights, FALSE, name); - MONO_EXIT_GC_SAFE; - *win32error = GetLastError (); - return sem; -} From b58f7c3180c25fd7d42f478698499b11d04eb9dc Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Fri, 22 Jan 2021 07:54:38 -0500 Subject: [PATCH 02/36] Wire up the build --- .../src/System.Private.CoreLib.Shared.projitems | 11 +++++++++++ .../System.Private.CoreLib.csproj | 6 +----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index d9900d80412cd2..a8b965e71b1f27 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1980,4 +1980,15 @@ + + + + + + + + + + + diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index fcb64a0ae6947b..7a9965bc66df73 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -110,6 +110,7 @@ true true true + true @@ -254,14 +255,9 @@ - - - - - From 515a5524134ee842353de9fa25da9367ed7abd18 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Fri, 22 Jan 2021 07:55:37 -0500 Subject: [PATCH 03/36] Remove old Mono managed implementations --- .../SafeHandles/SafeWaitHandle.Unix.Mono.cs | 20 ---- .../Threading/EventWaitHandle.Unix.Mono.cs | 99 ----------------- .../src/System/Threading/Mutex.Unix.Mono.cs | 78 ------------- .../System/Threading/Semaphore.Unix.Mono.cs | 104 ------------------ .../src/System/Threading/WaitHandle.Mono.cs | 53 --------- 5 files changed, 354 deletions(-) delete mode 100644 src/mono/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeWaitHandle.Unix.Mono.cs delete mode 100644 src/mono/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.Mono.cs delete mode 100644 src/mono/System.Private.CoreLib/src/System/Threading/Mutex.Unix.Mono.cs delete mode 100644 src/mono/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.Mono.cs delete mode 100644 src/mono/System.Private.CoreLib/src/System/Threading/WaitHandle.Mono.cs diff --git a/src/mono/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeWaitHandle.Unix.Mono.cs b/src/mono/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeWaitHandle.Unix.Mono.cs deleted file mode 100644 index 37e0b6a5962834..00000000000000 --- a/src/mono/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeWaitHandle.Unix.Mono.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Runtime.CompilerServices; - -namespace Microsoft.Win32.SafeHandles -{ - public partial class SafeWaitHandle - { - protected override bool ReleaseHandle() - { - CloseEventInternal(handle); - return true; - } - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern void CloseEventInternal(IntPtr handle); - } -} diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.Mono.cs deleted file mode 100644 index 854a6b4eae7086..00000000000000 --- a/src/mono/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.Mono.cs +++ /dev/null @@ -1,99 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.Win32.SafeHandles; -using System.Runtime.CompilerServices; - -namespace System.Threading -{ - public partial class EventWaitHandle - { - public bool Set() - { - SafeWaitHandle handle = ValidateHandle(out bool release); - - try - { - return SetEventInternal(handle.DangerousGetHandle()); - } - finally - { - if (release) - handle.DangerousRelease(); - } - } - - public bool Reset() - { - SafeWaitHandle handle = ValidateHandle(out bool release); - - try - { - return ResetEventInternal(handle.DangerousGetHandle()); - } - finally - { - if (release) - handle.DangerousRelease(); - } - } - - private unsafe void CreateEventCore(bool initialState, EventResetMode mode, string? name, out bool createdNew) - { - if (name != null) - throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); - - SafeWaitHandle handle = new SafeWaitHandle(CreateEventInternal(mode == EventResetMode.ManualReset, initialState, null, 0, out int errorCode), ownsHandle: true); - if (errorCode != 0) - throw new NotImplementedException("errorCode"); - SafeWaitHandle = handle; - - createdNew = true; - } - - private static OpenExistingResult OpenExistingWorker(string name, out EventWaitHandle result) - { - throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); - } - - internal static bool Set(SafeWaitHandle waitHandle) - { - bool release = false; - try - { - waitHandle.DangerousAddRef(ref release); - return SetEventInternal(waitHandle.DangerousGetHandle()); - } - finally - { - if (release) - waitHandle.DangerousRelease(); - } - } - - private SafeWaitHandle ValidateHandle(out bool success) - { - // The field value is modifiable via the public property, save it locally - // to ensure that one instance is used in all places in this method - SafeWaitHandle waitHandle = SafeWaitHandle; - if (waitHandle.IsInvalid) - { - throw new InvalidOperationException(); - } - - success = false; - waitHandle.DangerousAddRef(ref success); - return waitHandle; - } - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern unsafe IntPtr CreateEventInternal(bool manual, bool initialState, char* name, int name_length, out int errorCode); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern bool ResetEventInternal(IntPtr handle); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern bool SetEventInternal(IntPtr handle); - - } -} diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Mutex.Unix.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Mutex.Unix.Mono.cs deleted file mode 100644 index fc25c741a937dd..00000000000000 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Mutex.Unix.Mono.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; -using System.IO; - -namespace System.Threading -{ - public partial class Mutex - { - private Mutex(IntPtr handle) => Handle = handle; - - public void ReleaseMutex() - { - if (!ReleaseMutex_internal(Handle)) - throw new ApplicationException(SR.Arg_SynchronizationLockException); - } - - private void CreateMutexCore(bool initiallyOwned, string? name, out bool createdNew) => - Handle = CreateMutex_internal(initiallyOwned, name, out createdNew); - - private static unsafe IntPtr CreateMutex_internal(bool initiallyOwned, string? name, out bool created) - { - fixed (char* fixed_name = name) - return CreateMutex_icall(initiallyOwned, fixed_name, - name?.Length ?? 0, out created); - } - - private static OpenExistingResult OpenExistingWorker(string name, out Mutex? result) - { - if (name == null) - throw new ArgumentNullException(nameof(name)); - - result = null; - if ((name.Length == 0) || - (name.Length > 260)) - { - return OpenExistingResult.NameInvalid; - } - - MonoIOError error; - IntPtr handle = OpenMutex_internal(name, out error); - if (handle == IntPtr.Zero) - { - if (error == MonoIOError.ERROR_FILE_NOT_FOUND) - { - return OpenExistingResult.NameNotFound; - } - else if (error == MonoIOError.ERROR_ACCESS_DENIED) - { - throw new UnauthorizedAccessException(); - } - else - { - return OpenExistingResult.PathNotFound; - } - } - - result = new Mutex(handle); - return OpenExistingResult.Success; - } - - private static unsafe IntPtr OpenMutex_internal(string name, out MonoIOError error) - { - fixed (char* fixed_name = name) - return OpenMutex_icall(fixed_name, name?.Length ?? 0, 0x000001 /* MutexRights.Modify */, out error); - } - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern unsafe IntPtr CreateMutex_icall(bool initiallyOwned, char* name, int name_length, out bool created); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern unsafe IntPtr OpenMutex_icall(char* name, int name_length, int rights, out MonoIOError error); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern bool ReleaseMutex_internal(IntPtr handle); - } -} diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.Mono.cs deleted file mode 100644 index ac51ec48210cca..00000000000000 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.Mono.cs +++ /dev/null @@ -1,104 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; -using Microsoft.Win32.SafeHandles; -using System.IO; - -namespace System.Threading -{ - public partial class Semaphore - { - private const int MAX_PATH = 260; - - private Semaphore(SafeWaitHandle handle) => this.SafeWaitHandle = handle; - - private int ReleaseCore(int releaseCount) - { - if (!ReleaseSemaphore_internal(SafeWaitHandle.DangerousGetHandle(), releaseCount, out int previousCount)) - throw new SemaphoreFullException(); - - return previousCount; - } - - private static OpenExistingResult OpenExistingWorker(string name, out Semaphore? result) - { - if (name == null) - throw new ArgumentNullException(nameof(name)); - - if (name.Length == 0) - throw new ArgumentException(SR.Argument_StringZeroLength, nameof(name)); - - if (name.Length > MAX_PATH) - throw new ArgumentException(SR.Argument_WaitHandleNameTooLong); - - var myHandle = new SafeWaitHandle(OpenSemaphore_internal(name, - /*SemaphoreRights.Modify | SemaphoreRights.Synchronize*/ 0x000002 | 0x100000, - out MonoIOError errorCode), true); - - if (myHandle.IsInvalid) - { - result = null; - switch (errorCode) - { - case MonoIOError.ERROR_FILE_NOT_FOUND: - case MonoIOError.ERROR_INVALID_NAME: - return OpenExistingResult.NameNotFound; - case MonoIOError.ERROR_PATH_NOT_FOUND: - return OpenExistingResult.PathNotFound; - case MonoIOError.ERROR_INVALID_HANDLE when !string.IsNullOrEmpty(name): - return OpenExistingResult.NameInvalid; - default: - //this is for passed through NativeMethods Errors - throw new IOException($"Unknown Error '{errorCode}'"); - } - } - - result = new Semaphore(myHandle); - return OpenExistingResult.Success; - } - - private void CreateSemaphoreCore(int initialCount, int maximumCount, string? name, out bool createdNew) - { - if (name?.Length > MAX_PATH) - throw new ArgumentException(SR.Argument_WaitHandleNameTooLong); - - var myHandle = new SafeWaitHandle(CreateSemaphore_internal(initialCount, maximumCount, name, out MonoIOError errorCode), true); - - if (myHandle.IsInvalid) - { - if (errorCode == MonoIOError.ERROR_INVALID_HANDLE && !string.IsNullOrEmpty(name)) - throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name)); - - throw new IOException($"Unknown Error '{errorCode}'"); - } - - this.SafeWaitHandle = myHandle; - createdNew = errorCode != MonoIOError.ERROR_ALREADY_EXISTS; - } - - private static unsafe IntPtr CreateSemaphore_internal(int initialCount, int maximumCount, string? name, out MonoIOError errorCode) - { - // FIXME Check for embedded nuls in name. - fixed (char* fixed_name = name) - return CreateSemaphore_icall(initialCount, maximumCount, - fixed_name, name?.Length ?? 0, out errorCode); - } - - private static unsafe IntPtr OpenSemaphore_internal(string name, int rights, out MonoIOError errorCode) - { - // FIXME Check for embedded nuls in name. - fixed (char* fixed_name = name) - return OpenSemaphore_icall(fixed_name, name?.Length ?? 0, rights, out errorCode); - } - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern unsafe IntPtr CreateSemaphore_icall(int initialCount, int maximumCount, char* name, int nameLength, out MonoIOError errorCode); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern unsafe IntPtr OpenSemaphore_icall(char* name, int nameLength, int rights, out MonoIOError errorCode); - - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern bool ReleaseSemaphore_internal(IntPtr handle, int releaseCount, out int previousCount); - } -} diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/WaitHandle.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/WaitHandle.Mono.cs deleted file mode 100644 index 08ad89b8d032ce..00000000000000 --- a/src/mono/System.Private.CoreLib/src/System/Threading/WaitHandle.Mono.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace System.Threading -{ - public partial class WaitHandle - { - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern unsafe int Wait_internal(IntPtr* handles, int numHandles, bool waitAll, int ms); - - private static int WaitOneCore(IntPtr waitHandle, int millisecondsTimeout) - { - unsafe - { - return Wait_internal(&waitHandle, 1, false, millisecondsTimeout); - } - } - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern int SignalAndWait_Internal(IntPtr waitHandleToSignal, IntPtr waitHandleToWaitOn, int millisecondsTimeout); - - private const int ERROR_TOO_MANY_POSTS = 0x12A; - private const int ERROR_NOT_OWNED_BY_CALLER = 0x12B; - - private static int SignalAndWaitCore(IntPtr waitHandleToSignal, IntPtr waitHandleToWaitOn, int millisecondsTimeout) - { - int ret = SignalAndWait_Internal(waitHandleToSignal, waitHandleToWaitOn, millisecondsTimeout); - if (ret == ERROR_TOO_MANY_POSTS) - throw new InvalidOperationException(SR.Threading_WaitHandleTooManyPosts); - if (ret == ERROR_NOT_OWNED_BY_CALLER) - throw new ApplicationException("Attempt to release mutex not owned by caller"); - return ret; - } - - internal static int WaitMultipleIgnoringSyncContext(Span waitHandles, bool waitAll, int millisecondsTimeout) - { - unsafe - { - fixed (IntPtr* handles = &MemoryMarshal.GetReference(waitHandles)) - { - return Wait_internal(handles, waitHandles.Length, waitAll, millisecondsTimeout); - } - } - } - - // FIXME: Move to shared - internal static int WaitAny(ReadOnlySpan waitHandles, int millisecondsTimeout) => - WaitMultiple(waitHandles, false, millisecondsTimeout); - } -} From 549cb47604e1cb2170ec2a91dfcc7f4b12cb880f Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Fri, 22 Jan 2021 08:03:33 -0500 Subject: [PATCH 04/36] Miscellaneous additions and changes needed for porting These should be fairly uninteresting, so I've split them off into their own commit --- .../src/Resources/Strings.resx | 6 ++++++ .../System/Runtime/InteropServices/SafeHandle.cs | 7 +++++++ .../src/System/Threading/LowLevelMonitor.Unix.cs | 13 +++++++++++++ .../src/System/Threading/LowLevelMonitor.cs | 10 ++++++++++ .../src/System/Threading/WaitHandle.cs | 9 +++++++++ .../WaitSubsystem.HandleManager.Unix.cs | 8 ++++---- .../src/System/Threading/WaitSubsystem.Unix.cs | 2 ++ .../src/System/Threading/Thread.Mono.cs | 16 ++++++++++++++++ 8 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index 2278e4046c6de1..68b2ac5565d3cc 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -2998,6 +2998,9 @@ Value was either too large or too small for an Int64. + + The current thread attempted to reacquire a mutex that has reached its maximum acquire count. + Negating the minimum value of a twos complement number is invalid. @@ -3577,6 +3580,9 @@ COM unregister function must have a System.Type parameter and a void return type. + + The handle is invalid. + Type '{0}' has more than one COM registration function. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs index 78053e44621752..33c9dcb575ced8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeHandle.cs @@ -161,6 +161,13 @@ public void DangerousAddRef(ref bool success) success = true; } + // Used by internal callers to avoid declaring a bool to pass by ref + internal void DangerousAddRef() + { + bool success = false; + DangerousAddRef(ref success); + } + public void DangerousRelease() => InternalRelease(disposeOrFinalizeOperation: false); private void InternalRelease(bool disposeOrFinalizeOperation) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.Unix.cs index 92485a329a8f8e..4b3dfb3be1cc4b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.Unix.cs @@ -44,6 +44,19 @@ private void WaitCore() Interop.Sys.LowLevelMonitor_Wait(_nativeMonitor); } + private bool WaitCore(int timeoutMilliseconds) + { + Debug.Assert(timeoutMilliseconds >= -1); + + if (timeoutMilliseconds < 0) + { + WaitCore(); + return true; + } + + return Interop.Sys.LowLevelMonitor_TimedWait(_nativeMonitor, timeoutMilliseconds); + } + private void Signal_ReleaseCore() { Interop.Sys.LowLevelMonitor_Signal_Release(_nativeMonitor); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.cs index 6aa1e0cc195fa2..c9139eabd3613c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelMonitor.cs @@ -90,6 +90,16 @@ public void Wait() SetOwnerThreadToCurrent(); } + public bool Wait(int timeoutMilliseconds) + { + Debug.Assert(timeoutMilliseconds >= -1); + + ResetOwnerThread(); + bool waitResult = WaitCore(timeoutMilliseconds); + SetOwnerThreadToCurrent(); + return waitResult; + } + public void Signal_Release() { ResetOwnerThread(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.cs index 8311d9dadee04b..c82450488734ae 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.cs @@ -409,6 +409,13 @@ private static bool SignalAndWait(WaitHandle toSignal, WaitHandle toWaitOn, int } } + internal static void ThrowInvalidHandleException() + { + var ex = new InvalidOperationException(SR.InvalidOperation_InvalidHandle); + ex.HResult = HResults.E_HANDLE; + throw ex; + } + public virtual bool WaitOne(TimeSpan timeout) => WaitOneNoCheck(ToTimeoutMilliseconds(timeout)); public virtual bool WaitOne() => WaitOneNoCheck(-1); public virtual bool WaitOne(int millisecondsTimeout, bool exitContext) => WaitOne(millisecondsTimeout); @@ -429,6 +436,8 @@ public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout) => WaitMultiple(waitHandles, false, millisecondsTimeout); internal static int WaitAny(ReadOnlySpan safeWaitHandles, int millisecondsTimeout) => WaitAnyMultiple(safeWaitHandles, millisecondsTimeout); + internal static int WaitAny(ReadOnlySpan waitHandles, int millisecondsTimeout) => + WaitMultiple(waitHandles, false, millisecondsTimeout); public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout) => WaitMultiple(waitHandles, false, ToTimeoutMilliseconds(timeout)); public static int WaitAny(WaitHandle[] waitHandles) => diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.HandleManager.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.HandleManager.Unix.cs index dc922c465aa40b..5b95e92774165b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.HandleManager.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.HandleManager.Unix.cs @@ -16,7 +16,7 @@ public static IntPtr NewHandle(WaitableObject waitableObject) { Debug.Assert(waitableObject != null); - IntPtr handle = RuntimeImports.RhHandleAlloc(waitableObject, GCHandleType.Normal); + IntPtr handle = GCHandle.ToIntPtr(GCHandle.Alloc(waitableObject, GCHandleType.Normal)); // SafeWaitHandle treats -1 and 0 as invalid, and the handle should not be these values anyway Debug.Assert(handle != IntPtr.Zero); @@ -33,7 +33,7 @@ public static WaitableObject FromHandle(IntPtr handle) // We don't know if any other handles are invalid, and this may crash or otherwise do bad things, that is by // design, IntPtr is unsafe by nature. - return (WaitableObject)RuntimeImports.RhHandleGet(handle); + return (WaitableObject)GCHandle.FromIntPtr(handle).Target; } /// @@ -48,8 +48,8 @@ public static void DeleteHandle(IntPtr handle) // We don't know if any other handles are invalid, and this may crash or otherwise do bad things, that is by // design, IntPtr is unsafe by nature. - ((WaitableObject)RuntimeImports.RhHandleGet(handle)).OnDeleteHandle(); - RuntimeImports.RhHandleFree(handle); + FromHandle(handle).OnDeleteHandle(); + GCHandle.FromIntPtr(handle).Free(); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs index 91d21a140c9def..a3917ccae1df12 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs @@ -113,7 +113,9 @@ namespace System.Threading /// - Since provides mutual exclusion for the states of all s in the /// process, any operation that does not involve waiting or releasing a wait can occur with minimal p/invokes /// +#if CORERT [EagerStaticClassConstruction] // the wait subsystem is used during lazy class construction +#endif internal static partial class WaitSubsystem { private static readonly LowLevelLock s_lock = new LowLevelLock(); diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs index ddc62e11d11f83..0aa5e8adfbbc52 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs @@ -282,6 +282,22 @@ private ThreadState ValidateThreadState() return state; } + internal void SetWaitSleepJoinState() + { + Debug.Assert(this == CurrentThread); + Debug.Assert((GetState(this) & ThreadState.WaitSleepJoin) == 0); + + SetState(this, ThreadState.WaitSleepJoin); + } + + internal void ClearWaitSleepJoinState() + { + Debug.Assert(this == CurrentThread); + Debug.Assert((GetState(this) & ThreadState.WaitSleepJoin) != 0); + + ClrState(this, ThreadState.WaitSleepJoin); + } + [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern ulong GetCurrentOSThreadId(); From 4591f0f62c722c82ed521d47cad212c9b619240b Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Fri, 22 Jan 2021 08:07:24 -0500 Subject: [PATCH 05/36] Add Thread._waitInfo and switch over usage I'm not clear on what the best practice is for internal properties like this, so I've just copied the existing style used in Thread and renamed WaitInfo to _waitInfo. Happy to change that back if WaitInfo is preferable. --- .../Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs | 4 ++-- .../src/System/Threading/WaitSubsystem.Unix.cs | 14 +++++++------- .../Threading/WaitSubsystem.WaitableObject.Unix.cs | 2 +- .../src/System/Threading/Thread.Mono.cs | 9 ++++++++- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs index 92c67fcbfb6769..2f50a7853a4baf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs @@ -395,7 +395,7 @@ public static void Sleep(int timeoutMilliseconds, bool interruptible) if (timeoutMilliseconds == 0) { - if (interruptible && Thread.CurrentThread.WaitInfo.CheckAndResetPendingInterrupt_NotLocked) + if (interruptible && Thread.CurrentThread._waitInfo.CheckAndResetPendingInterrupt_NotLocked) { throw new ThreadInterruptedException(); } @@ -407,7 +407,7 @@ public static void Sleep(int timeoutMilliseconds, bool interruptible) int waitResult = Thread .CurrentThread - .WaitInfo + ._waitInfo .Wait(timeoutMilliseconds, interruptible, isSleep: true); Debug.Assert(waitResult == WaitHandle.WaitTimeout); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs index a3917ccae1df12..f000e846a5affe 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs @@ -23,7 +23,7 @@ namespace System.Threading /// /// /// - Keeps information about a thread's wait and provides functionlity to put a thread into a wait state and to take it - /// out of a wait state. Each thread has an instance available through . + /// out of a wait state. Each thread has an instance available through . /// /// /// - Provides functionality to allocate a handle associated with a , to retrieve the object @@ -160,7 +160,7 @@ public static SafeWaitHandle NewMutex(bool initiallyOwned) // Acquire the mutex. A thread's has a reference to all es locked // by the thread. See . So, acquire the lock only after all // possibilities for exceptions have been exhausted. - ThreadWaitInfo waitInfo = Thread.CurrentThread.WaitInfo; + ThreadWaitInfo waitInfo = Thread.CurrentThread._waitInfo; bool acquiredLock = waitableObject.Wait(waitInfo, timeoutMilliseconds: 0, interruptible: false, prioritize: false) == 0; Debug.Assert(acquiredLock); return safeWaitHandle; @@ -268,7 +268,7 @@ public static int Wait( Debug.Assert(waitableObject != null); Debug.Assert(timeoutMilliseconds >= -1); - return waitableObject.Wait(Thread.CurrentThread.WaitInfo, timeoutMilliseconds, interruptible, prioritize); + return waitableObject.Wait(Thread.CurrentThread._waitInfo, timeoutMilliseconds, interruptible, prioritize); } public static int Wait( @@ -281,7 +281,7 @@ public static int Wait( Debug.Assert(waitHandles.Length <= WaitHandle.MaxWaitHandles); Debug.Assert(timeoutMilliseconds >= -1); - ThreadWaitInfo waitInfo = Thread.CurrentThread.WaitInfo; + ThreadWaitInfo waitInfo = Thread.CurrentThread._waitInfo; WaitableObject[] waitableObjects = waitInfo.GetWaitedObjectArray(waitHandles.Length); bool success = false; try @@ -364,7 +364,7 @@ public static int SignalAndWait( Debug.Assert(waitableObjectToWaitOn != null); Debug.Assert(timeoutMilliseconds >= -1); - ThreadWaitInfo waitInfo = Thread.CurrentThread.WaitInfo; + ThreadWaitInfo waitInfo = Thread.CurrentThread._waitInfo; bool waitCalled = false; s_lock.Acquire(); try @@ -410,7 +410,7 @@ public static void Interrupt(Thread thread) s_lock.Acquire(); try { - thread.WaitInfo.TrySignalToInterruptWaitOrRecordPendingInterrupt(); + thread._waitInfo.TrySignalToInterruptWaitOrRecordPendingInterrupt(); } finally { @@ -420,7 +420,7 @@ public static void Interrupt(Thread thread) public static void OnThreadExiting(Thread thread) { - thread.WaitInfo.OnThreadExiting(); + thread._waitInfo.OnThreadExiting(); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs index 8963e7b04415d6..0504fa05edebaf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs @@ -833,7 +833,7 @@ public void RelinquishOwnership(WaitableObject waitableObject, bool isAbandoned) Debug.Assert(waitableObject._ownershipInfo == this); Debug.Assert(_thread != null); - ThreadWaitInfo waitInfo = _thread.WaitInfo; + ThreadWaitInfo waitInfo = _thread._waitInfo; Debug.Assert(isAbandoned ? _reacquireCount >= 0 : _reacquireCount == 0); Debug.Assert(!_isAbandoned); diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs index 0aa5e8adfbbc52..151a4682311c9d 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs @@ -67,6 +67,9 @@ public partial class Thread private StartHelper? _startHelper; internal ExecutionContext? _executionContext; internal SynchronizationContext? _synchronizationContext; +#if TARGET_UNIX + internal WaitSubsystem.ThreadWaitInfo _waitInfo; +#endif // This is used for a quick check on thread pool threads after running a work item to determine if the name, background // state, or priority were changed by the work item, and if so to reset it. Other threads may also change some of those, @@ -75,7 +78,7 @@ public partial class Thread private Thread() { - InitInternal(this); + Initialize(); } ~Thread() @@ -198,10 +201,14 @@ public bool Join(int millisecondsTimeout) return JoinInternal(this, millisecondsTimeout); } + [MemberNotNull(nameof(_waitInfo))] private void Initialize() { InitInternal(this); +#if TARGET_UNIX + _waitInfo = new WaitSubsystem.ThreadWaitInfo(this); +#endif // TODO: This can go away once the mono/mono mirror is disabled stack_size = _startHelper!._maxStackSize; } From ccb76f455ec2f4f7cb98c9ca2d52c7d0ccc853b9 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Fri, 22 Jan 2021 08:09:52 -0500 Subject: [PATCH 06/36] Attempt to annotate the new files I haven't had to annotate a significant amount of C# before and I'm sure I messed up somewhere, so apologies in advance. This design didn't seem very friendly to C# nullability, so it was a tough call in some places what layer to change. --- .../System/Threading/EventWaitHandle.Unix.cs | 4 +- .../src/System/Threading/Mutex.Unix.cs | 4 +- .../src/System/Threading/Semaphore.Unix.cs | 4 +- .../WaitSubsystem.HandleManager.Unix.cs | 2 +- .../WaitSubsystem.ThreadWaitInfo.Unix.cs | 32 +++---- .../System/Threading/WaitSubsystem.Unix.cs | 6 +- .../WaitSubsystem.WaitableObject.Unix.cs | 84 +++++++++---------- 7 files changed, 68 insertions(+), 68 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.cs index 2cdaeb6bb55c7a..eb9b4b171d4133 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/EventWaitHandle.Unix.cs @@ -10,7 +10,7 @@ namespace System.Threading { public partial class EventWaitHandle { - private void CreateEventCore(bool initialState, EventResetMode mode, string name, out bool createdNew) + private void CreateEventCore(bool initialState, EventResetMode mode, string? name, out bool createdNew) { if (name != null) throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); @@ -19,7 +19,7 @@ private void CreateEventCore(bool initialState, EventResetMode mode, string name createdNew = true; } - private static OpenExistingResult OpenExistingWorker(string name, out EventWaitHandle result) + private static OpenExistingResult OpenExistingWorker(string name, out EventWaitHandle? result) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs index 27f1d170916039..c8cebbe88d90a8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs @@ -10,7 +10,7 @@ namespace System.Threading { public sealed partial class Mutex { - private void CreateMutexCore(bool initiallyOwned, string name, out bool createdNew) + private void CreateMutexCore(bool initiallyOwned, string? name, out bool createdNew) { if (name != null) { @@ -21,7 +21,7 @@ private void CreateMutexCore(bool initiallyOwned, string name, out bool createdN createdNew = true; } - private static OpenExistingResult OpenExistingWorker(string name, out Mutex result) + private static OpenExistingResult OpenExistingWorker(string name, out Mutex? result) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.cs index b2184b6af4adef..61975a86ebb3f4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Semaphore.Unix.cs @@ -10,7 +10,7 @@ namespace System.Threading { public sealed partial class Semaphore { - private void CreateSemaphoreCore(int initialCount, int maximumCount, string name, out bool createdNew) + private void CreateSemaphoreCore(int initialCount, int maximumCount, string? name, out bool createdNew) { if (name != null) { @@ -21,7 +21,7 @@ private void CreateSemaphoreCore(int initialCount, int maximumCount, string name createdNew = true; } - private static OpenExistingResult OpenExistingWorker(string name, out Semaphore result) + private static OpenExistingResult OpenExistingWorker(string name, out Semaphore? result) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.HandleManager.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.HandleManager.Unix.cs index 5b95e92774165b..1ef3fabfde518b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.HandleManager.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.HandleManager.Unix.cs @@ -33,7 +33,7 @@ public static WaitableObject FromHandle(IntPtr handle) // We don't know if any other handles are invalid, and this may crash or otherwise do bad things, that is by // design, IntPtr is unsafe by nature. - return (WaitableObject)GCHandle.FromIntPtr(handle).Target; + return (WaitableObject)GCHandle.FromIntPtr(handle).Target!; } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs index 2f50a7853a4baf..23b36cea2c18e8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs @@ -53,7 +53,7 @@ public sealed class ThreadWaitInfo /// - The filled count is /// - Indexes in all arrays that use correspond /// - private WaitableObject[] _waitedObjects; + private WaitableObject?[] _waitedObjects; /// /// - Nodes used for registering a thread's wait on each , in the @@ -84,7 +84,7 @@ public sealed class ThreadWaitInfo /// the thread exits. The linked list has only a head and no tail, which means acquired mutexes are prepended and /// mutexes are abandoned in reverse order. /// - private WaitableObject _lockedMutexesHead; + private WaitableObject? _lockedMutexesHead; public ThreadWaitInfo(Thread thread) { @@ -120,7 +120,7 @@ private bool IsWaiting /// Callers must ensure to clear the array after use. Once is called (followed /// by a call to , the array will be cleared automatically. /// - public WaitableObject[] GetWaitedObjectArray(int requiredCapacity) + public WaitableObject?[] GetWaitedObjectArray(int requiredCapacity) { Debug.Assert(_thread == Thread.CurrentThread); Debug.Assert(_waitedCount == 0); @@ -174,7 +174,7 @@ public void RegisterWait(int waitedCount, bool prioritize, bool isWaitForAll) Debug.Assert(_waitedCount == 0); - WaitableObject[] waitedObjects = _waitedObjects; + WaitableObject?[] waitedObjects = _waitedObjects; #if DEBUG for (int i = 0; i < waitedCount; ++i) { @@ -212,14 +212,14 @@ public void RegisterWait(int waitedCount, bool prioritize, bool isWaitForAll) { for (int i = 0; i < waitedCount; ++i) { - waitedListNodes[i].RegisterPrioritizedWait(waitedObjects[i]); + waitedListNodes[i].RegisterPrioritizedWait(waitedObjects[i]!); } } else { for (int i = 0; i < waitedCount; ++i) { - waitedListNodes[i].RegisterWait(waitedObjects[i]); + waitedListNodes[i].RegisterWait(waitedObjects[i]!); } } } @@ -231,7 +231,7 @@ public void UnregisterWait() for (int i = 0; i < _waitedCount; ++i) { - _waitedListNodes[i].UnregisterWait(_waitedObjects[i]); + _waitedListNodes[i].UnregisterWait(_waitedObjects[i]!); _waitedObjects[i] = null; } _waitedCount = 0; @@ -538,7 +538,7 @@ private bool CheckAndResetPendingInterrupt_NotLocked } } - public WaitableObject LockedMutexesHead + public WaitableObject? LockedMutexesHead { get { @@ -561,7 +561,7 @@ public void OnThreadExiting() { while (true) { - WaitableObject waitableObject = LockedMutexesHead; + WaitableObject? waitableObject = LockedMutexesHead; if (waitableObject == null) { break; @@ -593,7 +593,7 @@ public sealed class WaitedListNode /// /// Link in the linked list /// - private WaitedListNode _previous, _next; + private WaitedListNode? _previous, _next; public WaitedListNode(ThreadWaitInfo waitInfo, int waitedObjectIndex) { @@ -623,7 +623,7 @@ public int WaitedObjectIndex } } - public WaitedListNode Previous + public WaitedListNode? Previous { get { @@ -632,7 +632,7 @@ public WaitedListNode Previous } } - public WaitedListNode Next + public WaitedListNode? Next { get { @@ -651,7 +651,7 @@ public void RegisterWait(WaitableObject waitableObject) Debug.Assert(_previous == null); Debug.Assert(_next == null); - WaitedListNode tail = waitableObject.WaitersTail; + WaitedListNode? tail = waitableObject.WaitersTail; if (tail != null) { _previous = tail; @@ -674,7 +674,7 @@ public void RegisterPrioritizedWait(WaitableObject waitableObject) Debug.Assert(_previous == null); Debug.Assert(_next == null); - WaitedListNode head = waitableObject.WaitersHead; + WaitedListNode? head = waitableObject.WaitersHead; if (head != null) { _next = head; @@ -692,8 +692,8 @@ public void UnregisterWait(WaitableObject waitableObject) s_lock.VerifyIsLocked(); Debug.Assert(waitableObject != null); - WaitedListNode previous = _previous; - WaitedListNode next = _next; + WaitedListNode? previous = _previous; + WaitedListNode? next = _next; if (previous != null) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs index f000e846a5affe..f3c886f308ae83 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs @@ -123,7 +123,7 @@ internal static partial class WaitSubsystem private static SafeWaitHandle NewHandle(WaitableObject waitableObject) { IntPtr handle = HandleManager.NewHandle(waitableObject); - SafeWaitHandle safeWaitHandle = null; + SafeWaitHandle? safeWaitHandle = null; try { safeWaitHandle = new SafeWaitHandle(handle, ownsHandle: true); @@ -282,7 +282,7 @@ public static int Wait( Debug.Assert(timeoutMilliseconds >= -1); ThreadWaitInfo waitInfo = Thread.CurrentThread._waitInfo; - WaitableObject[] waitableObjects = waitInfo.GetWaitedObjectArray(waitHandles.Length); + WaitableObject?[] waitableObjects = waitInfo.GetWaitedObjectArray(waitHandles.Length); bool success = false; try { @@ -322,7 +322,7 @@ public static int Wait( if (waitHandles.Length == 1) { - WaitableObject waitableObject = waitableObjects[0]; + WaitableObject waitableObject = waitableObjects[0]!; waitableObjects[0] = null; return waitableObject.Wait(waitInfo, timeoutMilliseconds, interruptible: true, prioritize : false); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs index 0504fa05edebaf..715c9c987141d1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs @@ -22,18 +22,18 @@ public sealed class WaitableObject /// Only has a thread ownership requirement, and it's a less common type to be used, so /// ownership info is separated to reduce the size. For other types, this is null. /// - private readonly OwnershipInfo _ownershipInfo; + private readonly OwnershipInfo? _ownershipInfo; /// /// Linked list of information about waiting threads /// - private ThreadWaitInfo.WaitedListNode _waitersHead, _waitersTail; + private ThreadWaitInfo.WaitedListNode? _waitersHead, _waitersTail; private WaitableObject( WaitableObjectType type, int initialSignalCount, int maximumSignalCount, - OwnershipInfo ownershipInfo) + OwnershipInfo? ownershipInfo) { Debug.Assert(initialSignalCount >= 0); Debug.Assert(maximumSignalCount > 0); @@ -157,11 +157,11 @@ private bool IsAbandonedMutex get { s_lock.VerifyIsLocked(); - return IsMutex && _ownershipInfo.IsAbandoned; + return IsMutex && _ownershipInfo != null && _ownershipInfo.IsAbandoned; } } - public ThreadWaitInfo.WaitedListNode WaitersHead + public ThreadWaitInfo.WaitedListNode? WaitersHead { get { @@ -175,7 +175,7 @@ public ThreadWaitInfo.WaitedListNode WaitersHead } } - public ThreadWaitInfo.WaitedListNode WaitersTail + public ThreadWaitInfo.WaitedListNode? WaitersTail { get { @@ -196,7 +196,7 @@ private bool IsSignaled s_lock.VerifyIsLocked(); bool isSignaled = _signalCount != 0; - Debug.Assert(isSignaled || !IsMutex || _ownershipInfo.Thread != null); + Debug.Assert(isSignaled || !IsMutex || (_ownershipInfo != null && _ownershipInfo.Thread != null)); return isSignaled; } } @@ -220,8 +220,8 @@ private void AcceptSignal(ThreadWaitInfo waitInfo) Debug.Assert(_type == WaitableObjectType.Mutex); --_signalCount; - Debug.Assert(_ownershipInfo.Thread == null); - _ownershipInfo.AssignOwnership(this, waitInfo); + Debug.Assert(_ownershipInfo!.Thread == null); + _ownershipInfo!.AssignOwnership(this, waitInfo); return; } } @@ -267,7 +267,7 @@ public int Wait_Locked(ThreadWaitInfo waitInfo, int timeoutMilliseconds, bool in return isAbandoned ? WaitHandle.WaitAbandoned : WaitHandle.WaitSuccess; } - if (IsMutex && _ownershipInfo.Thread == waitInfo.Thread) + if (IsMutex && _ownershipInfo != null && _ownershipInfo.Thread == waitInfo.Thread) { if (!_ownershipInfo.CanIncrementReacquireCount) { @@ -282,7 +282,7 @@ public int Wait_Locked(ThreadWaitInfo waitInfo, int timeoutMilliseconds, bool in return WaitHandle.WaitTimeout; } - WaitableObject[] waitableObjects = waitInfo.GetWaitedObjectArray(1); + WaitableObject?[] waitableObjects = waitInfo.GetWaitedObjectArray(1); waitableObjects[0] = this; waitInfo.RegisterWait(1, prioritize, isWaitForAll: false); needToWait = true; @@ -304,7 +304,7 @@ public int Wait_Locked(ThreadWaitInfo waitInfo, int timeoutMilliseconds, bool in } public static int Wait( - WaitableObject[] waitableObjects, + WaitableObject?[]? waitableObjects, int count, bool waitForAll, ThreadWaitInfo waitInfo, @@ -335,7 +335,7 @@ public static int Wait( // Check if any is already signaled for (int i = 0; i < count; ++i) { - WaitableObject waitableObject = waitableObjects[i]; + WaitableObject waitableObject = waitableObjects[i]!; Debug.Assert(waitableObject != null); if (waitableObject.IsSignaled) @@ -351,7 +351,7 @@ public static int Wait( if (waitableObject.IsMutex) { - OwnershipInfo ownershipInfo = waitableObject._ownershipInfo; + OwnershipInfo ownershipInfo = waitableObject._ownershipInfo!; if (ownershipInfo.Thread == waitInfo.Thread) { if (!ownershipInfo.CanIncrementReacquireCount) @@ -371,7 +371,7 @@ public static int Wait( bool isAnyAbandonedMutex = false; for (int i = 0; i < count; ++i) { - WaitableObject waitableObject = waitableObjects[i]; + WaitableObject waitableObject = waitableObjects[i]!; Debug.Assert(waitableObject != null); if (waitableObject.IsSignaled) @@ -385,7 +385,7 @@ public static int Wait( if (waitableObject.IsMutex) { - OwnershipInfo ownershipInfo = waitableObject._ownershipInfo; + OwnershipInfo ownershipInfo = waitableObject._ownershipInfo!; if (ownershipInfo.Thread == waitInfo.Thread) { if (!ownershipInfo.CanIncrementReacquireCount) @@ -404,7 +404,7 @@ public static int Wait( { for (int i = 0; i < count; ++i) { - WaitableObject waitableObject = waitableObjects[i]; + WaitableObject waitableObject = waitableObjects[i]!; if (waitableObject.IsSignaled) { waitableObject.AcceptSignal(waitInfo); @@ -412,7 +412,7 @@ public static int Wait( } Debug.Assert(waitableObject.IsMutex); - OwnershipInfo ownershipInfo = waitableObject._ownershipInfo; + OwnershipInfo ownershipInfo = waitableObject._ownershipInfo!; Debug.Assert(ownershipInfo.Thread == waitInfo.Thread); ownershipInfo.IncrementReacquireCount(); } @@ -456,7 +456,7 @@ public static int Wait( public static bool WouldWaitForAllBeSatisfiedOrAborted( Thread waitingThread, - WaitableObject[] waitedObjects, + WaitableObject?[] waitedObjects, int waitedCount, int signaledWaitedObjectIndex, ref bool wouldAnyMutexReacquireCountOverflow, @@ -480,7 +480,7 @@ public static bool WouldWaitForAllBeSatisfiedOrAborted( continue; } - WaitableObject waitedObject = waitedObjects[i]; + WaitableObject waitedObject = waitedObjects[i]!; if (waitedObject.IsSignaled) { if (!isAnyAbandonedMutex && waitedObject.IsAbandonedMutex) @@ -492,7 +492,7 @@ public static bool WouldWaitForAllBeSatisfiedOrAborted( if (waitedObject.IsMutex) { - OwnershipInfo ownershipInfo = waitedObject._ownershipInfo; + OwnershipInfo ownershipInfo = waitedObject._ownershipInfo!; if (ownershipInfo.Thread == waitingThread) { if (!ownershipInfo.CanIncrementReacquireCount) @@ -513,7 +513,7 @@ public static bool WouldWaitForAllBeSatisfiedOrAborted( public static void SatisfyWaitForAll( ThreadWaitInfo waitInfo, - WaitableObject[] waitedObjects, + WaitableObject?[] waitedObjects, int waitedCount, int signaledWaitedObjectIndex) { @@ -534,7 +534,7 @@ public static void SatisfyWaitForAll( continue; } - WaitableObject waitedObject = waitedObjects[i]; + WaitableObject waitedObject = waitedObjects[i]!; if (waitedObject.IsSignaled) { waitedObject.AcceptSignal(waitInfo); @@ -542,7 +542,7 @@ public static void SatisfyWaitForAll( } Debug.Assert(waitedObject.IsMutex); - OwnershipInfo ownershipInfo = waitedObject._ownershipInfo; + OwnershipInfo ownershipInfo = waitedObject._ownershipInfo!; Debug.Assert(ownershipInfo.Thread == waitInfo.Thread); ownershipInfo.IncrementReacquireCount(); } @@ -606,7 +606,7 @@ private void SignalManualResetEvent() return; } - for (ThreadWaitInfo.WaitedListNode waiterNode = _waitersHead, nextWaiterNode; + for (ThreadWaitInfo.WaitedListNode? waiterNode = _waitersHead, nextWaiterNode; waiterNode != null; waiterNode = nextWaiterNode) { @@ -629,7 +629,7 @@ private void SignalAutoResetEvent() return; } - for (ThreadWaitInfo.WaitedListNode waiterNode = _waitersHead, nextWaiterNode; + for (ThreadWaitInfo.WaitedListNode? waiterNode = _waitersHead, nextWaiterNode; waiterNode != null; waiterNode = nextWaiterNode) { @@ -684,7 +684,7 @@ public int SignalSemaphore(int count) return oldSignalCount; } - for (ThreadWaitInfo.WaitedListNode waiterNode = _waitersHead, nextWaiterNode; + for (ThreadWaitInfo.WaitedListNode? waiterNode = _waitersHead, nextWaiterNode; waiterNode != null; waiterNode = nextWaiterNode) { @@ -710,12 +710,12 @@ public void SignalMutex() WaitHandle.ThrowInvalidHandleException(); } - if (IsSignaled || _ownershipInfo.Thread != Thread.CurrentThread) + if (IsSignaled || _ownershipInfo!.Thread != Thread.CurrentThread) { throw new ApplicationException(SR.Arg_SynchronizationLockException); } - if (!_ownershipInfo.TryDecrementReacquireCount()) + if (!_ownershipInfo!.TryDecrementReacquireCount()) { SignalMutex(isAbandoned: false); } @@ -744,9 +744,9 @@ private void SignalMutex(bool isAbandoned) Debug.Assert(IsMutex); Debug.Assert(!IsSignaled); - _ownershipInfo.RelinquishOwnership(this, isAbandoned); + _ownershipInfo!.RelinquishOwnership(this, isAbandoned); - for (ThreadWaitInfo.WaitedListNode waiterNode = _waitersHead, nextWaiterNode; + for (ThreadWaitInfo.WaitedListNode? waiterNode = _waitersHead, nextWaiterNode; waiterNode != null; waiterNode = nextWaiterNode) { @@ -757,7 +757,7 @@ private void SignalMutex(bool isAbandoned) ThreadWaitInfo waitInfo = waiterNode.WaitInfo; if (waitInfo.TrySignalToSatisfyWait(waiterNode, isAbandoned)) { - _ownershipInfo.AssignOwnership(this, waitInfo); + _ownershipInfo!.AssignOwnership(this, waitInfo); return; } } @@ -767,21 +767,21 @@ private void SignalMutex(bool isAbandoned) private sealed class OwnershipInfo { - private Thread _thread; + private Thread? _thread; private int _reacquireCount; private bool _isAbandoned; /// /// Link in the linked list /// - private WaitableObject _previous; + private WaitableObject? _previous; /// /// Link in the linked list /// - private WaitableObject _next; + private WaitableObject? _next; - public Thread Thread + public Thread? Thread { get { @@ -815,11 +815,11 @@ public void AssignOwnership(WaitableObject waitableObject, ThreadWaitInfo waitIn _thread = waitInfo.Thread; _isAbandoned = false; - WaitableObject head = waitInfo.LockedMutexesHead; + WaitableObject? head = waitInfo.LockedMutexesHead; if (head != null) { _next = head; - head._ownershipInfo._previous = waitableObject; + head._ownershipInfo!._previous = waitableObject; } waitInfo.LockedMutexesHead = waitableObject; } @@ -844,12 +844,12 @@ public void RelinquishOwnership(WaitableObject waitableObject, bool isAbandoned) _isAbandoned = isAbandoned; } - WaitableObject previous = _previous; - WaitableObject next = _next; + WaitableObject? previous = _previous; + WaitableObject? next = _next; if (previous != null) { - previous._ownershipInfo._next = next; + previous._ownershipInfo!._next = next; _previous = null; } else @@ -860,7 +860,7 @@ public void RelinquishOwnership(WaitableObject waitableObject, bool isAbandoned) if (next != null) { - next._ownershipInfo._previous = previous; + next._ownershipInfo!._previous = previous; _next = null; } } From 64c4abfbb2723c8336d09e08e350c7a16694787f Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Mon, 8 Feb 2021 19:08:47 -0500 Subject: [PATCH 07/36] Fix todo Not sure if I can get rid of the property altogether? Waiting on aleksey to get back to me about the threading changes --- .../src/System/Threading/Thread.Mono.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs index 151a4682311c9d..d5778d7d272ada 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs @@ -17,7 +17,7 @@ namespace System.Threading public partial class Thread { #pragma warning disable 169, 414, 649 - #region Sync with metadata/object-internals.h and InternalThread in mcs/class/corlib/System.Threading/Thread.cs + #region Sync with metadata/object-internals.h private int lock_thread_id; // stores a thread handle private IntPtr handle; @@ -209,8 +209,6 @@ private void Initialize() #if TARGET_UNIX _waitInfo = new WaitSubsystem.ThreadWaitInfo(this); #endif - // TODO: This can go away once the mono/mono mirror is disabled - stack_size = _startHelper!._maxStackSize; } public static void SpinWait(int iterations) From f53dc2c8dba121bfcb17188795720b08bc8ba4e1 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Mon, 8 Feb 2021 20:16:30 -0500 Subject: [PATCH 08/36] Fix Windows build Another ifdef is needed --- .../System.Private.CoreLib/src/System/Threading/Thread.Mono.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs index d5778d7d272ada..798ebb35709eaf 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs @@ -201,7 +201,9 @@ public bool Join(int millisecondsTimeout) return JoinInternal(this, millisecondsTimeout); } +#if TARGET_UNIX [MemberNotNull(nameof(_waitInfo))] +#endif private void Initialize() { InitInternal(this); From 8add4e04fd6450412c2e1bf317d40e9973900886 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Wed, 10 Feb 2021 14:10:15 -0500 Subject: [PATCH 09/36] Back to WaitInfo --- .../Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs | 4 ++-- .../src/System/Threading/WaitSubsystem.Unix.cs | 14 +++++++------- .../Threading/WaitSubsystem.WaitableObject.Unix.cs | 2 +- .../src/System/Threading/Thread.Mono.cs | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs index 23b36cea2c18e8..58f61e4cd2ed75 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.cs @@ -395,7 +395,7 @@ public static void Sleep(int timeoutMilliseconds, bool interruptible) if (timeoutMilliseconds == 0) { - if (interruptible && Thread.CurrentThread._waitInfo.CheckAndResetPendingInterrupt_NotLocked) + if (interruptible && Thread.CurrentThread.WaitInfo.CheckAndResetPendingInterrupt_NotLocked) { throw new ThreadInterruptedException(); } @@ -407,7 +407,7 @@ public static void Sleep(int timeoutMilliseconds, bool interruptible) int waitResult = Thread .CurrentThread - ._waitInfo + .WaitInfo .Wait(timeoutMilliseconds, interruptible, isSleep: true); Debug.Assert(waitResult == WaitHandle.WaitTimeout); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs index f3c886f308ae83..be05d6c7bc497c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs @@ -23,7 +23,7 @@ namespace System.Threading /// /// /// - Keeps information about a thread's wait and provides functionlity to put a thread into a wait state and to take it - /// out of a wait state. Each thread has an instance available through . + /// out of a wait state. Each thread has an instance available through . /// /// /// - Provides functionality to allocate a handle associated with a , to retrieve the object @@ -160,7 +160,7 @@ public static SafeWaitHandle NewMutex(bool initiallyOwned) // Acquire the mutex. A thread's has a reference to all es locked // by the thread. See . So, acquire the lock only after all // possibilities for exceptions have been exhausted. - ThreadWaitInfo waitInfo = Thread.CurrentThread._waitInfo; + ThreadWaitInfo waitInfo = Thread.CurrentThread.WaitInfo; bool acquiredLock = waitableObject.Wait(waitInfo, timeoutMilliseconds: 0, interruptible: false, prioritize: false) == 0; Debug.Assert(acquiredLock); return safeWaitHandle; @@ -268,7 +268,7 @@ public static int Wait( Debug.Assert(waitableObject != null); Debug.Assert(timeoutMilliseconds >= -1); - return waitableObject.Wait(Thread.CurrentThread._waitInfo, timeoutMilliseconds, interruptible, prioritize); + return waitableObject.Wait(Thread.CurrentThread.WaitInfo, timeoutMilliseconds, interruptible, prioritize); } public static int Wait( @@ -281,7 +281,7 @@ public static int Wait( Debug.Assert(waitHandles.Length <= WaitHandle.MaxWaitHandles); Debug.Assert(timeoutMilliseconds >= -1); - ThreadWaitInfo waitInfo = Thread.CurrentThread._waitInfo; + ThreadWaitInfo waitInfo = Thread.CurrentThread.WaitInfo; WaitableObject?[] waitableObjects = waitInfo.GetWaitedObjectArray(waitHandles.Length); bool success = false; try @@ -364,7 +364,7 @@ public static int SignalAndWait( Debug.Assert(waitableObjectToWaitOn != null); Debug.Assert(timeoutMilliseconds >= -1); - ThreadWaitInfo waitInfo = Thread.CurrentThread._waitInfo; + ThreadWaitInfo waitInfo = Thread.CurrentThread.WaitInfo; bool waitCalled = false; s_lock.Acquire(); try @@ -410,7 +410,7 @@ public static void Interrupt(Thread thread) s_lock.Acquire(); try { - thread._waitInfo.TrySignalToInterruptWaitOrRecordPendingInterrupt(); + thread.WaitInfo.TrySignalToInterruptWaitOrRecordPendingInterrupt(); } finally { @@ -420,7 +420,7 @@ public static void Interrupt(Thread thread) public static void OnThreadExiting(Thread thread) { - thread._waitInfo.OnThreadExiting(); + thread.WaitInfo.OnThreadExiting(); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs index 715c9c987141d1..15d09c76f7cb8a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs @@ -833,7 +833,7 @@ public void RelinquishOwnership(WaitableObject waitableObject, bool isAbandoned) Debug.Assert(waitableObject._ownershipInfo == this); Debug.Assert(_thread != null); - ThreadWaitInfo waitInfo = _thread._waitInfo; + ThreadWaitInfo waitInfo = _thread.WaitInfo; Debug.Assert(isAbandoned ? _reacquireCount >= 0 : _reacquireCount == 0); Debug.Assert(!_isAbandoned); diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs index 798ebb35709eaf..7a7ae5fd8699f7 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs @@ -68,7 +68,7 @@ public partial class Thread internal ExecutionContext? _executionContext; internal SynchronizationContext? _synchronizationContext; #if TARGET_UNIX - internal WaitSubsystem.ThreadWaitInfo _waitInfo; + internal WaitSubsystem.ThreadWaitInfo WaitInfo; #endif // This is used for a quick check on thread pool threads after running a work item to determine if the name, background @@ -202,14 +202,14 @@ public bool Join(int millisecondsTimeout) } #if TARGET_UNIX - [MemberNotNull(nameof(_waitInfo))] + [MemberNotNull(nameof(WaitInfo))] #endif private void Initialize() { InitInternal(this); #if TARGET_UNIX - _waitInfo = new WaitSubsystem.ThreadWaitInfo(this); + WaitInfo = new WaitSubsystem.ThreadWaitInfo(this); #endif } From 13e5c80d2a22a6a581c3e9488efb975600621d6c Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Wed, 10 Feb 2021 14:23:52 -0500 Subject: [PATCH 10/36] Annotation fixes --- .../System/Threading/WaitSubsystem.WaitableObject.Unix.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs index 15d09c76f7cb8a..f5f37471440f7d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs @@ -221,7 +221,7 @@ private void AcceptSignal(ThreadWaitInfo waitInfo) --_signalCount; Debug.Assert(_ownershipInfo!.Thread == null); - _ownershipInfo!.AssignOwnership(this, waitInfo); + _ownershipInfo.AssignOwnership(this, waitInfo); return; } } @@ -743,8 +743,9 @@ private void SignalMutex(bool isAbandoned) Debug.Assert(IsMutex); Debug.Assert(!IsSignaled); + Debug.Assert(_ownershipInfo != null); - _ownershipInfo!.RelinquishOwnership(this, isAbandoned); + _ownershipInfo.RelinquishOwnership(this, isAbandoned); for (ThreadWaitInfo.WaitedListNode? waiterNode = _waitersHead, nextWaiterNode; waiterNode != null; @@ -757,7 +758,7 @@ private void SignalMutex(bool isAbandoned) ThreadWaitInfo waitInfo = waiterNode.WaitInfo; if (waitInfo.TrySignalToSatisfyWait(waiterNode, isAbandoned)) { - _ownershipInfo!.AssignOwnership(this, waitInfo); + _ownershipInfo.AssignOwnership(this, waitInfo); return; } } From 990efa1c8203af58379ff9df2ded98dbf702ce1d Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Wed, 10 Feb 2021 14:39:46 -0500 Subject: [PATCH 11/36] Add WaitHandle.Windows.cs This is what I get for not testing on a Windows machine, can split into a separate PR if needed --- .../System/Threading/WaitHandle.Windows.cs | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs new file mode 100644 index 00000000000000..63f430f66d9d0a --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs @@ -0,0 +1,168 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.IO; +using System.Runtime; +using System.Runtime.InteropServices; + +namespace System.Threading +{ + public abstract partial class WaitHandle + { + internal static unsafe int WaitMultipleIgnoringSyncContext(Span handles, bool waitAll, int millisecondsTimeout) + { + fixed (IntPtr* pHandles = &MemoryMarshal.GetReference(handles)) + { + return WaitForMultipleObjectsIgnoringSyncContext(pHandles, handles.Length, waitAll, millisecondsTimeout); + } + } + + private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr* pHandles, int numHandles, bool waitAll, int millisecondsTimeout) + { + Debug.Assert(millisecondsTimeout >= -1); + + // Normalize waitAll + if (numHandles == 1) + waitAll = false; + + bool reentrantWait = Thread.ReentrantWaitsEnabled; + + if (reentrantWait) + { + // + // In the CLR, we use CoWaitForMultipleHandles to pump messages while waiting in an STA. In that case, we cannot use WAIT_ALL. + // That's because the wait would only be satisfied if a message arrives while the handles are signalled. + // + if (waitAll) + throw new NotSupportedException(SR.NotSupported_WaitAllSTAThread); + + // CoWaitForMultipleHandles does not support more than 63 handles. It returns RPC_S_CALLPENDING for more than 63 handles + // that is impossible to differentiate from timeout. + if (numHandles > 63) + throw new NotSupportedException(SR.NotSupported_MaxWaitHandles_STA); + } + + Thread currentThread = Thread.CurrentThread; + currentThread.SetWaitSleepJoinState(); + + int result; + if (reentrantWait) + { + Debug.Assert(!waitAll); + result = RuntimeImports.RhCompatibleReentrantWaitAny(false, millisecondsTimeout, numHandles, pHandles); + } + else + { + result = (int)Interop.Kernel32.WaitForMultipleObjectsEx((uint)numHandles, (IntPtr)pHandles, waitAll, (uint)millisecondsTimeout, false); + } + + currentThread.ClearWaitSleepJoinState(); + + if (result == Interop.Kernel32.WAIT_FAILED) + { + int errorCode = Interop.Kernel32.GetLastError(); + if (waitAll && errorCode == Interop.Errors.ERROR_INVALID_PARAMETER) + { + // Check for duplicate handles. This is a brute force O(n^2) search, which is intended since the typical + // array length is short enough that this would actually be faster than using a hash set. Also, the worst + // case is not so bad considering that the array length is limited by + // . + for (int i = 1; i < numHandles; ++i) + { + IntPtr handle = pHandles[i]; + for (int j = 0; j < i; ++j) + { + if (pHandles[j] == handle) + { + throw new DuplicateWaitObjectException("waitHandles[" + i + ']'); + } + } + } + } + + ThrowWaitFailedException(errorCode); + } + + return result; + } + + internal static unsafe int WaitOneCore(IntPtr handle, int millisecondsTimeout) + { + return WaitForMultipleObjectsIgnoringSyncContext(&handle, 1, false, millisecondsTimeout); + } + + private static int SignalAndWaitCore(IntPtr handleToSignal, IntPtr handleToWaitOn, int millisecondsTimeout) + { + Debug.Assert(millisecondsTimeout >= -1); + + int ret = (int)Interop.Kernel32.SignalObjectAndWait(handleToSignal, handleToWaitOn, (uint)millisecondsTimeout, false); + + if (ret == Interop.Kernel32.WAIT_FAILED) + { + ThrowWaitFailedException(Interop.Kernel32.GetLastError()); + } + + return ret; + } + + private static void ThrowWaitFailedException(int errorCode) + { + switch (errorCode) + { + case Interop.Errors.ERROR_INVALID_HANDLE: + ThrowInvalidHandleException(); + return; + + case Interop.Errors.ERROR_INVALID_PARAMETER: + throw new ArgumentException(); + + case Interop.Errors.ERROR_ACCESS_DENIED: + throw new UnauthorizedAccessException(); + + case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY: + throw new OutOfMemoryException(); + + case Interop.Errors.ERROR_TOO_MANY_POSTS: + // Only applicable to . Note however, that + // if the semahpore already has the maximum signal count, the Windows SignalObjectAndWait function does not + // return an error, but this code is kept for historical reasons and to convey the intent, since ideally, + // that should be an error. + throw new InvalidOperationException(SR.Threading_WaitHandleTooManyPosts); + + case Interop.Errors.ERROR_NOT_OWNER: + // Only applicable to when signaling a mutex + // that is locked by a different thread. Note that if the mutex is already unlocked, the Windows + // SignalObjectAndWait function does not return an error. + throw new ApplicationException(SR.Arg_SynchronizationLockException); + + case Interop.Errors.ERROR_MUTANT_LIMIT_EXCEEDED: + throw new OverflowException(SR.Overflow_MutexReacquireCount); + + default: + throw new Exception { HResult = errorCode }; + } + } + + internal static Exception ExceptionFromCreationError(int errorCode, string path) + { + switch (errorCode) + { + case Interop.Errors.ERROR_PATH_NOT_FOUND: + return new IOException(SR.Format(SR.IO_PathNotFound_Path, path)); + + case Interop.Errors.ERROR_ACCESS_DENIED: + return new UnauthorizedAccessException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, path)); + + case Interop.Errors.ERROR_ALREADY_EXISTS: + return new IOException(SR.Format(SR.IO_AlreadyExists_Name, path)); + + case Interop.Errors.ERROR_FILENAME_EXCED_RANGE: + return new PathTooLongException(); + + default: + return new IOException(SR.Arg_IOException, errorCode); + } + } + } +} From 64c3af0b9ba5b35824ccf6e70345fe8741f02182 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Wed, 10 Feb 2021 14:40:29 -0500 Subject: [PATCH 12/36] Rename to just FeatureManagedThreading and add WaitHandle.Windows.cs --- .../src/System.Private.CoreLib.Shared.projitems | 5 ++++- .../System.Private.CoreLib/System.Private.CoreLib.csproj | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index a8b965e71b1f27..e6dc7713adb6d7 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1980,7 +1980,7 @@ - + @@ -1991,4 +1991,7 @@ + + + diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index 7a9965bc66df73..8a9fe3201b1e5a 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -110,7 +110,7 @@ true true true - true + true From 8d1d8b06a7ebf45fa969f3820a2ba1fe410651fd Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Wed, 10 Feb 2021 16:01:08 -0500 Subject: [PATCH 13/36] Thread down stack size as part of thread creation --- .../src/System/Threading/Thread.Mono.cs | 5 ++--- src/mono/mono/metadata/icall-def-netcore.h | 2 +- src/mono/mono/metadata/object-internals.h | 1 - src/mono/mono/metadata/threads.c | 13 +++++-------- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs index 7a7ae5fd8699f7..0ee3352882c9e1 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs @@ -39,7 +39,6 @@ public partial class Thread internal bool threadpool_thread; private bool thread_interrupt_requested; /* These are used from managed code */ - internal int stack_size; internal byte apartment_state; internal int managed_id; private int small_id; @@ -247,13 +246,13 @@ internal void StartCallback() private void StartCore() { - StartInternal(this); + StartInternal(this, _startHelper?._maxStackSize ?? 0); } [DynamicDependency(nameof(StartCallback))] [DynamicDependency(nameof(ThrowThreadStartException))] [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern void StartInternal(Thread runtime_thread); + private static extern void StartInternal(Thread runtimeThread, int stackSize); partial void ThreadNameChanged(string? value) { diff --git a/src/mono/mono/metadata/icall-def-netcore.h b/src/mono/mono/metadata/icall-def-netcore.h index 2f2f6192a2b733..f926dc3eb2c748 100644 --- a/src/mono/mono/metadata/icall-def-netcore.h +++ b/src/mono/mono/metadata/icall-def-netcore.h @@ -496,7 +496,7 @@ HANDLES(THREAD_8, "SetName_icall", ves_icall_System_Threading_Thread_SetName_ica HANDLES(THREAD_9, "SetPriority", ves_icall_System_Threading_Thread_SetPriority, void, 2, (MonoThreadObject, int)) HANDLES(THREAD_10, "SetState", ves_icall_System_Threading_Thread_SetState, void, 2, (MonoInternalThread, guint32)) HANDLES(THREAD_11, "SleepInternal", ves_icall_System_Threading_Thread_Sleep_internal, void, 2, (gint32, MonoBoolean)) -HANDLES(THREAD_13, "StartInternal", ves_icall_System_Threading_Thread_StartInternal, void, 1, (MonoThreadObject)) +HANDLES(THREAD_13, "StartInternal", ves_icall_System_Threading_Thread_StartInternal, void, 2, (MonoThreadObject, gint32)) NOHANDLES(ICALL(THREAD_14, "YieldInternal", ves_icall_System_Threading_Thread_YieldInternal)) ICALL_TYPE(TYPE, "System.Type", TYPE_1) diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index 9f66f9ca8bec03..e8a8ad94bb75d2 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -569,7 +569,6 @@ struct _MonoInternalThread { MonoLongLivedThreadData *longlived; MonoBoolean threadpool_thread; MonoBoolean thread_interrupt_requested; - int stack_size; guint8 apartment_state; gint32 managed_id; guint32 small_id; diff --git a/src/mono/mono/metadata/threads.c b/src/mono/mono/metadata/threads.c index a2153547992cfa..a33504d56ccff0 100644 --- a/src/mono/mono/metadata/threads.c +++ b/src/mono/mono/metadata/threads.c @@ -198,7 +198,6 @@ static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL; /* The default stack size for each thread */ static guint32 default_stacksize = 0; -#define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize) static void mono_free_static_data (gpointer* static_data); static void mono_init_static_data_info (StaticDataInfo *static_data); @@ -1228,7 +1227,7 @@ throw_thread_start_exception (guint32 error_code, MonoError *error) */ static gboolean create_thread (MonoThread *thread, MonoInternalThread *internal, MonoThreadStart start_func, gpointer start_func_arg, - MonoThreadCreateFlags flags, MonoError *error) + gint32 stack_size, MonoThreadCreateFlags flags, MonoError *error) { StartInfo *start_info = NULL; MonoNativeThreadId tid; @@ -1280,7 +1279,7 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, MonoThreadStart mono_coop_sem_init (&start_info->registered, 0); if (flags != MONO_THREAD_CREATE_FLAGS_SMALL_STACK) - stack_set_size = default_stacksize_for_thread (internal); + stack_set_size = stack_size ? stack_size : default_stacksize; else stack_set_size = 0; @@ -1298,8 +1297,6 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, MonoThreadStart goto done; } - internal->stack_size = (int) stack_set_size; - THREAD_DEBUG (g_message ("%s: (%" G_GSIZE_FORMAT ") Launching thread %p (%" G_GSIZE_FORMAT ")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid)); /* @@ -1373,7 +1370,7 @@ mono_thread_create_internal (MonoThreadStart func, gpointer arg, MonoThreadCreat LOCK_THREAD (internal); - res = create_thread (thread, internal, func, arg, flags, error); + res = create_thread (thread, internal, func, arg, 0, flags, error); (void)res; UNLOCK_THREAD (internal); @@ -5397,7 +5394,7 @@ mono_threads_summarize (MonoContext *ctx, gchar **out, MonoStackHash *hashes, gb #endif void -ves_icall_System_Threading_Thread_StartInternal (MonoThreadObjectHandle thread_handle, MonoError *error) +ves_icall_System_Threading_Thread_StartInternal (MonoThreadObjectHandle thread_handle, gint32 stack_size, MonoError *error) { MonoThread *internal = MONO_HANDLE_RAW (thread_handle); gboolean res; @@ -5422,7 +5419,7 @@ ves_icall_System_Threading_Thread_StartInternal (MonoThreadObjectHandle thread_h return; } - res = create_thread (internal, internal, NULL, NULL, MONO_THREAD_CREATE_FLAGS_NONE, error); + res = create_thread (internal, internal, NULL, NULL, stack_size, MONO_THREAD_CREATE_FLAGS_NONE, error); if (!res) { UNLOCK_THREAD (internal); return; From 1e910a4b3696a1cd51873eccb65a45f8d38aa63d Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Thu, 11 Feb 2021 08:40:43 -0500 Subject: [PATCH 14/36] No separate feature flag --- .../src/System.Private.CoreLib.Shared.projitems | 4 ++-- src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index e6dc7713adb6d7..b8f18dfd1f3dad 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1980,7 +1980,7 @@ - + @@ -1991,7 +1991,7 @@ - + diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index 8a9fe3201b1e5a..6faf1e8ca4f7cb 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -110,7 +110,6 @@ true true true - true From f5c36546b3a0057b4e6d31a3302d46ebfcfe2f88 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Thu, 11 Feb 2021 08:40:56 -0500 Subject: [PATCH 15/36] Expose property correctly --- .../src/System/Threading/Thread.Mono.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs index 0ee3352882c9e1..ec9589037eb233 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs @@ -67,7 +67,7 @@ public partial class Thread internal ExecutionContext? _executionContext; internal SynchronizationContext? _synchronizationContext; #if TARGET_UNIX - internal WaitSubsystem.ThreadWaitInfo WaitInfo; + internal WaitSubsystem.ThreadWaitInfo _waitInfo; #endif // This is used for a quick check on thread pool threads after running a work item to determine if the name, background @@ -148,6 +148,10 @@ internal static int OptimalMaxSpinWaitsPerSpinIteration } } +#if TARGET_UNIX + internal WaitSubsystem.ThreadWaitInfo WaitInfo => _waitInfo; +#endif + public ThreadPriority Priority { get @@ -201,14 +205,14 @@ public bool Join(int millisecondsTimeout) } #if TARGET_UNIX - [MemberNotNull(nameof(WaitInfo))] + [MemberNotNull(nameof(_waitInfo))] #endif private void Initialize() { InitInternal(this); #if TARGET_UNIX - WaitInfo = new WaitSubsystem.ThreadWaitInfo(this); + _waitInfo = new WaitSubsystem.ThreadWaitInfo(this); #endif } From 04d486a0a966e2e2bc3fcbeed6ca80e45b718faf Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Thu, 11 Feb 2021 11:41:59 -0500 Subject: [PATCH 16/36] Add Windows Interop files --- .../Windows/Kernel32/Interop.GetLastError.cs | 14 ++++ .../Windows/Kernel32/Interop.Threading.cs | 75 +++++++++++++++++++ .../System.Private.CoreLib.Shared.projitems | 6 ++ 3 files changed, 95 insertions(+) create mode 100644 src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetLastError.cs create mode 100644 src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetLastError.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetLastError.cs new file mode 100644 index 00000000000000..bc18e843404406 --- /dev/null +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetLastError.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; + +internal partial class Interop +{ + internal partial class Kernel32 + { + [DllImport(Libraries.Kernel32)] + [SuppressGCTransition] + internal static extern int GetLastError(); + } +} diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs new file mode 100644 index 00000000000000..5a5d469ae5ddb8 --- /dev/null +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Win32.SafeHandles; +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Kernel32 + { + internal const int WAIT_FAILED = unchecked((int)0xFFFFFFFF); + + [DllImport(Libraries.Kernel32)] + internal static extern uint WaitForMultipleObjectsEx(uint nCount, IntPtr lpHandles, bool bWaitAll, uint dwMilliseconds, bool bAlertable); + + [DllImport(Libraries.Kernel32)] + internal static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); + + [DllImport(Libraries.Kernel32)] + internal static extern uint SignalObjectAndWait(IntPtr hObjectToSignal, IntPtr hObjectToWaitOn, uint dwMilliseconds, bool bAlertable); + + [DllImport(Libraries.Kernel32)] + internal static extern void Sleep(uint milliseconds); + + internal const uint CREATE_SUSPENDED = 0x00000004; + internal const uint STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000; + + [DllImport(Libraries.Kernel32)] + internal static extern unsafe SafeWaitHandle CreateThread( + IntPtr lpThreadAttributes, + IntPtr dwStackSize, + delegate* unmanaged lpStartAddress, + IntPtr lpParameter, + uint dwCreationFlags, + out uint lpThreadId); + + [DllImport(Libraries.Kernel32)] + internal static extern uint ResumeThread(SafeWaitHandle hThread); + + [DllImport(Libraries.Kernel32)] + internal static extern IntPtr GetCurrentThread(); + + internal const int DUPLICATE_SAME_ACCESS = 2; + + [DllImport(Libraries.Kernel32, SetLastError = true)] + internal static extern bool DuplicateHandle( + IntPtr hSourceProcessHandle, + IntPtr hSourceHandle, + IntPtr hTargetProcessHandle, + out SafeWaitHandle lpTargetHandle, + uint dwDesiredAccess, + bool bInheritHandle, + uint dwOptions); + + internal enum ThreadPriority : int + { + Idle = -15, + Lowest = -2, + BelowNormal = -1, + Normal = 0, + AboveNormal = 1, + Highest = 2, + TimeCritical = 15, + + ErrorReturn = 0x7FFFFFFF + } + + [DllImport(Libraries.Kernel32)] + internal static extern ThreadPriority GetThreadPriority(SafeWaitHandle hThread); + + [DllImport(Libraries.Kernel32)] + internal static extern bool SetThreadPriority(SafeWaitHandle hThread, int nPriority); + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index b8f18dfd1f3dad..b565a4730bed46 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1993,5 +1993,11 @@ + + Interop\Windows\Kernel32\Interop.GetLastError.cs + + + Interop\Windows\Kernel32\Interop.Threading.cs + From b6bf424c5d394129a47f480f46749c3c7096d5de Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Thu, 11 Feb 2021 11:42:22 -0500 Subject: [PATCH 17/36] Disable reentrant wait functionality --- .../src/System/Threading/WaitHandle.Windows.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs index 63f430f66d9d0a..756d46947354ef 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs @@ -26,6 +26,8 @@ private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr* pHan if (numHandles == 1) waitAll = false; + Thread currentThread = Thread.CurrentThread; +#if !MONO // TODO: reentrant wait support bool reentrantWait = Thread.ReentrantWaitsEnabled; if (reentrantWait) @@ -43,7 +45,6 @@ private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr* pHan throw new NotSupportedException(SR.NotSupported_MaxWaitHandles_STA); } - Thread currentThread = Thread.CurrentThread; currentThread.SetWaitSleepJoinState(); int result; @@ -56,7 +57,9 @@ private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr* pHan { result = (int)Interop.Kernel32.WaitForMultipleObjectsEx((uint)numHandles, (IntPtr)pHandles, waitAll, (uint)millisecondsTimeout, false); } - +#else + int result = (int)Interop.Kernel32.WaitForMultipleObjectsEx((uint)numHandles, (IntPtr)pHandles, waitAll, (uint)millisecondsTimeout, false); +#endif currentThread.ClearWaitSleepJoinState(); if (result == Interop.Kernel32.WAIT_FAILED) From b24af36f8eda26bc17951960eb2bf2c3d4f085b2 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Tue, 16 Feb 2021 13:31:28 -0500 Subject: [PATCH 18/36] Attempt to fix wasm --- .../src/System.Private.CoreLib.Shared.projitems | 2 +- .../src/System/Threading/Thread.Mono.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index b565a4730bed46..b8cd92ad427082 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1980,7 +1980,7 @@ - + diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs index ec9589037eb233..54f2111dc4b802 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs @@ -66,7 +66,7 @@ public partial class Thread private StartHelper? _startHelper; internal ExecutionContext? _executionContext; internal SynchronizationContext? _synchronizationContext; -#if TARGET_UNIX +#if TARGET_UNIX || TARGET_BROWSER internal WaitSubsystem.ThreadWaitInfo _waitInfo; #endif @@ -148,7 +148,7 @@ internal static int OptimalMaxSpinWaitsPerSpinIteration } } -#if TARGET_UNIX +#if TARGET_UNIX || TARGET_BROWSER internal WaitSubsystem.ThreadWaitInfo WaitInfo => _waitInfo; #endif @@ -204,14 +204,14 @@ public bool Join(int millisecondsTimeout) return JoinInternal(this, millisecondsTimeout); } -#if TARGET_UNIX +#if TARGET_UNIX || TARGET_BROWSER [MemberNotNull(nameof(_waitInfo))] #endif private void Initialize() { InitInternal(this); -#if TARGET_UNIX +#if TARGET_UNIX || TARGET_BROWSER _waitInfo = new WaitSubsystem.ThreadWaitInfo(this); #endif } From 051fd47fa1fd1dba154a33c95480aa0860670ed0 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Tue, 16 Feb 2021 13:33:32 -0500 Subject: [PATCH 19/36] Fix ifdefs --- .../src/System/Threading/WaitHandle.Windows.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs index 756d46947354ef..7515e7be33f8e2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs @@ -26,7 +26,6 @@ private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr* pHan if (numHandles == 1) waitAll = false; - Thread currentThread = Thread.CurrentThread; #if !MONO // TODO: reentrant wait support bool reentrantWait = Thread.ReentrantWaitsEnabled; @@ -44,9 +43,12 @@ private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr* pHan if (numHandles > 63) throw new NotSupportedException(SR.NotSupported_MaxWaitHandles_STA); } +#endif + Thread currentThread = Thread.CurrentThread; currentThread.SetWaitSleepJoinState(); +#if !MONO int result; if (reentrantWait) { From 100c14a179583a291fae4f4809a9c084db4ba44a Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Tue, 16 Feb 2021 13:45:46 -0500 Subject: [PATCH 20/36] Switch bool to BOOL for interop --- .../src/Interop/Windows/Kernel32/Interop.Threading.cs | 4 ++-- .../src/System/Threading/WaitHandle.Windows.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs index 5a5d469ae5ddb8..d4919d725a52cd 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Threading.cs @@ -12,13 +12,13 @@ internal static partial class Kernel32 internal const int WAIT_FAILED = unchecked((int)0xFFFFFFFF); [DllImport(Libraries.Kernel32)] - internal static extern uint WaitForMultipleObjectsEx(uint nCount, IntPtr lpHandles, bool bWaitAll, uint dwMilliseconds, bool bAlertable); + internal static extern uint WaitForMultipleObjectsEx(uint nCount, IntPtr lpHandles, BOOL bWaitAll, uint dwMilliseconds, BOOL bAlertable); [DllImport(Libraries.Kernel32)] internal static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); [DllImport(Libraries.Kernel32)] - internal static extern uint SignalObjectAndWait(IntPtr hObjectToSignal, IntPtr hObjectToWaitOn, uint dwMilliseconds, bool bAlertable); + internal static extern uint SignalObjectAndWait(IntPtr hObjectToSignal, IntPtr hObjectToWaitOn, uint dwMilliseconds, BOOL bAlertable); [DllImport(Libraries.Kernel32)] internal static extern void Sleep(uint milliseconds); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs index 7515e7be33f8e2..2115e6b6e818f0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs @@ -57,10 +57,10 @@ private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr* pHan } else { - result = (int)Interop.Kernel32.WaitForMultipleObjectsEx((uint)numHandles, (IntPtr)pHandles, waitAll, (uint)millisecondsTimeout, false); + result = (int)Interop.Kernel32.WaitForMultipleObjectsEx((uint)numHandles, (IntPtr)pHandles, waitAll ? Interop.BOOL.TRUE : Interop.BOOL.FALSE, (uint)millisecondsTimeout, Interop.BOOL.FALSE); } #else - int result = (int)Interop.Kernel32.WaitForMultipleObjectsEx((uint)numHandles, (IntPtr)pHandles, waitAll, (uint)millisecondsTimeout, false); + int result = (int)Interop.Kernel32.WaitForMultipleObjectsEx((uint)numHandles, (IntPtr)pHandles, waitAll ? Interop.BOOL.TRUE : Interop.BOOL.FALSE, (uint)millisecondsTimeout, Interop.BOOL.FALSE); #endif currentThread.ClearWaitSleepJoinState(); @@ -101,7 +101,7 @@ private static int SignalAndWaitCore(IntPtr handleToSignal, IntPtr handleToWaitO { Debug.Assert(millisecondsTimeout >= -1); - int ret = (int)Interop.Kernel32.SignalObjectAndWait(handleToSignal, handleToWaitOn, (uint)millisecondsTimeout, false); + int ret = (int)Interop.Kernel32.SignalObjectAndWait(handleToSignal, handleToWaitOn, (uint)millisecondsTimeout, Interop.BOOL.FALSE); if (ret == Interop.Kernel32.WAIT_FAILED) { From 1a865ce1a5a440c41a2c335ba571ab1aefad80e5 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Wed, 24 Feb 2021 00:08:59 -0500 Subject: [PATCH 21/36] Always create _waitInfo --- .../src/System/Threading/Thread.Mono.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs index 54f2111dc4b802..cf238fad0a737e 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs @@ -216,6 +216,14 @@ private void Initialize() #endif } +#if TARGET_UNIX || TARGET_BROWSER + private void EnsureWaitInfo() + { + if (_waitInfo == null) + _waitInfo = new WaitSubsystem.ThreadWaitInfo(this); + } +#endif + public static void SpinWait(int iterations) { if (iterations < 0) @@ -322,6 +330,9 @@ internal void ClearWaitSleepJoinState() private static Thread InitializeCurrentThread() { InitializeCurrentThread_icall(ref t_currentThread); +#if TARGET_UNIX || TARGET_BROWSER + t_currentThread.EnsureWaitInfo(); +#endif return t_currentThread; } From aed3aac416b8302ce39a321a0efd319180fb92f1 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Wed, 24 Feb 2021 15:41:00 -0500 Subject: [PATCH 22/36] Some exclusions --- src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs | 1 + src/libraries/System.Threading/tests/MutexTests.cs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs b/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs index e18e564bd48f33..e8efca091f2b81 100644 --- a/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs +++ b/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs @@ -9,3 +9,4 @@ // it's own store. [assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)] [assembly: SkipOnMono("System.IO.IsolatedStorage is not supported on Browser", TestPlatforms.Browser)] +[assembly: ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] diff --git a/src/libraries/System.Threading/tests/MutexTests.cs b/src/libraries/System.Threading/tests/MutexTests.cs index 73e7d02a4a8031..1a4973d0a661a5 100644 --- a/src/libraries/System.Threading/tests/MutexTests.cs +++ b/src/libraries/System.Threading/tests/MutexTests.cs @@ -45,6 +45,7 @@ public void Ctor_InvalidNames_Unix() } [Theory] + [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [MemberData(nameof(GetValidNames))] public void Ctor_ValidName(string name) { @@ -96,6 +97,7 @@ public void Ctor_TryCreateGlobalMutexTest_Uwp() } [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [MemberData(nameof(GetValidNames))] public void OpenExisting(string name) { @@ -130,6 +132,7 @@ public void OpenExisting_InvalidNames() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] public void OpenExisting_UnavailableName() { string name = Guid.NewGuid().ToString("N"); From 942b575d886fb319d0191d4f950657c325508398 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Thu, 25 Feb 2021 20:44:14 -0500 Subject: [PATCH 23/36] Re-enable the tests and disable the name check Some of these are uncovering real issues, so I think it's better to silently ignore the argument for now --- .../System.IO.IsolatedStorage/tests/AssemblyInfo.cs | 1 - .../src/System/Threading/Mutex.Unix.cs | 5 +++-- src/libraries/System.Threading/tests/MutexTests.cs | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs b/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs index e8efca091f2b81..e18e564bd48f33 100644 --- a/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs +++ b/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs @@ -9,4 +9,3 @@ // it's own store. [assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)] [assembly: SkipOnMono("System.IO.IsolatedStorage is not supported on Browser", TestPlatforms.Browser)] -[assembly: ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs index c8cebbe88d90a8..88dc304211c80a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs @@ -12,10 +12,11 @@ public sealed partial class Mutex { private void CreateMutexCore(bool initiallyOwned, string? name, out bool createdNew) { - if (name != null) + // See https://github.com/dotnet/runtime/issues/48720 + /*if (name != null) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); - } + }*/ SafeWaitHandle = WaitSubsystem.NewMutex(initiallyOwned); createdNew = true; diff --git a/src/libraries/System.Threading/tests/MutexTests.cs b/src/libraries/System.Threading/tests/MutexTests.cs index 1a4973d0a661a5..38e8e23866d107 100644 --- a/src/libraries/System.Threading/tests/MutexTests.cs +++ b/src/libraries/System.Threading/tests/MutexTests.cs @@ -97,7 +97,6 @@ public void Ctor_TryCreateGlobalMutexTest_Uwp() } [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [MemberData(nameof(GetValidNames))] public void OpenExisting(string name) { @@ -132,7 +131,6 @@ public void OpenExisting_InvalidNames() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] public void OpenExisting_UnavailableName() { string name = Guid.NewGuid().ToString("N"); From 616188c23b2c7f6c7aa5e5a0d1cb8bed2320ef55 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Thu, 25 Feb 2021 20:45:25 -0500 Subject: [PATCH 24/36] Remove thread_interrupt_requested This might be a bad idea and we should just call into managed to check? --- .../src/System/Threading/Thread.Mono.cs | 4 +- src/mono/mono/metadata/monitor.c | 12 +---- src/mono/mono/metadata/object-internals.h | 1 - src/mono/mono/metadata/threads-types.h | 1 - src/mono/mono/metadata/threads.c | 44 ------------------- 5 files changed, 4 insertions(+), 58 deletions(-) diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs index cf238fad0a737e..e24fcb58d2fded 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs @@ -37,7 +37,6 @@ public partial class Thread private int interruption_requested; private IntPtr longlived; internal bool threadpool_thread; - private bool thread_interrupt_requested; /* These are used from managed code */ internal byte apartment_state; internal int managed_id; @@ -194,6 +193,9 @@ public static int GetCurrentProcessorId() public void Interrupt() { +#if TARGET_UNIX || TARGET_BROWSER + WaitSubsystem.Interrupt(this); +#endif InterruptInternal(this); } diff --git a/src/mono/mono/metadata/monitor.c b/src/mono/mono/metadata/monitor.c index 410f0d6103fed8..30cbe19e4300ef 100644 --- a/src/mono/mono/metadata/monitor.c +++ b/src/mono/mono/metadata/monitor.c @@ -1386,10 +1386,6 @@ mono_monitor_wait (MonoObjectHandle obj_handle, guint32 ms, MonoBoolean allow_in mon = lock_word_get_inflated_lock (lw); - /* Do this WaitSleepJoin check before creating the event handle */ - if (mono_thread_current_check_pending_interrupt ()) - return FALSE; - event = mono_w32event_create (FALSE, FALSE); if (event == NULL) { ERROR_DECL (error); @@ -1404,15 +1400,9 @@ mono_monitor_wait (MonoObjectHandle obj_handle, guint32 ms, MonoBoolean allow_in return FALSE; } #endif - + LOCK_DEBUG (g_message ("%s: (%d) queuing handle %p", __func__, id, event)); - /* This looks superfluous */ - if (allow_interruption && mono_thread_current_check_pending_interrupt ()) { - mono_w32event_close (event); - return FALSE; - } - mono_thread_set_state (thread, ThreadState_WaitSleepJoin); mon->wait_list = g_slist_append (mon->wait_list, event); diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index e8a8ad94bb75d2..fdc2e31f97766f 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -568,7 +568,6 @@ struct _MonoInternalThread { * longer */ MonoLongLivedThreadData *longlived; MonoBoolean threadpool_thread; - MonoBoolean thread_interrupt_requested; guint8 apartment_state; gint32 managed_id; guint32 small_id; diff --git a/src/mono/mono/metadata/threads-types.h b/src/mono/mono/metadata/threads-types.h index c53e735b80eb52..481ddf1cc60ade 100644 --- a/src/mono/mono/metadata/threads-types.h +++ b/src/mono/mono/metadata/threads-types.h @@ -206,7 +206,6 @@ void mono_thread_internal_reset_abort (MonoInternalThread *thread); void mono_thread_internal_unhandled_exception (MonoObject* exc); void mono_alloc_special_static_data_free (GHashTable *special_static_fields); -gboolean mono_thread_current_check_pending_interrupt (void); void mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state); void mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state); diff --git a/src/mono/mono/metadata/threads.c b/src/mono/mono/metadata/threads.c index a33504d56ccff0..3fc5af24be579c 100644 --- a/src/mono/mono/metadata/threads.c +++ b/src/mono/mono/metadata/threads.c @@ -1721,9 +1721,6 @@ mono_sleep_internal (gint32 ms, MonoBoolean allow_interruption, MonoError *error { THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms)); - if (mono_thread_current_check_pending_interrupt ()) - return; - MonoInternalThread * const thread = mono_thread_internal_current (); HANDLE_LOOP_PREPARE; @@ -1991,9 +1988,6 @@ mono_join_uninterrupted (MonoThreadHandle* thread_to_join, gint32 ms, MonoError MonoBoolean ves_icall_System_Threading_Thread_Join_internal (MonoThreadObjectHandle thread_handle, int ms, MonoError *error) { - if (mono_thread_current_check_pending_interrupt ()) - return FALSE; - // Internal threads are pinned so shallow coop/handle. MonoInternalThread * const thread = thread_handle_to_internal_ptr (thread_handle); MonoThreadHandle *handle = thread->handle; @@ -2328,7 +2322,6 @@ ves_icall_System_Threading_Thread_Interrupt_internal (MonoThreadObjectHandle thr LOCK_THREAD (thread); - thread->thread_interrupt_requested = TRUE; gboolean const throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin); UNLOCK_THREAD (thread); @@ -2337,34 +2330,6 @@ ves_icall_System_Threading_Thread_Interrupt_internal (MonoThreadObjectHandle thr async_abort_internal (thread, FALSE); } -/** - * mono_thread_current_check_pending_interrupt: - * Checks if there's a interruption request and set the pending exception if so. - * \returns true if a pending exception was set - */ -gboolean -mono_thread_current_check_pending_interrupt (void) -{ - MonoInternalThread *thread = mono_thread_internal_current (); - gboolean throw_ = FALSE; - - LOCK_THREAD (thread); - - if (thread->thread_interrupt_requested) { - throw_ = TRUE; - thread->thread_interrupt_requested = FALSE; - } - - UNLOCK_THREAD (thread); - - if (throw_) { - ERROR_DECL (error); - mono_error_set_thread_interrupted (error); - mono_error_set_pending_exception (error); - } - return throw_; -} - // state is a pointer to a handle in order to be optional, // and be passed unspecified from functions not using handles. // When raw pointers is gone, it need not be a pointer, @@ -3704,15 +3669,6 @@ mono_thread_execute_interruption (MonoExceptionHandle *pexc) /* calls UNLOCK_THREAD (thread) */ self_suspend_internal (); unlock = FALSE; - } else if (MONO_HANDLE_GETVAL (thread, thread_interrupt_requested)) { - // thread->thread_interrupt_requested = FALSE - MONO_HANDLE_SETVAL (thread, thread_interrupt_requested, MonoBoolean, FALSE); - unlock_thread_handle (thread); - unlock = FALSE; - ERROR_DECL (error); - exc = mono_exception_new_thread_interrupted (error); - mono_error_assert_ok (error); // FIXME - fexc = TRUE; } exit: if (unlock) From 61de05a138c2409fd2053b27bdee8f89cfac4aa7 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Thu, 25 Feb 2021 22:19:46 -0500 Subject: [PATCH 25/36] Correctly abandon mutexes This is probably not optimal from a linker perspective, but that can be dealt with later --- .../src/ILLink/ILLink.Descriptors.xml | 4 + src/mono/mono/metadata/w32mutex-unix.c | 182 ++---------------- 2 files changed, 24 insertions(+), 162 deletions(-) diff --git a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml index f066b8f010d43d..d43b86f838267f 100644 --- a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml +++ b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml @@ -611,6 +611,10 @@ + + + + diff --git a/src/mono/mono/metadata/w32mutex-unix.c b/src/mono/mono/metadata/w32mutex-unix.c index 32c33c52b811c4..7e821e4d48124a 100644 --- a/src/mono/mono/metadata/w32mutex-unix.c +++ b/src/mono/mono/metadata/w32mutex-unix.c @@ -33,9 +33,6 @@ struct MonoW32HandleNamedMutex { MonoW32HandleNamespace sharedns; }; -static gpointer -mono_w32mutex_open (const char* utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *win32error); - static void thread_own_mutex (MonoInternalThread *internal, gpointer handle, MonoW32Handle *handle_data) { @@ -253,180 +250,41 @@ mono_w32mutex_init (void) (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN)); } -static gpointer mutex_handle_create (MonoW32HandleMutex *mutex_handle, MonoW32Type type, gboolean owned) -{ - MonoW32Handle *handle_data; - gpointer handle; - gboolean abandoned; - - mutex_handle->tid = 0; - mutex_handle->recursion = 0; - mutex_handle->abandoned = FALSE; - - handle = mono_w32handle_new (type, mutex_handle); - if (handle == INVALID_HANDLE_VALUE) { - g_warning ("%s: error creating %s handle", - __func__, mono_w32handle_get_typename (type)); - mono_w32error_set_last (ERROR_GEN_FAILURE); - return NULL; - } - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) - g_error ("%s: unkown handle %p", __func__, handle); - - if (handle_data->type != type) - g_error ("%s: unknown mutex handle %p", __func__, handle); - - mono_w32handle_lock (handle_data); - - if (owned) - mutex_handle_own (handle_data, &abandoned); - else - mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); - - mono_w32handle_unlock (handle_data); - - /* Balance mono_w32handle_lookup_and_ref */ - mono_w32handle_unref (handle_data); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: created %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); - - return handle; -} - -static gpointer mutex_create (gboolean owned) -{ - MonoW32HandleMutex mutex_handle; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: creating %s handle", - __func__, mono_w32handle_get_typename (MONO_W32TYPE_MUTEX)); - return mutex_handle_create (&mutex_handle, MONO_W32TYPE_MUTEX, owned); -} - -static gpointer -namedmutex_create (gboolean owned, const char *utf8_name, gsize utf8_len) -{ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: creating %s handle", - __func__, mono_w32handle_get_typename (MONO_W32TYPE_NAMEDMUTEX)); - - // Opening named objects does not race. - mono_w32handle_namespace_lock (); - - gpointer handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDMUTEX, utf8_name); - - if (handle == INVALID_HANDLE_VALUE) { - /* The name has already been used for a different object. */ - handle = NULL; - mono_w32error_set_last (ERROR_INVALID_HANDLE); - } else if (handle) { - /* Not an error, but this is how the caller is informed that the mutex wasn't freshly created */ - mono_w32error_set_last (ERROR_ALREADY_EXISTS); - - /* mono_w32handle_namespace_search_handle already adds a ref to the handle */ - } else { - /* A new named mutex */ - MonoW32HandleNamedMutex namedmutex_handle; - - // FIXME Silent truncation. - - size_t len = utf8_len < MAX_PATH ? utf8_len : MAX_PATH; - memcpy (&namedmutex_handle.sharedns.name [0], utf8_name, len); - namedmutex_handle.sharedns.name [len] = '\0'; - - handle = mutex_handle_create ((MonoW32HandleMutex*) &namedmutex_handle, MONO_W32TYPE_NAMEDMUTEX, owned); - } - - mono_w32handle_namespace_unlock (); - - return handle; -} - -gpointer -mono_w32mutex_open (const char* utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *win32error) -{ - *win32error = ERROR_SUCCESS; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: Opening named mutex [%s]", - __func__, utf8_name); - - // Opening named objects does not race. - mono_w32handle_namespace_lock (); - - gpointer handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDMUTEX, utf8_name); - - mono_w32handle_namespace_unlock (); - - if (handle == INVALID_HANDLE_VALUE) { - /* The name has already been used for a different object. */ - *win32error = ERROR_INVALID_HANDLE; - return handle; - } else if (!handle) { - /* This name doesn't exist */ - *win32error = ERROR_FILE_NOT_FOUND; - return handle; - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: returning named mutex handle %p", - __func__, handle); - - return handle; -} +#ifndef HOST_WIN32 +static GENERATE_GET_CLASS_WITH_CACHE (wait_subsystem, "System.Threading", "WaitSubsystem"); void mono_w32mutex_abandon (MonoInternalThread *internal) { - // Thread and InternalThread are pinned/mature. - // Take advantage of that and do not use handles here. - g_assert (mono_thread_internal_is_current (internal)); - - if (!internal->owned_mutexes) - return; - - while (internal->owned_mutexes->len) { - MonoW32Handle *handle_data; - MonoW32HandleMutex *mutex_handle; - MonoNativeThreadId tid; - gpointer handle; + ERROR_DECL (error); - handle = g_ptr_array_index (internal->owned_mutexes, 0); + MONO_STATIC_POINTER_INIT (MonoMethod, thread_exiting) - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) - g_error ("%s: unkown handle %p", __func__, handle); + MonoClass *wait_subsystem_class = mono_class_get_wait_subsystem_class (); + g_assert (wait_subsystem_class); + thread_exiting = mono_class_get_method_from_name_checked (wait_subsystem_class, "OnThreadExiting", -1, 0, error); + mono_error_assert_ok (error); - if (handle_data->type != MONO_W32TYPE_MUTEX && handle_data->type != MONO_W32TYPE_NAMEDMUTEX) - g_error ("%s: unkown mutex handle %p", __func__, handle); + MONO_STATIC_POINTER_INIT_END (MonoMethod, thread_exiting) - mutex_handle = (MonoW32HandleMutex*) handle_data->specific; + g_assert (thread_exiting); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: abandoning %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle); - - tid = MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid); - - if (!pthread_equal (mutex_handle->tid, tid)) - g_error ("%s: trying to release mutex %p acquired by thread %p from thread %p", - __func__, handle, (gpointer) mutex_handle->tid, (gpointer) tid); - - mono_w32handle_lock (handle_data); - - mutex_handle->recursion = 0; - mutex_handle->tid = 0; - mutex_handle->abandoned = TRUE; + if (mono_runtime_get_no_exec ()) + return; - mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); + HANDLE_FUNCTION_ENTER (); - thread_disown_mutex (internal, handle); + ERROR_DECL (error); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: abandoned %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle); + gpointer args [1]; + args [0] = internal; + mono_runtime_try_invoke_handle (thread_exiting, NULL_HANDLE, args, error); - mono_w32handle_unlock (handle_data); - mono_w32handle_unref (handle_data); - } + mono_error_cleanup (error); - g_ptr_array_free (internal->owned_mutexes, TRUE); - internal->owned_mutexes = NULL; + HANDLE_FUNCTION_RETURN (); } +#endif MonoW32HandleNamespace* mono_w32mutex_get_namespace (MonoW32HandleNamedMutex *mutex) From 2a12e3fcfabbf9f163c264ad391ada6950c19fe5 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Thu, 25 Feb 2021 22:20:18 -0500 Subject: [PATCH 26/36] Disable tests again The remaining failures are just related to the named mutexes --- src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs | 1 + src/libraries/System.Threading/tests/MutexTests.cs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs b/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs index e18e564bd48f33..dadc27e2fbf2b3 100644 --- a/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs +++ b/src/libraries/System.IO.IsolatedStorage/tests/AssemblyInfo.cs @@ -8,4 +8,5 @@ // create unique identities for every test to allow every test to have // it's own store. [assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)] +[assembly: ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [assembly: SkipOnMono("System.IO.IsolatedStorage is not supported on Browser", TestPlatforms.Browser)] diff --git a/src/libraries/System.Threading/tests/MutexTests.cs b/src/libraries/System.Threading/tests/MutexTests.cs index 38e8e23866d107..aa88080a11530a 100644 --- a/src/libraries/System.Threading/tests/MutexTests.cs +++ b/src/libraries/System.Threading/tests/MutexTests.cs @@ -97,6 +97,7 @@ public void Ctor_TryCreateGlobalMutexTest_Uwp() } [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [MemberData(nameof(GetValidNames))] public void OpenExisting(string name) { @@ -131,6 +132,7 @@ public void OpenExisting_InvalidNames() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] public void OpenExisting_UnavailableName() { string name = Guid.NewGuid().ToString("N"); @@ -226,6 +228,7 @@ public static IEnumerable AbandonExisting_MemberData() } [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [MemberData(nameof(AbandonExisting_MemberData))] public void AbandonExisting( string name, @@ -466,6 +469,7 @@ private static void IncrementValueInFileNTimes(Mutex mutex, string fileName, int } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] public void NamedMutex_ThreadExitDisposeRaceTest() { var mutexName = Guid.NewGuid().ToString("N"); From b84385f52a6463f03397b47896667ea2269e8025 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Thu, 25 Feb 2021 22:23:46 -0500 Subject: [PATCH 27/36] Uncomment unsupported name exception --- .../System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs index 88dc304211c80a..5b1361247ae585 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Mutex.Unix.cs @@ -13,10 +13,10 @@ public sealed partial class Mutex private void CreateMutexCore(bool initiallyOwned, string? name, out bool createdNew) { // See https://github.com/dotnet/runtime/issues/48720 - /*if (name != null) + if (name != null) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives); - }*/ + } SafeWaitHandle = WaitSubsystem.NewMutex(initiallyOwned); createdNew = true; From 17ba8651e836b2c74404d27c255535df2a8aebf0 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Fri, 26 Feb 2021 00:05:55 -0500 Subject: [PATCH 28/36] Excise a lot more runtime code Yeehaw --- src/mono/mono/metadata/CMakeLists.txt | 13 - src/mono/mono/metadata/appdomain.c | 1 - src/mono/mono/metadata/domain.c | 4 - src/mono/mono/metadata/icall-decl.h | 3 - src/mono/mono/metadata/icall-table.h | 2 - src/mono/mono/metadata/icall.c | 92 - src/mono/mono/metadata/threads.c | 41 +- src/mono/mono/metadata/w32event-unix.c | 52 - src/mono/mono/metadata/w32event-win32.c | 6 - src/mono/mono/metadata/w32event.h | 7 - src/mono/mono/metadata/w32file-internals.h | 12 - src/mono/mono/metadata/w32file-unix-glob.c | 406 -- src/mono/mono/metadata/w32file-unix-glob.h | 70 - src/mono/mono/metadata/w32file-unix.c | 5000 ++---------------- src/mono/mono/metadata/w32file-win32.c | 636 --- src/mono/mono/metadata/w32file.h | 187 - src/mono/mono/metadata/w32handle-namespace.c | 6 - src/mono/mono/metadata/w32handle.c | 421 -- src/mono/mono/metadata/w32handle.h | 22 - src/mono/mono/metadata/w32mutex-unix.c | 293 - src/mono/mono/metadata/w32mutex-win32.c | 22 - src/mono/mono/metadata/w32mutex.h | 33 - src/mono/mono/metadata/w32semaphore-unix.c | 240 - src/mono/mono/metadata/w32semaphore-win32.c | 22 - src/mono/mono/metadata/w32semaphore.h | 22 - src/mono/mono/metadata/w32socket-internals.h | 150 - src/mono/mono/metadata/w32socket-unix.c | 1578 ------ src/mono/mono/metadata/w32socket-win32.c | 309 -- src/mono/mono/metadata/w32socket.h | 31 - src/mono/mono/mini/debugger-agent.c | 1 - src/mono/mono/mini/mini-wasm.c | 24 - 31 files changed, 497 insertions(+), 9209 deletions(-) delete mode 100644 src/mono/mono/metadata/w32file-internals.h delete mode 100644 src/mono/mono/metadata/w32file-unix-glob.c delete mode 100644 src/mono/mono/metadata/w32file-unix-glob.h delete mode 100644 src/mono/mono/metadata/w32mutex-unix.c delete mode 100644 src/mono/mono/metadata/w32mutex-win32.c delete mode 100644 src/mono/mono/metadata/w32mutex.h delete mode 100644 src/mono/mono/metadata/w32semaphore-unix.c delete mode 100644 src/mono/mono/metadata/w32semaphore-win32.c delete mode 100644 src/mono/mono/metadata/w32semaphore.h delete mode 100644 src/mono/mono/metadata/w32socket-internals.h delete mode 100644 src/mono/mono/metadata/w32socket-unix.c delete mode 100644 src/mono/mono/metadata/w32socket-win32.c delete mode 100644 src/mono/mono/metadata/w32socket.h diff --git a/src/mono/mono/metadata/CMakeLists.txt b/src/mono/mono/metadata/CMakeLists.txt index 5f200c5ffe5d88..b78a4a6625db47 100644 --- a/src/mono/mono/metadata/CMakeLists.txt +++ b/src/mono/mono/metadata/CMakeLists.txt @@ -34,24 +34,16 @@ set(metadata_win32_sources icall-windows.c marshal-windows.c mono-security-windows.c - w32mutex-win32.c - w32semaphore-win32.c w32event-win32.c - w32socket-win32.c w32error-win32.c) set(metadata_unix_sources - w32mutex-unix.c - w32semaphore-unix.c w32event-unix.c w32process-unix-osx.c w32process-unix-bsd.c w32process-unix-haiku.c w32process-unix-default.c - w32socket-unix.c w32file-unix.c - w32file-unix-glob.c - w32file-unix-glob.h w32error-unix.c) if(HOST_WIN32) @@ -94,7 +86,6 @@ set(metadata_common_sources exception.h exception-internals.h w32file.h - w32file-internals.h gc-internals.h icall.c icall-internals.h @@ -144,8 +135,6 @@ set(metadata_common_sources opcodes.c property-bag.h property-bag.c - w32socket.h - w32socket-internals.h w32process.h profiler.c profiler-private.h @@ -180,8 +169,6 @@ set(metadata_common_sources seq-points-data.c handle.c handle.h - w32mutex.h - w32semaphore.h w32event.h w32handle-namespace.h w32handle-namespace.c diff --git a/src/mono/mono/metadata/appdomain.c b/src/mono/mono/metadata/appdomain.c index e6bcf98bbaef53..170560c081f7b0 100644 --- a/src/mono/mono/metadata/appdomain.c +++ b/src/mono/mono/metadata/appdomain.c @@ -58,7 +58,6 @@ #include #include #include -#include #include #include #include diff --git a/src/mono/mono/metadata/domain.c b/src/mono/mono/metadata/domain.c index 78e552336d84a1..929c4ed538e6bc 100644 --- a/src/mono/mono/metadata/domain.c +++ b/src/mono/mono/metadata/domain.c @@ -42,8 +42,6 @@ #include #include #include -#include -#include #include #include #include @@ -369,8 +367,6 @@ mono_init_internal (const char *filename, const char *exe_filename, const char * mono_w32handle_namespace_init (); #endif - mono_w32mutex_init (); - mono_w32semaphore_init (); mono_w32event_init (); mono_w32file_init (); diff --git a/src/mono/mono/metadata/icall-decl.h b/src/mono/mono/metadata/icall-decl.h index cbaedb53d73a08..6e44d3b055cdcf 100644 --- a/src/mono/mono/metadata/icall-decl.h +++ b/src/mono/mono/metadata/icall-decl.h @@ -27,9 +27,6 @@ #include "mono/utils/mono-forward-internal.h" #include "w32event.h" #include "w32file.h" -#include "w32mutex.h" -#include "w32semaphore.h" -#include "w32socket.h" #include "mono/utils/mono-proclib.h" /* From MonoProperty.cs */ diff --git a/src/mono/mono/metadata/icall-table.h b/src/mono/mono/metadata/icall-table.h index f34658581bc438..31aa3aba238a04 100644 --- a/src/mono/mono/metadata/icall-table.h +++ b/src/mono/mono/metadata/icall-table.h @@ -69,7 +69,6 @@ typedef MonoVTable *MonoVTable_ptr; typedef unsigned *unsigned_ptr; typedef mono_unichar2 *mono_unichar2_ptr; typedef mono_unichar4 *mono_unichar4_ptr; -typedef WSABUF *WSABUF_ptr; typedef char **char_ptr_ref; typedef gint32 *gint32_ref; @@ -151,7 +150,6 @@ typedef MonoStringHandle MonoStringOutHandle; #define MONO_HANDLE_TYPE_WRAP_MonoProperty_ptr ICALL_HANDLES_WRAP_NONE #define MONO_HANDLE_TYPE_WRAP_size_t ICALL_HANDLES_WRAP_NONE #define MONO_HANDLE_TYPE_WRAP_MonoVTable_ptr ICALL_HANDLES_WRAP_NONE -#define MONO_HANDLE_TYPE_WRAP_WSABUF_ptr ICALL_HANDLES_WRAP_NONE #define MONO_HANDLE_TYPE_WRAP_MonoAssemblyName_ref ICALL_HANDLES_WRAP_VALUETYPE_REF #define MONO_HANDLE_TYPE_WRAP_MonoBoolean_ref ICALL_HANDLES_WRAP_VALUETYPE_REF diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 4d2a5ad773dff4..7492f82d2a6815 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -53,7 +53,6 @@ #include #include #include -#include #include #include #include @@ -82,8 +81,6 @@ #include #include #include -#include -#include #include #include #include @@ -6673,69 +6670,6 @@ mono_icall_get_windows_folder_path (int folder, MonoError *error) } #endif /* !HOST_WIN32 */ -static MonoArrayHandle -mono_icall_get_logical_drives (MonoError *error) -{ - gunichar2 buf [256], *ptr, *dname; - gunichar2 *u16; - guint initial_size = 127, size = 128; - gint ndrives; - MonoArrayHandle result = NULL_HANDLE_ARRAY; - MonoStringHandle drivestr; - gint len; - - buf [0] = '\0'; - ptr = buf; - - while (size > initial_size) { - size = (guint) mono_w32file_get_logical_drive (initial_size, ptr, error); - if (!is_ok (error)) - goto leave; - if (size > initial_size) { - if (ptr != buf) - g_free (ptr); - ptr = (gunichar2 *)g_malloc0 ((size + 1) * sizeof (gunichar2)); - initial_size = size; - size++; - } - } - - /* Count strings */ - dname = ptr; - ndrives = 0; - do { - while (*dname++); - ndrives++; - } while (*dname); - - dname = ptr; - result = mono_array_new_handle (mono_defaults.string_class, ndrives, error); - goto_if_nok (error, leave); - - drivestr = MONO_HANDLE_NEW (MonoString, NULL); - ndrives = 0; - do { - len = 0; - u16 = dname; - while (*u16) { - u16++; len ++; - } - MonoString *s = mono_string_new_utf16_checked (dname, len, error); - goto_if_nok (error, leave); - MONO_HANDLE_ASSIGN_RAW (drivestr, s); - - mono_array_handle_setref (result, ndrives, drivestr); - ndrives ++; - while (*dname++); - } while (*dname); - -leave: - if (ptr != buf) - g_free (ptr); - - return result; -} - MonoBoolean ves_icall_System_Environment_get_HasShutdownStarted (void) { @@ -6755,32 +6689,6 @@ ves_icall_System_Environment_get_TickCount64 (void) return mono_msec_boottime (); } -#ifndef PLATFORM_NO_DRIVEINFO -MonoBoolean -ves_icall_System_IO_DriveInfo_GetDiskFreeSpace (const gunichar2 *path_name, gint32 path_name_length, guint64 *free_bytes_avail, - guint64 *total_number_of_bytes, guint64 *total_number_of_free_bytes, - gint32 *error) -{ - g_assert (error); - g_assert (free_bytes_avail); - g_assert (total_number_of_bytes); - g_assert (total_number_of_free_bytes); - - // FIXME check for embedded nuls here or managed - - *error = ERROR_SUCCESS; - *free_bytes_avail = (guint64)-1; - *total_number_of_bytes = (guint64)-1; - *total_number_of_free_bytes = (guint64)-1; - - gboolean result = mono_w32file_get_disk_free_space (path_name, free_bytes_avail, total_number_of_bytes, total_number_of_free_bytes); - if (!result) - *error = mono_w32error_get_last (); - - return result; -} -#endif /* PLATFORM_NO_DRIVEINFO */ - gpointer ves_icall_RuntimeMethodHandle_GetFunctionPointer (MonoMethod *method, MonoError *error) { diff --git a/src/mono/mono/metadata/threads.c b/src/mono/mono/metadata/threads.c index 3fc5af24be579c..58e4bfb290aecf 100644 --- a/src/mono/mono/metadata/threads.c +++ b/src/mono/mono/metadata/threads.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include @@ -858,6 +857,42 @@ mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean return FALSE; } +#ifndef HOST_WIN32 +static GENERATE_GET_CLASS_WITH_CACHE (wait_subsystem, "System.Threading", "WaitSubsystem"); + +static void +abandon_mutexes (MonoInternalThread *internal) +{ + ERROR_DECL (error); + + MONO_STATIC_POINTER_INIT (MonoMethod, thread_exiting) + + MonoClass *wait_subsystem_class = mono_class_get_wait_subsystem_class (); + g_assert (wait_subsystem_class); + thread_exiting = mono_class_get_method_from_name_checked (wait_subsystem_class, "OnThreadExiting", -1, 0, error); + mono_error_assert_ok (error); + + MONO_STATIC_POINTER_INIT_END (MonoMethod, thread_exiting) + + g_assert (thread_exiting); + + if (mono_runtime_get_no_exec ()) + return; + + HANDLE_FUNCTION_ENTER (); + + ERROR_DECL (error); + + gpointer args [1]; + args [0] = internal; + mono_runtime_try_invoke_handle (thread_exiting, NULL_HANDLE, args, error); + + mono_error_cleanup (error); + + HANDLE_FUNCTION_RETURN (); +} +#endif + static void mono_thread_detach_internal (MonoInternalThread *thread) { @@ -890,7 +925,7 @@ mono_thread_detach_internal (MonoInternalThread *thread) threads_add_pending_joinable_runtime_thread (info); #ifndef HOST_WIN32 - mono_w32mutex_abandon (thread); + abandon_mutexes (thread); #endif mono_gchandle_free_internal (thread->abort_state_handle); @@ -2682,7 +2717,7 @@ mono_thread_cleanup (void) * won't exit in time. */ if (!mono_runtime_get_no_exec ()) - mono_w32mutex_abandon (mono_thread_internal_current ()); + abandon_mutexes (mono_thread_internal_current ()); #endif #if 0 diff --git a/src/mono/mono/metadata/w32event-unix.c b/src/mono/mono/metadata/w32event-unix.c index df8c04237696fa..64ff8eea4e8782 100644 --- a/src/mono/mono/metadata/w32event-unix.c +++ b/src/mono/mono/metadata/w32event-unix.c @@ -170,12 +170,6 @@ mono_w32event_set (gpointer handle) ves_icall_System_Threading_Events_SetEvent_internal (handle); } -void -mono_w32event_reset (gpointer handle) -{ - ves_icall_System_Threading_Events_ResetEvent_internal (handle); -} - static gpointer event_handle_create (MonoW32HandleEvent *event_handle, MonoW32Type type, gboolean manual, gboolean initial) { MonoW32Handle *handle_data; @@ -313,52 +307,6 @@ ves_icall_System_Threading_Events_SetEvent_internal (gpointer handle) return TRUE; } -gboolean -ves_icall_System_Threading_Events_ResetEvent_internal (gpointer handle) -{ - MonoW32Handle *handle_data; - MonoW32HandleEvent *event_handle; - - mono_w32error_set_last (ERROR_SUCCESS); - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) { - g_warning ("%s: unkown handle %p", __func__, handle); - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - if (handle_data->type != MONO_W32TYPE_EVENT && handle_data->type != MONO_W32TYPE_NAMEDEVENT) { - g_warning ("%s: unkown event handle %p", __func__, handle); - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_w32handle_unref (handle_data); - return FALSE; - } - - event_handle = (MonoW32HandleEvent*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: resetting %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle); - - mono_w32handle_lock (handle_data); - - if (!mono_w32handle_issignalled (handle_data)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: no need to reset %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle); - } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_EVENT, "%s: obtained write lock on %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle); - - mono_w32handle_set_signal_state (handle_data, FALSE, FALSE); - } - - event_handle->set_count = 0; - - mono_w32handle_unlock (handle_data); - - mono_w32handle_unref (handle_data); - return TRUE; -} - gpointer mono_w32event_open (const gchar *utf8_name, gint32 rights G_GNUC_UNUSED, gint32 *win32error) { diff --git a/src/mono/mono/metadata/w32event-win32.c b/src/mono/mono/metadata/w32event-win32.c index 4b3ee206726678..c068a199b7839c 100644 --- a/src/mono/mono/metadata/w32event-win32.c +++ b/src/mono/mono/metadata/w32event-win32.c @@ -38,9 +38,3 @@ mono_w32event_set (gpointer handle) { SetEvent (handle); } - -void -mono_w32event_reset (gpointer handle) -{ - ResetEvent (handle); -} diff --git a/src/mono/mono/metadata/w32event.h b/src/mono/mono/metadata/w32event.h index ee0102d5de305c..7bbbece7bf9be9 100644 --- a/src/mono/mono/metadata/w32event.h +++ b/src/mono/mono/metadata/w32event.h @@ -25,17 +25,10 @@ mono_w32event_close (gpointer handle); void mono_w32event_set (gpointer handle); -void -mono_w32event_reset (gpointer handle); - ICALL_EXPORT gboolean ves_icall_System_Threading_Events_SetEvent_internal (gpointer handle); -ICALL_EXPORT -gboolean -ves_icall_System_Threading_Events_ResetEvent_internal (gpointer handle); - typedef struct MonoW32HandleNamedEvent MonoW32HandleNamedEvent; MonoW32HandleNamespace* diff --git a/src/mono/mono/metadata/w32file-internals.h b/src/mono/mono/metadata/w32file-internals.h deleted file mode 100644 index 0f7876c9ddf3ef..00000000000000 --- a/src/mono/mono/metadata/w32file-internals.h +++ /dev/null @@ -1,12 +0,0 @@ -/** - * \file - * Copyright 2016 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ -#ifndef _MONO_METADATA_W32FILE_INTERNALS_H_ -#define _MONO_METADATA_W32FILE_INTERNALS_H_ - -#include -#include - -#endif /* _MONO_METADATA_W32FILE_INTERNALS_H_ */ diff --git a/src/mono/mono/metadata/w32file-unix-glob.c b/src/mono/mono/metadata/w32file-unix-glob.c deleted file mode 100644 index d07a7dc8297f22..00000000000000 --- a/src/mono/mono/metadata/w32file-unix-glob.c +++ /dev/null @@ -1,406 +0,0 @@ -/* $OpenBSD: glob.c,v 1.26 2005/11/28 17:50:12 deraadt Exp $ */ -/** - * \file - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Guido van Rossum. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * mono_w32file_unix_glob(3) -- a subset of the one defined in POSIX 1003.2. - * - * Optional extra services, controlled by flags not defined by POSIX: - * - * GLOB_MAGCHAR: - * Set in gl_flags if pattern contained a globbing character. - */ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "w32file-unix-glob.h" - -#define EOS '\0' -#define NOT '!' -#define QUESTION '?' -#define QUOTE '\\' -#define STAR '*' - -#ifndef DEBUG - -#define M_QUOTE 0x8000 -#define M_PROTECT 0x4000 -#define M_MASK 0xffff -#define M_ASCII 0x00ff - -typedef unsigned short Char; - -#else - -#define M_QUOTE 0x80 -#define M_PROTECT 0x40 -#define M_MASK 0xff -#define M_ASCII 0x7f - -typedef char Char; - -#endif - - -#define CHAR(c) ((gchar)((c)&M_ASCII)) -#define META(c) ((gchar)((c)|M_QUOTE)) -#define M_ALL META('*') -#define M_ONE META('?') -#define ismeta(c) (((c)&M_QUOTE) != 0) - - -static int -g_Ctoc(const gchar *, char *, unsigned int); - -static int -glob0(GDir *dir, const gchar *, mono_w32file_unix_glob_t *, gboolean, gboolean); -static int -glob1(GDir *dir, gchar *, gchar *, mono_w32file_unix_glob_t *, size_t *, gboolean, gboolean); - -static int -glob3(GDir *dir, gchar *, gchar *, mono_w32file_unix_glob_t *, size_t *, gboolean, gboolean); - -static int -globextend(const gchar *, mono_w32file_unix_glob_t *, size_t *); - -static int -match(const gchar *, gchar *, gchar *, gboolean); - -#ifdef DEBUG_ENABLED -static void qprintf(const char *, Char *); -#endif - -int -mono_w32file_unix_glob(GDir *dir, const char *pattern, int flags, mono_w32file_unix_glob_t *pglob) -{ - const unsigned char *patnext; - int c; - gchar *bufnext, *bufend, patbuf[PATH_MAX]; - - patnext = (unsigned char *) pattern; - if (!(flags & W32FILE_UNIX_GLOB_APPEND)) { - pglob->gl_pathc = 0; - pglob->gl_pathv = NULL; - pglob->gl_offs = 0; - } - pglob->gl_flags = flags & ~W32FILE_UNIX_GLOB_MAGCHAR; - - bufnext = patbuf; - bufend = bufnext + PATH_MAX - 1; - - /* Protect the quoted characters. */ - while (bufnext < bufend && (c = *patnext++) != EOS) - if (c == QUOTE) { - if ((c = *patnext++) == EOS) { - c = QUOTE; - --patnext; - } - *bufnext++ = c | M_PROTECT; - } else - *bufnext++ = c; - - *bufnext = EOS; - - return glob0(dir, patbuf, pglob, flags & W32FILE_UNIX_GLOB_IGNORECASE, - flags & W32FILE_UNIX_GLOB_UNIQUE); -} - -/* - * The main glob() routine: compiles the pattern (optionally processing - * quotes), calls glob1() to do the real pattern matching, and finally - * sorts the list (unless unsorted operation is requested). Returns 0 - * if things went well, nonzero if errors occurred. It is not an error - * to find no matches. - */ -static int -glob0(GDir *dir, const gchar *pattern, mono_w32file_unix_glob_t *pglob, gboolean ignorecase, - gboolean unique) -{ - const gchar *qpatnext; - int c, err, oldpathc; - gchar *bufnext, patbuf[PATH_MAX]; - size_t limit = 0; - - qpatnext = pattern; - oldpathc = pglob->gl_pathc; - bufnext = patbuf; - - /* We don't need to check for buffer overflow any more. */ - while ((c = *qpatnext++) != EOS) { - switch (c) { - case QUESTION: - pglob->gl_flags |= W32FILE_UNIX_GLOB_MAGCHAR; - *bufnext++ = M_ONE; - break; - case STAR: - pglob->gl_flags |= W32FILE_UNIX_GLOB_MAGCHAR; - /* collapse adjacent stars to one, - * to avoid exponential behavior - */ - if (bufnext == patbuf || bufnext[-1] != M_ALL) - *bufnext++ = M_ALL; - break; - default: - *bufnext++ = CHAR(c); - break; - } - } - *bufnext = EOS; -#ifdef DEBUG_ENABLED - qprintf("glob0:", patbuf); -#endif - - if ((err = glob1(dir, patbuf, patbuf+PATH_MAX-1, pglob, &limit, - ignorecase, unique)) != 0) - return(err); - - if (pglob->gl_pathc == oldpathc) { - return(W32FILE_UNIX_GLOB_NOMATCH); - } - - return(0); -} - -static int -glob1(GDir *dir, gchar *pattern, gchar *pattern_last, mono_w32file_unix_glob_t *pglob, - size_t *limitp, gboolean ignorecase, gboolean unique) -{ - /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ - if (*pattern == EOS) - return(0); - return(glob3(dir, pattern, pattern_last, pglob, limitp, ignorecase, - unique)); -} - -static gboolean contains (mono_w32file_unix_glob_t *pglob, const gchar *name) -{ - int i; - char **pp; - - if (pglob->gl_pathv != NULL) { - pp = pglob->gl_pathv + pglob->gl_offs; - for (i = pglob->gl_pathc; i--; ++pp) { - if (*pp) { - if (!strcmp (*pp, name)) { - return(TRUE); - } - } - } - } - - return(FALSE); -} - -static int -glob3(GDir *dir, gchar *pattern, gchar *pattern_last, mono_w32file_unix_glob_t *pglob, - size_t *limitp, gboolean ignorecase, gboolean unique) -{ - const gchar *name; - - /* Search directory for matching names. */ - while ((name = g_dir_read_name(dir))) { - if (!match(name, pattern, pattern + strlen (pattern), - ignorecase)) { - continue; - } - if (!unique || - !contains (pglob, name)) { - globextend (name, pglob, limitp); - } - } - - return(0); -} - - -/* - * Extend the gl_pathv member of a mono_w32file_unix_glob_t structure to accommodate a new item, - * add the new item, and update gl_pathc. - * - * This assumes the BSD realloc, which only copies the block when its size - * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic - * behavior. - * - * Return 0 if new item added, error code if memory couldn't be allocated. - * - * Invariant of the mono_w32file_unix_glob_t structure: - * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and - * gl_pathv points to (gl_offs + gl_pathc + 1) items. - */ -static int -globextend(const gchar *path, mono_w32file_unix_glob_t *pglob, size_t *limitp) -{ - char **pathv; - int i; - unsigned int newsize, len; - char *copy; - const gchar *p; - - newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); - /* FIXME: Can just use realloc(). */ - pathv = pglob->gl_pathv ? (char**)g_realloc (pglob->gl_pathv, newsize) : - (char**)g_malloc (newsize); - if (pathv == NULL) { - g_free (pglob->gl_pathv); - pglob->gl_pathv = NULL; - return(W32FILE_UNIX_GLOB_NOSPACE); - } - - if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { - /* first time around -- clear initial gl_offs items */ - pathv += pglob->gl_offs; - for (i = pglob->gl_offs; --i >= 0; ) - *--pathv = NULL; - } - pglob->gl_pathv = pathv; - - for (p = path; *p++;) - ; - len = (size_t)(p - path); - *limitp += len; - if ((copy = (char *)malloc(len)) != NULL) { - if (g_Ctoc(path, copy, len)) { - g_free (copy); - return(W32FILE_UNIX_GLOB_NOSPACE); - } - pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; - } - pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; - -#if 0 - /* Broken on opensuse 11 */ - if ((pglob->gl_flags & W32FILE_UNIX_GLOB_LIMIT) && - newsize + *limitp >= ARG_MAX) { - mono_set_errno (0); - return(W32FILE_UNIX_GLOB_NOSPACE); - } -#endif - - return(copy == NULL ? W32FILE_UNIX_GLOB_NOSPACE : 0); -} - - -/* - * pattern matching function for filenames. Each occurrence of the * - * pattern causes a recursion level. - */ -static int -match(const gchar *name, gchar *pat, gchar *patend, gboolean ignorecase) -{ - gchar c; - - while (pat < patend) { - c = *pat++; - switch (c & M_MASK) { - case M_ALL: - if (pat == patend) - return(1); - do { - if (match(name, pat, patend, ignorecase)) - return(1); - } while (*name++ != EOS); - return(0); - case M_ONE: - if (*name++ == EOS) - return(0); - break; - default: - if (ignorecase) { - if (g_ascii_tolower (*name++) != g_ascii_tolower (c)) - return(0); - } else { - if (*name++ != c) - return(0); - } - - break; - } - } - return(*name == EOS); -} - -/* Free allocated data belonging to a mono_w32file_unix_glob_t structure. */ -void -mono_w32file_unix_globfree(mono_w32file_unix_glob_t *pglob) -{ - int i; - char **pp; - - if (pglob->gl_pathv != NULL) { - pp = pglob->gl_pathv + pglob->gl_offs; - for (i = pglob->gl_pathc; i--; ++pp) - if (*pp) - g_free (*pp); - g_free (pglob->gl_pathv); - pglob->gl_pathv = NULL; - } -} - -static int -g_Ctoc(const gchar *str, char *buf, unsigned int len) -{ - - while (len--) { - if ((*buf++ = *str++) == EOS) - return (0); - } - return (1); -} - -#ifdef DEBUG_ENABLED -static void -qprintf(const char *str, Char *s) -{ - Char *p; - - (void)printf("%s:\n", str); - for (p = s; *p; p++) - (void)printf("%c", CHAR(*p)); - (void)printf("\n"); - for (p = s; *p; p++) - (void)printf("%c", *p & M_PROTECT ? '"' : ' '); - (void)printf("\n"); - for (p = s; *p; p++) - (void)printf("%c", ismeta(*p) ? '_' : ' '); - (void)printf("\n"); -} -#endif diff --git a/src/mono/mono/metadata/w32file-unix-glob.h b/src/mono/mono/metadata/w32file-unix-glob.h deleted file mode 100644 index e4d940ef189e6a..00000000000000 --- a/src/mono/mono/metadata/w32file-unix-glob.h +++ /dev/null @@ -1,70 +0,0 @@ -/* $OpenBSD: glob.h,v 1.10 2005/12/13 00:35:22 millert Exp $ */ -/* $NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $ */ - -/** - * \file - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Guido van Rossum. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)glob.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef __MONO_METADATA_W32FILE_UNIX_GLOB_H__ -#define __MONO_METADATA_W32FILE_UNIX_GLOB_H__ - -#include - -struct stat; -typedef struct { - int gl_pathc; /* Count of total paths so far. */ - int gl_offs; /* Reserved at beginning of gl_pathv. */ - int gl_flags; /* Copy of flags parameter to glob. */ - char **gl_pathv; /* List of paths matching pattern. */ -} mono_w32file_unix_glob_t; - -#define W32FILE_UNIX_GLOB_APPEND 0x0001 /* Append to output from previous call. */ -#define W32FILE_UNIX_GLOB_UNIQUE 0x0040 /* When appending only add items that aren't already in the list */ -#define W32FILE_UNIX_GLOB_NOSPACE (-1) /* Malloc call failed. */ -#define W32FILE_UNIX_GLOB_ABORTED (-2) /* Unignored error. */ -#define W32FILE_UNIX_GLOB_NOMATCH (-3) /* No match and W32FILE_UNIX_GLOB_NOCHECK not set. */ -#define W32FILE_UNIX_GLOB_NOSYS (-4) /* Function not supported. */ - -#define W32FILE_UNIX_GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */ -#define W32FILE_UNIX_GLOB_LIMIT 0x2000 /* Limit pattern match output to ARG_MAX */ -#define W32FILE_UNIX_GLOB_IGNORECASE 0x4000 /* Ignore case when matching */ -#define W32FILE_UNIX_GLOB_ABEND W32FILE_UNIX_GLOB_ABORTED /* backward compatibility */ - -int -mono_w32file_unix_glob (GDir *dir, const char *, int, mono_w32file_unix_glob_t *); - -void -mono_w32file_unix_globfree (mono_w32file_unix_glob_t *); - -#endif /* !__MONO_METADATA_W32FILE_UNIX_GLOB_H__ */ diff --git a/src/mono/mono/metadata/w32file-unix.c b/src/mono/mono/metadata/w32file-unix.c index 0d842853b876e9..306af8436d1dea 100644 --- a/src/mono/mono/metadata/w32file-unix.c +++ b/src/mono/mono/metadata/w32file-unix.c @@ -44,8 +44,6 @@ #endif #include "w32file.h" -#include "w32file-internals.h" -#include "w32file-unix-glob.h" #include "w32error.h" #include "fdhandle.h" #include "utils/mono-error-internals.h" @@ -60,17 +58,6 @@ #include "icall-decl.h" #include "utils/mono-errno.h" -#define NANOSECONDS_PER_MICROSECOND 1000LL -#define TICKS_PER_MICROSECOND 10L -#define TICKS_PER_MILLISECOND 10000L -#define TICKS_PER_SECOND 10000000LL -#define TICKS_PER_MINUTE 600000000LL -#define TICKS_PER_HOUR 36000000000LL -#define TICKS_PER_DAY 864000000000LL - -// Constants to convert Unix times to the API expected by .NET and Windows -#define CONVERT_BASE 116444736000000000ULL - #define INVALID_HANDLE_VALUE ((gpointer)-1) typedef struct { @@ -94,15 +81,6 @@ typedef struct { guint32 attrs; } FileHandle; -typedef struct { - MonoRefCount ref; - MonoCoopMutex mutex; - gchar **namelist; - gchar *dir_part; - gint num; - gsize count; -} FindHandle; - /* * If SHM is disabled, this will point to a hash of FileShare structures, otherwise * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a @@ -111,25 +89,6 @@ typedef struct { static GHashTable *file_share_table; static MonoCoopMutex file_share_mutex; -static GHashTable *finds; -static MonoCoopMutex finds_mutex; - -#if HOST_DARWIN -typedef int (*clonefile_fn) (const char *from, const char *to, int flags); -static MonoDl *libc_handle; -static clonefile_fn clonefile_ptr; -#endif - -static void -time_t_to_filetime (time_t timeval, FILETIME *filetime) -{ - guint64 ticks; - - ticks = ((guint64)timeval * 10000000) + CONVERT_BASE; - filetime->dwLowDateTime = ticks & 0xFFFFFFFF; - filetime->dwHighDateTime = ticks >> 32; -} - static FileHandle* file_data_create (MonoFDType type, gint fd) { @@ -340,18 +299,14 @@ _wapi_access (const gchar *pathname, gint mode) } static gint -_wapi_chmod (const gchar *pathname, mode_t mode) +_wapi_unlink (const gchar *pathname) { gint ret; MONO_ENTER_GC_SAFE; -#if defined(HAVE_CHMOD) - ret = chmod (pathname, mode); -#else - ret = -1; -#endif + ret = unlink (pathname); MONO_EXIT_GC_SAFE; - if (ret == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) { + if (ret == -1 && (errno == ENOENT || errno == ENOTDIR || errno == EISDIR) && IS_PORTABILITY_SET) { gint saved_errno = errno; gchar *located_filename = mono_portability_find_file (pathname, TRUE); @@ -360,4534 +315,394 @@ _wapi_chmod (const gchar *pathname, mode_t mode) return -1; } -#if defined(HAVE_CHMOD) MONO_ENTER_GC_SAFE; - ret = chmod (located_filename, mode); + ret = unlink (located_filename); MONO_EXIT_GC_SAFE; -#else - ret = -1; -#endif g_free (located_filename); } return ret; } -#ifndef HAVE_STRUCT_TIMEVAL -static gint -_wapi_utime (const gchar *filename, const struct utimbuf *buf) +static gchar* +_wapi_dirname (const gchar *filename) { - gint ret = -1; + gchar *new_filename = g_strdup (filename), *ret; -#ifdef HAVE_UTIME - MONO_ENTER_GC_SAFE; - ret = utime (filename, buf); - MONO_EXIT_GC_SAFE; - if (ret == -1 && errno == ENOENT && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_filename = mono_portability_find_file (filename, TRUE); + if (IS_PORTABILITY_SET) + g_strdelimit (new_filename, '\\', '/'); - if (located_filename == NULL) { - mono_set_errno (saved_errno); - return -1; - } + if (IS_PORTABILITY_DRIVE && g_ascii_isalpha (new_filename[0]) && (new_filename[1] == ':')) { + gint len = strlen (new_filename); - MONO_ENTER_GC_SAFE; - ret = utime (located_filename, buf); - MONO_EXIT_GC_SAFE; - g_free (located_filename); + g_memmove (new_filename, new_filename + 2, len - 2); + new_filename[len - 2] = '\0'; } -#endif + + ret = g_path_get_dirname (new_filename); + g_free (new_filename); return ret; } -#else -static gint -_wapi_utimes (const gchar *filename, const struct timeval times[2]) +static gboolean +_wapi_lock_file_region (gint fd, off_t offset, off_t length) { - gint ret = -1; - -#ifdef HAVE_UTIMES - MONO_ENTER_GC_SAFE; - ret = utimes (filename, times); - MONO_EXIT_GC_SAFE; - if (ret == -1 && errno == ENOENT && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_filename = mono_portability_find_file (filename, TRUE); - - if (located_filename == NULL) { - mono_set_errno (saved_errno); - return -1; - } + struct flock lock_data; + gint ret; - MONO_ENTER_GC_SAFE; - ret = utimes (located_filename, times); - MONO_EXIT_GC_SAFE; - g_free (located_filename); + if (offset < 0 || length < 0) { + mono_w32error_set_last (ERROR_INVALID_PARAMETER); + return FALSE; } -#endif - return ret; -} -#endif + lock_data.l_type = F_WRLCK; + lock_data.l_whence = SEEK_SET; + lock_data.l_start = offset; + lock_data.l_len = length; -static gint -_wapi_unlink (const gchar *pathname) -{ - gint ret; + do { + ret = fcntl (fd, F_SETLK, &lock_data); + } while(ret == -1 && errno == EINTR); - MONO_ENTER_GC_SAFE; - ret = unlink (pathname); - MONO_EXIT_GC_SAFE; - if (ret == -1 && (errno == ENOENT || errno == ENOTDIR || errno == EISDIR) && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_filename = mono_portability_find_file (pathname, TRUE); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fcntl returns %d", __func__, ret); - if (located_filename == NULL) { - mono_set_errno (saved_errno); - return -1; + if (ret == -1) { + /* + * if locks are not available (NFS for example), + * ignore the error + */ + if (errno == ENOLCK +#ifdef EOPNOTSUPP + || errno == EOPNOTSUPP +#endif +#ifdef ENOTSUP + || errno == ENOTSUP +#endif + ) { + return TRUE; } - MONO_ENTER_GC_SAFE; - ret = unlink (located_filename); - MONO_EXIT_GC_SAFE; - g_free (located_filename); + mono_w32error_set_last (ERROR_LOCK_VIOLATION); + return FALSE; } - return ret; + return TRUE; } -static gint -_wapi_rename (const gchar *oldpath, const gchar *newpath) +static gboolean +_wapi_unlock_file_region (gint fd, off_t offset, off_t length) { + struct flock lock_data; gint ret; - gchar *located_newpath = mono_portability_find_file (newpath, FALSE); - - if (located_newpath == NULL) { - MONO_ENTER_GC_SAFE; - ret = rename (oldpath, newpath); - MONO_EXIT_GC_SAFE; - } else { - MONO_ENTER_GC_SAFE; - ret = rename (oldpath, located_newpath); - MONO_EXIT_GC_SAFE; - if (ret == -1 && (errno == EISDIR || errno == ENAMETOOLONG || errno == ENOENT || errno == ENOTDIR || errno == EXDEV) && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_oldpath = mono_portability_find_file (oldpath, TRUE); + lock_data.l_type = F_UNLCK; + lock_data.l_whence = SEEK_SET; + lock_data.l_start = offset; + lock_data.l_len = length; - if (located_oldpath == NULL) { - g_free (located_oldpath); - g_free (located_newpath); + do { + ret = fcntl (fd, F_SETLK, &lock_data); + } while(ret == -1 && errno == EINTR); - mono_set_errno (saved_errno); - return -1; - } + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fcntl returns %d", __func__, ret); - MONO_ENTER_GC_SAFE; - ret = rename (located_oldpath, located_newpath); - MONO_EXIT_GC_SAFE; - g_free (located_oldpath); + if (ret == -1) { + /* + * if locks are not available (NFS for example), + * ignore the error + */ + if (errno == ENOLCK +#ifdef EOPNOTSUPP + || errno == EOPNOTSUPP +#endif +#ifdef ENOTSUP + || errno == ENOTSUP +#endif + ) { + return TRUE; } - g_free (located_newpath); + + mono_w32error_set_last (ERROR_LOCK_VIOLATION); + return FALSE; } - return ret; + return TRUE; } -static gint -_wapi_stat (const gchar *path, struct stat *buf) -{ - gint ret; - - MONO_ENTER_GC_SAFE; - ret = stat (path, buf); - MONO_EXIT_GC_SAFE; - if (ret == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_filename = mono_portability_find_file (path, TRUE); - - if (located_filename == NULL) { - mono_set_errno (saved_errno); - return -1; - } - - MONO_ENTER_GC_SAFE; - ret = stat (located_filename, buf); - MONO_EXIT_GC_SAFE; - g_free (located_filename); - } +static gboolean lock_while_writing = FALSE; - return ret; +static void +_wapi_set_last_error_from_errno (void) +{ + mono_w32error_set_last (mono_w32error_unix_to_win32 (errno)); } -static gint -_wapi_lstat (const gchar *path, struct stat *buf) +static void _wapi_set_last_path_error_from_errno (const gchar *dir, + const gchar *path) { - gint ret; + if (errno == ENOENT) { + /* Check the path - if it's a missing directory then + * we need to set PATH_NOT_FOUND not FILE_NOT_FOUND + */ + gchar *dirname; -#ifdef HAVE_LSTAT - MONO_ENTER_GC_SAFE; - ret = lstat (path, buf); - MONO_EXIT_GC_SAFE; - if (ret == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_filename = mono_portability_find_file (path, TRUE); - if (located_filename == NULL) { - mono_set_errno (saved_errno); - return -1; + if (dir == NULL) { + dirname = _wapi_dirname (path); + } else { + dirname = g_strdup (dir); + } + + if (_wapi_access (dirname, F_OK) == 0) { + mono_w32error_set_last (ERROR_FILE_NOT_FOUND); + } else { + mono_w32error_set_last (ERROR_PATH_NOT_FOUND); } - ret = lstat (located_filename, buf); - g_free (located_filename); + g_free (dirname); + } else { + _wapi_set_last_error_from_errno (); } -#else - ret = -1; -#endif - - return ret; } -static gint -_wapi_mkdir (const gchar *pathname, mode_t mode) +static gboolean +file_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *byteswritten) { gint ret; - gchar *located_filename = mono_portability_find_file (pathname, FALSE); + off_t current_pos = 0; + MonoThreadInfo *info = mono_thread_info_current (); + + if(byteswritten!=NULL) { + *byteswritten=0; + } + + if(!(filehandle->fileaccess & GENERIC_WRITE) && !(filehandle->fileaccess & GENERIC_ALL)) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - if (located_filename == NULL) { + mono_w32error_set_last (ERROR_ACCESS_DENIED); + return(FALSE); + } + + if (lock_while_writing) { + /* Need to lock the region we're about to write to, + * because we only do advisory locking on POSIX + * systems + */ MONO_ENTER_GC_SAFE; - ret = mkdir (pathname, mode); + current_pos = lseek (((MonoFDHandle*) filehandle)->fd, (off_t)0, SEEK_CUR); MONO_EXIT_GC_SAFE; - } else { + if (current_pos == -1) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d lseek failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror (errno)); + _wapi_set_last_error_from_errno (); + return(FALSE); + } + + if (_wapi_lock_file_region (((MonoFDHandle*) filehandle)->fd, current_pos, numbytes) == FALSE) { + /* The error has already been set */ + return(FALSE); + } + } + + do { MONO_ENTER_GC_SAFE; - ret = mkdir (located_filename, mode); + ret = write (((MonoFDHandle*) filehandle)->fd, buffer, numbytes); MONO_EXIT_GC_SAFE; - g_free (located_filename); + } while (ret == -1 && errno == EINTR && + !mono_thread_info_is_interrupt_state (info)); + + if (lock_while_writing) { + _wapi_unlock_file_region (((MonoFDHandle*) filehandle)->fd, current_pos, numbytes); } - return ret; -} - -static gint -_wapi_rmdir (const gchar *pathname) -{ - gint ret; - - MONO_ENTER_GC_SAFE; - ret = rmdir (pathname); - MONO_EXIT_GC_SAFE; - if (ret == -1 && (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG) && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_filename = mono_portability_find_file (pathname, TRUE); - - if (located_filename == NULL) { - mono_set_errno (saved_errno); - return -1; - } - - MONO_ENTER_GC_SAFE; - ret = rmdir (located_filename); - MONO_EXIT_GC_SAFE; - g_free (located_filename); - } - - return ret; -} - -static gint -_wapi_chdir (const gchar *path) -{ - gint ret; - - MONO_ENTER_GC_SAFE; - ret = chdir (path); - MONO_EXIT_GC_SAFE; - if (ret == -1 && (errno == ENOENT || errno == ENOTDIR || errno == ENAMETOOLONG) && IS_PORTABILITY_SET) { - gint saved_errno = errno; - gchar *located_filename = mono_portability_find_file (path, TRUE); - - if (located_filename == NULL) { - mono_set_errno (saved_errno); - return -1; - } - - MONO_ENTER_GC_SAFE; - ret = chdir (located_filename); - MONO_EXIT_GC_SAFE; - g_free (located_filename); - } - - return ret; -} - -static gchar* -_wapi_basename (const gchar *filename) -{ - gchar *new_filename = g_strdup (filename), *ret; - - if (IS_PORTABILITY_SET) - g_strdelimit (new_filename, '\\', '/'); - - if (IS_PORTABILITY_DRIVE && g_ascii_isalpha (new_filename[0]) && (new_filename[1] == ':')) { - gint len = strlen (new_filename); - - g_memmove (new_filename, new_filename + 2, len - 2); - new_filename[len - 2] = '\0'; - } - - ret = g_path_get_basename (new_filename); - g_free (new_filename); - - return ret; -} - -static gchar* -_wapi_dirname (const gchar *filename) -{ - gchar *new_filename = g_strdup (filename), *ret; - - if (IS_PORTABILITY_SET) - g_strdelimit (new_filename, '\\', '/'); - - if (IS_PORTABILITY_DRIVE && g_ascii_isalpha (new_filename[0]) && (new_filename[1] == ':')) { - gint len = strlen (new_filename); - - g_memmove (new_filename, new_filename + 2, len - 2); - new_filename[len - 2] = '\0'; - } - - ret = g_path_get_dirname (new_filename); - g_free (new_filename); - - return ret; -} - -static GDir* -_wapi_g_dir_open (const gchar *path, guint flags, GError **gerror) -{ - GDir *ret; - - MONO_ENTER_GC_SAFE; - ret = g_dir_open (path, flags, gerror); - MONO_EXIT_GC_SAFE; - if (ret == NULL && ((*gerror)->code == G_FILE_ERROR_NOENT || (*gerror)->code == G_FILE_ERROR_NOTDIR || (*gerror)->code == G_FILE_ERROR_NAMETOOLONG) && IS_PORTABILITY_SET) { - gchar *located_filename = mono_portability_find_file (path, TRUE); - GError *tmp_error = NULL; - - if (located_filename == NULL) { - return(NULL); - } - - MONO_ENTER_GC_SAFE; - ret = g_dir_open (located_filename, flags, &tmp_error); - MONO_EXIT_GC_SAFE; - g_free (located_filename); - if (tmp_error == NULL) { - g_clear_error (gerror); - } - } - - return ret; -} - -static gint -get_errno_from_g_file_error (gint error) -{ - switch (error) { -#ifdef EACCES - case G_FILE_ERROR_ACCES: return EACCES; -#endif -#ifdef ENAMETOOLONG - case G_FILE_ERROR_NAMETOOLONG: return ENAMETOOLONG; -#endif -#ifdef ENOENT - case G_FILE_ERROR_NOENT: return ENOENT; -#endif -#ifdef ENOTDIR - case G_FILE_ERROR_NOTDIR: return ENOTDIR; -#endif -#ifdef ENXIO - case G_FILE_ERROR_NXIO: return ENXIO; -#endif -#ifdef ENODEV - case G_FILE_ERROR_NODEV: return ENODEV; -#endif -#ifdef EROFS - case G_FILE_ERROR_ROFS: return EROFS; -#endif -#ifdef ETXTBSY - case G_FILE_ERROR_TXTBSY: return ETXTBSY; -#endif -#ifdef EFAULT - case G_FILE_ERROR_FAULT: return EFAULT; -#endif -#ifdef ELOOP - case G_FILE_ERROR_LOOP: return ELOOP; -#endif -#ifdef ENOSPC - case G_FILE_ERROR_NOSPC: return ENOSPC; -#endif -#ifdef ENOMEM - case G_FILE_ERROR_NOMEM: return ENOMEM; -#endif -#ifdef EMFILE - case G_FILE_ERROR_MFILE: return EMFILE; -#endif -#ifdef ENFILE - case G_FILE_ERROR_NFILE: return ENFILE; -#endif -#ifdef EBADF - case G_FILE_ERROR_BADF: return EBADF; -#endif -#ifdef EINVAL - case G_FILE_ERROR_INVAL: return EINVAL; -#endif -#ifdef EPIPE - case G_FILE_ERROR_PIPE: return EPIPE; -#endif -#ifdef EAGAIN - case G_FILE_ERROR_AGAIN: return EAGAIN; -#endif -#ifdef EINTR - case G_FILE_ERROR_INTR: return EINTR; -#endif -#ifdef EIO - case G_FILE_ERROR_IO: return EIO; -#endif -#ifdef EPERM - case G_FILE_ERROR_PERM: return EPERM; -#endif - case G_FILE_ERROR_FAILED: return ERROR_INVALID_PARAMETER; - default: - g_assert_not_reached (); - } -} - -static gint -file_compare (gconstpointer a, gconstpointer b) -{ - gchar *astr = *(gchar **) a; - gchar *bstr = *(gchar **) b; - - return strcmp (astr, bstr); -} - -/* scandir using glib */ -static gint -_wapi_io_scandir (const gchar *dirname, const gchar *pattern, gchar ***namelist) -{ - GError *gerror = NULL; - GDir *dir; - GPtrArray *names; - gint result; - mono_w32file_unix_glob_t glob_buf; - gint flags = 0, i; - - dir = _wapi_g_dir_open (dirname, 0, &gerror); - if (dir == NULL) { - /* g_dir_open returns ENOENT on directories on which we don't - * have read/x permission */ - gint errnum = get_errno_from_g_file_error (gerror->code); - g_error_free (gerror); - if (errnum == ENOENT && - !_wapi_access (dirname, F_OK) && - _wapi_access (dirname, R_OK|X_OK)) { - errnum = EACCES; - } - - mono_set_errno (errnum); - return -1; - } - - if (IS_PORTABILITY_CASE) { - flags = W32FILE_UNIX_GLOB_IGNORECASE; - } - - result = mono_w32file_unix_glob (dir, pattern, flags, &glob_buf); - if (g_str_has_suffix (pattern, ".*")) { - /* Special-case the patterns ending in '.*', as - * windows also matches entries with no extension with - * this pattern. - * - * TODO: should this be a MONO_IOMAP option? - */ - gchar *pattern2 = g_strndup (pattern, strlen (pattern) - 2); - gint result2; - - MONO_ENTER_GC_SAFE; - g_dir_rewind (dir); - MONO_EXIT_GC_SAFE; - result2 = mono_w32file_unix_glob (dir, pattern2, flags | W32FILE_UNIX_GLOB_APPEND | W32FILE_UNIX_GLOB_UNIQUE, &glob_buf); - - g_free (pattern2); - - if (result != 0) { - result = result2; - } - } - - MONO_ENTER_GC_SAFE; - g_dir_close (dir); - MONO_EXIT_GC_SAFE; - if (glob_buf.gl_pathc == 0) { - return(0); - } else if (result != 0) { - return -1; - } - - names = g_ptr_array_new (); - for (i = 0; i < glob_buf.gl_pathc; i++) { - g_ptr_array_add (names, g_strdup (glob_buf.gl_pathv[i])); - } - - mono_w32file_unix_globfree (&glob_buf); - - result = names->len; - if (result > 0) { - g_ptr_array_sort (names, file_compare); - g_ptr_array_set_size (names, result + 1); - - *namelist = (gchar **) g_ptr_array_free (names, FALSE); - } else { - g_ptr_array_free (names, TRUE); - } - - return result; -} - -static gboolean -_wapi_lock_file_region (gint fd, off_t offset, off_t length) -{ - struct flock lock_data; - gint ret; - - if (offset < 0 || length < 0) { - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return FALSE; - } - - lock_data.l_type = F_WRLCK; - lock_data.l_whence = SEEK_SET; - lock_data.l_start = offset; - lock_data.l_len = length; - - do { - ret = fcntl (fd, F_SETLK, &lock_data); - } while(ret == -1 && errno == EINTR); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fcntl returns %d", __func__, ret); - - if (ret == -1) { - /* - * if locks are not available (NFS for example), - * ignore the error - */ - if (errno == ENOLCK -#ifdef EOPNOTSUPP - || errno == EOPNOTSUPP -#endif -#ifdef ENOTSUP - || errno == ENOTSUP -#endif - ) { - return TRUE; - } - - mono_w32error_set_last (ERROR_LOCK_VIOLATION); - return FALSE; - } - - return TRUE; -} - -static gboolean -_wapi_unlock_file_region (gint fd, off_t offset, off_t length) -{ - struct flock lock_data; - gint ret; - - lock_data.l_type = F_UNLCK; - lock_data.l_whence = SEEK_SET; - lock_data.l_start = offset; - lock_data.l_len = length; - - do { - ret = fcntl (fd, F_SETLK, &lock_data); - } while(ret == -1 && errno == EINTR); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fcntl returns %d", __func__, ret); - - if (ret == -1) { - /* - * if locks are not available (NFS for example), - * ignore the error - */ - if (errno == ENOLCK -#ifdef EOPNOTSUPP - || errno == EOPNOTSUPP -#endif -#ifdef ENOTSUP - || errno == ENOTSUP -#endif - ) { - return TRUE; - } - - mono_w32error_set_last (ERROR_LOCK_VIOLATION); - return FALSE; - } - - return TRUE; -} - -static gboolean lock_while_writing = FALSE; - -/* Some utility functions. - */ - -/* - * Check if a file is writable by the current user. - * - * This is is a best effort kind of thing. It assumes a reasonable sane set - * of permissions by the underlying OS. - * - * We generally assume that basic unix permission bits are authoritative. Which might not - * be the case under systems with extended permissions systems (posix ACLs, SELinux, OSX/iOS sandboxing, etc) - * - * The choice of access as the fallback is due to the expected lower overhead compared to trying to open the file. - * - * The only expected problem with using access are for root, setuid or setgid programs as access is not consistent - * under those situations. It's to be expected that this should not happen in practice as those bits are very dangerous - * and should not be used with a dynamic runtime. - */ -static gboolean -is_file_writable (struct stat *st, const gchar *path) -{ - gboolean ret; - gchar *located_path; - -#if __APPLE__ - // OS X Finder "locked" or `ls -lO` "uchg". - // This only covers one of several cases where an OS X file could be unwritable through special flags. - if (st->st_flags & (UF_IMMUTABLE|SF_IMMUTABLE)) - return 0; -#endif - - /* Is it globally writable? */ - if (st->st_mode & S_IWOTH) - return 1; - - /* Am I the owner? */ - if ((st->st_uid == geteuid ()) && (st->st_mode & S_IWUSR)) - return 1; - - /* Am I in the same group? */ - if ((st->st_gid == getegid ()) && (st->st_mode & S_IWGRP)) - return 1; - - located_path = mono_portability_find_file (path, FALSE); - - /* Fallback to using access(2). It's not ideal as it might not take into consideration euid/egid - * but it's the only sane option we have on unix. - */ - MONO_ENTER_GC_SAFE; - ret = access (located_path != NULL ? located_path : path, W_OK) == 0; - MONO_EXIT_GC_SAFE; - - g_free (located_path); - - return ret; -} - - -static guint32 _wapi_stat_to_file_attributes (const gchar *pathname, - struct stat *buf, - struct stat *lbuf) -{ - guint32 attrs = 0; - gchar *filename; - - /* FIXME: this could definitely be better, but there seems to - * be no pattern to the attributes that are set - */ - - /* Sockets (0140000) != Directory (040000) + Regular file (0100000) */ - if (S_ISSOCK (buf->st_mode)) - buf->st_mode &= ~S_IFSOCK; /* don't consider socket protection */ - - filename = _wapi_basename (pathname); - - if (S_ISDIR (buf->st_mode)) { - attrs = FILE_ATTRIBUTE_DIRECTORY; - if (!is_file_writable (buf, pathname)) { - attrs |= FILE_ATTRIBUTE_READONLY; - } - if (filename[0] == '.') { - attrs |= FILE_ATTRIBUTE_HIDDEN; - } - } else { - if (!is_file_writable (buf, pathname)) { - attrs = FILE_ATTRIBUTE_READONLY; - - if (filename[0] == '.') { - attrs |= FILE_ATTRIBUTE_HIDDEN; - } - } else if (filename[0] == '.') { - attrs = FILE_ATTRIBUTE_HIDDEN; - } else { - attrs = FILE_ATTRIBUTE_NORMAL; - } - } - - if (lbuf != NULL) { - if (S_ISLNK (lbuf->st_mode)) { - attrs |= FILE_ATTRIBUTE_REPARSE_POINT; - } - } - - g_free (filename); - - return attrs; -} - -static void -_wapi_set_last_error_from_errno (void) -{ - mono_w32error_set_last (mono_w32error_unix_to_win32 (errno)); -} - -static void _wapi_set_last_path_error_from_errno (const gchar *dir, - const gchar *path) -{ - if (errno == ENOENT) { - /* Check the path - if it's a missing directory then - * we need to set PATH_NOT_FOUND not FILE_NOT_FOUND - */ - gchar *dirname; - - - if (dir == NULL) { - dirname = _wapi_dirname (path); - } else { - dirname = g_strdup (dir); - } - - if (_wapi_access (dirname, F_OK) == 0) { - mono_w32error_set_last (ERROR_FILE_NOT_FOUND); - } else { - mono_w32error_set_last (ERROR_PATH_NOT_FOUND); - } - - g_free (dirname); - } else { - _wapi_set_last_error_from_errno (); - } -} - -static gboolean -file_read(FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *bytesread) -{ - gint ret; - MonoThreadInfo *info = mono_thread_info_current (); - - if(bytesread!=NULL) { - *bytesread=0; - } - - if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - do { - MONO_ENTER_GC_SAFE; - ret = read (((MonoFDHandle*) filehandle)->fd, buffer, numbytes); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && - !mono_thread_info_is_interrupt_state (info)); - - if(ret==-1) { - gint err = errno; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: read of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(err)); - mono_w32error_set_last (mono_w32error_unix_to_win32 (err)); - return(FALSE); - } - - if (bytesread != NULL) { - *bytesread = ret; - } - - return(TRUE); -} - -static gboolean -file_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *byteswritten) -{ - gint ret; - off_t current_pos = 0; - MonoThreadInfo *info = mono_thread_info_current (); - - if(byteswritten!=NULL) { - *byteswritten=0; - } - - if(!(filehandle->fileaccess & GENERIC_WRITE) && !(filehandle->fileaccess & GENERIC_ALL)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - if (lock_while_writing) { - /* Need to lock the region we're about to write to, - * because we only do advisory locking on POSIX - * systems - */ - MONO_ENTER_GC_SAFE; - current_pos = lseek (((MonoFDHandle*) filehandle)->fd, (off_t)0, SEEK_CUR); - MONO_EXIT_GC_SAFE; - if (current_pos == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d lseek failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror (errno)); - _wapi_set_last_error_from_errno (); - return(FALSE); - } - - if (_wapi_lock_file_region (((MonoFDHandle*) filehandle)->fd, current_pos, numbytes) == FALSE) { - /* The error has already been set */ - return(FALSE); - } - } - - do { - MONO_ENTER_GC_SAFE; - ret = write (((MonoFDHandle*) filehandle)->fd, buffer, numbytes); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && - !mono_thread_info_is_interrupt_state (info)); - - if (lock_while_writing) { - _wapi_unlock_file_region (((MonoFDHandle*) filehandle)->fd, current_pos, numbytes); - } - - if (ret == -1) { - if (errno == EINTR) { - ret = 0; - } else { - _wapi_set_last_error_from_errno (); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - return(FALSE); - } - } - if (byteswritten != NULL) { - *byteswritten = ret; - } - return(TRUE); -} - -static gboolean file_flush(FileHandle *filehandle) -{ - gint ret; - - if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - MONO_ENTER_GC_SAFE; - ret=fsync(((MonoFDHandle*) filehandle)->fd); - MONO_EXIT_GC_SAFE; - if (ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fsync of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(FALSE); - } - - return(TRUE); -} - -static guint32 file_seek(FileHandle *filehandle, gint32 movedistance, - gint32 *highmovedistance, gint method) -{ - gint64 offset, newpos; - gint whence; - guint32 ret; - - if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(INVALID_SET_FILE_POINTER); - } - - switch(method) { - case FILE_BEGIN: - whence=SEEK_SET; - break; - case FILE_CURRENT: - whence=SEEK_CUR; - break; - case FILE_END: - whence=SEEK_END; - break; - default: - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: invalid seek type %d", __func__, method); - - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return(INVALID_SET_FILE_POINTER); - } - -#ifdef HAVE_LARGE_FILE_SUPPORT - if(highmovedistance==NULL) { - offset=movedistance; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: setting offset to %" G_GINT64_FORMAT " (low %" G_GINT32_FORMAT ")", __func__, - offset, movedistance); - } else { - offset=((gint64) *highmovedistance << 32) | (guint32)movedistance; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: setting offset to %" G_GINT64_FORMAT " 0x%" PRIx64 " (high %" G_GINT32_FORMAT " 0x%" PRIx32 ", low %" G_GINT32_FORMAT " 0x%" PRIx32 ")", - __func__, offset, offset, *highmovedistance, *highmovedistance, movedistance, movedistance); - } -#else - offset=movedistance; -#endif - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: moving fd %d by %" G_GINT64_FORMAT " bytes from %d", __func__, ((MonoFDHandle*) filehandle)->fd, offset, whence); - -#ifdef HOST_ANDROID - /* bionic doesn't support -D_FILE_OFFSET_BITS=64 */ - MONO_ENTER_GC_SAFE; - newpos=lseek64(((MonoFDHandle*) filehandle)->fd, offset, whence); - MONO_EXIT_GC_SAFE; -#else - MONO_ENTER_GC_SAFE; - newpos=lseek(((MonoFDHandle*) filehandle)->fd, offset, whence); - MONO_EXIT_GC_SAFE; -#endif - if(newpos==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: lseek on fd %d returned error %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(INVALID_SET_FILE_POINTER); - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: lseek returns %" G_GINT64_FORMAT, __func__, newpos); - -#ifdef HAVE_LARGE_FILE_SUPPORT - ret=newpos & 0xFFFFFFFF; - if(highmovedistance!=NULL) { - *highmovedistance=newpos>>32; - } -#else - ret=newpos; - if(highmovedistance!=NULL) { - /* Accurate, but potentially dodgy :-) */ - *highmovedistance=0; - } -#endif - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: move of fd %d returning %" G_GUINT32_FORMAT "/%" G_GINT32_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, ret, highmovedistance==NULL?0:*highmovedistance); - - return(ret); -} - -static gboolean file_setendoffile(FileHandle *filehandle) -{ - struct stat statbuf; - off_t pos; - gint ret; - MonoThreadInfo *info = mono_thread_info_current (); - - if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - /* Find the current file position, and the file length. If - * the file position is greater than the length, write to - * extend the file with a hole. If the file position is less - * than the length, truncate the file. - */ - - MONO_ENTER_GC_SAFE; - ret=fstat(((MonoFDHandle*) filehandle)->fd, &statbuf); - MONO_EXIT_GC_SAFE; - if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d fstat failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(FALSE); - } - - MONO_ENTER_GC_SAFE; - pos=lseek(((MonoFDHandle*) filehandle)->fd, (off_t)0, SEEK_CUR); - MONO_EXIT_GC_SAFE; - if(pos==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d lseek failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(FALSE); - } - -#ifdef FTRUNCATE_DOESNT_EXTEND - off_t size = statbuf.st_size; - /* I haven't bothered to write the configure.ac stuff for this - * because I don't know if any platform needs it. I'm leaving - * this code just in case though - */ - if(pos>size) { - /* Extend the file. Use write() here, because some - * manuals say that ftruncate() behaviour is undefined - * when the file needs extending. The POSIX spec says - * that on XSI-conformant systems it extends, so if - * every system we care about conforms, then we can - * drop this write. - */ - do { - MONO_ENTER_GC_SAFE; - ret = write (((MonoFDHandle*) filehandle)->fd, "", 1); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && - !mono_thread_info_is_interrupt_state (info)); - - if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d extend write failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(FALSE); - } - - /* And put the file position back after the write */ - MONO_ENTER_GC_SAFE; - ret = lseek (((MonoFDHandle*) filehandle)->fd, pos, SEEK_SET); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d second lseek failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(FALSE); - } - } -#endif - - /* always truncate, because the extend write() adds an extra - * byte to the end of the file - */ - do { - MONO_ENTER_GC_SAFE; - ret=ftruncate(((MonoFDHandle*) filehandle)->fd, pos); - MONO_EXIT_GC_SAFE; - } - while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info)); - if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d ftruncate failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(FALSE); - } - - return(TRUE); -} - -static guint32 file_getfilesize(FileHandle *filehandle, guint32 *highsize) -{ - struct stat statbuf; - guint32 size; - gint ret; - - if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(INVALID_FILE_SIZE); - } - - /* If the file has a size with the low bits 0xFFFFFFFF the - * caller can't tell if this is an error, so clear the error - * value - */ - mono_w32error_set_last (ERROR_SUCCESS); - - MONO_ENTER_GC_SAFE; - ret = fstat(((MonoFDHandle*) filehandle)->fd, &statbuf); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d fstat failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(INVALID_FILE_SIZE); - } - - /* fstat indicates block devices as zero-length, so go a different path */ -#ifdef BLKGETSIZE64 - if (S_ISBLK(statbuf.st_mode)) { - guint64 bigsize; - gint res; - MONO_ENTER_GC_SAFE; - res = ioctl (((MonoFDHandle*) filehandle)->fd, BLKGETSIZE64, &bigsize); - MONO_EXIT_GC_SAFE; - if (res < 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d ioctl BLKGETSIZE64 failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(INVALID_FILE_SIZE); - } - - size = bigsize & 0xFFFFFFFF; - if (highsize != NULL) { - *highsize = bigsize>>32; - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Returning block device size %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT, - __func__, size, *highsize); - - return(size); - } -#endif - -#ifdef HAVE_LARGE_FILE_SUPPORT - size = statbuf.st_size & 0xFFFFFFFF; - if (highsize != NULL) { - *highsize = statbuf.st_size>>32; - } -#else - if (highsize != NULL) { - /* Accurate, but potentially dodgy :-) */ - *highsize = 0; - } - size = statbuf.st_size; -#endif - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Returning size %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT, __func__, size, *highsize); - - return(size); -} - -static guint64 -convert_unix_filetime_ms (const FILETIME *file_time, const char *ttype) -{ - guint64 t = ((guint64) file_time->dwHighDateTime << 32) + file_time->dwLowDateTime; - - /* This is (time_t)0. We can actually go to INT_MIN, - * but this will do for now. - */ - if (t < CONVERT_BASE) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: attempt to set %s time too early", __func__, ttype); - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return (FALSE); - } - - return t - CONVERT_BASE; -} - -#ifndef HAVE_STRUCT_TIMEVAL -static guint64 -convert_unix_filetime (const FILETIME *file_time, size_t field_size, const char *ttype) -{ - guint64 t = convert_unix_filetime_ms (file_time, ttype); - - if (field_size == 4 && (t / 10000000) > INT_MAX) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: attempt to set %s time that is too big for a 32bits time_t", __func__, ttype); - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return (FALSE); - } - - return t / 10000000; -} -#endif - -static void convert_stattime_access_to_timeval (struct timeval *dest, struct stat *statbuf) -{ -#if HAVE_STRUCT_STAT_ST_ATIMESPEC - dest->tv_sec = statbuf->st_atimespec.tv_sec; - dest->tv_usec = statbuf->st_atimespec.tv_nsec / NANOSECONDS_PER_MICROSECOND; -#else - dest->tv_sec = statbuf->st_atime; -#if HAVE_STRUCT_STAT_ST_ATIM - dest->tv_usec = statbuf->st_atim.tv_nsec / NANOSECONDS_PER_MICROSECOND; -#endif -#endif -} - -static void convert_stattime_mod_to_timeval (struct timeval *dest, struct stat *statbuf) -{ -#if HAVE_STRUCT_STAT_ST_ATIMESPEC - dest->tv_sec = statbuf->st_mtimespec.tv_sec; - dest->tv_usec = statbuf->st_mtimespec.tv_nsec / NANOSECONDS_PER_MICROSECOND; -#else - dest->tv_sec = statbuf->st_mtime; -#if HAVE_STRUCT_STAT_ST_ATIM - dest->tv_usec = statbuf->st_mtim.tv_nsec / NANOSECONDS_PER_MICROSECOND; -#endif -#endif -} - -static gboolean file_setfiletime(FileHandle *filehandle, - const FILETIME *create_time G_GNUC_UNUSED, - const FILETIME *access_time, - const FILETIME *write_time) -{ - struct stat statbuf; - gint ret; - - if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - if(filehandle->filename == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d unknown filename", __func__, ((MonoFDHandle*) filehandle)->fd); - - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return(FALSE); - } - - /* Get the current times, so we can put the same times back in - * the event that one of the FileTime structs is NULL - */ - MONO_ENTER_GC_SAFE; - ret=fstat (((MonoFDHandle*) filehandle)->fd, &statbuf); - MONO_EXIT_GC_SAFE; - if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d fstat failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return(FALSE); - } - -#ifdef HAVE_STRUCT_TIMEVAL - struct timeval times [2]; - memset (times, 0, sizeof (times)); - - if (access_time) { - guint64 actime = convert_unix_filetime_ms (access_time, "access"); - times [0].tv_sec = actime / TICKS_PER_SECOND; - times [0].tv_usec = (actime % TICKS_PER_SECOND) / TICKS_PER_MICROSECOND; - } else { - convert_stattime_access_to_timeval (× [0], &statbuf); - } - - if (write_time) { - guint64 wtime = convert_unix_filetime_ms (write_time, "write"); - times [1].tv_sec = wtime / TICKS_PER_SECOND; - times [1].tv_usec = (wtime % TICKS_PER_SECOND) / TICKS_PER_MICROSECOND; - } else { - convert_stattime_mod_to_timeval (× [1], &statbuf); - } - - ret = _wapi_utimes (filehandle->filename, times); -#else - struct utimbuf utbuf; - utbuf.actime = access_time ? convert_unix_filetime (access_time, sizeof (utbuf.actime), "access") : statbuf.st_atime; - utbuf.modtime = write_time ? convert_unix_filetime (write_time, sizeof (utbuf.modtime), "write") : statbuf.st_mtime; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: setting fd %d access %ld write %ld", __func__, ((MonoFDHandle*) filehandle)->fd, utbuf.actime, utbuf.modtime); - - ret = _wapi_utime (filehandle->filename, &utbuf); -#endif - if (ret == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d [%s] utime failed: %s", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->filename, g_strerror(errno)); - - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return(FALSE); - } - - return(TRUE); -} - -static gboolean -console_read(FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *bytesread) -{ - gint ret; - MonoThreadInfo *info = mono_thread_info_current (); - - if(bytesread!=NULL) { - *bytesread=0; - } - - if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - do { - MONO_ENTER_GC_SAFE; - ret=read(((MonoFDHandle*) filehandle)->fd, buffer, numbytes); - MONO_EXIT_GC_SAFE; - } while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info)); - - if(ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: read of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - _wapi_set_last_error_from_errno (); - return(FALSE); - } - - if(bytesread!=NULL) { - *bytesread=ret; - } - - return(TRUE); -} - -static gboolean -console_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *byteswritten) -{ - gint ret; - MonoThreadInfo *info = mono_thread_info_current (); - - if(byteswritten!=NULL) { - *byteswritten=0; - } - - if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - do { - MONO_ENTER_GC_SAFE; - ret = write(((MonoFDHandle*) filehandle)->fd, buffer, numbytes); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && - !mono_thread_info_is_interrupt_state (info)); - - if (ret == -1) { - if (errno == EINTR) { - ret = 0; - } else { - _wapi_set_last_error_from_errno (); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - return(FALSE); - } - } - if(byteswritten!=NULL) { - *byteswritten=ret; - } - - return(TRUE); -} - -static gboolean -pipe_read (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *bytesread) -{ - gint ret; - MonoThreadInfo *info = mono_thread_info_current (); - - if(bytesread!=NULL) { - *bytesread=0; - } - - if(!(filehandle->fileaccess & (GENERIC_READ | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: reading up to %" G_GUINT32_FORMAT " bytes from pipe %d", __func__, numbytes, ((MonoFDHandle*) filehandle)->fd); - - do { - MONO_ENTER_GC_SAFE; - ret=read(((MonoFDHandle*) filehandle)->fd, buffer, numbytes); - MONO_EXIT_GC_SAFE; - } while (ret==-1 && errno==EINTR && !mono_thread_info_is_interrupt_state (info)); - - if (ret == -1) { - if (errno == EINTR) { - ret = 0; - } else { - _wapi_set_last_error_from_errno (); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: read of fd %d error: %s", __func__,((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - return(FALSE); - } - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: read %d bytes from pipe %d", __func__, ret, ((MonoFDHandle*) filehandle)->fd); - - if(bytesread!=NULL) { - *bytesread=ret; - } - - return(TRUE); -} - -static gboolean -pipe_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *byteswritten) -{ - gint ret; - MonoThreadInfo *info = mono_thread_info_current (); - - if(byteswritten!=NULL) { - *byteswritten=0; - } - - if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return(FALSE); - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: writing up to %" G_GUINT32_FORMAT " bytes to pipe %d", __func__, numbytes, ((MonoFDHandle*) filehandle)->fd); - - do { - MONO_ENTER_GC_SAFE; - ret = write (((MonoFDHandle*) filehandle)->fd, buffer, numbytes); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && - !mono_thread_info_is_interrupt_state (info)); - - if (ret == -1) { - if (errno == EINTR) { - ret = 0; - } else { - _wapi_set_last_error_from_errno (); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__,((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - - return(FALSE); - } - } - if(byteswritten!=NULL) { - *byteswritten=ret; - } - - return(TRUE); -} - -static gint convert_flags(guint32 fileaccess, guint32 createmode) -{ - gint flags=0; - - switch(fileaccess) { - case GENERIC_READ: - flags=O_RDONLY; - break; - case GENERIC_WRITE: - flags=O_WRONLY; - break; - case GENERIC_READ|GENERIC_WRITE: - flags=O_RDWR; - break; - default: - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Unknown access type 0x%" PRIx32, __func__, - fileaccess); - break; - } - - switch(createmode) { - case CREATE_NEW: - flags|=O_CREAT|O_EXCL; - break; - case CREATE_ALWAYS: - flags|=O_CREAT|O_TRUNC; - break; - case OPEN_EXISTING: - break; - case OPEN_ALWAYS: - flags|=O_CREAT; - break; - case TRUNCATE_EXISTING: - flags|=O_TRUNC; - break; - default: - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Unknown create mode 0x%" PRIx32, __func__, - createmode); - break; - } - - return(flags); -} - -#if 0 /* unused */ -static mode_t convert_perms(guint32 sharemode) -{ - mode_t perms=0600; - - if(sharemode&FILE_SHARE_READ) { - perms|=044; - } - if(sharemode&FILE_SHARE_WRITE) { - perms|=022; - } - - return(perms); -} -#endif - -static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode, - guint32 fileaccess, - FileShare **share_info) -{ - gboolean file_already_shared; - guint32 file_existing_share, file_existing_access; - - file_already_shared = file_share_get (statbuf->st_dev, statbuf->st_ino, sharemode, fileaccess, &file_existing_share, &file_existing_access, share_info); - - if (file_already_shared) { - /* The reference to this share info was incremented - * when we looked it up, so be careful to put it back - * if we conclude we can't use this file. - */ - if ((file_existing_share == FILE_SHARE_NONE) || (sharemode == FILE_SHARE_NONE)) { - /* Quick and easy, no possibility to share */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing = NONE", __func__, fileaccess); - - file_share_release (*share_info); - *share_info = NULL; - - return(FALSE); - } - - if (((file_existing_share == FILE_SHARE_READ) && - (fileaccess != GENERIC_READ)) || - ((file_existing_share == FILE_SHARE_WRITE) && - (fileaccess != GENERIC_WRITE))) { - /* New access mode doesn't match up */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing: 0x%" PRIx32, __func__, fileaccess, file_existing_share); - - file_share_release (*share_info); - *share_info = NULL; - - return(FALSE); - } - } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: New file!", __func__); - } - - return(TRUE); -} - - -static gboolean -share_allows_delete (struct stat *statbuf, FileShare **share_info) -{ - gboolean file_already_shared; - guint32 file_existing_share, file_existing_access; - - file_already_shared = file_share_get (statbuf->st_dev, statbuf->st_ino, FILE_SHARE_DELETE, GENERIC_READ, &file_existing_share, &file_existing_access, share_info); - - if (file_already_shared) { - /* The reference to this share info was incremented - * when we looked it up, so be careful to put it back - * if we conclude we can't use this file. - */ - if (file_existing_share == 0) { - /* Quick and easy, no possibility to share */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing = NONE", __func__, (*share_info)->access); - - file_share_release (*share_info); - *share_info = NULL; - - return(FALSE); - } - - if (!(file_existing_share & FILE_SHARE_DELETE)) { - /* New access mode doesn't match up */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing: 0x%" PRIx32, __func__, (*share_info)->access, file_existing_share); - - file_share_release (*share_info); - *share_info = NULL; - - return(FALSE); - } - } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: New file!", __func__); - } - - return(TRUE); -} - -gpointer -mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs) -{ - FileHandle *filehandle; - MonoFDType type; - gint flags=convert_flags(fileaccess, createmode); - /*mode_t perms=convert_perms(sharemode);*/ - /* we don't use sharemode, because that relates to sharing of - * the file when the file is open and is already handled by - * other code, perms instead are the on-disk permissions and - * this is a sane default. - */ - mode_t perms=0666; - gchar *filename; - gint fd, ret; - struct stat statbuf; - ERROR_DECL (error); - - if (attrs & FILE_ATTRIBUTE_TEMPORARY) - perms = 0600; - - if (attrs & FILE_ATTRIBUTE_ENCRYPTED){ - mono_w32error_set_last (ERROR_ENCRYPTION_FAILED); - return INVALID_HANDLE_VALUE; - } - - if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(INVALID_HANDLE_VALUE); - } - - filename = mono_unicode_to_external_checked (name, error); - if (filename == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); - return(INVALID_HANDLE_VALUE); - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Opening %s with share 0x%" PRIx32 " and access 0x%" PRIx32, __func__, - filename, sharemode, fileaccess); - - fd = _wapi_open (filename, flags, perms); - - /* If we were trying to open a directory with write permissions - * (e.g. O_WRONLY or O_RDWR), this call will fail with - * EISDIR. However, this is a bit bogus because calls to - * manipulate the directory (e.g. mono_w32file_set_times) will still work on - * the directory because they use other API calls - * (e.g. utime()). Hence, if we failed with the EISDIR error, try - * to open the directory again without write permission. - */ - if (fd == -1 && errno == EISDIR) - { - /* Try again but don't try to make it writable */ - fd = _wapi_open (filename, flags & ~(O_RDWR|O_WRONLY), perms); - } - - if (fd == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Error opening file %s: %s", __func__, filename, g_strerror(errno)); - _wapi_set_last_path_error_from_errno (NULL, filename); - g_free (filename); - - return(INVALID_HANDLE_VALUE); - } - - MONO_ENTER_GC_SAFE; - ret = fstat (fd, &statbuf); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fstat error of file %s: %s", __func__, filename, g_strerror (errno)); - _wapi_set_last_error_from_errno (); - MONO_ENTER_GC_SAFE; - close (fd); - MONO_EXIT_GC_SAFE; - - return(INVALID_HANDLE_VALUE); - } - -#ifndef S_ISFIFO -#define S_ISFIFO(m) ((m & S_IFIFO) != 0) -#endif - if (S_ISFIFO (statbuf.st_mode)) { - type = MONO_FDTYPE_PIPE; - /* maintain invariant that pipes have no filename */ - g_free (filename); - filename = NULL; - } else if (S_ISCHR (statbuf.st_mode)) { - type = MONO_FDTYPE_CONSOLE; - } else { - type = MONO_FDTYPE_FILE; - } - - filehandle = file_data_create (type, fd); - filehandle->filename = filename; - filehandle->fileaccess = fileaccess; - filehandle->sharemode = sharemode; - filehandle->attrs = attrs; - - if (!share_allows_open (&statbuf, filehandle->sharemode, filehandle->fileaccess, &filehandle->share_info)) { - mono_w32error_set_last (ERROR_SHARING_VIOLATION); - MONO_ENTER_GC_SAFE; - close (((MonoFDHandle*) filehandle)->fd); - MONO_EXIT_GC_SAFE; - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return (INVALID_HANDLE_VALUE); - } - if (!filehandle->share_info) { - /* No space, so no more files can be opened */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: No space in the share table", __func__); - - mono_w32error_set_last (ERROR_TOO_MANY_OPEN_FILES); - MONO_ENTER_GC_SAFE; - close (((MonoFDHandle*) filehandle)->fd); - MONO_EXIT_GC_SAFE; - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return(INVALID_HANDLE_VALUE); - } - -#ifdef HAVE_POSIX_FADVISE - if (attrs & FILE_FLAG_SEQUENTIAL_SCAN) { - MONO_ENTER_GC_SAFE; - posix_fadvise (((MonoFDHandle*) filehandle)->fd, 0, 0, POSIX_FADV_SEQUENTIAL); - MONO_EXIT_GC_SAFE; - } - if (attrs & FILE_FLAG_RANDOM_ACCESS) { - MONO_ENTER_GC_SAFE; - posix_fadvise (((MonoFDHandle*) filehandle)->fd, 0, 0, POSIX_FADV_RANDOM); - MONO_EXIT_GC_SAFE; - } -#endif - -#ifdef F_RDAHEAD - if (attrs & FILE_FLAG_SEQUENTIAL_SCAN) { - MONO_ENTER_GC_SAFE; - fcntl(((MonoFDHandle*) filehandle)->fd, F_RDAHEAD, 1); - MONO_EXIT_GC_SAFE; - } -#endif - - mono_fdhandle_insert ((MonoFDHandle*) filehandle); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: returning handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd)); - - return GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd); -} - -gboolean -mono_w32file_cancel (gpointer handle) -{ - mono_w32error_set_last (ERROR_NOT_SUPPORTED); - return FALSE; -} - -gboolean -mono_w32file_close (gpointer handle) -{ - if (!mono_fdhandle_close (GPOINTER_TO_INT (handle))) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - return TRUE; -} - -gboolean mono_w32file_delete(const gunichar2 *name) -{ - gchar *filename; - gint retval; - gboolean ret = FALSE; - ERROR_DECL (error); -#if 0 - struct stat statbuf; - FileShare *shareinfo; -#endif - - if(name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - filename = mono_unicode_to_external_checked (name, error); - if(filename==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - -#if 0 - /* Check to make sure sharing allows us to open the file for - * writing. See bug 323389. - * - * Do the checks that don't need an open file descriptor, for - * simplicity's sake. If we really have to do the full checks - * then we can implement that later. - */ - if (_wapi_stat (filename, &statbuf) < 0) { - _wapi_set_last_path_error_from_errno (NULL, filename); - g_free (filename); - return(FALSE); - } - - if (share_allows_open (&statbuf, 0, GENERIC_WRITE, - &shareinfo) == FALSE) { - mono_w32error_set_last (ERROR_SHARING_VIOLATION); - g_free (filename); - return FALSE; - } - if (shareinfo) - file_share_release (shareinfo); -#endif - - retval = _wapi_unlink (filename); - - if (retval == -1) { - /* On linux, calling unlink on an non-existing file in a read-only mount will fail with EROFS. - * The expected behavior is for this function to return FALSE and not trigger an exception. - * To work around this behavior, we stat the file on failure. - * - * This was supposedly fixed on kernel 3.0 [1] but we could reproduce it with Ubuntu 16.04 which has kernel 4.4. - * We can't remove this workaround until the early 2020's when most Android deviced will have a fix. - * [1] https://github.com/torvalds/linux/commit/50338b889dc504c69e0cb316ac92d1b9e51f3c8a - */ - if (errno == EROFS) { - MonoIOStat stat; - if (mono_w32file_get_attributes_ex (name, &stat)) //The file exists, so must be due the RO file system - mono_set_errno (EROFS); - } - _wapi_set_last_path_error_from_errno (NULL, filename); - } else { - ret = TRUE; - } - - g_free(filename); - - return(ret); -} - -static gboolean -MoveFile (const gunichar2 *name, const gunichar2 *dest_name) -{ - gchar *utf8_name, *utf8_dest_name; - gint result, errno_copy; - struct stat stat_src, stat_dest; - gboolean ret = FALSE; - FileShare *shareinfo; - ERROR_DECL (error); - - if(name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_name = mono_unicode_to_external_checked (name, error); - if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); - return FALSE; - } - - if(dest_name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - g_free (utf8_name); - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_dest_name = mono_unicode_to_external_checked (dest_name, error); - if (utf8_dest_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - g_free (utf8_name); - mono_w32error_set_last (ERROR_INVALID_NAME); - return FALSE; - } - - /* - * In C# land we check for the existence of src, but not for dest. - * We check it here and return the failure if dest exists and is not - * the same file as src. - */ - if (_wapi_stat (utf8_name, &stat_src) < 0) { - if (errno != ENOENT || _wapi_lstat (utf8_name, &stat_src) < 0) { - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - g_free (utf8_dest_name); - return FALSE; - } - } - - if (!_wapi_stat (utf8_dest_name, &stat_dest)) { - if (stat_dest.st_dev != stat_src.st_dev || - stat_dest.st_ino != stat_src.st_ino) { - g_free (utf8_name); - g_free (utf8_dest_name); - mono_w32error_set_last (ERROR_ALREADY_EXISTS); - return FALSE; - } - } - - /* Check to make that we have delete sharing permission. - * See https://bugzilla.xamarin.com/show_bug.cgi?id=17009 - * - * Do the checks that don't need an open file descriptor, for - * simplicity's sake. If we really have to do the full checks - * then we can implement that later. - */ - if (share_allows_delete (&stat_src, &shareinfo) == FALSE) { - mono_w32error_set_last (ERROR_SHARING_VIOLATION); - return FALSE; - } - if (shareinfo) { - file_share_release (shareinfo); - shareinfo = NULL; - } - - result = _wapi_rename (utf8_name, utf8_dest_name); - errno_copy = errno; - - if (result == -1) { - switch(errno_copy) { - case EEXIST: - mono_w32error_set_last (ERROR_ALREADY_EXISTS); - break; - - case EXDEV: - /* Ignore here, it is dealt with below */ - break; - - case ENOENT: - /* We already know src exists. Must be dest that doesn't exist. */ - _wapi_set_last_path_error_from_errno (NULL, utf8_dest_name); - break; - - default: - _wapi_set_last_error_from_errno (); - } - } - - g_free (utf8_name); - g_free (utf8_dest_name); - - if (result != 0 && errno_copy == EXDEV) { - gint32 copy_error; - - if (S_ISDIR (stat_src.st_mode)) { - mono_w32error_set_last (ERROR_NOT_SAME_DEVICE); - return FALSE; - } - /* Try a copy to the new location, and delete the source */ - if (!mono_w32file_copy (name, dest_name, FALSE, ©_error)) { - /* mono_w32file_copy will set the error */ - return(FALSE); - } - - return(mono_w32file_delete (name)); - } - - if (result == 0) { - ret = TRUE; - } - - return(ret); -} - -static gboolean -write_file (gint src_fd, gint dest_fd, struct stat *st_src, gboolean report_errors) -{ - gint remain, n; - gchar *buf, *wbuf; - gint buf_size = st_src->st_blksize; - MonoThreadInfo *info = mono_thread_info_current (); - - buf_size = buf_size < 8192 ? 8192 : (buf_size > 65536 ? 65536 : buf_size); - buf = (gchar *) g_malloc (buf_size); - - for (;;) { - MONO_ENTER_GC_SAFE; - remain = read (src_fd, buf, buf_size); - MONO_EXIT_GC_SAFE; - if (remain < 0) { - if (errno == EINTR && !mono_thread_info_is_interrupt_state (info)) - continue; - - if (report_errors) - _wapi_set_last_error_from_errno (); - - g_free (buf); - return FALSE; - } - if (remain == 0) { - break; - } - - wbuf = buf; - while (remain > 0) { - MONO_ENTER_GC_SAFE; - n = write (dest_fd, wbuf, remain); - MONO_EXIT_GC_SAFE; - if (n < 0) { - if (errno == EINTR && !mono_thread_info_is_interrupt_state (info)) - continue; - - if (report_errors) - _wapi_set_last_error_from_errno (); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write failed.", __func__); - g_free (buf); - return FALSE; - } - - remain -= n; - wbuf += n; - } - } - - g_free (buf); - return TRUE ; -} - -#if HOST_DARWIN -static int -_wapi_clonefile(const char *from, const char *to, int flags) -{ - gchar *located_from, *located_to; - int ret; - - g_assert (clonefile_ptr != NULL); - - located_from = mono_portability_find_file (from, FALSE); - located_to = mono_portability_find_file (to, FALSE); - - MONO_ENTER_GC_SAFE; - ret = clonefile_ptr ( - located_from == NULL ? from : located_from, - located_to == NULL ? to : located_to, - flags); - MONO_EXIT_GC_SAFE; - - g_free (located_from); - g_free (located_to); - - return ret; -} -#endif - -static gboolean -CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_exists) -{ - gchar *utf8_src, *utf8_dest; - struct stat st, dest_st; - gboolean ret = TRUE; - ERROR_DECL (error); - - if(name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_src = mono_unicode_to_external_checked (name, error); - if (utf8_src == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion of source returned NULL; %s", - __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return(FALSE); - } - - if(dest_name==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: dest is NULL", __func__); - - g_free (utf8_src); - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_dest = mono_unicode_to_external_checked (dest_name, error); - if (utf8_dest == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion of dest returned NULL; %s", - __func__, mono_error_get_message (error)); - - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - - mono_error_cleanup (error); - g_free (utf8_src); - - return(FALSE); - } - - gint src_fd, dest_fd; - gint ret_utime; - gint syscall_res; - - src_fd = _wapi_open (utf8_src, O_RDONLY, 0); - if (src_fd < 0) { - _wapi_set_last_path_error_from_errno (NULL, utf8_src); - - g_free (utf8_src); - g_free (utf8_dest); - - return(FALSE); - } - - MONO_ENTER_GC_SAFE; - syscall_res = fstat (src_fd, &st); - MONO_EXIT_GC_SAFE; - if (syscall_res < 0) { - _wapi_set_last_error_from_errno (); - - g_free (utf8_src); - g_free (utf8_dest); - MONO_ENTER_GC_SAFE; - close (src_fd); - MONO_EXIT_GC_SAFE; - - return(FALSE); - } - - if (!_wapi_stat (utf8_dest, &dest_st)) { - /* Before trying to open/create the dest, we need to report a 'file busy' - * error if src and dest are actually the same file. We do the check here to take - * advantage of the IOMAP capability */ - if (st.st_dev == dest_st.st_dev && st.st_ino == dest_st.st_ino) { - g_free (utf8_src); - g_free (utf8_dest); - MONO_ENTER_GC_SAFE; - close (src_fd); - MONO_EXIT_GC_SAFE; - - mono_w32error_set_last (ERROR_SHARING_VIOLATION); - return (FALSE); - } - - /* Take advantage of the fact that we already know the file exists and bail out - * early */ - if (fail_if_exists) { - g_free (utf8_src); - g_free (utf8_dest); - MONO_ENTER_GC_SAFE; - close (src_fd); - MONO_EXIT_GC_SAFE; - - mono_w32error_set_last (ERROR_ALREADY_EXISTS); - return (FALSE); - } - -#if HOST_DARWIN - /* If we attempt to use clonefile API we need to unlink the destination file - * first */ - if (clonefile_ptr != NULL) { - - /* Bail out if the destination is read-only */ - if (!is_file_writable (&dest_st, utf8_dest)) { - g_free (utf8_src); - g_free (utf8_dest); - MONO_ENTER_GC_SAFE; - close (src_fd); - MONO_EXIT_GC_SAFE; - - mono_w32error_set_last (ERROR_ACCESS_DENIED); - return (FALSE); - } - - _wapi_unlink (utf8_dest); - } -#endif - } - -#if HOST_DARWIN - if (clonefile_ptr != NULL) { - ret = _wapi_clonefile (utf8_src, utf8_dest, 0); - if (ret == 0 || (errno != ENOTSUP && errno != EXDEV)) { - g_free (utf8_src); - g_free (utf8_dest); - MONO_ENTER_GC_SAFE; - close (src_fd); - MONO_EXIT_GC_SAFE; - - if (ret == 0) { - return (TRUE); - } else { - _wapi_set_last_error_from_errno (); - return (FALSE); - } - } - } -#endif - - if (fail_if_exists) { - dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_CREAT | O_EXCL, st.st_mode); - } else { - /* FIXME: it's bad that this code path potentially scans - * the directory twice due to the weird mono_w32error_set_last() - * behavior. */ - dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_TRUNC, st.st_mode); - if (dest_fd < 0) { - /* The file does not exist, try creating it */ - dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_CREAT | O_TRUNC, st.st_mode); - } else { - /* Apparently this error is set if we - * overwrite the dest file - */ - mono_w32error_set_last (ERROR_ALREADY_EXISTS); - } - } - if (dest_fd < 0) { - _wapi_set_last_error_from_errno (); - - g_free (utf8_src); - g_free (utf8_dest); - MONO_ENTER_GC_SAFE; - close (src_fd); - MONO_EXIT_GC_SAFE; - - return(FALSE); - } - - if (!write_file (src_fd, dest_fd, &st, TRUE)) - ret = FALSE; - - close (src_fd); - close (dest_fd); - -#ifdef HAVE_STRUCT_TIMEVAL - struct timeval times [2]; - memset (times, 0, sizeof (times)); - - convert_stattime_access_to_timeval (× [0], &st); - convert_stattime_mod_to_timeval (× [1], &st); - - ret_utime = _wapi_utimes (utf8_dest, times); -#else - struct utimbuf dest_time; - dest_time.modtime = st.st_mtime; - dest_time.actime = st.st_atime; - - ret_utime = _wapi_utime (utf8_dest, &dest_time); -#endif - if (ret_utime == -1) - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: file [%s] utime failed: %s", __func__, utf8_dest, g_strerror(errno)); - - g_free (utf8_src); - g_free (utf8_dest); - - return ret; -} - -static gchar* -convert_arg_to_utf8 (const gunichar2 *arg, const gchar *arg_name) -{ - gchar *utf8_ret; - ERROR_DECL (error); - - if (arg == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: %s is NULL", __func__, arg_name); - mono_w32error_set_last (ERROR_INVALID_NAME); - return NULL; - } - - utf8_ret = mono_unicode_to_external_checked (arg, error); - if (utf8_ret == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion of %s returned NULL; %s", - __func__, arg_name, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return NULL; - } - - return utf8_ret; -} - -static gboolean -ReplaceFile (const gunichar2 *replacedFileName, const gunichar2 *replacementFileName, const gunichar2 *backupFileName, guint32 replaceFlags, gpointer exclude, gpointer reserved) -{ - gint result, backup_fd = -1,replaced_fd = -1; - gchar *utf8_replacedFileName, *utf8_replacementFileName = NULL, *utf8_backupFileName = NULL; - struct stat stBackup; - gboolean ret = FALSE; - - if (!(utf8_replacedFileName = convert_arg_to_utf8 (replacedFileName, "replacedFileName"))) - return FALSE; - if (!(utf8_replacementFileName = convert_arg_to_utf8 (replacementFileName, "replacementFileName"))) - goto replace_cleanup; - if (backupFileName != NULL) { - if (!(utf8_backupFileName = convert_arg_to_utf8 (backupFileName, "backupFileName"))) - goto replace_cleanup; - } - - if (utf8_backupFileName) { - // Open the backup file for read so we can restore the file if an error occurs. - backup_fd = _wapi_open (utf8_backupFileName, O_RDONLY, 0); - result = _wapi_rename (utf8_replacedFileName, utf8_backupFileName); - if (result == -1) - goto replace_cleanup; - } - - result = _wapi_rename (utf8_replacementFileName, utf8_replacedFileName); - if (result == -1) { - _wapi_set_last_path_error_from_errno (NULL, utf8_replacementFileName); - _wapi_rename (utf8_backupFileName, utf8_replacedFileName); - if (backup_fd != -1 && !fstat (backup_fd, &stBackup)) { - replaced_fd = _wapi_open (utf8_backupFileName, O_WRONLY | O_CREAT | O_TRUNC, - stBackup.st_mode); - - if (replaced_fd == -1) - goto replace_cleanup; - - write_file (backup_fd, replaced_fd, &stBackup, FALSE); - } - - goto replace_cleanup; - } - - ret = TRUE; - -replace_cleanup: - g_free (utf8_replacedFileName); - g_free (utf8_replacementFileName); - g_free (utf8_backupFileName); - if (backup_fd != -1) { - MONO_ENTER_GC_SAFE; - close (backup_fd); - MONO_EXIT_GC_SAFE; - } - if (replaced_fd != -1) { - MONO_ENTER_GC_SAFE; - close (replaced_fd); - MONO_EXIT_GC_SAFE; - } - return ret; -} - -static gpointer -_wapi_stdhandle_create (gint fd, const gchar *name) -{ - gint flags; - FileHandle *filehandle; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: creating standard handle type %s, fd %d", __func__, name, fd); - - /* Check if fd is valid */ - do { - flags = fcntl(fd, F_GETFL); - } while (flags == -1 && errno == EINTR); - - if (flags == -1) { - /* Invalid fd. Not really much point checking for EBADF - * specifically - */ - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fcntl error on fd %d: %s", __func__, fd, g_strerror(errno)); - - mono_w32error_set_last (mono_w32error_unix_to_win32 (errno)); - return INVALID_HANDLE_VALUE; - } - - filehandle = file_data_create (MONO_FDTYPE_CONSOLE, fd); - filehandle->filename = g_strdup(name); - - switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) { - case O_RDONLY: - filehandle->fileaccess = GENERIC_READ; - break; - case O_WRONLY: - filehandle->fileaccess = GENERIC_WRITE; - break; - case O_RDWR: - filehandle->fileaccess = GENERIC_READ | GENERIC_WRITE; - break; - default: - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Can't figure out flags 0x%x", __func__, flags); - filehandle->fileaccess = 0; - break; - } - - /* some default security attributes might be needed */ - filehandle->security_attributes = 0; - - /* Apparently input handles can't be written to. (I don't - * know if output or error handles can't be read from.) - */ - if (fd == 0) - filehandle->fileaccess &= ~GENERIC_WRITE; - - filehandle->sharemode = 0; - filehandle->attrs = 0; - - if (!mono_fdhandle_try_insert ((MonoFDHandle*) filehandle)) { - /* we raced between 2 invocations of _wapi_stdhandle_create */ - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return GINT_TO_POINTER(fd); - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: returning handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd)); - - return GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd); -} - -enum { - STD_INPUT_HANDLE = -10, - STD_OUTPUT_HANDLE = -11, - STD_ERROR_HANDLE = -12, -}; - -static gpointer -mono_w32file_get_std_handle (gint stdhandle) -{ - FileHandle **filehandle; - gint fd; - const gchar *name; - - switch(stdhandle) { - case STD_INPUT_HANDLE: - fd = 0; - name = ""; - break; - - case STD_OUTPUT_HANDLE: - fd = 1; - name = ""; - break; - - case STD_ERROR_HANDLE: - fd = 2; - name = ""; - break; - - default: - g_assert_not_reached (); - } - - if (!mono_fdhandle_lookup_and_ref(fd, (MonoFDHandle**) &filehandle)) { - gpointer handle; - - handle = _wapi_stdhandle_create (fd, name); - if (handle == INVALID_HANDLE_VALUE) { - mono_w32error_set_last (ERROR_NO_MORE_FILES); - return INVALID_HANDLE_VALUE; - } - } - - return GINT_TO_POINTER (fd); -} - -static gboolean -mono_w32file_read_or_write (gboolean read, gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread, gint32 *win32error) -{ - MONO_REQ_GC_UNSAFE_MODE; - - FileHandle *filehandle; - gboolean ret = FALSE; - - gboolean const ref = mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle); - if (!ref) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - goto exit; - } - - switch (((MonoFDHandle*) filehandle)->type) { - case MONO_FDTYPE_FILE: - ret = (read ? file_read : file_write) (filehandle, buffer, numbytes, bytesread); - break; - case MONO_FDTYPE_CONSOLE: - ret = (read ? console_read : console_write) (filehandle, buffer, numbytes, bytesread); - break; - case MONO_FDTYPE_PIPE: - ret = (read ? pipe_read : pipe_write) (filehandle, buffer, numbytes, bytesread); - break; - default: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - break; - } - -exit: - if (ref) - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - if (!ret) - *win32error = mono_w32error_get_last (); - return ret; -} - -gboolean -mono_w32file_read (gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread, gint32 *win32error) -{ - return mono_w32file_read_or_write (TRUE, handle, buffer, numbytes, bytesread, win32error); -} - -gboolean -mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error) -{ - return mono_w32file_read_or_write (FALSE, handle, (gpointer)buffer, numbytes, byteswritten, win32error); -} - -gboolean -mono_w32file_flush (gpointer handle) -{ - FileHandle *filehandle; - gboolean ret; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - switch (((MonoFDHandle*) filehandle)->type) { - case MONO_FDTYPE_FILE: - ret = file_flush(filehandle); - break; - default: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; - } - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; -} - -gboolean -mono_w32file_truncate (gpointer handle) -{ - FileHandle *filehandle; - gboolean ret; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - switch (((MonoFDHandle*) filehandle)->type) { - case MONO_FDTYPE_FILE: - ret = file_setendoffile(filehandle); - break; - default: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; - } - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; -} - -guint32 -mono_w32file_seek (gpointer handle, gint32 movedistance, gint32 *highmovedistance, guint32 method) -{ - FileHandle *filehandle; - guint32 ret; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return INVALID_SET_FILE_POINTER; - } - - switch (((MonoFDHandle*) filehandle)->type) { - case MONO_FDTYPE_FILE: - ret = file_seek(filehandle, movedistance, highmovedistance, method); - break; - default: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return INVALID_SET_FILE_POINTER; - } - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; -} - -gint -mono_w32file_get_type(gpointer handle) -{ - FileHandle *filehandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FILE_TYPE_UNKNOWN; - } - - switch (((MonoFDHandle*) filehandle)->type) { - case MONO_FDTYPE_FILE: - ret = FILE_TYPE_DISK; - break; - case MONO_FDTYPE_CONSOLE: - ret = FILE_TYPE_CHAR; - break; - case MONO_FDTYPE_PIPE: - ret = FILE_TYPE_PIPE; - break; - default: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FILE_TYPE_UNKNOWN; - } - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; -} - -static guint32 -GetFileSize(gpointer handle, guint32 *highsize) -{ - FileHandle *filehandle; - guint32 ret; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return INVALID_FILE_SIZE; - } - - switch (((MonoFDHandle*) filehandle)->type) { - case MONO_FDTYPE_FILE: - ret = file_getfilesize(filehandle, highsize); - break; - default: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return INVALID_FILE_SIZE; - } - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; -} - -gboolean -mono_w32file_set_times(gpointer handle, const FILETIME *create_time, const FILETIME *access_time, const FILETIME *write_time) -{ - FileHandle *filehandle; - gboolean ret; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - switch (((MonoFDHandle*) filehandle)->type) { - case MONO_FDTYPE_FILE: - ret = file_setfiletime(filehandle, create_time, access_time, write_time); - break; - default: - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; - } - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; -} - -/* A tick is a 100-nanosecond interval. File time epoch is Midnight, - * January 1 1601 GMT - */ - -#define isleap(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0)) - -static const guint16 mon_yday[2][13]={ - {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, - {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}, -}; - -gboolean -mono_w32file_filetime_to_systemtime(const FILETIME *file_time, SYSTEMTIME *system_time) -{ - gint64 file_ticks, totaldays, rem, y; - const guint16 *ip; - - if(system_time==NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: system_time NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return(FALSE); - } - - file_ticks=((gint64)file_time->dwHighDateTime << 32) + - file_time->dwLowDateTime; - - /* Really compares if file_ticks>=0x8000000000000000 - * (LLONG_MAX+1) but we're working with a signed value for the - * year and day calculation to work later - */ - if(file_ticks<0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: file_time too big", __func__); - - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return(FALSE); - } - - totaldays=(file_ticks / TICKS_PER_DAY); - rem = file_ticks % TICKS_PER_DAY; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: totaldays: %" G_GINT64_FORMAT " rem: %" G_GINT64_FORMAT, __func__, - totaldays, rem); - - system_time->wHour=rem/TICKS_PER_HOUR; - rem %= TICKS_PER_HOUR; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Hour: %d rem: %" G_GINT64_FORMAT, __func__, - system_time->wHour, rem); - - system_time->wMinute = rem / TICKS_PER_MINUTE; - rem %= TICKS_PER_MINUTE; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Minute: %d rem: %" G_GINT64_FORMAT, __func__, - system_time->wMinute, rem); - - system_time->wSecond = rem / TICKS_PER_SECOND; - rem %= TICKS_PER_SECOND; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Second: %d rem: %" G_GINT64_FORMAT, __func__, - system_time->wSecond, rem); - - system_time->wMilliseconds = rem / TICKS_PER_MILLISECOND; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Milliseconds: %d", __func__, - system_time->wMilliseconds); - - /* January 1, 1601 was a Monday, according to Emacs calendar */ - system_time->wDayOfWeek = ((1 + totaldays) % 7) + 1; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Day of week: %d", __func__, system_time->wDayOfWeek); - - /* This algorithm to find year and month given days from epoch - * from glibc - */ - y=1601; - -#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) -#define LEAPS_THRU_END_OF(y) (DIV(y, 4) - DIV (y, 100) + DIV (y, 400)) - - while(totaldays < 0 || totaldays >= (isleap(y)?366:365)) { - /* Guess a corrected year, assuming 365 days per year */ - gint64 yg = y + totaldays / 365 - (totaldays % 365 < 0); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: totaldays: %" G_GINT64_FORMAT " yg: %" G_GINT64_FORMAT " y: %" G_GINT64_FORMAT, __func__, - totaldays, yg, y); - g_message("%s: LEAPS(yg): %li LEAPS(y): %li", __func__, - LEAPS_THRU_END_OF(yg-1), LEAPS_THRU_END_OF(y-1)); - - /* Adjust days and y to match the guessed year. */ - totaldays -= ((yg - y) * 365 - + LEAPS_THRU_END_OF (yg - 1) - - LEAPS_THRU_END_OF (y - 1)); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: totaldays: %" G_GINT64_FORMAT, - __func__, totaldays); - y = yg; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: y: %" G_GINT64_FORMAT, __func__, y); - } - - system_time->wYear = y; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Year: %d", __func__, system_time->wYear); - - ip = mon_yday[isleap(y)]; - - for(y=11; totaldays < ip[y]; --y) { - continue; - } - totaldays-=ip[y]; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: totaldays: %" G_GINT64_FORMAT, __func__, totaldays); - - system_time->wMonth = y + 1; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Month: %d", __func__, system_time->wMonth); - - system_time->wDay = totaldays + 1; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Day: %d", __func__, system_time->wDay); - - return(TRUE); -} - -static void -findhandle_destroy (gpointer data) -{ - FindHandle *findhandle; - - findhandle = (FindHandle*) data; - g_assert (findhandle); - - mono_coop_mutex_destroy (&findhandle->mutex); - - if (findhandle->namelist) - g_strfreev (findhandle->namelist); - if (findhandle->dir_part) - g_free (findhandle->dir_part); - - g_free (findhandle); -} - -static FindHandle* -findhandle_create (void) -{ - FindHandle* findhandle; - - findhandle = g_new0 (FindHandle, 1); - mono_refcount_init (findhandle, findhandle_destroy); - - mono_coop_mutex_init (&findhandle->mutex); - - return findhandle; -} - -static void -findhandle_insert (FindHandle *findhandle) -{ - mono_coop_mutex_lock (&finds_mutex); - - if (g_hash_table_lookup_extended (finds, (gpointer) findhandle, NULL, NULL)) - g_error("%s: duplicate Find handle %p", __func__, (gpointer) findhandle); - - g_hash_table_insert (finds, (gpointer) findhandle, findhandle); - - mono_coop_mutex_unlock (&finds_mutex); -} - -static gboolean -findhandle_lookup_and_ref (gpointer handle, FindHandle **findhandle) -{ - mono_coop_mutex_lock (&finds_mutex); - - if (!g_hash_table_lookup_extended (finds, handle, NULL, (gpointer*) findhandle)) { - mono_coop_mutex_unlock (&finds_mutex); - return FALSE; - } - - mono_refcount_inc (*findhandle); - - mono_coop_mutex_unlock (&finds_mutex); - - return TRUE; -} - -static void -findhandle_unref (FindHandle *findhandle) -{ - mono_refcount_dec (findhandle); -} - -static gboolean -findhandle_close (gpointer handle) -{ - FindHandle *findhandle; - gboolean removed; - - mono_coop_mutex_lock (&finds_mutex); - - if (!g_hash_table_lookup_extended (finds, handle, NULL, (gpointer*) &findhandle)) { - mono_coop_mutex_unlock (&finds_mutex); - - return FALSE; - } - - removed = g_hash_table_remove (finds, (gpointer) findhandle); - g_assert (removed); - - mono_coop_mutex_unlock (&finds_mutex); - - return TRUE; -} - -static void -finds_remove (gpointer data) -{ - FindHandle* findhandle; - - findhandle = (FindHandle*) data; - g_assert (findhandle); - - mono_refcount_dec (findhandle); -} - -gpointer -mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data) -{ - FindHandle *findhandle; - gchar *utf8_pattern = NULL, *dir_part, *entry_part, **namelist; - gint result; - ERROR_DECL (error); - - if (pattern == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: pattern is NULL", __func__); - - mono_w32error_set_last (ERROR_PATH_NOT_FOUND); - return(INVALID_HANDLE_VALUE); - } - - utf8_pattern = mono_unicode_to_external_checked (pattern, error); - if (utf8_pattern == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); - return(INVALID_HANDLE_VALUE); - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: looking for [%s]", __func__, utf8_pattern); - - /* Figure out which bit of the pattern is the directory */ - dir_part = _wapi_dirname (utf8_pattern); - entry_part = _wapi_basename (utf8_pattern); - -#if 0 - /* Don't do this check for now, it breaks if directories - * really do have metachars in their names (see bug 58116). - * FIXME: Figure out a better solution to keep some checks... - */ - if (strchr (dir_part, '*') || strchr (dir_part, '?')) { - mono_w32error_set_last (ERROR_INVALID_NAME); - g_free (dir_part); - g_free (entry_part); - g_free (utf8_pattern); - return(INVALID_HANDLE_VALUE); - } -#endif - - /* The pattern can specify a directory or a set of files. - * - * The pattern can have wildcard characters ? and *, but only - * in the section after the last directory delimiter. (Return - * ERROR_INVALID_NAME if there are wildcards in earlier path - * sections.) "*" has the usual 0-or-more chars meaning. "?" - * means "match one character", "??" seems to mean "match one - * or two characters", "???" seems to mean "match one, two or - * three characters", etc. Windows will also try and match - * the mangled "short name" of files, so 8 character patterns - * with wildcards will show some surprising results. - * - * All the written documentation I can find says that '?' - * should only match one character, and doesn't mention '??', - * '???' etc. I'm going to assume that the strict behaviour - * (ie '???' means three and only three characters) is the - * correct one, because that lets me use fnmatch(3) rather - * than mess around with regexes. - */ - - namelist = NULL; - result = _wapi_io_scandir (dir_part, entry_part, - &namelist); - - if (result == 0) { - /* No files, which windows seems to call - * FILE_NOT_FOUND - */ - mono_w32error_set_last (ERROR_FILE_NOT_FOUND); - g_free (utf8_pattern); - g_free (entry_part); - g_free (dir_part); - g_strfreev (namelist); - return (INVALID_HANDLE_VALUE); - } - - if (result < 0) { - _wapi_set_last_path_error_from_errno (dir_part, NULL); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: scandir error: %s", __func__, g_strerror (errno)); - g_free (utf8_pattern); - g_free (entry_part); - g_free (dir_part); - g_strfreev (namelist); - return (INVALID_HANDLE_VALUE); - } - - g_free (utf8_pattern); - g_free (entry_part); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Got %d matches", __func__, result); - - findhandle = findhandle_create (); - findhandle->namelist = namelist; - findhandle->dir_part = dir_part; - findhandle->num = result; - findhandle->count = 0; - - findhandle_insert (findhandle); - - if (!mono_w32file_find_next ((gpointer) findhandle, find_data)) { - mono_w32file_find_close ((gpointer) findhandle); - mono_w32error_set_last (ERROR_NO_MORE_FILES); - return INVALID_HANDLE_VALUE; - } - - return (gpointer) findhandle; -} - -gboolean -mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data) -{ - FindHandle *findhandle; - struct stat buf, linkbuf; - gint result; - gchar *filename; - gchar *utf8_filename, *utf8_basename; - gunichar2 *utf16_basename; - time_t create_time; - glong bytes; - gboolean ret = FALSE; - - if (!findhandle_lookup_and_ref (handle, &findhandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - mono_coop_mutex_lock (&findhandle->mutex); - -retry: - if (findhandle->count >= findhandle->num) { - mono_w32error_set_last (ERROR_NO_MORE_FILES); - goto cleanup; - } - - /* stat next match */ - - filename = g_build_filename (findhandle->dir_part, findhandle->namelist[findhandle->count ++], (const char*)NULL); - - result = _wapi_stat (filename, &buf); - if (result == -1 && errno == ENOENT) { - /* Might be a dangling symlink */ - result = _wapi_lstat (filename, &buf); - } - - if (result != 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: stat failed: %s", __func__, filename); - - g_free (filename); - goto retry; - } - - result = _wapi_lstat (filename, &linkbuf); - if (result != 0) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: lstat failed: %s", __func__, filename); - - g_free (filename); - goto retry; - } - - utf8_filename = mono_utf8_from_external (filename); - if (utf8_filename == NULL) { - /* We couldn't turn this filename into utf8 (eg the - * encoding of the name wasn't convertible), so just - * ignore it. - */ - g_warning ("%s: Bad encoding for '%s'\nConsider using MONO_EXTERNAL_ENCODINGS\n", __func__, filename); - - g_free (filename); - goto retry; - } - g_free (filename); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Found [%s]", __func__, utf8_filename); - - /* fill data block */ - - if (buf.st_mtime < buf.st_ctime) - create_time = buf.st_mtime; - else - create_time = buf.st_ctime; - - find_data->dwFileAttributes = _wapi_stat_to_file_attributes (utf8_filename, &buf, &linkbuf); - - time_t_to_filetime (create_time, &find_data->ftCreationTime); - time_t_to_filetime (buf.st_atime, &find_data->ftLastAccessTime); - time_t_to_filetime (buf.st_mtime, &find_data->ftLastWriteTime); - - if (find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - find_data->nFileSizeHigh = 0; - find_data->nFileSizeLow = 0; - } else { - find_data->nFileSizeHigh = buf.st_size >> 32; - find_data->nFileSizeLow = buf.st_size & 0xFFFFFFFF; - } - - find_data->dwReserved0 = 0; - find_data->dwReserved1 = 0; - - utf8_basename = _wapi_basename (utf8_filename); - utf16_basename = g_utf8_to_utf16 (utf8_basename, -1, NULL, &bytes, - NULL); - if(utf16_basename==NULL) { - g_free (utf8_basename); - g_free (utf8_filename); - goto retry; - } - ret = TRUE; - - /* utf16 is 2 * utf8 */ - bytes *= 2; - - memset (find_data->cFileName, '\0', (MAX_PATH*2)); - - /* Truncating a utf16 string like this might leave the last - * gchar incomplete - */ - memcpy (find_data->cFileName, utf16_basename, - bytes<(MAX_PATH*2)-2?bytes:(MAX_PATH*2)-2); - - find_data->cAlternateFileName [0] = 0; /* not used */ - - g_free (utf8_basename); - g_free (utf8_filename); - g_free (utf16_basename); - -cleanup: - mono_coop_mutex_unlock (&findhandle->mutex); - - findhandle_unref (findhandle); - - return(ret); -} - -gboolean -mono_w32file_find_close (gpointer handle) -{ - if (!findhandle_close (handle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - return TRUE; -} - -gboolean -mono_w32file_create_directory (const gunichar2 *name) -{ - gchar *utf8_name; - gint result; - ERROR_DECL (error); - - if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_name = mono_unicode_to_external_checked (name, error); - if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); - return FALSE; - } - - result = _wapi_mkdir (utf8_name, 0777); - - if (result == 0) { - g_free (utf8_name); - return TRUE; - } - - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - return FALSE; -} - -gboolean -mono_w32file_remove_directory (const gunichar2 *name) -{ - gchar *utf8_name; - gint result; - ERROR_DECL (error); - - if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_name = mono_unicode_to_external_checked (name, error); - if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); - return FALSE; - } - - result = _wapi_rmdir (utf8_name); - if (result == -1) { - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - - return(FALSE); - } - g_free (utf8_name); - - return(TRUE); -} - -guint32 -mono_w32file_get_attributes (const gunichar2 *name) -{ - gchar *utf8_name; - struct stat buf, linkbuf; - gint result; - guint32 ret; - ERROR_DECL (error); - - if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_name = mono_unicode_to_external_checked (name, error); - if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return (INVALID_FILE_ATTRIBUTES); - } - - result = _wapi_stat (utf8_name, &buf); - if (result == -1 && (errno == ENOENT || errno == ELOOP)) { - /* Might be a dangling symlink... */ - result = _wapi_lstat (utf8_name, &buf); - } - - if (result != 0) { - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - return (INVALID_FILE_ATTRIBUTES); - } - - result = _wapi_lstat (utf8_name, &linkbuf); - if (result != 0) { - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - return (INVALID_FILE_ATTRIBUTES); - } - - ret = _wapi_stat_to_file_attributes (utf8_name, &buf, &linkbuf); - - g_free (utf8_name); - - return(ret); -} - -gboolean -mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat) -{ - gchar *utf8_name; - - struct stat buf, linkbuf; - gint result; - ERROR_DECL (error); - - if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_name = mono_unicode_to_external_checked (name, error); - if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return FALSE; - } - - result = _wapi_stat (utf8_name, &buf); - if (result == -1 && errno == ENOENT) { - /* Might be a dangling symlink... */ - result = _wapi_lstat (utf8_name, &buf); - } - - if (result != 0) { - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - return FALSE; - } - - result = _wapi_lstat (utf8_name, &linkbuf); - if (result != 0) { - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - return(FALSE); - } - - /* fill stat block */ - - stat->attributes = _wapi_stat_to_file_attributes (utf8_name, &buf, &linkbuf); - stat->length = (stat->attributes & FILE_ATTRIBUTE_DIRECTORY) ? 0 : buf.st_size; - -#if HAVE_STRUCT_STAT_ST_ATIMESPEC - if (linkbuf.st_mtimespec.tv_sec < linkbuf.st_ctimespec.tv_sec || (linkbuf.st_mtimespec.tv_sec == linkbuf.st_ctimespec.tv_sec && linkbuf.st_mtimespec.tv_nsec < linkbuf.st_ctimespec.tv_nsec)) - stat->creation_time = linkbuf.st_mtimespec.tv_sec * TICKS_PER_SECOND + (linkbuf.st_mtimespec.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; - else - stat->creation_time = linkbuf.st_ctimespec.tv_sec * TICKS_PER_SECOND + (linkbuf.st_ctimespec.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; - - stat->last_access_time = linkbuf.st_atimespec.tv_sec * TICKS_PER_SECOND + (linkbuf.st_atimespec.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; - stat->last_write_time = linkbuf.st_mtimespec.tv_sec * TICKS_PER_SECOND + (linkbuf.st_mtimespec.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; -#elif HAVE_STRUCT_STAT_ST_ATIM - if (linkbuf.st_mtime < linkbuf.st_ctime || (linkbuf.st_mtime == linkbuf.st_ctime && linkbuf.st_mtim.tv_nsec < linkbuf.st_ctim.tv_nsec)) - stat->creation_time = linkbuf.st_mtime * TICKS_PER_SECOND + (linkbuf.st_mtim.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; - else - stat->creation_time = linkbuf.st_ctime * TICKS_PER_SECOND + (linkbuf.st_ctim.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; - - stat->last_access_time = linkbuf.st_atime * TICKS_PER_SECOND + (linkbuf.st_atim.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; - stat->last_write_time = linkbuf.st_mtime * TICKS_PER_SECOND + (linkbuf.st_mtim.tv_nsec / NANOSECONDS_PER_MICROSECOND) * TICKS_PER_MICROSECOND + CONVERT_BASE; -#else - stat->creation_time = (((guint64) (linkbuf.st_mtime < linkbuf.st_ctime ? linkbuf.st_mtime : linkbuf.st_ctime)) * TICKS_PER_SECOND) + CONVERT_BASE; - stat->last_access_time = (((guint64) (linkbuf.st_atime)) * TICKS_PER_SECOND) + CONVERT_BASE; - stat->last_write_time = (((guint64) (linkbuf.st_mtime)) * TICKS_PER_SECOND) + CONVERT_BASE; -#endif - - g_free (utf8_name); - return TRUE; -} - -gboolean -mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs) -{ - /* FIXME: think of something clever to do on unix */ - gchar *utf8_name; - struct stat buf; - gint result; - ERROR_DECL (error); - - /* - * Currently we only handle one *internal* case, with a value that is - * not standard: 0x80000000, which means `set executable bit' - */ - - if (name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); - - mono_w32error_set_last (ERROR_INVALID_NAME); - return(FALSE); - } - - utf8_name = mono_unicode_to_external_checked (name, error); - if (utf8_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); - return FALSE; - } - - result = _wapi_stat (utf8_name, &buf); - if (result == -1 && errno == ENOENT) { - /* Might be a dangling symlink... */ - result = _wapi_lstat (utf8_name, &buf); - } - - if (result != 0) { - _wapi_set_last_path_error_from_errno (NULL, utf8_name); - g_free (utf8_name); - return FALSE; - } - - /* Contrary to the documentation, ms allows NORMAL to be - * specified along with other attributes, so dont bother to - * catch that case here. - */ - if (attrs & FILE_ATTRIBUTE_READONLY) { - result = _wapi_chmod (utf8_name, buf.st_mode & ~(S_IWUSR | S_IWOTH | S_IWGRP)); - } else { - result = _wapi_chmod (utf8_name, buf.st_mode | S_IWUSR); - } - - /* Ignore the other attributes for now */ - - if (attrs & 0x80000000){ - mode_t exec_mask = 0; - - if ((buf.st_mode & S_IRUSR) != 0) - exec_mask |= S_IXUSR; - - if ((buf.st_mode & S_IRGRP) != 0) - exec_mask |= S_IXGRP; - - if ((buf.st_mode & S_IROTH) != 0) - exec_mask |= S_IXOTH; - -#if defined(HAVE_CHMOD) - MONO_ENTER_GC_SAFE; - result = chmod (utf8_name, buf.st_mode | exec_mask); - MONO_EXIT_GC_SAFE; -#else - result = -1; -#endif - } - /* Don't bother to reset executable (might need to change this - * policy) - */ - - g_free (utf8_name); - - return(TRUE); -} - -guint32 -mono_w32file_get_cwd (guint32 length, gunichar2 *buffer) -{ - gunichar2 *utf16_path; - glong count; - gsize bytes; - - if (getcwd ((gchar*)buffer, length) == NULL) { - if (errno == ERANGE) { /*buffer length is not big enough */ - gchar *path = g_get_current_dir (); /*FIXME g_get_current_dir doesn't work with broken paths and calling it just to know the path length is silly*/ - if (path == NULL) - return 0; - utf16_path = mono_unicode_from_external (path, &bytes); - g_free (utf16_path); - g_free (path); - return (bytes/2)+1; - } - _wapi_set_last_error_from_errno (); - return 0; - } - - utf16_path = mono_unicode_from_external ((gchar*)buffer, &bytes); - count = (bytes/2)+1; - g_assert (count <= length); /*getcwd must have failed before with ERANGE*/ - - /* Add the terminator */ - memset (buffer, '\0', bytes+2); - memcpy (buffer, utf16_path, bytes); - - g_free (utf16_path); - - return count; -} - -gboolean -mono_w32file_set_cwd (const gunichar2 *path) -{ - gchar *utf8_path; - gboolean result; - ERROR_DECL (error); - - if (path == NULL) { - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return(FALSE); - } - - utf8_path = mono_unicode_to_external_checked (path, error); - if (utf8_path == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - return FALSE; - } - - if (_wapi_chdir (utf8_path) != 0) { - _wapi_set_last_error_from_errno (); - result = FALSE; - } - else - result = TRUE; - - g_free (utf8_path); - return result; -} - -gboolean -mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size) -{ - FileHandle *read_filehandle, *write_filehandle; - gint filedes[2]; - gint ret; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Creating pipe", __func__); - - MONO_ENTER_GC_SAFE; - ret=pipe (filedes); - MONO_EXIT_GC_SAFE; - if (ret==-1) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Error creating pipe: (%d) %s", - __func__, errno, g_strerror (errno)); - - _wapi_set_last_error_from_errno (); - return FALSE; - } - - /* filedes[0] is open for reading, filedes[1] for writing */ - - read_filehandle = file_data_create (MONO_FDTYPE_PIPE, filedes[0]); - read_filehandle->fileaccess = GENERIC_READ; - - write_filehandle = file_data_create (MONO_FDTYPE_PIPE, filedes[1]); - write_filehandle->fileaccess = GENERIC_WRITE; - - mono_fdhandle_insert ((MonoFDHandle*) read_filehandle); - mono_fdhandle_insert ((MonoFDHandle*) write_filehandle); - - *readpipe = GINT_TO_POINTER(((MonoFDHandle*) read_filehandle)->fd); - *writepipe = GINT_TO_POINTER(((MonoFDHandle*) write_filehandle)->fd); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Returning pipe: read handle %p, write handle %p", - __func__, GINT_TO_POINTER(((MonoFDHandle*) read_filehandle)->fd), GINT_TO_POINTER(((MonoFDHandle*) write_filehandle)->fd)); - - return(TRUE); -} - -#ifdef HAVE_GETFSSTAT -/* Darwin has getfsstat */ -gint32 -mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf, MonoError *error) -{ - struct statfs *stats; - gint size, n, i; - gunichar2 *dir; - glong length, total = 0; - gint syscall_res; - - MONO_ENTER_GC_SAFE; - n = getfsstat (NULL, 0, MNT_NOWAIT); - MONO_EXIT_GC_SAFE; - if (n == -1) - return 0; - size = n * sizeof (struct statfs); - stats = (struct statfs *) g_malloc (size); - if (stats == NULL) - return 0; - MONO_ENTER_GC_SAFE; - syscall_res = getfsstat (stats, size, MNT_NOWAIT); - MONO_EXIT_GC_SAFE; - if (syscall_res == -1){ - g_free (stats); - return 0; - } - for (i = 0; i < n; i++){ - dir = g_utf8_to_utf16 (stats [i].f_mntonname, -1, NULL, &length, NULL); - if (total + length < len){ - memcpy (buf + total, dir, sizeof (gunichar2) * length); - buf [total+length] = 0; - } - g_free (dir); - total += length + 1; - } - if (total < len) - buf [total] = 0; - total++; - g_free (stats); - return total; -} -#elif _AIX -gint32 -mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf, MonoError *error) -{ - struct vmount *mounts; - // ret will first be the errno cond, then no of structs - int needsize, ret, total; - gunichar2 *dir; - glong length; - total = 0; - - MONO_ENTER_GC_SAFE; - ret = mntctl (MCTL_QUERY, sizeof(needsize), (char*)&needsize); - MONO_EXIT_GC_SAFE; - if (ret == -1) - return 0; - mounts = (struct vmount *) g_malloc (needsize); - if (mounts == NULL) - return 0; - MONO_ENTER_GC_SAFE; - ret = mntctl (MCTL_QUERY, needsize, (char*)mounts); - MONO_EXIT_GC_SAFE; if (ret == -1) { - g_free (mounts); - return 0; - } - - for (int i = 0; i < ret; i++) { - dir = g_utf8_to_utf16 (vmt2dataptr(mounts, VMT_STUB), -1, NULL, &length, NULL); - if (total + length < len){ - memcpy (buf + total, dir, sizeof (gunichar2) * length); - buf [total+length] = 0; - } - g_free (dir); - total += length + 1; - mounts = (struct vmount *)((char*)mounts + mounts->vmt_length); // next! - } - if (total < len) - buf [total] = 0; - total++; - g_free (mounts); - return total; -} -#else -/* In-place octal sequence replacement */ -static void -unescape_octal (gchar *str) -{ - gchar *rptr; - gchar *wptr; - - if (str == NULL) - return; - - rptr = wptr = str; - while (*rptr != '\0') { - if (*rptr == '\\') { - gchar c; - rptr++; - c = (*(rptr++) - '0') << 6; - c += (*(rptr++) - '0') << 3; - c += *(rptr++) - '0'; - *wptr++ = c; - } else if (wptr != rptr) { - *wptr++ = *rptr++; + if (errno == EINTR) { + ret = 0; } else { - rptr++; wptr++; - } - } - *wptr = '\0'; -} -static gint32 GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf); - -#if __linux__ -#define GET_LOGICAL_DRIVE_STRINGS_BUFFER 512 -#define GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER 512 -#define GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER 64 - -typedef struct -{ - glong total; - guint32 buffer_index; - guint32 mountpoint_index; - guint32 field_number; - guint32 allocated_size; - guint32 fsname_index; - guint32 fstype_index; - gchar mountpoint [GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER + 1]; - gchar *mountpoint_allocated; - gchar buffer [GET_LOGICAL_DRIVE_STRINGS_BUFFER]; - gchar fsname [GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER + 1]; - gchar fstype [GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER + 1]; - ssize_t nbytes; - gchar delimiter; - gboolean check_mount_source; -} LinuxMountInfoParseState; - -static gboolean GetLogicalDriveStrings_Mounts (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state); -static gboolean GetLogicalDriveStrings_MountInfo (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state); -static void append_to_mountpoint (LinuxMountInfoParseState *state); -static gboolean add_drive_string (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state); - -gint32 -mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf, MonoError *error) -{ - gint fd; - gint32 ret = 0; - LinuxMountInfoParseState state; - gboolean (*parser)(guint32, gunichar2*, LinuxMountInfoParseState*) = NULL; - - memset (buf, 0, len * sizeof (gunichar2)); - MONO_ENTER_GC_SAFE; - fd = open ("/proc/self/mountinfo", O_RDONLY); - MONO_EXIT_GC_SAFE; - if (fd != -1) - parser = GetLogicalDriveStrings_MountInfo; - else { - MONO_ENTER_GC_SAFE; - fd = open ("/proc/mounts", O_RDONLY); - MONO_EXIT_GC_SAFE; - if (fd != -1) - parser = GetLogicalDriveStrings_Mounts; - } - - if (!parser) { - ret = GetLogicalDriveStrings_Mtab (len, buf); - goto done_and_out; - } - - memset (&state, 0, sizeof (LinuxMountInfoParseState)); - state.field_number = 1; - state.delimiter = ' '; - - while (1) { - MONO_ENTER_GC_SAFE; - state.nbytes = read (fd, state.buffer, GET_LOGICAL_DRIVE_STRINGS_BUFFER); - MONO_EXIT_GC_SAFE; - if (!(state.nbytes > 0)) - break; - state.buffer_index = 0; - - while ((*parser)(len, buf, &state)) { - if (state.buffer [state.buffer_index] == '\n') { - gboolean quit = add_drive_string (len, buf, &state); - state.field_number = 1; - state.buffer_index++; - if (state.mountpoint_allocated) { - g_free (state.mountpoint_allocated); - state.mountpoint_allocated = NULL; - } - if (quit) { - ret = state.total; - goto done_and_out; - } - } - } - }; - ret = state.total; - - done_and_out: - if (fd != -1) { - MONO_ENTER_GC_SAFE; - close (fd); - MONO_EXIT_GC_SAFE; - } - return ret; -} - -static gboolean GetLogicalDriveStrings_Mounts (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state) -{ - gchar *ptr; - - if (state->field_number == 1) - state->check_mount_source = TRUE; - - while (state->buffer_index < (guint32)state->nbytes) { - if (state->buffer [state->buffer_index] == state->delimiter) { - state->field_number++; - switch (state->field_number) { - case 2: - state->mountpoint_index = 0; - break; - - case 3: - if (state->mountpoint_allocated) - state->mountpoint_allocated [state->mountpoint_index] = 0; - else - state->mountpoint [state->mountpoint_index] = 0; - break; - - default: - ptr = (gchar*)memchr (state->buffer + state->buffer_index, '\n', GET_LOGICAL_DRIVE_STRINGS_BUFFER - state->buffer_index); - if (ptr) - state->buffer_index = (ptr - (gchar*)state->buffer) - 1; - else - state->buffer_index = state->nbytes; - return TRUE; - } - state->buffer_index++; - continue; - } else if (state->buffer [state->buffer_index] == '\n') - return TRUE; - - switch (state->field_number) { - case 1: - if (state->check_mount_source) { - if (state->fsname_index == 0 && state->buffer [state->buffer_index] == '/') { - /* We can ignore the rest, it's a device - * path */ - state->check_mount_source = FALSE; - state->fsname [state->fsname_index++] = '/'; - break; - } - if (state->fsname_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER) - state->fsname [state->fsname_index++] = state->buffer [state->buffer_index]; - } - break; - - case 2: - append_to_mountpoint (state); - break; - - case 3: - if (state->fstype_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER) - state->fstype [state->fstype_index++] = state->buffer [state->buffer_index]; - break; - } - - state->buffer_index++; - } - - return FALSE; -} - -static gboolean GetLogicalDriveStrings_MountInfo (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state) -{ - while (state->buffer_index < (guint32)state->nbytes) { - if (state->buffer [state->buffer_index] == state->delimiter) { - state->field_number++; - switch (state->field_number) { - case 5: - state->mountpoint_index = 0; - break; - - case 6: - if (state->mountpoint_allocated) - state->mountpoint_allocated [state->mountpoint_index] = 0; - else - state->mountpoint [state->mountpoint_index] = 0; - break; - - case 7: - state->delimiter = '-'; - break; - - case 8: - state->delimiter = ' '; - break; - - case 10: - state->check_mount_source = TRUE; - break; - } - state->buffer_index++; - continue; - } else if (state->buffer [state->buffer_index] == '\n') - return TRUE; - - switch (state->field_number) { - case 5: - append_to_mountpoint (state); - break; - - case 9: - if (state->fstype_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER) - state->fstype [state->fstype_index++] = state->buffer [state->buffer_index]; - break; - - case 10: - if (state->check_mount_source) { - if (state->fsname_index == 0 && state->buffer [state->buffer_index] == '/') { - /* We can ignore the rest, it's a device - * path */ - state->check_mount_source = FALSE; - state->fsname [state->fsname_index++] = '/'; - break; - } - if (state->fsname_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER) - state->fsname [state->fsname_index++] = state->buffer [state->buffer_index]; - } - break; - } - - state->buffer_index++; - } - - return FALSE; -} + _wapi_set_last_error_from_errno (); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); -static void -append_to_mountpoint (LinuxMountInfoParseState *state) -{ - gchar ch = state->buffer [state->buffer_index]; - if (state->mountpoint_allocated) { - if (state->mountpoint_index >= state->allocated_size) { - guint32 newsize = (state->allocated_size << 1) + 1; - gchar *newbuf = (gchar *)g_malloc0 (newsize * sizeof (gchar)); - - memcpy (newbuf, state->mountpoint_allocated, state->mountpoint_index); - g_free (state->mountpoint_allocated); - state->mountpoint_allocated = newbuf; - state->allocated_size = newsize; + return(FALSE); } - state->mountpoint_allocated [state->mountpoint_index++] = ch; - } else { - if (state->mountpoint_index >= GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER) { - state->allocated_size = (state->mountpoint_index << 1) + 1; - state->mountpoint_allocated = (gchar *)g_malloc0 (state->allocated_size * sizeof (gchar)); - memcpy (state->mountpoint_allocated, state->mountpoint, state->mountpoint_index); - state->mountpoint_allocated [state->mountpoint_index++] = ch; - } else - state->mountpoint [state->mountpoint_index++] = ch; } + if (byteswritten != NULL) { + *byteswritten = ret; + } + return(TRUE); } static gboolean -add_drive_string (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state) -{ - gboolean quit = FALSE; - gboolean ignore_entry; - - if (state->fsname_index == 1 && state->fsname [0] == '/') - ignore_entry = FALSE; - else if (memcmp ("overlay", state->fsname, state->fsname_index) == 0 || - memcmp ("aufs", state->fstype, state->fstype_index) == 0) { - /* Don't ignore overlayfs and aufs - these might be used on Docker - * (https://bugzilla.xamarin.com/show_bug.cgi?id=31021) */ - ignore_entry = FALSE; - } else if (state->fsname_index == 0 || memcmp ("none", state->fsname, state->fsname_index) == 0) { - ignore_entry = TRUE; - } else if (state->fstype_index >= 5 && memcmp ("fuse.", state->fstype, 5) == 0) { - /* Ignore GNOME's gvfs */ - if (state->fstype_index == 21 && memcmp ("fuse.gvfs-fuse-daemon", state->fstype, state->fstype_index) == 0) - ignore_entry = TRUE; - else - ignore_entry = FALSE; - } else if (state->fstype_index == 3 && memcmp ("nfs", state->fstype, state->fstype_index) == 0) - ignore_entry = FALSE; - else - ignore_entry = TRUE; - - if (!ignore_entry) { - gunichar2 *dir; - glong length; - gchar *mountpoint = state->mountpoint_allocated ? state->mountpoint_allocated : state->mountpoint; - - unescape_octal (mountpoint); - dir = g_utf8_to_utf16 (mountpoint, -1, NULL, &length, NULL); - if (state->total + length + 1 > len) { - quit = TRUE; - state->total = len * 2; - } else { - length++; - memcpy (buf + state->total, dir, sizeof (gunichar2) * length); - state->total += length; - } - g_free (dir); - } - state->fsname_index = 0; - state->fstype_index = 0; - - return quit; -} -#else -gint32 -mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf, MonoError *error) -{ - return GetLogicalDriveStrings_Mtab (len, buf); -} -#endif -static gint32 -GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf) +console_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *byteswritten) { - FILE *fp; - gunichar2 *ptr, *dir; - glong length, total = 0; - gchar buffer [512]; - gchar **splitted; - - memset (buf, 0, sizeof (gunichar2) * (len + 1)); - buf [0] = '/'; - buf [1] = 0; - buf [2] = 0; - - /* Sigh, mntent and friends don't work well. - * It stops on the first line that doesn't begin with a '/'. - * (linux 2.6.5, libc 2.3.2.ds1-12) - Gonz */ - MONO_ENTER_GC_SAFE; - fp = fopen ("/etc/mtab", "rt"); - MONO_EXIT_GC_SAFE; - if (fp == NULL) { - MONO_ENTER_GC_SAFE; - fp = fopen ("/etc/mnttab", "rt"); - MONO_EXIT_GC_SAFE; - if (fp == NULL) - return 1; - } - - ptr = buf; - while (1) { - gchar *fgets_res; - MONO_ENTER_GC_SAFE; - fgets_res = fgets (buffer, 512, fp); - MONO_EXIT_GC_SAFE; - if (!fgets_res) - break; - if (*buffer != '/') - continue; - - splitted = g_strsplit (buffer, " ", 0); - if (!*splitted || !*(splitted + 1)) { - g_strfreev (splitted); - continue; - } - - unescape_octal (*(splitted + 1)); - dir = g_utf8_to_utf16 (*(splitted + 1), -1, NULL, &length, NULL); - g_strfreev (splitted); - if (total + length + 1 > len) { - MONO_ENTER_GC_SAFE; - fclose (fp); - MONO_EXIT_GC_SAFE; - g_free (dir); - return len * 2; /* guess */ - } - - memcpy (ptr + total, dir, sizeof (gunichar2) * length); - g_free (dir); - total += length + 1; + gint ret; + MonoThreadInfo *info = mono_thread_info_current (); + + if(byteswritten!=NULL) { + *byteswritten=0; } - - MONO_ENTER_GC_SAFE; - fclose (fp); - MONO_EXIT_GC_SAFE; - return total; -/* Commented out, does not work with my mtab!!! - Gonz */ -#ifdef NOTENABLED /* HAVE_MNTENT_H */ -{ - FILE *fp; - struct mntent *mnt; - gunichar2 *ptr, *dir; - glong len, total = 0; + if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - MONO_ENTER_GC_SAFE; - fp = setmntent ("/etc/mtab", "rt"); - MONO_EXIT_GC_SAFE; - if (fp == NULL) { - MONO_ENTER_GC_SAFE; - fp = setmntent ("/etc/mnttab", "rt"); - MONO_EXIT_GC_SAFE; - if (fp == NULL) - return; + mono_w32error_set_last (ERROR_ACCESS_DENIED); + return(FALSE); } - - ptr = buf; - while (1) { + + do { MONO_ENTER_GC_SAFE; - mnt = getmntent (fp); + ret = write(((MonoFDHandle*) filehandle)->fd, buffer, numbytes); MONO_EXIT_GC_SAFE; - if (mnt == NULL) - break; - g_print ("GOT %s\n", mnt->mnt_dir); - dir = g_utf8_to_utf16 (mnt->mnt_dir, &len, NULL, NULL, NULL); - if (total + len + 1 > len) { - MONO_ENTER_GC_SAFE; - endmntent (fp); - MONO_EXIT_GC_SAFE; - return len * 2; /* guess */ - } - - memcpy (ptr + total, dir, sizeof (gunichar2) * len); - g_free (dir); - total += len + 1; - } - - MONO_ENTER_GC_SAFE; - endmntent (fp); - MONO_EXIT_GC_SAFE; - return total; -} -#endif -} -#endif - -#ifndef PLATFORM_NO_DRIVEINFO -gboolean -mono_w32file_get_disk_free_space (const gunichar2 *path_name, guint64 *free_bytes_avail, guint64 *total_number_of_bytes, guint64 *total_number_of_free_bytes) -{ - g_assert (free_bytes_avail); - g_assert (total_number_of_bytes); - g_assert (total_number_of_free_bytes); - -#if defined(HAVE_STATVFS) || defined(HAVE_STATFS) -#ifdef HAVE_STATVFS - struct statvfs fsstat; -#elif defined(HAVE_STATFS) - struct statfs fsstat; -#endif - gchar *utf8_path_name; - gint ret; - unsigned long block_size; - ERROR_DECL (error); + } while (ret == -1 && errno == EINTR && + !mono_thread_info_is_interrupt_state (info)); - if (path_name == NULL) { - utf8_path_name = g_strdup (g_get_current_dir()); - if (utf8_path_name == NULL) { - mono_w32error_set_last (ERROR_DIRECTORY); - return(FALSE); - } - } - else { - utf8_path_name = mono_unicode_to_external_checked (path_name, error); - if (utf8_path_name == NULL) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); + if (ret == -1) { + if (errno == EINTR) { + ret = 0; + } else { + _wapi_set_last_error_from_errno (); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__, ((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - mono_error_cleanup (error); - mono_w32error_set_last (ERROR_INVALID_NAME); return(FALSE); } } - - do { -#ifdef HAVE_STATVFS - MONO_ENTER_GC_SAFE; - ret = statvfs (utf8_path_name, &fsstat); - MONO_EXIT_GC_SAFE; - block_size = fsstat.f_frsize; -#elif defined(HAVE_STATFS) - MONO_ENTER_GC_SAFE; - ret = statfs (utf8_path_name, &fsstat); - MONO_EXIT_GC_SAFE; - block_size = fsstat.f_bsize; -#endif - } while(ret == -1 && errno == EINTR); - - g_free(utf8_path_name); - - if (ret == -1) { - _wapi_set_last_error_from_errno (); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: statvfs failed: %s", __func__, g_strerror (errno)); - return(FALSE); + if(byteswritten!=NULL) { + *byteswritten=ret; } - - /* total number of free bytes for non-root */ - *free_bytes_avail = block_size * (guint64)fsstat.f_bavail; - - /* total number of bytes available for non-root */ - *total_number_of_bytes = block_size * (guint64)fsstat.f_blocks; - - /* total number of bytes available for root */ - *total_number_of_free_bytes = block_size * (guint64)fsstat.f_bfree; -#endif + return(TRUE); } -#endif // PLATFORM_NO_DRIVEINFO - -/* - * General Unix support - */ -typedef struct { - guint32 drive_type; -#if __linux__ - // http://man7.org/linux/man-pages/man2/statfs.2.html - // - // The __fsword_t type used for various fields in the statfs structure - // definition is a glibc internal type, not intended for public use. - // This leaves the programmer in a bit of a conundrum when trying to - // copy or compare these fields to local variables in a program. Using - // unsigned int for such variables suffices on most systems. - // - // Let's hope "most" is enough, and that it works with other libc. - unsigned fstypeid; -#endif - const gchar* fstype; -} _wapi_drive_type; - -static const _wapi_drive_type _wapi_drive_types[] = { -#if HOST_DARWIN - { DRIVE_REMOTE, "afp" }, - { DRIVE_REMOTE, "afpfs" }, - { DRIVE_REMOTE, "autofs" }, - { DRIVE_CDROM, "cddafs" }, - { DRIVE_CDROM, "cd9660" }, - { DRIVE_RAMDISK, "devfs" }, - { DRIVE_RAMDISK, "nullfs" }, - { DRIVE_FIXED, "exfat" }, - { DRIVE_RAMDISK, "fdesc" }, - { DRIVE_REMOTE, "ftp" }, - { DRIVE_FIXED, "hfs" }, - { DRIVE_FIXED, "apfs" }, - { DRIVE_REMOTE, "kbfuse" }, - { DRIVE_FIXED, "msdos" }, - { DRIVE_REMOTE, "nfs" }, - { DRIVE_FIXED, "ntfs" }, - { DRIVE_REMOTE, "smbfs" }, - { DRIVE_FIXED, "udf" }, - { DRIVE_REMOTE, "webdav" }, - { DRIVE_FIXED, "ufsd_NTFS"}, - { DRIVE_UNKNOWN, NULL } -#elif __linux__ - { DRIVE_FIXED, ADFS_SUPER_MAGIC, "adfs"}, - { DRIVE_FIXED, AFFS_SUPER_MAGIC, "affs"}, - { DRIVE_REMOTE, AFS_SUPER_MAGIC, "afs"}, - { DRIVE_RAMDISK, AUTOFS_SUPER_MAGIC, "autofs"}, - { DRIVE_RAMDISK, AUTOFS_SBI_MAGIC, "autofs4"}, - { DRIVE_REMOTE, CODA_SUPER_MAGIC, "coda" }, - { DRIVE_RAMDISK, CRAMFS_MAGIC, "cramfs"}, - { DRIVE_RAMDISK, CRAMFS_MAGIC_WEND, "cramfs"}, - { DRIVE_REMOTE, CIFS_MAGIC_NUMBER, "cifs"}, - { DRIVE_RAMDISK, DEBUGFS_MAGIC, "debugfs"}, - { DRIVE_RAMDISK, SYSFS_MAGIC, "sysfs"}, - { DRIVE_RAMDISK, SECURITYFS_MAGIC, "securityfs"}, - { DRIVE_RAMDISK, SELINUX_MAGIC, "selinuxfs"}, - { DRIVE_RAMDISK, RAMFS_MAGIC, "ramfs"}, - { DRIVE_FIXED, SQUASHFS_MAGIC, "squashfs"}, - { DRIVE_FIXED, EFS_SUPER_MAGIC, "efs"}, - { DRIVE_FIXED, EXT2_SUPER_MAGIC, "ext"}, - { DRIVE_FIXED, EXT3_SUPER_MAGIC, "ext"}, - { DRIVE_FIXED, EXT4_SUPER_MAGIC, "ext"}, - { DRIVE_REMOTE, XENFS_SUPER_MAGIC, "xenfs"}, - { DRIVE_FIXED, BTRFS_SUPER_MAGIC, "btrfs"}, - { DRIVE_FIXED, HFS_SUPER_MAGIC, "hfs"}, - { DRIVE_FIXED, HFSPLUS_SUPER_MAGIC, "hfsplus"}, - { DRIVE_FIXED, HPFS_SUPER_MAGIC, "hpfs"}, - { DRIVE_RAMDISK, HUGETLBFS_MAGIC, "hugetlbfs"}, - { DRIVE_CDROM, ISOFS_SUPER_MAGIC, "iso"}, - { DRIVE_FIXED, JFFS2_SUPER_MAGIC, "jffs2"}, - { DRIVE_RAMDISK, ANON_INODE_FS_MAGIC, "anon_inode"}, - { DRIVE_FIXED, JFS_SUPER_MAGIC, "jfs"}, - { DRIVE_FIXED, MINIX_SUPER_MAGIC, "minix"}, - { DRIVE_FIXED, MINIX_SUPER_MAGIC2, "minix v2"}, - { DRIVE_FIXED, MINIX2_SUPER_MAGIC, "minix2"}, - { DRIVE_FIXED, MINIX2_SUPER_MAGIC2, "minix2 v2"}, - { DRIVE_FIXED, MINIX3_SUPER_MAGIC, "minix3"}, - { DRIVE_FIXED, MSDOS_SUPER_MAGIC, "msdos"}, - { DRIVE_REMOTE, NCP_SUPER_MAGIC, "ncp"}, - { DRIVE_REMOTE, NFS_SUPER_MAGIC, "nfs"}, - { DRIVE_FIXED, NTFS_SB_MAGIC, "ntfs"}, - { DRIVE_RAMDISK, OPENPROM_SUPER_MAGIC, "openpromfs"}, - { DRIVE_RAMDISK, PROC_SUPER_MAGIC, "proc"}, - { DRIVE_FIXED, QNX4_SUPER_MAGIC, "qnx4"}, - { DRIVE_FIXED, REISERFS_SUPER_MAGIC, "reiserfs"}, - { DRIVE_RAMDISK, ROMFS_MAGIC, "romfs"}, - { DRIVE_REMOTE, SMB_SUPER_MAGIC, "samba"}, - { DRIVE_RAMDISK, CGROUP_SUPER_MAGIC, "cgroupfs"}, - { DRIVE_RAMDISK, FUTEXFS_SUPER_MAGIC, "futexfs"}, - { DRIVE_FIXED, SYSV2_SUPER_MAGIC, "sysv2"}, - { DRIVE_FIXED, SYSV4_SUPER_MAGIC, "sysv4"}, - { DRIVE_RAMDISK, TMPFS_MAGIC, "tmpfs"}, - { DRIVE_RAMDISK, DEVPTS_SUPER_MAGIC, "devpts"}, - { DRIVE_CDROM, UDF_SUPER_MAGIC, "udf"}, - { DRIVE_FIXED, UFS_MAGIC, "ufs"}, - { DRIVE_FIXED, UFS_MAGIC_BW, "ufs"}, - { DRIVE_FIXED, UFS2_MAGIC, "ufs2"}, - { DRIVE_FIXED, UFS_CIGAM, "ufs"}, - { DRIVE_RAMDISK, USBDEVICE_SUPER_MAGIC, "usbdev"}, - { DRIVE_FIXED, XENIX_SUPER_MAGIC, "xenix"}, - { DRIVE_FIXED, XFS_SB_MAGIC, "xfs"}, - { DRIVE_RAMDISK, FUSE_SUPER_MAGIC, "fuse"}, - { DRIVE_FIXED, V9FS_MAGIC, "9p"}, - { DRIVE_REMOTE, CEPH_SUPER_MAGIC, "ceph"}, - { DRIVE_RAMDISK, CONFIGFS_MAGIC, "configfs"}, - { DRIVE_RAMDISK, ECRYPTFS_SUPER_MAGIC, "eCryptfs"}, - { DRIVE_FIXED, EXOFS_SUPER_MAGIC, "exofs"}, - { DRIVE_FIXED, VXFS_SUPER_MAGIC, "vxfs"}, - { DRIVE_FIXED, VXFS_OLT_MAGIC, "vxfs_olt"}, - { DRIVE_REMOTE, GFS2_MAGIC, "gfs2"}, - { DRIVE_FIXED, LOGFS_MAGIC_U32, "logfs"}, - { DRIVE_FIXED, OCFS2_SUPER_MAGIC, "ocfs2"}, - { DRIVE_FIXED, OMFS_MAGIC, "omfs"}, - { DRIVE_FIXED, UBIFS_SUPER_MAGIC, "ubifs"}, - { DRIVE_UNKNOWN, 0, NULL} -#else - { DRIVE_RAMDISK, "ramfs" }, - { DRIVE_RAMDISK, "tmpfs" }, - { DRIVE_RAMDISK, "proc" }, - { DRIVE_RAMDISK, "sysfs" }, - { DRIVE_RAMDISK, "debugfs" }, - { DRIVE_RAMDISK, "devpts" }, - { DRIVE_RAMDISK, "securityfs" }, - { DRIVE_RAMDISK, "procfs" }, // AIX procfs - { DRIVE_RAMDISK, "namefs" }, // AIX soft mounts - { DRIVE_RAMDISK, "nullfs" }, - { DRIVE_CDROM, "iso9660" }, - { DRIVE_CDROM, "cdrfs" }, // AIX ISO9660 CDs - { DRIVE_CDROM, "udfs" }, // AIX UDF CDs - { DRIVE_CDROM, "QOPT" }, // IBM i CD mount - { DRIVE_FIXED, "ext2" }, - { DRIVE_FIXED, "ext3" }, - { DRIVE_FIXED, "ext4" }, - { DRIVE_FIXED, "sysv" }, - { DRIVE_FIXED, "reiserfs" }, - { DRIVE_FIXED, "ufs" }, - { DRIVE_FIXED, "vfat" }, - { DRIVE_FIXED, "msdos" }, - { DRIVE_FIXED, "udf" }, - { DRIVE_FIXED, "hfs" }, - { DRIVE_FIXED, "hpfs" }, - { DRIVE_FIXED, "qnx4" }, - { DRIVE_FIXED, "ntfs" }, - { DRIVE_FIXED, "ntfs-3g" }, - { DRIVE_FIXED, "jfs" }, // IBM JFS - { DRIVE_FIXED, "jfs2" }, // IBM JFS (AIX defalt filesystem) - { DRIVE_FIXED, "EPFS" }, // IBM i IFS (root and QOpenSys) - { DRIVE_FIXED, "EPFSP" }, // IBM i auxiliary storage pool FS - { DRIVE_FIXED, "QSYS" }, // IBM i native system libraries - { DRIVE_FIXED, "QDLS" }, // IBM i legacy S/36 directories - { DRIVE_REMOTE, "smbfs" }, - { DRIVE_REMOTE, "fuse" }, - { DRIVE_REMOTE, "nfs" }, - { DRIVE_REMOTE, "nfs4" }, - { DRIVE_REMOTE, "cifs" }, - { DRIVE_REMOTE, "ncpfs" }, - { DRIVE_REMOTE, "coda" }, - { DRIVE_REMOTE, "afs" }, - { DRIVE_REMOTE, "nfs3" }, - { DRIVE_REMOTE, "stnfs" }, // AIX "short-term" NFS - { DRIVE_REMOTE, "autofs" }, // AIX automounter NFS - { DRIVE_REMOTE, "cachefs" }, // AIX cached NFS - { DRIVE_REMOTE, "NFS" }, // IBM i NFS - { DRIVE_REMOTE, "QNETC" }, // IBM i CIFS - { DRIVE_REMOTE, "QRFS" }, // IBM i native remote FS - { DRIVE_UNKNOWN, NULL } -#endif -}; -#if __linux__ -static guint32 _wapi_get_drive_type(unsigned f_type) +static gboolean +pipe_write (FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *byteswritten) { - const _wapi_drive_type *current; - - current = &_wapi_drive_types[0]; - while (current->drive_type != DRIVE_UNKNOWN) { - if (current->fstypeid == f_type) - return current->drive_type; - current++; + gint ret; + MonoThreadInfo *info = mono_thread_info_current (); + + if(byteswritten!=NULL) { + *byteswritten=0; } + + if(!(filehandle->fileaccess & (GENERIC_WRITE | GENERIC_ALL))) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - return DRIVE_UNKNOWN; -} -#else -static guint32 _wapi_get_drive_type(const gchar* fstype) -{ - const _wapi_drive_type *current; - - current = &_wapi_drive_types[0]; - while (current->drive_type != DRIVE_UNKNOWN) { - if (strcmp (current->fstype, fstype) == 0) - return current->drive_type; - - current++; + mono_w32error_set_last (ERROR_ACCESS_DENIED); + return(FALSE); } - return DRIVE_UNKNOWN; -} -#endif - -#if defined (HOST_DARWIN) || defined (__linux__) || defined (_AIX) -static guint32 -GetDriveTypeFromPath (const gchar *utf8_root_path_name) -{ -#if defined (_AIX) - struct statvfs buf; -#else - struct statfs buf; -#endif - gint res; - - MONO_ENTER_GC_SAFE; -#if defined (_AIX) - res = statvfs (utf8_root_path_name, &buf); -#else - res = statfs (utf8_root_path_name, &buf); -#endif - MONO_EXIT_GC_SAFE; - if (res == -1) - return DRIVE_UNKNOWN; -#if HOST_DARWIN - return _wapi_get_drive_type (buf.f_fstypename); -#elif defined (_AIX) - return _wapi_get_drive_type (buf.f_basetype); -#else - return _wapi_get_drive_type (buf.f_type); -#endif -} -#else -static guint32 -GetDriveTypeFromPath (const gchar *utf8_root_path_name) -{ - guint32 drive_type; - FILE *fp; - gchar buffer [512]; - gchar **splitted; + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: writing up to %" G_GUINT32_FORMAT " bytes to pipe %d", __func__, numbytes, ((MonoFDHandle*) filehandle)->fd); - MONO_ENTER_GC_SAFE; - fp = fopen ("/etc/mtab", "rt"); - MONO_EXIT_GC_SAFE; - if (fp == NULL) { + do { MONO_ENTER_GC_SAFE; - fp = fopen ("/etc/mnttab", "rt"); + ret = write (((MonoFDHandle*) filehandle)->fd, buffer, numbytes); MONO_EXIT_GC_SAFE; - if (fp == NULL) - return(DRIVE_UNKNOWN); - } + } while (ret == -1 && errno == EINTR && + !mono_thread_info_is_interrupt_state (info)); - drive_type = DRIVE_NO_ROOT_DIR; - while (1) { - gchar *fgets_res; - MONO_ENTER_GC_SAFE; - fgets_res = fgets (buffer, 512, fp); - MONO_EXIT_GC_SAFE; - if (fgets_res == NULL) - break; - splitted = g_strsplit (buffer, " ", 0); - if (!*splitted || !*(splitted + 1) || !*(splitted + 2)) { - g_strfreev (splitted); - continue; - } + if (ret == -1) { + if (errno == EINTR) { + ret = 0; + } else { + _wapi_set_last_error_from_errno (); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: write of fd %d error: %s", __func__,((MonoFDHandle*) filehandle)->fd, g_strerror(errno)); - /* compare given root_path_name with the one from mtab, - if length of utf8_root_path_name is zero it must be the root dir */ - if (strcmp (*(splitted + 1), utf8_root_path_name) == 0 || - (strcmp (*(splitted + 1), "/") == 0 && strlen (utf8_root_path_name) == 0)) { - drive_type = _wapi_get_drive_type (*(splitted + 2)); - /* it is possible this path might be mounted again with - a known type...keep looking */ - if (drive_type != DRIVE_UNKNOWN) { - g_strfreev (splitted); - break; - } + return(FALSE); } - - g_strfreev (splitted); - } - - MONO_ENTER_GC_SAFE; - fclose (fp); - MONO_EXIT_GC_SAFE; - return drive_type; -} -#endif - -#if defined (HOST_DARWIN) || defined (__linux__) || defined(HOST_BSD) || defined(__FreeBSD_kernel__) || defined(__HAIKU__) || defined(_AIX) -static gchar* -get_fstypename (gchar *utfpath) -{ -#if defined (_AIX) - /* statvfs offers the FS type name, easily, no need to iterate */ - struct statvfs stat; - gint statvfs_res; - - MONO_ENTER_GC_SAFE; - statvfs_res = statvfs (utfpath, &stat); - MONO_EXIT_GC_SAFE; - - if (statvfs_res != -1) { - return g_strdup (stat.f_basetype); } - - return NULL; -#elif defined (HOST_DARWIN) || defined (__linux__) - struct statfs stat; -#if __linux__ - const _wapi_drive_type *current; -#endif - gint statfs_res; - MONO_ENTER_GC_SAFE; - statfs_res = statfs (utfpath, &stat); - MONO_EXIT_GC_SAFE; - if (statfs_res == -1) - return NULL; -#if HOST_DARWIN - return g_strdup (stat.f_fstypename); -#else - current = &_wapi_drive_types[0]; - while (current->drive_type != DRIVE_UNKNOWN) { - if (stat.f_type == current->fstypeid) - return g_strdup (current->fstype); - current++; + if(byteswritten!=NULL) { + *byteswritten=ret; } - return NULL; -#endif -#else - return NULL; -#endif -} - -/* Linux has struct statfs which has a different layout */ -gboolean -mono_w32file_get_file_system_type (const gunichar2 *path, gunichar2 *fsbuffer, gint fsbuffersize) -{ - gchar *utfpath; - gchar *fstypename; - gboolean status = FALSE; - glong len; - - // We only support getting the file system type - if (fsbuffer == NULL) - return 0; - utfpath = mono_unicode_to_external (path); - if ((fstypename = get_fstypename (utfpath)) != NULL){ - gunichar2 *ret = g_utf8_to_utf16 (fstypename, -1, NULL, &len, NULL); - if (ret != NULL && len < fsbuffersize){ - memcpy (fsbuffer, ret, len * sizeof (gunichar2)); - fsbuffer [len] = 0; - status = TRUE; - } - if (ret != NULL) - g_free (ret); - g_free (fstypename); - } - g_free (utfpath); - return status; + return(TRUE); } -#endif -static gboolean -LockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 length_low, guint32 length_high) +static gint convert_flags(guint32 fileaccess, guint32 createmode) { - FileHandle *filehandle; - gboolean ret; - off_t offset, length; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - if (((MonoFDHandle*) filehandle)->type != MONO_FDTYPE_FILE) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; - } - - if (!(filehandle->fileaccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - mono_w32error_set_last (ERROR_ACCESS_DENIED); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; - } - -#ifdef HAVE_LARGE_FILE_SUPPORT - offset = ((gint64)offset_high << 32) | offset_low; - length = ((gint64)length_high << 32) | length_low; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Locking fd %d, offset %" G_GINT64_FORMAT ", length %" G_GINT64_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, (gint64) offset, (gint64) length); -#else - if (offset_high > 0 || length_high > 0) { - mono_w32error_set_last (ERROR_INVALID_PARAMETER); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; + gint flags=0; + + switch(fileaccess) { + case GENERIC_READ: + flags=O_RDONLY; + break; + case GENERIC_WRITE: + flags=O_WRONLY; + break; + case GENERIC_READ|GENERIC_WRITE: + flags=O_RDWR; + break; + default: + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Unknown access type 0x%" PRIx32, __func__, + fileaccess); + break; } - offset = offset_low; - length = length_low; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Locking fd %d, offset %" G_GINT64_FORMAT ", length %" G_GINT64_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, (gint64) offset, (gint64) length); -#endif - - ret = _wapi_lock_file_region (((MonoFDHandle*) filehandle)->fd, offset, length); - - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; + switch(createmode) { + case CREATE_NEW: + flags|=O_CREAT|O_EXCL; + break; + case CREATE_ALWAYS: + flags|=O_CREAT|O_TRUNC; + break; + case OPEN_EXISTING: + break; + case OPEN_ALWAYS: + flags|=O_CREAT; + break; + case TRUNCATE_EXISTING: + flags|=O_TRUNC; + break; + default: + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Unknown create mode 0x%" PRIx32, __func__, + createmode); + break; + } + + return(flags); } -static gboolean -UnlockFile (gpointer handle, guint32 offset_low, guint32 offset_high, guint32 length_low, guint32 length_high) +static gboolean share_allows_open (struct stat *statbuf, guint32 sharemode, + guint32 fileaccess, + FileShare **share_info) { - FileHandle *filehandle; - gboolean ret; - off_t offset, length; - - if (!mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } + gboolean file_already_shared; + guint32 file_existing_share, file_existing_access; - if (((MonoFDHandle*) filehandle)->type != MONO_FDTYPE_FILE) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; - } + file_already_shared = file_share_get (statbuf->st_dev, statbuf->st_ino, sharemode, fileaccess, &file_existing_share, &file_existing_access, share_info); + + if (file_already_shared) { + /* The reference to this share info was incremented + * when we looked it up, so be careful to put it back + * if we conclude we can't use this file. + */ + if ((file_existing_share == FILE_SHARE_NONE) || (sharemode == FILE_SHARE_NONE)) { + /* Quick and easy, no possibility to share */ + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing = NONE", __func__, fileaccess); - if (!(filehandle->fileaccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_ALL))) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fd %d doesn't have GENERIC_READ or GENERIC_WRITE access: %u", __func__, ((MonoFDHandle*) filehandle)->fd, filehandle->fileaccess); - mono_w32error_set_last (ERROR_ACCESS_DENIED); - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return FALSE; - } + file_share_release (*share_info); + *share_info = NULL; + + return(FALSE); + } -#ifdef HAVE_LARGE_FILE_SUPPORT - offset = ((gint64)offset_high << 32) | offset_low; - length = ((gint64)length_high << 32) | length_low; -#else - offset = offset_low; - length = length_low; -#endif - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Unlocking fd %d, offset %" G_GINT64_FORMAT ", length %" G_GINT64_FORMAT, __func__, ((MonoFDHandle*) filehandle)->fd, (gint64) offset, (gint64) length); + if (((file_existing_share == FILE_SHARE_READ) && + (fileaccess != GENERIC_READ)) || + ((file_existing_share == FILE_SHARE_WRITE) && + (fileaccess != GENERIC_WRITE))) { + /* New access mode doesn't match up */ + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Share mode prevents open: requested access: 0x%" PRIx32 ", file has sharing: 0x%" PRIx32, __func__, fileaccess, file_existing_share); - ret = _wapi_unlock_file_region (((MonoFDHandle*) filehandle)->fd, offset, length); + file_share_release (*share_info); + *share_info = NULL; + + return(FALSE); + } + } else { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: New file!", __func__); + } - mono_fdhandle_unref ((MonoFDHandle*) filehandle); - return ret; + return(TRUE); } void @@ -4904,15 +719,6 @@ mono_w32file_init (void) mono_coop_mutex_init (&file_share_mutex); - finds = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, finds_remove); - mono_coop_mutex_init (&finds_mutex); - -#if HOST_DARWIN - libc_handle = mono_dl_open ("/usr/lib/libc.dylib", 0, NULL); - g_assert (libc_handle); - g_free (mono_dl_symbol (libc_handle, "clonefile", (void**)&clonefile_ptr)); -#endif - if (g_hasenv ("MONO_STRICT_IO_EMULATION")) lock_while_writing = TRUE; } @@ -4924,99 +730,211 @@ mono_w32file_cleanup (void) if (file_share_table) g_hash_table_destroy (file_share_table); - - g_hash_table_destroy (finds); - mono_coop_mutex_destroy (&finds_mutex); - -#if HOST_DARWIN - mono_dl_close (libc_handle); -#endif } -gboolean -mono_w32file_move (const gunichar2 *path, const gunichar2 *dest, gint32 *error) +gpointer +mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs) { - gboolean result; + FileHandle *filehandle; + MonoFDType type; + gint flags=convert_flags(fileaccess, createmode); + /*mode_t perms=convert_perms(sharemode);*/ + /* we don't use sharemode, because that relates to sharing of + * the file when the file is open and is already handled by + * other code, perms instead are the on-disk permissions and + * this is a sane default. + */ + mode_t perms=0666; + gchar *filename; + gint fd, ret; + struct stat statbuf; + ERROR_DECL (error); - result = MoveFile (path, dest); - if (!result) - *error = mono_w32error_get_last (); - return result; -} + if (attrs & FILE_ATTRIBUTE_TEMPORARY) + perms = 0600; + + if (attrs & FILE_ATTRIBUTE_ENCRYPTED){ + mono_w32error_set_last (ERROR_ENCRYPTION_FAILED); + return INVALID_HANDLE_VALUE; + } + + if (name == NULL) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: name is NULL", __func__); -gboolean -mono_w32file_copy (const gunichar2 *path, const gunichar2 *dest, gboolean overwrite, gint32 *error) -{ - gboolean result; + mono_w32error_set_last (ERROR_INVALID_NAME); + return(INVALID_HANDLE_VALUE); + } - result = CopyFile (path, dest, !overwrite); - if (!result) - *error = mono_w32error_get_last (); + filename = mono_unicode_to_external_checked (name, error); + if (filename == NULL) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: unicode conversion returned NULL; %s", __func__, mono_error_get_message (error)); - return result; -} + mono_error_cleanup (error); + mono_w32error_set_last (ERROR_INVALID_NAME); + return(INVALID_HANDLE_VALUE); + } + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Opening %s with share 0x%" PRIx32 " and access 0x%" PRIx32, __func__, + filename, sharemode, fileaccess); + + fd = _wapi_open (filename, flags, perms); + + /* If we were trying to open a directory with write permissions + * (e.g. O_WRONLY or O_RDWR), this call will fail with + * EISDIR. However, this is a bit bogus because calls to + * manipulate the directory (e.g. mono_w32file_set_times) will still work on + * the directory because they use other API calls + * (e.g. utime()). Hence, if we failed with the EISDIR error, try + * to open the directory again without write permission. + */ + if (fd == -1 && errno == EISDIR) + { + /* Try again but don't try to make it writable */ + fd = _wapi_open (filename, flags & ~(O_RDWR|O_WRONLY), perms); + } + + if (fd == -1) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: Error opening file %s: %s", __func__, filename, g_strerror(errno)); + _wapi_set_last_path_error_from_errno (NULL, filename); + g_free (filename); -gboolean -mono_w32file_replace (const gunichar2 *destination_file_name, const gunichar2 *source_file_name, const gunichar2 *destination_backup_file_name, guint32 flags, gint32 *error) -{ - gboolean result; + return(INVALID_HANDLE_VALUE); + } - result = ReplaceFile (destination_file_name, source_file_name, destination_backup_file_name, flags, NULL, NULL); - if (!result) - *error = mono_w32error_get_last (); - return result; -} + MONO_ENTER_GC_SAFE; + ret = fstat (fd, &statbuf); + MONO_EXIT_GC_SAFE; + if (ret == -1) { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: fstat error of file %s: %s", __func__, filename, g_strerror (errno)); + _wapi_set_last_error_from_errno (); + MONO_ENTER_GC_SAFE; + close (fd); + MONO_EXIT_GC_SAFE; -gint64 -mono_w32file_get_file_size (gpointer handle, gint32 *error) -{ - gint64 length; - guint32 length_hi = 0; + return(INVALID_HANDLE_VALUE); + } - length = GetFileSize (handle, &length_hi); - if(length==INVALID_FILE_SIZE) { - *error=mono_w32error_get_last (); +#ifndef S_ISFIFO +#define S_ISFIFO(m) ((m & S_IFIFO) != 0) +#endif + if (S_ISFIFO (statbuf.st_mode)) { + type = MONO_FDTYPE_PIPE; + /* maintain invariant that pipes have no filename */ + g_free (filename); + filename = NULL; + } else if (S_ISCHR (statbuf.st_mode)) { + type = MONO_FDTYPE_CONSOLE; + } else { + type = MONO_FDTYPE_FILE; } - return length | ((gint64)length_hi << 32); -} + filehandle = file_data_create (type, fd); + filehandle->filename = filename; + filehandle->fileaccess = fileaccess; + filehandle->sharemode = sharemode; + filehandle->attrs = attrs; -gboolean -mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *error) -{ - gboolean result; + if (!share_allows_open (&statbuf, filehandle->sharemode, filehandle->fileaccess, &filehandle->share_info)) { + mono_w32error_set_last (ERROR_SHARING_VIOLATION); + MONO_ENTER_GC_SAFE; + close (((MonoFDHandle*) filehandle)->fd); + MONO_EXIT_GC_SAFE; + + mono_fdhandle_unref ((MonoFDHandle*) filehandle); + return (INVALID_HANDLE_VALUE); + } + if (!filehandle->share_info) { + /* No space, so no more files can be opened */ + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: No space in the share table", __func__); + + mono_w32error_set_last (ERROR_TOO_MANY_OPEN_FILES); + MONO_ENTER_GC_SAFE; + close (((MonoFDHandle*) filehandle)->fd); + MONO_EXIT_GC_SAFE; + + mono_fdhandle_unref ((MonoFDHandle*) filehandle); + return(INVALID_HANDLE_VALUE); + } + +#ifdef HAVE_POSIX_FADVISE + if (attrs & FILE_FLAG_SEQUENTIAL_SCAN) { + MONO_ENTER_GC_SAFE; + posix_fadvise (((MonoFDHandle*) filehandle)->fd, 0, 0, POSIX_FADV_SEQUENTIAL); + MONO_EXIT_GC_SAFE; + } + if (attrs & FILE_FLAG_RANDOM_ACCESS) { + MONO_ENTER_GC_SAFE; + posix_fadvise (((MonoFDHandle*) filehandle)->fd, 0, 0, POSIX_FADV_RANDOM); + MONO_EXIT_GC_SAFE; + } +#endif + +#ifdef F_RDAHEAD + if (attrs & FILE_FLAG_SEQUENTIAL_SCAN) { + MONO_ENTER_GC_SAFE; + fcntl(((MonoFDHandle*) filehandle)->fd, F_RDAHEAD, 1); + MONO_EXIT_GC_SAFE; + } +#endif - result = LockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32); - if (!result) - *error = mono_w32error_get_last (); - return result; + mono_fdhandle_insert ((MonoFDHandle*) filehandle); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_FILE, "%s: returning handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd)); + + return GINT_TO_POINTER(((MonoFDHandle*) filehandle)->fd); } + gboolean -mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *error) +mono_w32file_close (gpointer handle) { - gboolean result; + if (!mono_fdhandle_close (GPOINTER_TO_INT (handle))) { + mono_w32error_set_last (ERROR_INVALID_HANDLE); + return FALSE; + } - result = UnlockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32); - if (!result) - *error = mono_w32error_get_last (); - return result; + return TRUE; } -gpointer -mono_w32file_get_console_input (void) +static gboolean +mono_w32file_read_or_write (gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread, gint32 *win32error) { - return mono_w32file_get_std_handle (STD_INPUT_HANDLE); -} + MONO_REQ_GC_UNSAFE_MODE; -gpointer -mono_w32file_get_console_output (void) -{ - return mono_w32file_get_std_handle (STD_OUTPUT_HANDLE); + FileHandle *filehandle; + gboolean ret = FALSE; + + gboolean const ref = mono_fdhandle_lookup_and_ref(GPOINTER_TO_INT(handle), (MonoFDHandle**) &filehandle); + if (!ref) { + mono_w32error_set_last (ERROR_INVALID_HANDLE); + goto exit; + } + + switch (((MonoFDHandle*) filehandle)->type) { + case MONO_FDTYPE_FILE: + ret = (file_write) (filehandle, buffer, numbytes, bytesread); + break; + case MONO_FDTYPE_CONSOLE: + ret = (console_write) (filehandle, buffer, numbytes, bytesread); + break; + case MONO_FDTYPE_PIPE: + ret = (pipe_write) (filehandle, buffer, numbytes, bytesread); + break; + default: + mono_w32error_set_last (ERROR_INVALID_HANDLE); + break; + } + +exit: + if (ref) + mono_fdhandle_unref ((MonoFDHandle*) filehandle); + if (!ret) + *win32error = mono_w32error_get_last (); + return ret; } -gpointer -mono_w32file_get_console_error (void) +gboolean +mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error) { - return mono_w32file_get_std_handle (STD_ERROR_HANDLE); + return mono_w32file_read_or_write (handle, (gpointer)buffer, numbytes, byteswritten, win32error); } diff --git a/src/mono/mono/metadata/w32file-win32.c b/src/mono/mono/metadata/w32file-win32.c index ab6efc56f6a6fe..70405c9eac2af7 100644 --- a/src/mono/mono/metadata/w32file-win32.c +++ b/src/mono/mono/metadata/w32file-win32.c @@ -23,35 +23,6 @@ mono_w32file_cleanup (void) { } -gunichar2 -ves_icall_System_IO_MonoIO_get_VolumeSeparatorChar () -{ - return (gunichar2) ':'; /* colon */ -} - -gunichar2 -ves_icall_System_IO_MonoIO_get_DirectorySeparatorChar () -{ - return (gunichar2) '\\'; /* backslash */ -} - -gunichar2 -ves_icall_System_IO_MonoIO_get_AltDirectorySeparatorChar () -{ - return (gunichar2) '/'; /* forward slash */ -} - -gunichar2 -ves_icall_System_IO_MonoIO_get_PathSeparator () -{ - return (gunichar2) ';'; /* semicolon */ -} - -void ves_icall_System_IO_MonoIO_DumpHandles (void) -{ - return; -} - gpointer mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs) { @@ -62,12 +33,6 @@ mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode return res; } -gboolean -mono_w32file_cancel (gpointer handle) -{ - return CancelIoEx (handle, NULL); -} - gboolean mono_w32file_close (gpointer handle) { @@ -78,58 +43,6 @@ mono_w32file_close (gpointer handle) return res; } -gboolean -mono_w32file_delete (const gunichar2 *name) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = DeleteFileW (name); - MONO_EXIT_GC_SAFE; - return res; -} - -// See win32_wait_interrupt_handler for details. -static void -win32_io_interrupt_handler (gpointer ignored) -{ -} - -gboolean -mono_w32file_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread, gint32 *win32error) -{ - gboolean res; - MonoThreadInfo *info = mono_thread_info_current (); - gboolean alerted = FALSE; - - if (info) { - mono_thread_info_install_interrupt (win32_io_interrupt_handler, NULL, &alerted); - if (alerted) { - SetLastError (ERROR_OPERATION_ABORTED); - *win32error = ERROR_OPERATION_ABORTED; - return FALSE; - } - mono_win32_enter_blocking_io_call (info, handle); - } - - MONO_ENTER_GC_SAFE; - if (info && mono_thread_info_is_interrupt_state (info)) { - res = FALSE; - SetLastError (ERROR_OPERATION_ABORTED); - } else { - res = ReadFile (handle, buffer, numbytes, (PDWORD)bytesread, NULL); - } - if (!res) - *win32error = GetLastError (); - MONO_EXIT_GC_SAFE; - - if (info) { - mono_win32_leave_blocking_io_call (info, handle); - mono_thread_info_uninstall_interrupt (&alerted); - } - - return res; -} - gboolean mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error) { @@ -165,552 +78,3 @@ mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, gui return res; } - -gboolean -mono_w32file_flush (gpointer handle) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = FlushFileBuffers (handle); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_truncate (gpointer handle) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = SetEndOfFile (handle); - MONO_EXIT_GC_SAFE; - return res; -} - -guint32 -mono_w32file_seek (gpointer handle, gint32 movedistance, gint32 *highmovedistance, guint32 method) -{ - guint32 res; - MONO_ENTER_GC_SAFE; - res = SetFilePointer (handle, movedistance, (PLONG)highmovedistance, method); - MONO_EXIT_GC_SAFE; - return res; -} - -gint -mono_w32file_get_type (gpointer handle) -{ - gint res; - MONO_ENTER_GC_SAFE; - res = GetFileType (handle); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_set_times (gpointer handle, const FILETIME *create_time, const FILETIME *access_time, const FILETIME *write_time) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = SetFileTime (handle, create_time, access_time, write_time); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_filetime_to_systemtime (const FILETIME *file_time, SYSTEMTIME *system_time) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = FileTimeToSystemTime (file_time, system_time); - MONO_EXIT_GC_SAFE; - return res; -} - -gpointer -mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATAW *find_data) -{ - gpointer res; - MONO_ENTER_GC_SAFE; - res = FindFirstFileW (pattern, find_data); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_find_next (gpointer handle, WIN32_FIND_DATAW *find_data) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = FindNextFileW (handle, find_data); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_find_close (gpointer handle) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = FindClose (handle); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_create_directory (const gunichar2 *name) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = CreateDirectoryW (name, NULL); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_remove_directory (const gunichar2 *name) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = RemoveDirectoryW (name); - MONO_EXIT_GC_SAFE; - return res; -} - -/* - * GetFileAttributes|Ex () seems to try opening the file, which might lead to sharing violation errors, whereas - * FindFirstFile always succeeds. - */ -guint32 -mono_w32file_get_attributes (const gunichar2 *name) -{ - guint32 res; - HANDLE find_handle; - WIN32_FIND_DATAW find_data; - - MONO_ENTER_GC_SAFE; - - res = GetFileAttributesW (name); - if (res == INVALID_FILE_ATTRIBUTES && GetLastError () == ERROR_SHARING_VIOLATION) { - find_handle = FindFirstFileW (name, &find_data); - if (find_handle != INVALID_HANDLE_VALUE) { - FindClose (find_handle); - res = find_data.dwFileAttributes; - } else { - res = INVALID_FILE_ATTRIBUTES; - } - } - - MONO_EXIT_GC_SAFE; - - return res; -} - -static gint64 -convert_filetime (const FILETIME *filetime) -{ - return (gint64) ((((guint64) filetime->dwHighDateTime) << 32) + filetime->dwLowDateTime); -} - -gboolean -mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat) -{ - gboolean res; - HANDLE find_handle; - WIN32_FIND_DATAW find_data; - WIN32_FILE_ATTRIBUTE_DATA file_attribute_data; - - MONO_ENTER_GC_SAFE; - - res = GetFileAttributesExW (name, GetFileExInfoStandard, &file_attribute_data); - if (res) { - stat->attributes = file_attribute_data.dwFileAttributes; - stat->creation_time = convert_filetime (&file_attribute_data.ftCreationTime); - stat->last_access_time = convert_filetime (&file_attribute_data.ftLastAccessTime); - stat->last_write_time = convert_filetime (&file_attribute_data.ftLastWriteTime); - stat->length = ((gint64)file_attribute_data.nFileSizeHigh << 32) | file_attribute_data.nFileSizeLow; - } else if (!res && GetLastError () == ERROR_SHARING_VIOLATION) { - find_handle = FindFirstFileW (name, &find_data); - if (find_handle != INVALID_HANDLE_VALUE) { - FindClose (find_handle); - stat->attributes = find_data.dwFileAttributes; - stat->creation_time = convert_filetime (&find_data.ftCreationTime); - stat->last_access_time = convert_filetime (&find_data.ftLastAccessTime); - stat->last_write_time = convert_filetime (&find_data.ftLastWriteTime); - stat->length = ((gint64)find_data.nFileSizeHigh << 32) | find_data.nFileSizeLow; - res = TRUE; - } - } - - MONO_EXIT_GC_SAFE; - - return res; -} - -gboolean -mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = SetFileAttributesW (name, attrs); - MONO_EXIT_GC_SAFE; - return res; -} - -guint32 -mono_w32file_get_cwd (guint32 length, gunichar2 *buffer) -{ - guint32 res; - MONO_ENTER_GC_SAFE; - res = GetCurrentDirectoryW (length, buffer); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_set_cwd (const gunichar2 *path) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = SetCurrentDirectoryW (path); - MONO_EXIT_GC_SAFE; - return res; -} - -gboolean -mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size) -{ - gboolean res; - SECURITY_ATTRIBUTES attr; - attr.nLength = sizeof(SECURITY_ATTRIBUTES); - attr.bInheritHandle = TRUE; - attr.lpSecurityDescriptor = NULL; - MONO_ENTER_GC_SAFE; - res = CreatePipe (readpipe, writepipe, &attr, size); - MONO_EXIT_GC_SAFE; - return res; -} - -#ifndef PLATFORM_NO_DRIVEINFO -gboolean -mono_w32file_get_disk_free_space (const gunichar2 *path_name, guint64 *free_bytes_avail, guint64 *total_number_of_bytes, guint64 *total_number_of_free_bytes) -{ - gboolean result; - ULARGE_INTEGER wapi_free_bytes_avail = { 0 }; - ULARGE_INTEGER wapi_total_number_of_bytes = { 0 }; - ULARGE_INTEGER wapi_total_number_of_free_bytes = { 0 }; - - g_assert (free_bytes_avail); - g_assert (total_number_of_bytes); - g_assert (total_number_of_free_bytes); - - MONO_ENTER_GC_SAFE; - result = GetDiskFreeSpaceExW (path_name, &wapi_free_bytes_avail, &wapi_total_number_of_bytes, &wapi_total_number_of_free_bytes); - MONO_EXIT_GC_SAFE; - - *free_bytes_avail = wapi_free_bytes_avail.QuadPart; - *total_number_of_bytes = wapi_total_number_of_bytes.QuadPart; - *total_number_of_free_bytes = wapi_total_number_of_free_bytes.QuadPart; - - return result; -} -#endif // PLATFORM_NO_DRIVEINFO - -gboolean -mono_w32file_get_file_system_type (const gunichar2 *path, gunichar2 *fsbuffer, gint fsbuffersize) -{ - gboolean res; - MONO_ENTER_GC_SAFE; - res = GetVolumeInformationW (path, NULL, 0, NULL, NULL, NULL, fsbuffer, fsbuffersize); - MONO_EXIT_GC_SAFE; - return res; -} - -#if HAVE_API_SUPPORT_WIN32_MOVE_FILE -gboolean -mono_w32file_move (const gunichar2 *path, const gunichar2 *dest, gint32 *error) -{ - gboolean result = FALSE; - MONO_ENTER_GC_SAFE; - - result = MoveFileW (path, dest); - if (!result) - *error = GetLastError (); - - MONO_EXIT_GC_SAFE; - return result; -} -#elif HAVE_API_SUPPORT_WIN32_MOVE_FILE_EX -gboolean -mono_w32file_move (const gunichar2 *path, const gunichar2 *dest, gint32 *error) -{ - gboolean result = FALSE; - MONO_ENTER_GC_SAFE; - - result = MoveFileExW (path, dest, MOVEFILE_COPY_ALLOWED); - if (!result) { - *error = GetLastError (); - } - - MONO_EXIT_GC_SAFE; - return result; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_MOVE_FILE && !HAVE_EXTERN_DEFINED_WIN32_MOVE_FILE_EX -gboolean -mono_w32file_move (const gunichar2 *path, const gunichar2 *dest, gint32 *error) -{ - g_unsupported_api ("MoveFile, MoveFileEx"); - *error = ERROR_NOT_SUPPORTED; - SetLastError (ERROR_NOT_SUPPORTED); - return FALSE; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_REPLACE_FILE -gboolean -mono_w32file_replace (const gunichar2 *destination_file_name, const gunichar2 *source_file_name, const gunichar2 *destination_backup_file_name, guint32 flags, gint32 *error) -{ - gboolean result = FALSE; - MONO_ENTER_GC_SAFE; - - result = ReplaceFileW (destination_file_name, source_file_name, destination_backup_file_name, flags, NULL, NULL); - if (!result) - *error = GetLastError (); - - MONO_EXIT_GC_SAFE; - return result; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_REPLACE_FILE -gboolean -mono_w32file_replace (const gunichar2 *destination_file_name, const gunichar2 *source_file_name, const gunichar2 *destination_backup_file_name, guint32 flags, gint32 *error) -{ - g_unsupported_api ("ReplaceFile"); - *error = ERROR_NOT_SUPPORTED; - SetLastError (ERROR_NOT_SUPPORTED); - return FALSE; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_COPY_FILE - -gboolean -mono_w32file_copy (const gunichar2 *path, const gunichar2 *dest, gboolean overwrite, gint32 *error) -{ - gboolean result = FALSE; - MONO_ENTER_GC_SAFE; - - result = CopyFileW (path, dest, !overwrite); - if (!result) - *error = GetLastError (); - - MONO_EXIT_GC_SAFE; - return result; -} -#elif HAVE_API_SUPPORT_WIN32_COPY_FILE2 -gboolean -mono_w32file_copy (const gunichar2 *path, const gunichar2 *dest, gboolean overwrite, gint32 *error) -{ - gboolean result = FALSE; - COPYFILE2_EXTENDED_PARAMETERS copy_param = {0}; - - copy_param.dwSize = sizeof (COPYFILE2_EXTENDED_PARAMETERS); - copy_param.dwCopyFlags = (!overwrite) ? COPY_FILE_FAIL_IF_EXISTS : 0; - - MONO_ENTER_GC_SAFE; - - result = SUCCEEDED (CopyFile2 (path, dest, ©_param)); - if (result == FALSE) { - *error=GetLastError (); - } - - MONO_EXIT_GC_SAFE; - return result; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_COPY_FILE && !HAVE_EXTERN_DEFINED_WIN32_COPY_FILE2 -gboolean -mono_w32file_copy (const gunichar2 *path, const gunichar2 *dest, gboolean overwrite, gint32 *error) -{ - g_unsupported_api ("CopyFile, CopyFile2"); - *error = ERROR_NOT_SUPPORTED; - SetLastError (ERROR_NOT_SUPPORTED); - return FALSE; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_LOCK_FILE -gboolean -mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *error) -{ - gboolean result; - - MONO_ENTER_GC_SAFE; - - result = LockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32); - if (!result) - *error = GetLastError (); - - MONO_EXIT_GC_SAFE; - - return result; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_LOCK_FILE -gboolean -mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *error) -{ - g_unsupported_api ("LockFile"); - *error = ERROR_NOT_SUPPORTED; - SetLastError (ERROR_NOT_SUPPORTED); - return FALSE; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_UNLOCK_FILE -gboolean -mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *error) -{ - gboolean result; - - MONO_ENTER_GC_SAFE; - - result = UnlockFile (handle, position & 0xFFFFFFFF, position >> 32, length & 0xFFFFFFFF, length >> 32); - if (!result) - *error = GetLastError (); - - MONO_EXIT_GC_SAFE; - - return result; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_UNLOCK_FILE -gboolean -mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *error) -{ - g_unsupported_api ("UnlockFile"); - *error = ERROR_NOT_SUPPORTED; - SetLastError (ERROR_NOT_SUPPORTED); - return FALSE; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_GET_STD_HANDLE -gpointer -mono_w32file_get_console_input (void) -{ - HANDLE res; - MONO_ENTER_GC_SAFE; - res = GetStdHandle (STD_INPUT_HANDLE); - MONO_EXIT_GC_SAFE; - return res; -} - -gpointer -mono_w32file_get_console_output (void) -{ - HANDLE res; - MONO_ENTER_GC_SAFE; - res = GetStdHandle (STD_OUTPUT_HANDLE); - MONO_EXIT_GC_SAFE; - return res; -} - -gpointer -mono_w32file_get_console_error (void) -{ - HANDLE res; - MONO_ENTER_GC_SAFE; - res = GetStdHandle (STD_ERROR_HANDLE); - MONO_EXIT_GC_SAFE; - return res; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_GET_STD_HANDLE -gpointer -mono_w32file_get_console_input (void) -{ - g_unsupported_api ("GetStdHandle (STD_INPUT_HANDLE)"); - SetLastError (ERROR_NOT_SUPPORTED); - return INVALID_HANDLE_VALUE; -} - -gpointer -mono_w32file_get_console_output (void) -{ - g_unsupported_api ("GetStdHandle (STD_OUTPUT_HANDLE)"); - SetLastError (ERROR_NOT_SUPPORTED); - return INVALID_HANDLE_VALUE; -} - -gpointer -mono_w32file_get_console_error (void) -{ - g_unsupported_api ("GetStdHandle (STD_ERROR_HANDLE)"); - SetLastError (ERROR_NOT_SUPPORTED); - return INVALID_HANDLE_VALUE; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_GET_FILE_SIZE_EX -gint64 -mono_w32file_get_file_size (HANDLE handle, gint32 *error) -{ - LARGE_INTEGER length; - - MONO_ENTER_GC_SAFE; - - if (!GetFileSizeEx (handle, &length)) { - *error=GetLastError (); - length.QuadPart = INVALID_FILE_SIZE; - } - - MONO_EXIT_GC_SAFE; - return length.QuadPart; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_GET_FILE_SIZE_EX -gint64 -mono_w32file_get_file_size (HANDLE handle, gint32 *error) -{ - g_unsupported_api ("GetFileSizeEx"); - *error = ERROR_NOT_SUPPORTED; - SetLastError (ERROR_NOT_SUPPORTED); - return 0; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_GET_DRIVE_TYPE -guint32 -mono_w32file_get_drive_type (const gunichar2 *root_path_name, gint32 root_path_name_length, MonoError *error) -{ - guint32 res; - MONO_ENTER_GC_SAFE; - res = GetDriveTypeW (root_path_name); - MONO_EXIT_GC_SAFE; - return res; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_GET_DRIVE_TYPE -guint32 -mono_w32file_get_drive_type (const gunichar2 *root_path_name, gint32 root_path_name_length, MonoError *error) -{ - g_unsupported_api ("GetDriveType"); - mono_error_set_not_supported (error, G_UNSUPPORTED_API, "GetDriveType"); - SetLastError (ERROR_NOT_SUPPORTED); - return DRIVE_UNKNOWN; -} -#endif - -#if HAVE_API_SUPPORT_WIN32_GET_LOGICAL_DRIVE_STRINGS -gint32 -mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf, MonoError *error) -{ - gint32 res; - MONO_ENTER_GC_SAFE; - res = GetLogicalDriveStringsW (len, buf); - MONO_EXIT_GC_SAFE; - return res; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_GET_LOGICAL_DRIVE_STRINGS -gint32 -mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf, MonoError *error) -{ - g_unsupported_api ("GetLogicalDriveStrings"); - mono_error_set_not_supported (error, G_UNSUPPORTED_API, "GetLogicalDriveStrings"); - SetLastError (ERROR_NOT_SUPPORTED); - return 0; -} -#endif diff --git a/src/mono/mono/metadata/w32file.h b/src/mono/mono/metadata/w32file.h index c69554fe4db325..26bc897e5d0620 100644 --- a/src/mono/mono/metadata/w32file.h +++ b/src/mono/mono/metadata/w32file.h @@ -21,60 +21,6 @@ #include #include -/* This is a copy of System.IO.FileAccess */ -typedef enum { - FileAccess_Read=0x01, - FileAccess_Write=0x02, - FileAccess_ReadWrite=FileAccess_Read|FileAccess_Write -} MonoFileAccess; - -/* This is a copy of System.IO.FileMode */ -typedef enum { - FileMode_CreateNew=1, - FileMode_Create=2, - FileMode_Open=3, - FileMode_OpenOrCreate=4, - FileMode_Truncate=5, - FileMode_Append=6 -} MonoFileMode; - -/* This is a copy of System.IO.FileShare */ -typedef enum { - FileShare_None=0x0, - FileShare_Read=0x01, - FileShare_Write=0x02, - FileShare_ReadWrite=FileShare_Read|FileShare_Write, - FileShare_Delete=0x04 -} MonoFileShare; - -/* This is a copy of System.IO.FileOptions */ -typedef enum { - FileOptions_None = 0, - FileOptions_Temporary = 1, // Internal. See note in System.IO.FileOptions - FileOptions_Encrypted = 0x4000, - FileOptions_DeleteOnClose = 0x4000000, - FileOptions_SequentialScan = 0x8000000, - FileOptions_RandomAccess = 0x10000000, - FileOptions_Asynchronous = 0x40000000, - FileOptions_WriteThrough = 0x80000000 -} MonoFileOptions; - -/* This is a copy of System.IO.SeekOrigin */ -typedef enum { - SeekOrigin_Begin=0, - SeekOrigin_Current=1, - SeekOrigin_End=2 -} MonoSeekOrigin; - -/* This is a copy of System.IO.MonoIOStat */ -typedef struct _MonoIOStat { - gint32 attributes; - gint64 length; - gint64 creation_time; - gint64 last_access_time; - gint64 last_write_time; -} MonoIOStat; - /* This is a copy of System.IO.FileAttributes */ typedef enum { FileAttributes_ReadOnly=0x00001, @@ -93,25 +39,6 @@ typedef enum { FileAttributes_Encrypted=0x04000, FileAttributes_MonoExecutable= (int) 0x80000000 } MonoFileAttributes; -/* This is not used anymore -typedef struct _MonoFSAsyncResult { - MonoObject obj; - MonoObject *state; - MonoBoolean completed; - MonoBoolean done; - MonoException *exc; - MonoWaitHandle *wait_handle; - MonoDelegate *async_callback; - MonoBoolean completed_synch; - MonoArray *buffer; - gint offset; - gint count; - gint original_count; - gint bytes_read; - MonoDelegate *real_cb; -} MonoFSAsyncResult; -*/ -/* System.IO.MonoIO */ #if defined (TARGET_IOS) || defined (TARGET_ANDROID) @@ -213,19 +140,6 @@ typedef struct { #endif } FILETIME; -typedef struct { - guint32 dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - guint32 nFileSizeHigh; - guint32 nFileSizeLow; - guint32 dwReserved0; - guint32 dwReserved1; - gunichar2 cFileName [MAX_PATH]; - gunichar2 cAlternateFileName [14]; -} WIN32_FIND_DATA; - #endif /* !defined(HOST_WIN32) */ void @@ -237,111 +151,10 @@ mono_w32file_cleanup (void); gpointer mono_w32file_create(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs); -gboolean -mono_w32file_cancel (gpointer handle); - gboolean mono_w32file_close (gpointer handle); -gboolean -mono_w32file_delete (const gunichar2 *name); - -gboolean -mono_w32file_read (gpointer handle, gpointer buffer, guint32 numbytes, guint32 *bytesread, gint32 *win32error); - gboolean mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error); -gboolean -mono_w32file_flush (gpointer handle); - -gboolean -mono_w32file_truncate (gpointer handle); - -guint32 -mono_w32file_seek (gpointer handle, gint32 movedistance, gint32 *highmovedistance, guint32 method); - -gboolean -mono_w32file_move (const gunichar2 *path, const gunichar2 *dest, gint32 *error); - -gboolean -mono_w32file_copy (const gunichar2 *path, const gunichar2 *dest, gboolean overwrite, gint32 *error); - -gboolean -mono_w32file_lock (gpointer handle, gint64 position, gint64 length, gint32 *error); - -gboolean -mono_w32file_replace (const gunichar2 *destination_file_name, const gunichar2 *source_file_name, const gunichar2 *destination_backup_file_name, guint32 flags, gint32 *error); - -gboolean -mono_w32file_unlock (gpointer handle, gint64 position, gint64 length, gint32 *error); - -gpointer -mono_w32file_get_console_output (void); - -gpointer -mono_w32file_get_console_error (void); - -gpointer -mono_w32file_get_console_input (void); - -gint64 -mono_w32file_get_file_size (gpointer handle, gint32 *error); - -gint -mono_w32file_get_type (gpointer handle); - -gboolean -mono_w32file_set_times (gpointer handle, const FILETIME *create_time, const FILETIME *access_time, const FILETIME *write_time); - -gboolean -mono_w32file_filetime_to_systemtime (const FILETIME *file_time, SYSTEMTIME *system_time); - -gpointer -mono_w32file_find_first (const gunichar2 *pattern, WIN32_FIND_DATA *find_data); - -gboolean -mono_w32file_find_next (gpointer handle, WIN32_FIND_DATA *find_data); - -gboolean -mono_w32file_find_close (gpointer handle); - -gboolean -mono_w32file_create_directory (const gunichar2 *name); - -gboolean -mono_w32file_remove_directory (const gunichar2 *name); - -guint32 -mono_w32file_get_attributes (const gunichar2 *name); - -gboolean -mono_w32file_get_attributes_ex (const gunichar2 *name, MonoIOStat *stat); - -gboolean -mono_w32file_set_attributes (const gunichar2 *name, guint32 attrs); - -guint32 -mono_w32file_get_cwd (guint32 length, gunichar2 *buffer); - -gboolean -mono_w32file_set_cwd (const gunichar2 *path); - -gboolean -mono_w32file_create_pipe (gpointer *readpipe, gpointer *writepipe, guint32 size); - -guint32 -mono_w32file_get_drive_type (const gunichar2 *root_path_name, gint32 root_path_name_length, MonoError *error); - -gint32 -mono_w32file_get_logical_drive (guint32 len, gunichar2 *buf, MonoError *error); - -#ifndef PLATFORM_NO_DRIVEINFO -gboolean -mono_w32file_get_disk_free_space (const gunichar2 *path_name, guint64 *free_bytes_avail, guint64 *total_number_of_bytes, guint64 *total_number_of_free_bytes); -#endif // PLATFORM_NO_DRIVEINFO - -gboolean -mono_w32file_get_file_system_type (const gunichar2 *path, gunichar2 *fsbuffer, gint fsbuffersize); - #endif /* _MONO_METADATA_W32FILE_H_ */ diff --git a/src/mono/mono/metadata/w32handle-namespace.c b/src/mono/mono/metadata/w32handle-namespace.c index c141b28909fd63..490ea43eca5bca 100644 --- a/src/mono/mono/metadata/w32handle-namespace.c +++ b/src/mono/mono/metadata/w32handle-namespace.c @@ -14,8 +14,6 @@ #include "w32handle-namespace.h" -#include "w32mutex.h" -#include "w32semaphore.h" #include "w32event.h" #include "mono/utils/mono-logger-internals.h" #include "mono/utils/mono-coop-mutex.h" @@ -44,8 +42,6 @@ static gboolean has_namespace (MonoW32Type type) { switch (type) { - case MONO_W32TYPE_NAMEDMUTEX: - case MONO_W32TYPE_NAMEDSEM: case MONO_W32TYPE_NAMEDEVENT: return TRUE; default: @@ -71,8 +67,6 @@ mono_w32handle_namespace_search_handle_callback (MonoW32Handle *handle_data, gpo search_data = (NamespaceSearchHandleData*) user_data; switch (handle_data->type) { - case MONO_W32TYPE_NAMEDMUTEX: sharedns = mono_w32mutex_get_namespace ((MonoW32HandleNamedMutex*) handle_data->specific); break; - case MONO_W32TYPE_NAMEDSEM: sharedns = mono_w32semaphore_get_namespace ((MonoW32HandleNamedSemaphore*) handle_data->specific); break; case MONO_W32TYPE_NAMEDEVENT: sharedns = mono_w32event_get_namespace ((MonoW32HandleNamedEvent*) handle_data->specific); break; default: g_assert_not_reached (); diff --git a/src/mono/mono/metadata/w32handle.c b/src/mono/mono/metadata/w32handle.c index 6de478863912b7..0aa023141ad585 100644 --- a/src/mono/mono/metadata/w32handle.c +++ b/src/mono/mono/metadata/w32handle.c @@ -133,12 +133,6 @@ mono_w32handle_lock (MonoW32Handle *handle_data) mono_coop_mutex_lock (&handle_data->signal_mutex); } -gboolean -mono_w32handle_trylock (MonoW32Handle *handle_data) -{ - return mono_coop_mutex_trylock (&handle_data->signal_mutex) == 0; -} - void mono_w32handle_unlock (MonoW32Handle *handle_data) { @@ -583,53 +577,6 @@ mono_w32handle_ops_prewait (MonoW32Handle *handle_data) handle_ops [handle_data->type]->prewait (handle_data); } -static void -mono_w32handle_lock_handles (MonoW32Handle **handles_data, gsize nhandles) -{ - gint i, j, iter = 0; -#ifndef HOST_WIN32 - struct timespec sleepytime; -#endif - - /* Lock all the handles, with backoff */ -again: - for (i = 0; i < nhandles; i++) { - if (!handles_data [i]) - continue; - if (!mono_w32handle_trylock (handles_data [i])) { - - for (j = i - 1; j >= 0; j--) { - if (!handles_data [j]) - continue; - mono_w32handle_unlock (handles_data [j]); - } - - iter += 10; - if (iter == 1000) - iter = 10; - - MONO_ENTER_GC_SAFE; -#ifdef HOST_WIN32 - SleepEx (iter, TRUE); -#else - /* If iter ever reaches 1000 the nanosleep will - * return EINVAL immediately, but we have a - * design flaw if that happens. */ - g_assert (iter < 1000); - - sleepytime.tv_sec = 0; - sleepytime.tv_nsec = iter * 1000000; - nanosleep (&sleepytime, NULL); -#endif /* HOST_WIN32 */ - MONO_EXIT_GC_SAFE; - - goto again; - } - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: Locked all handles", __func__); -} - static void mono_w32handle_unlock_handles (MonoW32Handle **handles_data, gsize nhandles) { @@ -776,22 +723,6 @@ mono_w32handle_timedwait_signal_handle (MonoW32Handle *handle_data, guint32 time return res; } -static gboolean -dump_callback (MonoW32Handle *handle_data, gpointer user_data) -{ - g_print ("%p [%7s] signalled: %5s ref: %3d ", - handle_data, mono_w32handle_ops_typename (handle_data->type), handle_data->signalled ? "true" : "false", handle_data->ref - 1 /* foreach increase ref by 1 */); - mono_w32handle_ops_details (handle_data); - g_print ("\n"); - - return FALSE; -} - -void mono_w32handle_dump (void) -{ - mono_w32handle_foreach (dump_callback, NULL); -} - static gboolean own_if_signalled (MonoW32Handle *handle_data, gboolean *abandoned) { @@ -814,34 +745,6 @@ own_if_owned (MonoW32Handle *handle_data, gboolean *abandoned) return TRUE; } -gboolean -mono_w32handle_handle_is_signalled (gpointer handle) -{ - MonoW32Handle *handle_data; - gboolean res; - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) - return FALSE; - - res = mono_w32handle_issignalled (handle_data); - mono_w32handle_unref (handle_data); - return res; -} - -gboolean -mono_w32handle_handle_is_owned (gpointer handle) -{ - MonoW32Handle *handle_data; - gboolean res; - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) - return FALSE; - - res = mono_w32handle_ops_isowned (handle_data); - mono_w32handle_unref (handle_data); - return res; -} - #ifdef HOST_WIN32 MonoW32HandleWaitRet mono_w32handle_wait_one (gpointer handle, guint32 timeout, gboolean alertable) @@ -1001,327 +904,3 @@ mono_w32handle_check_duplicates (MonoW32Handle *handles [ ], gsize nhandles, gbo mono_w32handle_clear_duplicates (handles, nhandles); } - -#ifdef HOST_WIN32 -MonoW32HandleWaitRet -mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable, MonoError *error) -{ - DWORD const wait_result = (nhandles != 1) - ? mono_coop_win32_wait_for_multiple_objects_ex (nhandles, handles, waitall, timeout, alertable, error) - : mono_coop_win32_wait_for_single_object_ex (handles [0], timeout, alertable); - return mono_w32handle_convert_wait_ret (wait_result, nhandles); -} -#else -MonoW32HandleWaitRet -mono_w32handle_wait_multiple (gpointer *handles, gsize nhandles, gboolean waitall, guint32 timeout, gboolean alertable, MonoError *error) -{ - MonoW32HandleWaitRet ret; - gboolean alerted, poll; - gint i; - gint64 start = 0; - MonoW32Handle *handles_data [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS]; - gboolean abandoned [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_IO_LAYER_HANDLE, "%s: too many handles: %" G_GSIZE_FORMAT "d", - __func__, nhandles); - - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - - for (i = 0; i < nhandles; ++i) { - if (!mono_w32handle_lookup_and_ref (handles [i], &handles_data [i])) { - for (; i >= 0; --i) - mono_w32handle_unref (handles_data [i]); - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - } - - for (i = 0; i < nhandles; ++i) { - if (!mono_w32handle_test_capabilities (handles_data[i], MONO_W32HANDLE_CAP_WAIT) - && !mono_w32handle_test_capabilities (handles_data[i], MONO_W32HANDLE_CAP_SPECIAL_WAIT)) - { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p can't be waited for", __func__, handles_data [i]); - - ret = MONO_W32HANDLE_WAIT_RET_FAILED; - goto done; - } - } - - mono_w32handle_check_duplicates (handles_data, nhandles, waitall, error); - if (!is_ok (error)) { - ret = MONO_W32HANDLE_WAIT_RET_FAILED; - goto done; - } - - poll = FALSE; - for (i = 0; i < nhandles; ++i) { - if (!handles_data [i]) - continue; - if (handles_data [i]->type == MONO_W32TYPE_PROCESS) { - /* Can't wait for a process handle + another handle without polling */ - poll = TRUE; - } - } - - if (timeout != MONO_INFINITE_WAIT) - start = mono_msec_ticks (); - - for (;;) { - gsize count, lowest; - gboolean signalled; - gint waited; - - count = 0; - lowest = nhandles; - - mono_w32handle_lock_handles (handles_data, nhandles); - - for (i = 0; i < nhandles; i++) { - if (!handles_data [i]) - continue; - if ((mono_w32handle_test_capabilities (handles_data [i], MONO_W32HANDLE_CAP_OWN) && mono_w32handle_ops_isowned (handles_data [i])) - || mono_w32handle_issignalled (handles_data [i])) - { - count ++; - - if (i < lowest) - lowest = i; - } - } - - signalled = (waitall && count == nhandles) || (!waitall && count > 0); - - if (signalled) { - for (i = 0; i < nhandles; i++) { - if (!handles_data [i]) - continue; - if (own_if_signalled (handles_data [i], &abandoned [i]) && !waitall) { - /* if we are calling WaitHandle.WaitAny, .NET only owns the first one; it matters for Mutex which - * throw AbandonedMutexException in case we owned it but didn't release it */ - break; - } - } - } - - mono_w32handle_unlock_handles (handles_data, nhandles); - - if (signalled) { - ret = (MonoW32HandleWaitRet)(MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + lowest); - for (i = lowest; i < nhandles; i++) { - if (abandoned [i]) { - ret = (MonoW32HandleWaitRet)(MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + lowest); - break; - } - } - goto done; - } - - for (i = 0; i < nhandles; i++) { - if (!handles_data [i]) - continue; - mono_w32handle_ops_prewait (handles_data [i]); - - if (mono_w32handle_test_capabilities (handles_data [i], MONO_W32HANDLE_CAP_SPECIAL_WAIT) - && !mono_w32handle_issignalled (handles_data [i])) - { - mono_w32handle_ops_specialwait (handles_data [i], 0, alertable ? &alerted : NULL); - } - } - - mono_w32handle_lock_signal_mutex (); - - // FIXME These two loops can be just one. - if (waitall) { - signalled = TRUE; - for (i = 0; i < nhandles; ++i) { - if (!handles_data [i]) - continue; - if (!mono_w32handle_issignalled (handles_data [i])) { - signalled = FALSE; - break; - } - } - } else { - signalled = FALSE; - for (i = 0; i < nhandles; ++i) { - if (!handles_data [i]) - continue; - if (mono_w32handle_issignalled (handles_data [i])) { - signalled = TRUE; - break; - } - } - } - - waited = 0; - - if (!signalled) { - if (timeout == MONO_INFINITE_WAIT) { - waited = mono_w32handle_timedwait_signal (MONO_INFINITE_WAIT, poll, alertable ? &alerted : NULL); - } else { - gint64 elapsed; - - elapsed = mono_msec_ticks () - start; - if (elapsed > timeout) { - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - - mono_w32handle_unlock_signal_mutex (); - - goto done; - } - - waited = mono_w32handle_timedwait_signal (timeout - elapsed, poll, alertable ? &alerted : NULL); - } - } - - mono_w32handle_unlock_signal_mutex (); - - if (alerted) { - ret = MONO_W32HANDLE_WAIT_RET_ALERTED; - goto done; - } - - if (waited != 0) { - ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT; - goto done; - } - } - -done: - for (i = nhandles - 1; i >= 0; i--) { - /* Unref everything we reffed above */ - if (!handles_data [i]) - continue; - mono_w32handle_unref (handles_data [i]); - } - - return ret; -} -#endif /* HOST_WIN32 */ - -#ifdef HOST_WIN32 -MonoW32HandleWaitRet -mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable) -{ - return mono_w32handle_convert_wait_ret (mono_coop_win32_signal_object_and_wait (signal_handle, wait_handle, timeout, alertable), 1); -} -#else -MonoW32HandleWaitRet -mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable) -{ - MonoW32Handle *signal_handle_data, *wait_handle_data, *handles_data [2]; - MonoW32HandleWaitRet ret; - gint64 start = 0; - gboolean alerted; - gboolean abandoned = FALSE; - - alerted = FALSE; - - if (!mono_w32handle_lookup_and_ref (signal_handle, &signal_handle_data)) { - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - if (!mono_w32handle_lookup_and_ref (wait_handle, &wait_handle_data)) { - mono_w32handle_unref (signal_handle_data); - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - - if (!mono_w32handle_test_capabilities (signal_handle_data, MONO_W32HANDLE_CAP_SIGNAL)) { - mono_w32handle_unref (wait_handle_data); - mono_w32handle_unref (signal_handle_data); - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - if (!mono_w32handle_test_capabilities (wait_handle_data, MONO_W32HANDLE_CAP_WAIT)) { - mono_w32handle_unref (wait_handle_data); - mono_w32handle_unref (signal_handle_data); - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - - if (mono_w32handle_test_capabilities (wait_handle_data, MONO_W32HANDLE_CAP_SPECIAL_WAIT)) { - g_warning ("%s: handle %p has special wait, implement me!!", __func__, wait_handle_data); - mono_w32handle_unref (wait_handle_data); - mono_w32handle_unref (signal_handle_data); - return MONO_W32HANDLE_WAIT_RET_FAILED; - } - - handles_data [0] = wait_handle_data; - handles_data [1] = signal_handle_data; - - mono_w32handle_lock_handles (handles_data, 2); - - gint32 signal_ret = mono_w32handle_ops_signal (signal_handle_data); - - mono_w32handle_unlock (signal_handle_data); - - if (signal_ret == MONO_W32HANDLE_WAIT_RET_TOO_MANY_POSTS || - signal_ret == MONO_W32HANDLE_WAIT_RET_NOT_OWNED_BY_CALLER) { - ret = (MonoW32HandleWaitRet) signal_ret; - goto done; - } - - if (mono_w32handle_test_capabilities (wait_handle_data, MONO_W32HANDLE_CAP_OWN)) { - if (own_if_owned (wait_handle_data, &abandoned)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p already owned", __func__, wait_handle_data); - - ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; - goto done; - } - } - - if (timeout != MONO_INFINITE_WAIT) - start = mono_msec_ticks (); - - for (;;) { - gint waited; - - if (own_if_signalled (wait_handle_data, &abandoned)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_HANDLE, "%s: handle %p signalled", __func__, wait_handle_data); - - ret = abandoned ? MONO_W32HANDLE_WAIT_RET_ABANDONED_0 : MONO_W32HANDLE_WAIT_RET_SUCCESS_0; - goto done; - } - - mono_w32handle_ops_prewait (wait_handle_data); - - if (timeout == MONO_INFINITE_WAIT) { - waited = mono_w32handle_timedwait_signal_handle (wait_handle_data, MONO_INFINITE_WAIT, 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_data, 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: - mono_w32handle_unlock (wait_handle_data); - - mono_w32handle_unref (wait_handle_data); - mono_w32handle_unref (signal_handle_data); - - return ret; -} -#endif /* HOST_WIN32 */ diff --git a/src/mono/mono/metadata/w32handle.h b/src/mono/mono/metadata/w32handle.h index d0c50a9357b34e..f70fb140e6c270 100644 --- a/src/mono/mono/metadata/w32handle.h +++ b/src/mono/mono/metadata/w32handle.h @@ -22,12 +22,8 @@ typedef enum { MONO_W32TYPE_UNUSED = 0, - MONO_W32TYPE_SEM, - MONO_W32TYPE_MUTEX, MONO_W32TYPE_EVENT, MONO_W32TYPE_PROCESS, - MONO_W32TYPE_NAMEDMUTEX, - MONO_W32TYPE_NAMEDSEM, MONO_W32TYPE_NAMEDEVENT, MONO_W32TYPE_COUNT } MonoW32Type; @@ -133,9 +129,6 @@ mono_w32handle_unref (MonoW32Handle *handle_data); void mono_w32handle_foreach (gboolean (*on_each)(MonoW32Handle *handle_data, gpointer user_data), gpointer user_data); -void -mono_w32handle_dump (void); - void mono_w32handle_register_capabilities (MonoW32Type type, MonoW32HandleCapability caps); @@ -148,27 +141,12 @@ mono_w32handle_issignalled (MonoW32Handle *handle_data); void mono_w32handle_lock (MonoW32Handle *handle_data); -gboolean -mono_w32handle_trylock (MonoW32Handle *handle_data); - void mono_w32handle_unlock (MonoW32Handle *handle_data); -gboolean -mono_w32handle_handle_is_signalled (gpointer handle); - -gboolean -mono_w32handle_handle_is_owned (gpointer handle); - 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, MonoError *error); - -MonoW32HandleWaitRet -mono_w32handle_signal_and_wait (gpointer signal_handle, gpointer wait_handle, guint32 timeout, gboolean alertable); - #ifdef HOST_WIN32 static inline MonoW32HandleWaitRet mono_w32handle_convert_wait_ret (guint32 res, guint32 numobjects) diff --git a/src/mono/mono/metadata/w32mutex-unix.c b/src/mono/mono/metadata/w32mutex-unix.c deleted file mode 100644 index 7e821e4d48124a..00000000000000 --- a/src/mono/mono/metadata/w32mutex-unix.c +++ /dev/null @@ -1,293 +0,0 @@ -/** - * \file - * Runtime support for managed Mutex on Unix - * - * Author: - * Ludovic Henry (luhenry@microsoft.com) - * - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include "w32mutex.h" - -#include - -#include "w32error.h" -#include "w32handle-namespace.h" -#include "mono/metadata/object-internals.h" -#include "mono/utils/mono-logger-internals.h" -#include "mono/utils/mono-threads.h" -#include "mono/metadata/w32handle.h" -#include "icall-decl.h" - -#define MAX_PATH 260 - -typedef struct { - MonoNativeThreadId tid; - guint32 recursion; - gboolean abandoned; -} MonoW32HandleMutex; - -struct MonoW32HandleNamedMutex { - MonoW32HandleMutex m; - MonoW32HandleNamespace sharedns; -}; - -static void -thread_own_mutex (MonoInternalThread *internal, gpointer handle, MonoW32Handle *handle_data) -{ - // Thread and InternalThread are pinned/mature. - // Take advantage of that and do not use handles here. - - /* if we are not on the current thread, there is a - * race condition when allocating internal->owned_mutexes */ - g_assert (mono_thread_internal_is_current (internal)); - - if (!internal->owned_mutexes) - internal->owned_mutexes = g_ptr_array_new (); - - g_ptr_array_add (internal->owned_mutexes, mono_w32handle_duplicate (handle_data)); -} - -static void -thread_disown_mutex (MonoInternalThread *internal, gpointer handle) -{ - // Thread and InternalThread are pinned/mature. - // Take advantage of that and do not use handles here. - gboolean removed; - - g_assert (mono_thread_internal_is_current (internal)); - - g_assert (internal->owned_mutexes); - removed = g_ptr_array_remove (internal->owned_mutexes, handle); - g_assert (removed); - - mono_w32handle_close (handle); -} - -static gint32 -mutex_handle_signal (MonoW32Handle *handle_data) -{ - MonoW32HandleMutex *mutex_handle; - pthread_t tid; - - mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: signalling %s handle %p, tid: %p recursion: %d", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) mutex_handle->tid, mutex_handle->recursion); - - tid = pthread_self (); - - if (mutex_handle->abandoned) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: %s handle %p is abandoned", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data); - } else if (!pthread_equal (mutex_handle->tid, tid)) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: we don't own %s handle %p (owned by %ld, me %ld)", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (long)mutex_handle->tid, (long)tid); - return MONO_W32HANDLE_WAIT_RET_NOT_OWNED_BY_CALLER; - } else { - /* OK, we own this mutex */ - mutex_handle->recursion--; - - if (mutex_handle->recursion == 0) { - thread_disown_mutex (mono_thread_internal_current (), handle_data); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: unlocking %s handle %p, tid: %p recusion : %d", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) mutex_handle->tid, mutex_handle->recursion); - - mutex_handle->tid = 0; - mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); - } - } - return MONO_W32HANDLE_WAIT_RET_SUCCESS_0; -} - -static gboolean -mutex_handle_own (MonoW32Handle *handle_data, gboolean *abandoned) -{ - MonoW32HandleMutex *mutex_handle; - - *abandoned = FALSE; - - mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: owning %s handle %p, before: [tid: %p, recursion: %d], after: [tid: %p, recursion: %d], abandoned: %s", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) mutex_handle->tid, mutex_handle->recursion, (gpointer) pthread_self (), mutex_handle->recursion + 1, mutex_handle->abandoned ? "true" : "false"); - - if (mutex_handle->recursion != 0) { - g_assert (pthread_equal (pthread_self (), mutex_handle->tid)); - mutex_handle->recursion++; - } else { - mutex_handle->tid = pthread_self (); - mutex_handle->recursion = 1; - - thread_own_mutex (mono_thread_internal_current (), handle_data, handle_data); - } - - if (mutex_handle->abandoned) { - mutex_handle->abandoned = FALSE; - *abandoned = TRUE; - } - - mono_w32handle_set_signal_state (handle_data, FALSE, FALSE); - return TRUE; -} - -static gboolean -mutex_handle_is_owned (MonoW32Handle *handle_data) -{ - MonoW32HandleMutex *mutex_handle; - - mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: testing ownership %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data); - - if (mutex_handle->recursion > 0 && pthread_equal (mutex_handle->tid, pthread_self ())) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: %s handle %p owned by %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) pthread_self ()); - return TRUE; - } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: %s handle %p not owned by %p, tid: %p recursion: %d", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, (gpointer) pthread_self (), (gpointer) mutex_handle->tid, mutex_handle->recursion); - return FALSE; - } -} - -static void mutex_handle_prewait (MonoW32Handle *handle_data) -{ - /* If the mutex is not currently owned, do nothing and let the - * usual wait carry on. If it is owned, check that the owner - * is still alive; if it isn't we override the previous owner - * and assume that process exited abnormally and failed to - * clean up. - */ - MonoW32HandleMutex *mutex_handle; - - mutex_handle = (MonoW32HandleMutex*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_MUTEX, "%s: pre-waiting %s handle %p, owned? %s", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, mutex_handle->recursion != 0 ? "true" : "false"); -} - -static void mutex_details (MonoW32Handle *handle_data) -{ - MonoW32HandleMutex *mut = (MonoW32HandleMutex *)handle_data->specific; - -#ifdef PTHREAD_POINTER_ID - g_print ("own: %5p, count: %5u", mut->tid, mut->recursion); -#else - g_print ("own: %5ld, count: %5u", mut->tid, mut->recursion); -#endif -} - -static void namedmutex_details (MonoW32Handle *handle_data) -{ - MonoW32HandleNamedMutex *namedmut = (MonoW32HandleNamedMutex *)handle_data->specific; - -#ifdef PTHREAD_POINTER_ID - g_print ("own: %5p, count: %5u, name: \"%s\"", - namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name); -#else - g_print ("own: %5ld, count: %5u, name: \"%s\"", - namedmut->m.tid, namedmut->m.recursion, namedmut->sharedns.name); -#endif -} - -static const gchar* mutex_typename (void) -{ - return "Mutex"; -} - -static gsize mutex_typesize (void) -{ - return sizeof (MonoW32HandleMutex); -} - -static const gchar* namedmutex_typename (void) -{ - return "N.Mutex"; -} - -static gsize namedmutex_typesize (void) -{ - return sizeof (MonoW32HandleNamedMutex); -} - -void -mono_w32mutex_init (void) -{ - static const MonoW32HandleOps mutex_ops = { - NULL, /* close */ - mutex_handle_signal, /* signal */ - mutex_handle_own, /* own */ - mutex_handle_is_owned, /* is_owned */ - NULL, /* special_wait */ - mutex_handle_prewait, /* prewait */ - mutex_details, /* details */ - mutex_typename, /* typename */ - mutex_typesize, /* typesize */ - }; - - static const MonoW32HandleOps namedmutex_ops = { - NULL, /* close */ - mutex_handle_signal, /* signal */ - mutex_handle_own, /* own */ - mutex_handle_is_owned, /* is_owned */ - NULL, /* special_wait */ - mutex_handle_prewait, /* prewait */ - namedmutex_details, /* details */ - namedmutex_typename, /* typename */ - namedmutex_typesize, /* typesize */ - }; - - mono_w32handle_register_ops (MONO_W32TYPE_MUTEX, &mutex_ops); - mono_w32handle_register_ops (MONO_W32TYPE_NAMEDMUTEX, &namedmutex_ops); - - mono_w32handle_register_capabilities (MONO_W32TYPE_MUTEX, - (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN)); - mono_w32handle_register_capabilities (MONO_W32TYPE_NAMEDMUTEX, - (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL | MONO_W32HANDLE_CAP_OWN)); -} - -#ifndef HOST_WIN32 -static GENERATE_GET_CLASS_WITH_CACHE (wait_subsystem, "System.Threading", "WaitSubsystem"); - -void -mono_w32mutex_abandon (MonoInternalThread *internal) -{ - ERROR_DECL (error); - - MONO_STATIC_POINTER_INIT (MonoMethod, thread_exiting) - - MonoClass *wait_subsystem_class = mono_class_get_wait_subsystem_class (); - g_assert (wait_subsystem_class); - thread_exiting = mono_class_get_method_from_name_checked (wait_subsystem_class, "OnThreadExiting", -1, 0, error); - mono_error_assert_ok (error); - - MONO_STATIC_POINTER_INIT_END (MonoMethod, thread_exiting) - - g_assert (thread_exiting); - - if (mono_runtime_get_no_exec ()) - return; - - HANDLE_FUNCTION_ENTER (); - - ERROR_DECL (error); - - gpointer args [1]; - args [0] = internal; - mono_runtime_try_invoke_handle (thread_exiting, NULL_HANDLE, args, error); - - mono_error_cleanup (error); - - HANDLE_FUNCTION_RETURN (); -} -#endif - -MonoW32HandleNamespace* -mono_w32mutex_get_namespace (MonoW32HandleNamedMutex *mutex) -{ - return &mutex->sharedns; -} diff --git a/src/mono/mono/metadata/w32mutex-win32.c b/src/mono/mono/metadata/w32mutex-win32.c deleted file mode 100644 index 3e50e1269d8dec..00000000000000 --- a/src/mono/mono/metadata/w32mutex-win32.c +++ /dev/null @@ -1,22 +0,0 @@ -/** - * \file - * Runtime support for managed Mutex on Win32 - * - * Author: - * Ludovic Henry (luhenry@microsoft.com) - * - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include "w32mutex.h" - -#include -#include -#include -#include -#include "icall-decl.h" - -void -mono_w32mutex_init (void) -{ -} diff --git a/src/mono/mono/metadata/w32mutex.h b/src/mono/mono/metadata/w32mutex.h deleted file mode 100644 index 264a22b7fee9fe..00000000000000 --- a/src/mono/mono/metadata/w32mutex.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * \file - */ - -#ifndef _MONO_METADATA_W32MUTEX_H_ -#define _MONO_METADATA_W32MUTEX_H_ - -#include -#include - -#include "object.h" -#include "object-internals.h" -#include "w32handle-namespace.h" -#include - -void -mono_w32mutex_init (void); - -ICALL_EXPORT -MonoBoolean -ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle); - -typedef struct MonoW32HandleNamedMutex MonoW32HandleNamedMutex; - -MonoW32HandleNamespace* -mono_w32mutex_get_namespace (MonoW32HandleNamedMutex *mutex); - -#ifndef HOST_WIN32 -void -mono_w32mutex_abandon (MonoInternalThread *internal); -#endif - -#endif /* _MONO_METADATA_W32MUTEX_H_ */ diff --git a/src/mono/mono/metadata/w32semaphore-unix.c b/src/mono/mono/metadata/w32semaphore-unix.c deleted file mode 100644 index 539f3683232ef1..00000000000000 --- a/src/mono/mono/metadata/w32semaphore-unix.c +++ /dev/null @@ -1,240 +0,0 @@ -/** - * \file - * Runtime support for managed Semaphore on Unix - * - * Author: - * Ludovic Henry (luhenry@microsoft.com) - * - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include "w32semaphore.h" -#include "w32error.h" -#include "w32handle-namespace.h" -#include "mono/utils/mono-logger-internals.h" -#include "mono/metadata/w32handle.h" -#include "object-internals.h" -#include "icall-decl.h" - -#define MAX_PATH 260 - -typedef struct { - guint32 val; - gint32 max; -} MonoW32HandleSemaphore; - -struct MonoW32HandleNamedSemaphore { - MonoW32HandleSemaphore s; - MonoW32HandleNamespace sharedns; -}; - -static gint32 sem_handle_signal (MonoW32Handle *handle_data) -{ - MonoW32HandleSemaphore *sem_handle; - - sem_handle = (MonoW32HandleSemaphore*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: signalling %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data); - - /* No idea why max is signed, but thats the spec :-( */ - if (sem_handle->val + 1 > (guint32)sem_handle->max) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: %s handle %p val %d count %d max %d, max value would be exceeded", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, sem_handle->val, 1, sem_handle->max); - return MONO_W32HANDLE_WAIT_RET_TOO_MANY_POSTS; - } else { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: %s handle %p val %d count %d max %d", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data, sem_handle->val, 1, sem_handle->max); - - sem_handle->val += 1; - mono_w32handle_set_signal_state (handle_data, TRUE, TRUE); - } - return MONO_W32HANDLE_WAIT_RET_SUCCESS_0; -} - -static gboolean sem_handle_own (MonoW32Handle *handle_data, gboolean *abandoned) -{ - MonoW32HandleSemaphore *sem_handle; - - *abandoned = FALSE; - - sem_handle = (MonoW32HandleSemaphore*) handle_data->specific; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: owning %s handle %p", - __func__, mono_w32handle_get_typename (handle_data->type), handle_data); - - sem_handle->val--; - - if (sem_handle->val == 0) - mono_w32handle_set_signal_state (handle_data, FALSE, FALSE); - - return TRUE; -} - -static void sema_details (MonoW32Handle *handle_data) -{ - MonoW32HandleSemaphore *sem = (MonoW32HandleSemaphore *)handle_data->specific; - g_print ("val: %5u, max: %5d", sem->val, sem->max); -} - -static void namedsema_details (MonoW32Handle *handle_data) -{ - MonoW32HandleNamedSemaphore *namedsem = (MonoW32HandleNamedSemaphore *)handle_data->specific; - g_print ("val: %5u, max: %5d, name: \"%s\"", namedsem->s.val, namedsem->s.max, namedsem->sharedns.name); -} - -static const gchar* sema_typename (void) -{ - return "Semaphore"; -} - -static gsize sema_typesize (void) -{ - return sizeof (MonoW32HandleSemaphore); -} - -static const gchar* namedsema_typename (void) -{ - return "N.Semaphore"; -} - -static gsize namedsema_typesize (void) -{ - return sizeof (MonoW32HandleNamedSemaphore); -} - -void -mono_w32semaphore_init (void) -{ - static const MonoW32HandleOps sem_ops = { - NULL, /* close */ - sem_handle_signal, /* signal */ - sem_handle_own, /* own */ - NULL, /* is_owned */ - NULL, /* special_wait */ - NULL, /* prewait */ - sema_details, /* details */ - sema_typename, /* typename */ - sema_typesize, /* typesize */ - }; - - static const MonoW32HandleOps namedsem_ops = { - NULL, /* close */ - sem_handle_signal, /* signal */ - sem_handle_own, /* own */ - NULL, /* is_owned */ - NULL, /* special_wait */ - NULL, /* prewait */ - namedsema_details, /* details */ - namedsema_typename, /* typename */ - namedsema_typesize, /* typesize */ - }; - - mono_w32handle_register_ops (MONO_W32TYPE_SEM, &sem_ops); - mono_w32handle_register_ops (MONO_W32TYPE_NAMEDSEM, &namedsem_ops); - - mono_w32handle_register_capabilities (MONO_W32TYPE_SEM, - (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL)); - mono_w32handle_register_capabilities (MONO_W32TYPE_NAMEDSEM, - (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SIGNAL)); -} - -static gpointer -sem_handle_create (MonoW32HandleSemaphore *sem_handle, MonoW32Type type, gint32 initial, gint32 max) -{ - MonoW32Handle *handle_data; - gpointer handle; - - sem_handle->val = initial; - sem_handle->max = max; - - handle = mono_w32handle_new (type, sem_handle); - if (handle == INVALID_HANDLE_VALUE) { - g_warning ("%s: error creating %s handle", - __func__, mono_w32handle_get_typename (type)); - mono_w32error_set_last (ERROR_GEN_FAILURE); - return NULL; - } - - if (!mono_w32handle_lookup_and_ref (handle, &handle_data)) - g_error ("%s: unkown handle %p", __func__, handle); - - if (handle_data->type != type) - g_error ("%s: unknown semaphore handle %p", __func__, handle); - - mono_w32handle_lock (handle_data); - - if (initial != 0) - mono_w32handle_set_signal_state (handle_data, TRUE, FALSE); - - mono_w32handle_unlock (handle_data); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: created %s handle %p", - __func__, mono_w32handle_get_typename (type), handle); - - mono_w32handle_unref (handle_data); - - return handle; -} - -static gpointer -sem_create (gint32 initial, gint32 max) -{ - MonoW32HandleSemaphore sem_handle; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: creating %s handle, initial %d max %d", - __func__, mono_w32handle_get_typename (MONO_W32TYPE_SEM), initial, max); - return sem_handle_create (&sem_handle, MONO_W32TYPE_SEM, initial, max); -} - -static gpointer -namedsem_create (gint32 initial, gint32 max, const gunichar2 *name, gint32 name_length, MonoError *error) -{ - g_assert (name); - - gpointer handle = NULL; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: creating %s handle, initial %d max %d name \"%s\"", - __func__, mono_w32handle_get_typename (MONO_W32TYPE_NAMEDSEM), initial, max, (const char*)name); - - gsize utf8_len = 0; - char *utf8_name = mono_utf16_to_utf8len (name, name_length, &utf8_len, error); - goto_if_nok (error, exit); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SEMAPHORE, "%s: Creating named sem name [%s] initial %d max %d", __func__, utf8_name, initial, max); - - // Opening named objects does not race. - mono_w32handle_namespace_lock (); - - handle = mono_w32handle_namespace_search_handle (MONO_W32TYPE_NAMEDSEM, utf8_name); - if (handle == INVALID_HANDLE_VALUE) { - /* The name has already been used for a different object. */ - handle = NULL; - mono_w32error_set_last (ERROR_INVALID_HANDLE); - } else if (handle) { - /* Not an error, but this is how the caller is informed that the semaphore wasn't freshly created */ - mono_w32error_set_last (ERROR_ALREADY_EXISTS); - - /* mono_w32handle_namespace_search_handle already adds a ref to the handle */ - } else { - /* A new named semaphore */ - MonoW32HandleNamedSemaphore namedsem_handle; - - // FIXME Silent truncation. - size_t len = utf8_len < MAX_PATH ? utf8_len : MAX_PATH; - memcpy (&namedsem_handle.sharedns.name [0], utf8_name, len); - namedsem_handle.sharedns.name [len] = '\0'; - - handle = sem_handle_create ((MonoW32HandleSemaphore*) &namedsem_handle, MONO_W32TYPE_NAMEDSEM, initial, max); - } - - mono_w32handle_namespace_unlock (); -exit: - g_free (utf8_name); - return handle; -} - -MonoW32HandleNamespace* -mono_w32semaphore_get_namespace (MonoW32HandleNamedSemaphore *semaphore) -{ - return &semaphore->sharedns; -} diff --git a/src/mono/mono/metadata/w32semaphore-win32.c b/src/mono/mono/metadata/w32semaphore-win32.c deleted file mode 100644 index 677cc79c54c5aa..00000000000000 --- a/src/mono/mono/metadata/w32semaphore-win32.c +++ /dev/null @@ -1,22 +0,0 @@ -/** - * \file - * Runtime support for managed Semaphore on Win32 - * - * Author: - * Ludovic Henry (luhenry@microsoft.com) - * - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include "w32semaphore.h" - -#include -#include -#include -#include -#include "icall-decl.h" - -void -mono_w32semaphore_init (void) -{ -} diff --git a/src/mono/mono/metadata/w32semaphore.h b/src/mono/mono/metadata/w32semaphore.h deleted file mode 100644 index adfa228e2c8f92..00000000000000 --- a/src/mono/mono/metadata/w32semaphore.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * \file - */ - -#ifndef _MONO_METADATA_W32SEMAPHORE_H_ -#define _MONO_METADATA_W32SEMAPHORE_H_ - -#include -#include -#include "object.h" -#include "w32handle-namespace.h" -#include - -void -mono_w32semaphore_init (void); - -typedef struct MonoW32HandleNamedSemaphore MonoW32HandleNamedSemaphore; - -MonoW32HandleNamespace* -mono_w32semaphore_get_namespace (MonoW32HandleNamedSemaphore *semaphore); - -#endif /* _MONO_METADATA_W32SEMAPHORE_H_ */ diff --git a/src/mono/mono/metadata/w32socket-internals.h b/src/mono/mono/metadata/w32socket-internals.h deleted file mode 100644 index 6e4785db5d6a5f..00000000000000 --- a/src/mono/mono/metadata/w32socket-internals.h +++ /dev/null @@ -1,150 +0,0 @@ -/** - * \file - * - * Copyright 2016 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ -#ifndef __MONO_METADATA_W32SOCKET_INTERNALS_H__ -#define __MONO_METADATA_W32SOCKET_INTERNALS_H__ - -#include -#include - -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif - -#include - -#ifndef HAVE_SOCKLEN_T -#define socklen_t int -#endif - -#include - -#if defined(HOST_WIN32) && (HAVE_API_SUPPORT_WIN32_TRANSMIT_FILE || HAVE_API_SUPPORT_WIN32_DISCONNECT_EX) -#include -#else -typedef struct { - gpointer Head; - guint32 HeadLength; - gpointer Tail; - guint32 TailLength; -} TRANSMIT_FILE_BUFFERS, *LPTRANSMIT_FILE_BUFFERS; -#endif - -#ifndef HOST_WIN32 -#define TF_DISCONNECT 0x01 -#define TF_REUSE_SOCKET 0x02 - -typedef struct { - guint32 Data1; - guint16 Data2; - guint16 Data3; - guint8 Data4[8]; -} GUID; - -typedef struct { - guint32 Internal; - guint32 InternalHigh; - guint32 Offset; - guint32 OffsetHigh; - gpointer hEvent; - gpointer handle1; - gpointer handle2; -} OVERLAPPED; -#endif - -void -mono_w32socket_initialize (void); - -void -mono_w32socket_cleanup (void); - -SOCKET -mono_w32socket_accept (SOCKET s, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking); - -int -mono_w32socket_connect (SOCKET s, const struct sockaddr *name, socklen_t namelen, gboolean blocking); - -int -mono_w32socket_recv (SOCKET s, char *buf, int len, int flags, gboolean blocking); - -int -mono_w32socket_recvfrom (SOCKET s, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking); - -int -mono_w32socket_recvbuffers (SOCKET s, LPWSABUF lpBuffers, guint32 dwBufferCount, guint32 *lpNumberOfBytesRecvd, guint32 *lpFlags, gpointer lpOverlapped, gpointer lpCompletionRoutine, gboolean blocking); - -int -mono_w32socket_send (SOCKET s, void *buf, int len, int flags, gboolean blocking); - -int -mono_w32socket_sendto (SOCKET s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking); - -int -mono_w32socket_sendbuffers (SOCKET s, LPWSABUF lpBuffers, guint32 dwBufferCount, guint32 *lpNumberOfBytesRecvd, guint32 lpFlags, gpointer lpOverlapped, gpointer lpCompletionRoutine, gboolean blocking); - -BOOL -mono_w32socket_transmit_file (SOCKET hSocket, gpointer hFile, gpointer lpTransmitBuffers, guint32 dwReserved, gboolean blocking); - - -#ifndef HOST_WIN32 - -SOCKET -mono_w32socket_socket (int domain, int type, int protocol); - -gint -mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen); - -gint -mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen); - -gint -mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen); - -gint -mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen); - -gint -mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, gconstpointer optval, socklen_t optlen); - -gint -mono_w32socket_listen (SOCKET sock, gint backlog); - -gint -mono_w32socket_shutdown (SOCKET sock, gint how); - -gint -mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written); - -gboolean -mono_w32socket_close (SOCKET sock); - -#endif /* HOST_WIN32 */ - -gint -mono_w32socket_disconnect (SOCKET sock, gboolean reuse); - -gint -mono_w32socket_set_blocking (SOCKET socket, gboolean blocking); - -gint -mono_w32socket_get_available (SOCKET socket, guint64 *amount); - -void -mono_w32socket_set_last_error (gint32 error); - -gint32 -mono_w32socket_get_last_error (void); - -gint32 -mono_w32socket_convert_error (gint error); - -gboolean -mono_w32socket_duplicate (gpointer handle, gint32 targetProcessId, gpointer *duplicate_handle); - -#endif // __MONO_METADATA_W32SOCKET_INTERNALS_H__ diff --git a/src/mono/mono/metadata/w32socket-unix.c b/src/mono/mono/metadata/w32socket-unix.c deleted file mode 100644 index 2c19b035678764..00000000000000 --- a/src/mono/mono/metadata/w32socket-unix.c +++ /dev/null @@ -1,1578 +0,0 @@ -/** - * \file - * Unix specific socket code. - * - * Copyright 2016 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include -#include - -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#include -#include -#ifdef HAVE_NETDB_H -#include -#endif -#ifdef HAVE_NETINET_TCP_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#include -#ifdef HAVE_SYS_UIO_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#ifdef HAVE_SYS_FILIO_H -#include /* defines FIONBIO and FIONREAD */ -#endif -#ifdef HAVE_SYS_SOCKIO_H -#include /* defines SIOCATMARK */ -#endif -#include -#ifdef HAVE_SYS_SENDFILE_H -#include -#endif -#include - -#include "w32socket.h" -#include "w32socket-internals.h" -#include "w32error.h" -#include "fdhandle.h" -#include "utils/mono-logger-internals.h" -#include "utils/mono-poll.h" -#include "utils/mono-compiler.h" -#include "icall-decl.h" -#include "utils/mono-errno.h" - -typedef struct { - MonoFDHandle fdhandle; - gint domain; - gint type; - gint protocol; - gint saved_error; - gint still_readable; -} SocketHandle; - -static SocketHandle* -socket_data_create (MonoFDType type, gint fd) -{ - SocketHandle *sockethandle; - - sockethandle = g_new0 (SocketHandle, 1); - mono_fdhandle_init ((MonoFDHandle*) sockethandle, type, fd); - - return sockethandle; -} - -static void -socket_data_close (MonoFDHandle *fdhandle) -{ - MonoThreadInfo *info; - SocketHandle* sockethandle; - gint ret; - - sockethandle = (SocketHandle*) fdhandle; - g_assert (sockethandle); - - info = mono_thread_info_current (); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: closing fd %d", __func__, ((MonoFDHandle*) sockethandle)->fd); - - /* Shutdown the socket for reading, to interrupt any potential - * receives that may be blocking for data. See bug 75705. */ - MONO_ENTER_GC_SAFE; - shutdown (((MonoFDHandle*) sockethandle)->fd, SHUT_RD); - MONO_EXIT_GC_SAFE; - -retry_close: - MONO_ENTER_GC_SAFE; - ret = close (((MonoFDHandle*) sockethandle)->fd); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - if (errno == EINTR && !mono_thread_info_is_interrupt_state (info)) - goto retry_close; - } - - sockethandle->saved_error = 0; -} - -static void -socket_data_destroy (MonoFDHandle *fdhandle) -{ - SocketHandle *sockethandle; - - sockethandle = (SocketHandle*) fdhandle; - g_assert (sockethandle); - - g_free (sockethandle); -} - -void -mono_w32socket_initialize (void) -{ - MonoFDHandleCallback socket_data_callbacks; - memset (&socket_data_callbacks, 0, sizeof (socket_data_callbacks)); - socket_data_callbacks.close = socket_data_close; - socket_data_callbacks.destroy = socket_data_destroy; - - mono_fdhandle_register (MONO_FDTYPE_SOCKET, &socket_data_callbacks); -} - -void -mono_w32socket_cleanup (void) -{ -} - -SOCKET -mono_w32socket_accept (SOCKET sock, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking) -{ - SocketHandle *sockethandle, *accepted_socket_data; - MonoThreadInfo *info; - gint accepted_fd; - - if (addr != NULL && *addrlen < sizeof(struct sockaddr)) { - mono_w32socket_set_last_error (WSAEFAULT); - return INVALID_SOCKET; - } - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return INVALID_SOCKET; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return INVALID_SOCKET; - } - - info = mono_thread_info_current (); - - do { - MONO_ENTER_GC_SAFE; - accepted_fd = accept (((MonoFDHandle*) sockethandle)->fd, addr, addrlen); - MONO_EXIT_GC_SAFE; - } while (accepted_fd == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - if (accepted_fd == -1) { - gint error = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: accept error: %s", __func__, g_strerror(errno)); - mono_w32socket_set_last_error (error); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return INVALID_SOCKET; - } - - accepted_socket_data = socket_data_create (MONO_FDTYPE_SOCKET, accepted_fd); - accepted_socket_data->domain = sockethandle->domain; - accepted_socket_data->type = sockethandle->type; - accepted_socket_data->protocol = sockethandle->protocol; - accepted_socket_data->still_readable = 1; - - mono_fdhandle_insert ((MonoFDHandle*) accepted_socket_data); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: returning accepted handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) accepted_socket_data)->fd)); - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return ((MonoFDHandle*) accepted_socket_data)->fd; -} - -int -mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, socklen_t addrlen, gboolean blocking) -{ - SocketHandle *sockethandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - MONO_ENTER_GC_SAFE; - ret = connect (((MonoFDHandle*) sockethandle)->fd, addr, addrlen); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - MonoThreadInfo *info; - mono_pollfd fds; - gint errnum, so_error; - socklen_t len; - - errnum = errno; - - if (errno != EINTR) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect error: %s", __func__, - g_strerror (errnum)); - - errnum = mono_w32socket_convert_error (errnum); - if (errnum == WSAEINPROGRESS) - errnum = WSAEWOULDBLOCK; /* see bug #73053 */ - - mono_w32socket_set_last_error (errnum); - - /* - * On solaris x86 getsockopt (SO_ERROR) is not set after - * connect () fails so we need to save this error. - * - * But don't do this for EWOULDBLOCK (bug 317315) - */ - if (errnum != WSAEWOULDBLOCK) { - /* ECONNRESET means the socket was closed by another thread */ - /* Async close on mac raises ECONNABORTED. */ - sockethandle->saved_error = errnum; - } - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - info = mono_thread_info_current (); - - fds.fd = ((MonoFDHandle*) sockethandle)->fd; - fds.events = MONO_POLLOUT; - for (;;) { - MONO_ENTER_GC_SAFE; - ret = mono_poll (&fds, 1, -1); - MONO_EXIT_GC_SAFE; - if (ret != -1 || mono_thread_info_is_interrupt_state (info)) - break; - - if (errno != EINTR) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect poll error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - } - - len = sizeof(so_error); - MONO_ENTER_GC_SAFE; - ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_ERROR, &so_error, &len); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect getsockopt error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - if (so_error != 0) { - gint errnum = mono_w32socket_convert_error (so_error); - - /* Need to save this socket error */ - sockethandle->saved_error = errnum; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect getsockopt returned error: %s", - __func__, g_strerror (so_error)); - - mono_w32socket_set_last_error (errnum); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -int -mono_w32socket_recv (SOCKET sock, char *buf, int len, int flags, gboolean blocking) -{ - return mono_w32socket_recvfrom (sock, buf, len, flags, NULL, 0, blocking); -} - -int -mono_w32socket_recvfrom (SOCKET sock, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking) -{ - SocketHandle *sockethandle; - int ret; - MonoThreadInfo *info; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - info = mono_thread_info_current (); - - do { - MONO_ENTER_GC_SAFE; - ret = recvfrom (((MonoFDHandle*) sockethandle)->fd, buf, len, flags, from, fromlen); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - if (ret == 0 && len > 0) { - /* According to the Linux man page, recvfrom only - * returns 0 when the socket has been shut down - * cleanly. Turn this into an EINTR to simulate win32 - * behaviour of returning EINTR when a socket is - * closed while the recvfrom is blocking (we use a - * shutdown() in socket_close() to trigger this.) See - * bug 75705. - */ - /* Distinguish between the socket being shut down at - * the local or remote ends, and reads that request 0 - * bytes to be read - */ - - /* If this returns FALSE, it means the socket has been - * closed locally. If it returns TRUE, but - * still_readable != 1 then shutdown - * (SHUT_RD|SHUT_RDWR) has been called locally. - */ - if (sockethandle->still_readable != 1) { - ret = -1; - mono_set_errno (EINTR); - } - } - - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: recv error: %s", __func__, g_strerror(errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return ret; -} - -static void -wsabuf_to_msghdr (WSABUF *buffers, guint32 count, struct msghdr *hdr) -{ - guint32 i; - - memset (hdr, 0, sizeof (struct msghdr)); - hdr->msg_iovlen = count; - hdr->msg_iov = g_new0 (struct iovec, count); - for (i = 0; i < count; i++) { - hdr->msg_iov [i].iov_base = buffers [i].buf; - hdr->msg_iov [i].iov_len = buffers [i].len; - } -} - -static void -msghdr_iov_free (struct msghdr *hdr) -{ - g_free (hdr->msg_iov); -} - -int -mono_w32socket_recvbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *received, guint32 *flags, gpointer overlapped, gpointer complete, gboolean blocking) -{ - SocketHandle *sockethandle; - MonoThreadInfo *info; - gint ret; - struct msghdr hdr; - - g_assert (overlapped == NULL); - g_assert (complete == NULL); - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - info = mono_thread_info_current (); - - wsabuf_to_msghdr (buffers, count, &hdr); - - do { - MONO_ENTER_GC_SAFE; - ret = recvmsg (((MonoFDHandle*) sockethandle)->fd, &hdr, *flags); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - msghdr_iov_free (&hdr); - - if (ret == 0) { - /* see mono_w32socket_recvfrom */ - if (sockethandle->still_readable != 1) { - ret = -1; - mono_set_errno (EINTR); - } - } - - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: recvmsg error: %s", __func__, g_strerror(errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - *received = ret; - *flags = hdr.msg_flags; - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -int -mono_w32socket_send (SOCKET sock, void *buf, int len, int flags, gboolean blocking) -{ - SocketHandle *sockethandle; - int ret; - MonoThreadInfo *info; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - info = mono_thread_info_current (); - - do { - MONO_ENTER_GC_SAFE; - ret = send (((MonoFDHandle*) sockethandle)->fd, buf, len, flags); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: send error: %s", __func__, g_strerror (errno)); - -#ifdef O_NONBLOCK - /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on - * a blocking socket. See bug #599488 */ - if (errnum == EAGAIN) { - MONO_ENTER_GC_SAFE; - ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_GETFL, 0); - MONO_EXIT_GC_SAFE; - if (ret != -1 && (ret & O_NONBLOCK) == 0) - errnum = ETIMEDOUT; - } -#endif /* O_NONBLOCK */ - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return ret; -} - -int -mono_w32socket_sendto (SOCKET sock, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking) -{ - SocketHandle *sockethandle; - int ret; - MonoThreadInfo *info; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - info = mono_thread_info_current (); - - do { - MONO_ENTER_GC_SAFE; - ret = sendto (((MonoFDHandle*) sockethandle)->fd, buf, len, flags, to, tolen); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: send error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return ret; -} - -int -mono_w32socket_sendbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *sent, guint32 flags, gpointer overlapped, gpointer complete, gboolean blocking) -{ - struct msghdr hdr; - MonoThreadInfo *info; - SocketHandle *sockethandle; - gint ret; - - g_assert (overlapped == NULL); - g_assert (complete == NULL); - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - info = mono_thread_info_current (); - - wsabuf_to_msghdr (buffers, count, &hdr); - - do { - MONO_ENTER_GC_SAFE; - ret = sendmsg (((MonoFDHandle*) sockethandle)->fd, &hdr, flags); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - msghdr_iov_free (&hdr); - - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: sendmsg error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - *sent = ret; - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -#define SF_BUFFER_SIZE 16384 - -BOOL -mono_w32socket_transmit_file (SOCKET sock, gpointer file_handle, gpointer lpTransmitBuffers, guint32 flags, gboolean blocking) -{ - MonoThreadInfo *info; - SocketHandle *sockethandle; - gint file; - gssize ret; -#if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN)) - struct stat statbuf; -#else - gpointer buffer; -#endif - TRANSMIT_FILE_BUFFERS *buffers = (TRANSMIT_FILE_BUFFERS *)lpTransmitBuffers; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return FALSE; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return FALSE; - } - - /* Write the header */ - if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) { - ret = mono_w32socket_send (((MonoFDHandle*) sockethandle)->fd, buffers->Head, buffers->HeadLength, 0, FALSE); - if (ret == SOCKET_ERROR) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return FALSE; - } - } - - info = mono_thread_info_current (); - - file = GPOINTER_TO_INT (file_handle); - -#if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN)) - MONO_ENTER_GC_SAFE; - ret = fstat (file, &statbuf); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return FALSE; - } - - do { - MONO_ENTER_GC_SAFE; -#ifdef __linux__ - ret = sendfile (((MonoFDHandle*) sockethandle)->fd, file, NULL, statbuf.st_size); -#elif defined(DARWIN) - /* TODO: header/tail could be sent in the 5th argument */ - /* TODO: Might not send the entire file for non-blocking sockets */ - ret = sendfile (file, ((MonoFDHandle*) sockethandle)->fd, 0, &statbuf.st_size, NULL, 0); -#endif - MONO_EXIT_GC_SAFE; - } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); -#else - buffer = g_malloc (SF_BUFFER_SIZE); - - do { - do { - MONO_ENTER_GC_SAFE; - ret = read (file, buffer, SF_BUFFER_SIZE); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - if (ret == -1 || ret == 0) - break; - - do { - MONO_ENTER_GC_SAFE; - ret = send (((MonoFDHandle*) sockethandle)->fd, buffer, ret, 0); /* short sends? enclose this in a loop? */ - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - g_free (buffer); -#endif - - if (ret == -1) { - gint errnum = errno; - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return FALSE; - } - - /* Write the tail */ - if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) { - ret = mono_w32socket_send (((MonoFDHandle*) sockethandle)->fd, buffers->Tail, buffers->TailLength, 0, FALSE); - if (ret == SOCKET_ERROR) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return FALSE; - } - } - - if ((flags & TF_DISCONNECT) == TF_DISCONNECT) - mono_w32socket_close (((MonoFDHandle*) sockethandle)->fd); - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return TRUE; -} - -SOCKET -mono_w32socket_socket (int domain, int type, int protocol) -{ - SocketHandle *sockethandle; - gint fd; - -retry_socket: - MONO_ENTER_GC_SAFE; - fd = socket (domain, type, protocol); - MONO_EXIT_GC_SAFE; - if (fd == -1) { - if (domain == AF_INET && type == SOCK_RAW && protocol == 0) { - /* Retry with protocol == 4 (see bug #54565) */ - // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565 - protocol = 4; - goto retry_socket; - } - - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: socket error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - return INVALID_SOCKET; - } - - sockethandle = socket_data_create(MONO_FDTYPE_SOCKET, fd); - sockethandle->domain = domain; - sockethandle->type = type; - sockethandle->protocol = protocol; - sockethandle->still_readable = 1; - - /* .net seems to set this by default for SOCK_STREAM, not for - * SOCK_DGRAM (see bug #36322) - * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322 - * - * It seems winsock has a rather different idea of what - * SO_REUSEADDR means. If it's set, then a new socket can be - * bound over an existing listening socket. There's a new - * windows-specific option called SO_EXCLUSIVEADDRUSE but - * using that means the socket MUST be closed properly, or a - * denial of service can occur. Luckily for us, winsock - * behaves as though any other system would when SO_REUSEADDR - * is true, so we don't need to do anything else here. See - * bug 53992. - * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992 - */ - { - int ret; - const int true_ = 1; - - MONO_ENTER_GC_SAFE; - ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_REUSEADDR, &true_, sizeof (true_)); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: Error setting SO_REUSEADDR", __func__); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - - MONO_ENTER_GC_SAFE; - close (((MonoFDHandle*) sockethandle)->fd); - MONO_EXIT_GC_SAFE; - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return INVALID_SOCKET; - } - } - - mono_fdhandle_insert ((MonoFDHandle*) sockethandle); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: returning socket handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) sockethandle)->fd)); - - return ((MonoFDHandle*) sockethandle)->fd; -} - -gint -mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen) -{ - SocketHandle *sockethandle; - int ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - MONO_ENTER_GC_SAFE; - ret = bind (((MonoFDHandle*) sockethandle)->fd, addr, addrlen); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: bind error: %s", __func__, g_strerror(errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -gint -mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen) -{ - SocketHandle *sockethandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - -#ifdef HAVE_GETPEERNAME - MONO_ENTER_GC_SAFE; - ret = getpeername (((MonoFDHandle*) sockethandle)->fd, name, namelen); - MONO_EXIT_GC_SAFE; -#else - ret = -1; -#endif - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getpeername error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -gint -mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen) -{ - SocketHandle *sockethandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - MONO_ENTER_GC_SAFE; - ret = getsockname (((MonoFDHandle*) sockethandle)->fd, name, namelen); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockname error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -gint -mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen) -{ - SocketHandle *sockethandle; - gint ret; - struct timeval tv; - gpointer tmp_val; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - tmp_val = optval; - if (level == SOL_SOCKET && - (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) { - tmp_val = &tv; - *optlen = sizeof (tv); - } - - MONO_ENTER_GC_SAFE; - ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, level, optname, tmp_val, optlen); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockopt error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - if (level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) { - *((int *) optval) = tv.tv_sec * 1000 + (tv.tv_usec / 1000); // milli from micro - *optlen = sizeof (int); - } - - if (optname == SO_ERROR) { - if (*((int *)optval) != 0) { - *((int *) optval) = mono_w32socket_convert_error (*((int *)optval)); - sockethandle->saved_error = *((int *)optval); - } else { - *((int *)optval) = sockethandle->saved_error; - } - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -gint -mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, gconstpointer optval, socklen_t optlen) -{ - SocketHandle *sockethandle; - gint ret; - gconstpointer tmp_val; -#if defined (__linux__) - /* This has its address taken so it cannot be moved to the if block which uses it */ - gint bufsize = 0; -#endif - struct timeval tv; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - tmp_val = optval; - if (level == SOL_SOCKET && - (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) { - int ms = *((int *) optval); - tv.tv_sec = ms / 1000; - tv.tv_usec = (ms % 1000) * 1000; // micro from milli - tmp_val = &tv; - optlen = sizeof (tv); - } -#if defined (__linux__) - else if (level == SOL_SOCKET && - (optname == SO_SNDBUF || optname == SO_RCVBUF)) { - /* According to socket(7) the Linux kernel doubles the - * buffer sizes "to allow space for bookkeeping - * overhead." - */ - bufsize = *((int *) optval); - - bufsize /= 2; - tmp_val = &bufsize; - } -#endif - - MONO_ENTER_GC_SAFE; - ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, level, optname, tmp_val, optlen); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: setsockopt error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - -#if defined (SO_REUSEPORT) - /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */ - if (level == SOL_SOCKET && optname == SO_REUSEADDR) { - int type; - socklen_t type_len = sizeof (type); - - MONO_ENTER_GC_SAFE; - ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, level, SO_TYPE, &type, &type_len); - MONO_EXIT_GC_SAFE; - if (!ret) { - if (type == SOCK_DGRAM || type == SOCK_STREAM) { - MONO_ENTER_GC_SAFE; - setsockopt (((MonoFDHandle*) sockethandle)->fd, level, SO_REUSEPORT, tmp_val, optlen); - MONO_EXIT_GC_SAFE; - } - } - } -#endif - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return ret; -} - -gint -mono_w32socket_listen (SOCKET sock, gint backlog) -{ - SocketHandle *sockethandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - MONO_ENTER_GC_SAFE; - ret = listen (((MonoFDHandle*) sockethandle)->fd, backlog); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: listen error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -gint -mono_w32socket_shutdown (SOCKET sock, gint how) -{ - SocketHandle *sockethandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (how == SHUT_RD || how == SHUT_RDWR) - sockethandle->still_readable = 0; - - MONO_ENTER_GC_SAFE; - ret = shutdown (((MonoFDHandle*) sockethandle)->fd, how); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: shutdown error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return ret; -} - -gint -mono_w32socket_disconnect (SOCKET sock, gboolean reuse) -{ - SocketHandle *sockethandle; - SOCKET newsock; - gint ret; - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: called on socket %d!", __func__, sock); - - /* We could check the socket type here and fail unless its - * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn) - * if we really wanted to */ - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - MONO_ENTER_GC_SAFE; - newsock = socket (sockethandle->domain, sockethandle->type, sockethandle->protocol); - MONO_EXIT_GC_SAFE; - if (newsock == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: socket error: %s", __func__, g_strerror (errnum)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - /* According to Stevens "Advanced Programming in the UNIX - * Environment: UNIX File I/O" dup2() is atomic so there - * should not be a race condition between the old fd being - * closed and the new socket fd being copied over */ - do { - MONO_ENTER_GC_SAFE; - ret = dup2 (newsock, ((MonoFDHandle*) sockethandle)->fd); - MONO_EXIT_GC_SAFE; - } while (ret == -1 && errno == EAGAIN); - - if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: dup2 error: %s", __func__, g_strerror (errnum)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - MONO_ENTER_GC_SAFE; - close (newsock); - MONO_EXIT_GC_SAFE; - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -static gboolean -extension_disconect (SOCKET sock, OVERLAPPED *overlapped, guint32 flags, guint32 reserved) -{ - gboolean ret; - MONO_ENTER_GC_UNSAFE; - ret = mono_w32socket_disconnect (sock, flags & TF_REUSE_SOCKET) == 0; - MONO_EXIT_GC_UNSAFE; - return ret; -} - -static gboolean -extension_transmit_file (SOCKET sock, gpointer file_handle, guint32 bytes_to_write, guint32 bytes_per_send, - OVERLAPPED *ol, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags) -{ - gboolean ret; - MONO_ENTER_GC_UNSAFE; - ret = mono_w32socket_transmit_file (sock, file_handle, buffers, flags, FALSE); - MONO_EXIT_GC_UNSAFE; - return ret; -} - -const -static struct { - GUID guid; - gpointer func; -} extension_functions[] = { - { {0x7fda2e11,0x8630,0x436f,{0xa0,0x31,0xf5,0x36,0xa6,0xee,0xc1,0x57}} /* WSAID_DISCONNECTEX */, (gpointer)extension_disconect }, - { {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} /* WSAID_TRANSMITFILE */, (gpointer)extension_transmit_file }, - { {0} , NULL }, -}; - -gint -mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written) -{ - SocketHandle *sockethandle; - gint ret; - gpointer buffer; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (command == 0xC8000006 /* SIO_GET_EXTENSION_FUNCTION_POINTER */) { - gint i; - GUID *guid; - - if (inputlen < sizeof(GUID)) { - /* As far as I can tell, windows doesn't - * actually set an error here... - */ - mono_w32socket_set_last_error (WSAEINVAL); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - if (outputlen < sizeof(gpointer)) { - /* Or here... */ - mono_w32socket_set_last_error (WSAEINVAL); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - if (output == NULL) { - /* Or here */ - mono_w32socket_set_last_error (WSAEINVAL); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - guid = (GUID*) input; - for (i = 0; extension_functions[i].func; i++) { - if (memcmp (guid, &extension_functions[i].guid, sizeof(GUID)) == 0) { - memcpy (output, &extension_functions[i].func, sizeof(gpointer)); - *written = sizeof(gpointer); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; - } - } - - mono_w32socket_set_last_error (WSAEINVAL); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - if (command == 0x98000004 /* SIO_KEEPALIVE_VALS */) { - guint32 onoff; - - if (inputlen < 3 * sizeof (guint32)) { - mono_w32socket_set_last_error (WSAEINVAL); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - onoff = *((guint32*) input); - - MONO_ENTER_GC_SAFE; - ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (guint32)); - MONO_EXIT_GC_SAFE; - if (ret < 0) { - mono_w32socket_set_last_error (mono_w32socket_convert_error (errno)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - -#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) - if (onoff != 0) { - /* Values are in ms, but we need s */ - guint32 keepalivetime, keepaliveinterval, rem; - - keepalivetime = *(((guint32*) input) + 1); - keepaliveinterval = *(((guint32*) input) + 2); - - /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */ - rem = keepalivetime % 1000; - keepalivetime /= 1000; - if (keepalivetime == 0 || rem >= 500) - keepalivetime++; - MONO_ENTER_GC_SAFE; - ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (guint32)); - MONO_EXIT_GC_SAFE; - if (ret == 0) { - rem = keepaliveinterval % 1000; - keepaliveinterval /= 1000; - if (keepaliveinterval == 0 || rem >= 500) - keepaliveinterval++; - MONO_ENTER_GC_SAFE; - ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (guint32)); - MONO_EXIT_GC_SAFE; - } - if (ret != 0) { - mono_w32socket_set_last_error (mono_w32socket_convert_error (errno)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; - } -#endif - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; - } - - buffer = inputlen > 0 ? (gchar*) g_memdup (input, inputlen) : NULL; - - MONO_ENTER_GC_SAFE; - ret = ioctl (((MonoFDHandle*) sockethandle)->fd, command, buffer); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - g_free (buffer); - - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: WSAIoctl error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - if (!buffer) { - *written = 0; - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; - } - - /* We just copy the buffer to the output. Some ioctls - * don't even output any data, but, well... - * - * NB windows returns WSAEFAULT if outputlen is too small */ - inputlen = (inputlen > outputlen) ? outputlen : inputlen; - - if (inputlen > 0 && output != NULL) - memcpy (output, buffer, inputlen); - - g_free (buffer); - *written = inputlen; - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -gboolean -mono_w32socket_close (SOCKET sock) -{ - if (!mono_fdhandle_close (sock)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - return TRUE; -} - -gint -mono_w32socket_set_blocking (SOCKET sock, gboolean blocking) -{ -#ifdef O_NONBLOCK - SocketHandle *sockethandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - /* This works better than ioctl(...FIONBIO...) - * on Linux (it causes connect to return - * EINPROGRESS, but the ioctl doesn't seem to) */ - MONO_ENTER_GC_SAFE; - ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_GETFL, 0); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: fcntl(F_GETFL) error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (errnum); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - MONO_ENTER_GC_SAFE; - ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_SETFL, blocking ? (ret & (~O_NONBLOCK)) : (ret | (O_NONBLOCK))); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: fcntl(F_SETFL) error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (errnum); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -#else - mono_w32socket_set_last_error (ERROR_NOT_SUPPORTED); - return SOCKET_ERROR; -#endif /* O_NONBLOCK */ -} - -gint -mono_w32socket_get_available (SOCKET sock, guint64 *amount) -{ - SocketHandle *sockethandle; - gint ret; - - if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (WSAENOTSOCK); - return SOCKET_ERROR; - } - -#if defined (HOST_DARWIN) - // ioctl (socket, FIONREAD, XXX) returns the size of - // the UDP header as well on Darwin. - // - // Use getsockopt SO_NREAD instead to get the - // right values for TCP and UDP. - // - // ai_canonname can be null in some cases on darwin, - // where the runtime assumes it will be the value of - // the ip buffer. - - socklen_t optlen = sizeof (int); - MONO_ENTER_GC_SAFE; - ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_NREAD, (gulong*) amount, &optlen); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockopt error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (errnum); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } -#else - MONO_ENTER_GC_SAFE; - ret = ioctl (((MonoFDHandle*) sockethandle)->fd, FIONREAD, (gulong*) amount); - MONO_EXIT_GC_SAFE; - if (ret == -1) { - gint errnum = mono_w32socket_convert_error (errno); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: ioctl error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (errnum); - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return SOCKET_ERROR; - } -#endif - - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - return 0; -} - -void -mono_w32socket_set_last_error (gint32 error) -{ - mono_w32error_set_last (error); -} - -gint32 -mono_w32socket_get_last_error (void) -{ - return mono_w32error_get_last (); -} - -gint32 -mono_w32socket_convert_error (gint error) -{ - switch (error) { - case 0: return ERROR_SUCCESS; - case EACCES: return WSAEACCES; -#ifdef EADDRINUSE - case EADDRINUSE: return WSAEADDRINUSE; -#endif -#ifdef EAFNOSUPPORT - case EAFNOSUPPORT: return WSAEAFNOSUPPORT; -#endif -#if EAGAIN != EWOULDBLOCK - case EAGAIN: return WSAEWOULDBLOCK; -#endif -#ifdef EALREADY - case EALREADY: return WSAEALREADY; -#endif - case EBADF: return WSAENOTSOCK; -#ifdef ECONNABORTED - case ECONNABORTED: return WSAENETDOWN; -#endif -#ifdef ECONNREFUSED - case ECONNREFUSED: return WSAECONNREFUSED; -#endif -#ifdef ECONNRESET - case ECONNRESET: return WSAECONNRESET; -#endif - case EDOM: return WSAEINVAL; /* not a precise match, best wecan do. */ - case EFAULT: return WSAEFAULT; -#ifdef EHOSTUNREACH - case EHOSTUNREACH: return WSAEHOSTUNREACH; -#endif -#ifdef EINPROGRESS - case EINPROGRESS: return WSAEINPROGRESS; -#endif - case EINTR: return WSAEINTR; - case EINVAL: return WSAEINVAL; - case EIO: return WSA_INVALID_HANDLE; /* not a precise match, best we can do. */ -#ifdef EISCONN - case EISCONN: return WSAEISCONN; -#endif - case ELOOP: return WSAELOOP; - case ENFILE: return WSAEMFILE; /* not a precise match, best we can do. */ - case EMFILE: return WSAEMFILE; -#ifdef EMSGSIZE - case EMSGSIZE: return WSAEMSGSIZE; -#endif - case ENAMETOOLONG: return WSAENAMETOOLONG; -#ifdef ENETUNREACH - case ENETUNREACH: return WSAENETUNREACH; -#endif -#ifdef ENOBUFS - case ENOBUFS: return WSAENOBUFS; /* not documented */ -#endif - case ENOMEM: return WSAENOBUFS; -#ifdef ENOPROTOOPT - case ENOPROTOOPT: return WSAENOPROTOOPT; -#endif -#ifdef ENOSR - case ENOSR: return WSAENETDOWN; -#endif -#ifdef ENOTCONN - case ENOTCONN: return WSAENOTCONN; -#endif - case ENOTDIR: return WSA_INVALID_PARAMETER; /* not a precise match, best we can do. */ -#ifdef ENOTSOCK - case ENOTSOCK: return WSAENOTSOCK; -#endif - case ENOTTY: return WSAENOTSOCK; -#ifdef EOPNOTSUPP - case EOPNOTSUPP: return WSAEOPNOTSUPP; -#endif - case EPERM: return WSAEACCES; - case EPIPE: return WSAESHUTDOWN; -#ifdef EPROTONOSUPPORT - case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT; -#endif -#if ERESTARTSYS - case ERESTARTSYS: return WSAENETDOWN; -#endif - /*FIXME: case EROFS: return WSAE????; */ -#ifdef ESOCKTNOSUPPORT - case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT; -#endif -#ifdef ETIMEDOUT - case ETIMEDOUT: return WSAETIMEDOUT; -#endif -#ifdef EWOULDBLOCK - case EWOULDBLOCK: return WSAEWOULDBLOCK; -#endif -#ifdef EADDRNOTAVAIL - case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL; -#endif - /* This might happen with unix sockets */ - case ENOENT: return WSAECONNREFUSED; -#ifdef EDESTADDRREQ - case EDESTADDRREQ: return WSAEDESTADDRREQ; -#endif -#ifdef EHOSTDOWN - case EHOSTDOWN: return WSAEHOSTDOWN; -#endif -#ifdef ENETDOWN - case ENETDOWN: return WSAENETDOWN; -#endif - case ENODEV: return WSAENETDOWN; -#ifdef EPROTOTYPE - case EPROTOTYPE: return WSAEPROTOTYPE; -#endif -#ifdef ENXIO - case ENXIO: return WSAENXIO; -#endif -#ifdef ENONET - case ENONET: return WSAENETUNREACH; -#endif -#ifdef ENOKEY - case ENOKEY: return WSAENETUNREACH; -#endif - default: - g_error ("%s: no translation into winsock error for (%d) \"%s\"", __func__, error, g_strerror (error)); - } -} - -gboolean -mono_w32socket_duplicate (gpointer handle, gint32 targetProcessId, gpointer *duplicate_handle) -{ - SocketHandle *sockethandle; - - if (!mono_fdhandle_lookup_and_ref (GPOINTER_TO_INT(handle), (MonoFDHandle**) &sockethandle)) { - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { - mono_fdhandle_unref ((MonoFDHandle*) sockethandle); - mono_w32error_set_last (ERROR_INVALID_HANDLE); - return FALSE; - } - - *duplicate_handle = handle; - return TRUE; -} diff --git a/src/mono/mono/metadata/w32socket-win32.c b/src/mono/mono/metadata/w32socket-win32.c deleted file mode 100644 index 40eb6c89415564..00000000000000 --- a/src/mono/mono/metadata/w32socket-win32.c +++ /dev/null @@ -1,309 +0,0 @@ -/** - * \file - * Windows specific socket code. - * - * Copyright 2016 Microsoft - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -#include -#include - -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include - -#include - -#include "w32socket.h" -#include "w32socket-internals.h" - -#include "utils/w32api.h" -#include "utils/mono-os-wait.h" -#include "icall-decl.h" - -#define LOGDEBUG(...) - -void -mono_w32socket_initialize (void) -{ -} - -void -mono_w32socket_cleanup (void) -{ -} - -// See win32_wait_interrupt_handler for details. -static void -win32_io_interrupt_handler(gpointer ignored) -{ -} - -#define INTERRUPTABLE_SOCKET_CALL(blocking, ret, op, sock, ...) \ - MonoThreadInfo *info = mono_thread_info_current (); \ - gboolean alerted = FALSE; \ - if (blocking && info) { \ - mono_thread_info_install_interrupt (win32_io_interrupt_handler, NULL, &alerted); \ - if (alerted) { \ - WSASetLastError (WSAEINTR); \ - } else { \ - mono_win32_enter_blocking_io_call (info, (HANDLE)sock); \ - } \ - } \ - if (!alerted) { \ - MONO_ENTER_GC_SAFE; \ - if (blocking && info && mono_thread_info_is_interrupt_state (info)) { \ - WSASetLastError (WSAEINTR); \ - } else { \ - ret = op (sock, __VA_ARGS__); \ - } \ - MONO_EXIT_GC_SAFE; \ - } \ - if (blocking && info && !alerted) { \ - mono_win32_leave_blocking_io_call (info, (HANDLE)sock); \ - mono_thread_info_uninstall_interrupt (&alerted); \ - } - -SOCKET mono_w32socket_accept (SOCKET s, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking) -{ - SOCKET ret = INVALID_SOCKET; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, accept, s, addr, addrlen); - return ret; -} - -int mono_w32socket_connect (SOCKET s, const struct sockaddr *name, int namelen, gboolean blocking) -{ - int ret = SOCKET_ERROR; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, connect, s, name, namelen); - return ret; -} - -int mono_w32socket_recv (SOCKET s, char *buf, int len, int flags, gboolean blocking) -{ - int ret = SOCKET_ERROR; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, recv, s, buf, len, flags); - return ret; -} - -int mono_w32socket_recvfrom (SOCKET s, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking) -{ - int ret = SOCKET_ERROR; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, recvfrom, s, buf, len, flags, from, fromlen); - return ret; -} - -int mono_w32socket_recvbuffers (SOCKET s, WSABUF *lpBuffers, guint32 dwBufferCount, guint32 *lpNumberOfBytesRecvd, guint32 *lpFlags, gpointer lpOverlapped, gpointer lpCompletionRoutine, gboolean blocking) -{ - int ret = SOCKET_ERROR; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, WSARecv, s, lpBuffers, dwBufferCount, (LPDWORD)lpNumberOfBytesRecvd, (LPDWORD)lpFlags, (LPWSAOVERLAPPED)lpOverlapped, (LPWSAOVERLAPPED_COMPLETION_ROUTINE)lpCompletionRoutine); - return ret; -} - -int mono_w32socket_send (SOCKET s, void *buf, int len, int flags, gboolean blocking) -{ - int ret = SOCKET_ERROR; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, send, s, (const char *)buf, len, flags); - return ret; -} - -int mono_w32socket_sendto (SOCKET s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking) -{ - int ret = SOCKET_ERROR; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, sendto, s, buf, len, flags, to, tolen); - return ret; -} - -int mono_w32socket_sendbuffers (SOCKET s, WSABUF *lpBuffers, guint32 dwBufferCount, guint32 *lpNumberOfBytesRecvd, guint32 lpFlags, gpointer lpOverlapped, gpointer lpCompletionRoutine, gboolean blocking) -{ - int ret = SOCKET_ERROR; - INTERRUPTABLE_SOCKET_CALL (blocking, ret, WSASend, s, lpBuffers, dwBufferCount, (LPDWORD)lpNumberOfBytesRecvd, lpFlags, (LPWSAOVERLAPPED)lpOverlapped, (LPWSAOVERLAPPED_COMPLETION_ROUTINE)lpCompletionRoutine); - return ret; -} - -#if HAVE_API_SUPPORT_WIN32_TRANSMIT_FILE -static gint -internal_w32socket_transmit_file (SOCKET sock, gpointer file, TRANSMIT_FILE_BUFFERS *lpTransmitBuffers, guint32 dwReserved, gboolean blocking) -{ - gint ret = ERROR_NOT_SUPPORTED; - LPFN_TRANSMITFILE transmit_file; - GUID transmit_file_guid = WSAID_TRANSMITFILE; - DWORD output_bytes; - - if (!WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &transmit_file_guid, sizeof (GUID), &transmit_file, sizeof (LPFN_TRANSMITFILE), &output_bytes, NULL, NULL)) { - MonoThreadInfo *info = mono_thread_info_current (); - gboolean alerted = FALSE; - - if (blocking && info) { - mono_thread_info_install_interrupt (win32_io_interrupt_handler, NULL, &alerted); - if (alerted) { - WSASetLastError (WSAEINTR); - } else { - mono_win32_enter_blocking_io_call (info, (HANDLE)sock); - } - } - - if (!alerted) { - MONO_ENTER_GC_SAFE; - if (blocking && info && mono_thread_info_is_interrupt_state (info)) { - WSASetLastError (WSAEINTR); - } else { - if (transmit_file (sock, file, 0, 0, NULL, lpTransmitBuffers, dwReserved)) - ret = 0; - } - MONO_EXIT_GC_SAFE; - } - - if (blocking && info && !alerted) { - mono_win32_leave_blocking_io_call (info, (HANDLE)sock); - mono_thread_info_uninstall_interrupt (&alerted); - } - } - - if (ret != 0) - ret = WSAGetLastError (); - - return ret; -} -#endif /* HAVE_API_SUPPORT_WIN32_TRANSMIT_FILE */ - -#if HAVE_API_SUPPORT_WIN32_DISCONNECT_EX -static gint -internal_w32socket_disconnect (SOCKET sock, gboolean reuse, gboolean blocking) -{ - gint ret = ERROR_NOT_SUPPORTED; - LPFN_DISCONNECTEX disconnect; - GUID disconnect_guid = WSAID_DISCONNECTEX; - DWORD output_bytes; - - if (!WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &disconnect_guid, sizeof (GUID), &disconnect, sizeof (LPFN_DISCONNECTEX), &output_bytes, NULL, NULL)) { - MonoThreadInfo *info = mono_thread_info_current (); - gboolean alerted = FALSE; - - if (blocking && info) { - mono_thread_info_install_interrupt (win32_io_interrupt_handler, NULL, &alerted); - if (alerted) { - WSASetLastError (WSAEINTR); - } else { - mono_win32_enter_blocking_io_call (info, (HANDLE)sock); - } - } - - if (!alerted) { - MONO_ENTER_GC_SAFE; - if (blocking && info && mono_thread_info_is_interrupt_state (info)) { - WSASetLastError (WSAEINTR); - } else { - if (disconnect (sock, NULL, reuse ? TF_REUSE_SOCKET : 0, 0)) - ret = 0; - } - MONO_EXIT_GC_SAFE; - } - - if (blocking && info && !alerted) { - mono_win32_leave_blocking_io_call (info, (HANDLE)sock); - mono_thread_info_uninstall_interrupt (&alerted); - } - } - - if (ret != 0) - ret = WSAGetLastError (); - - return ret; -} -#endif /* HAVE_API_SUPPORT_WIN32_DISCONNECT_EX */ - -#if HAVE_API_SUPPORT_WIN32_TRANSMIT_FILE -BOOL mono_w32socket_transmit_file (SOCKET hSocket, gpointer hFile, gpointer lpTransmitBuffers, guint32 dwReserved, gboolean blocking) -{ - return internal_w32socket_transmit_file (hSocket, hFile, (LPTRANSMIT_FILE_BUFFERS)lpTransmitBuffers, dwReserved, blocking) == 0 ? TRUE : FALSE; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_TRANSMIT_FILE -BOOL mono_w32socket_transmit_file (SOCKET hSocket, gpointer hFile, gpointer lpTransmitBuffers, guint32 dwReserved, gboolean blocking) -{ - g_unsupported_api ("TransmitFile"); - SetLastError (ERROR_NOT_SUPPORTED); - return FALSE; -} -#endif /* HAVE_API_SUPPORT_WIN32_TRANSMIT_FILE */ - -#if HAVE_API_SUPPORT_WIN32_DISCONNECT_EX -gint -mono_w32socket_disconnect (SOCKET sock, gboolean reuse) -{ - gint ret = SOCKET_ERROR; - - ret = internal_w32socket_disconnect (sock, reuse, TRUE); -#if HAVE_API_SUPPORT_WIN32_TRANSMIT_FILE - if (ret == 0) - ret = internal_w32socket_transmit_file (sock, NULL, NULL, TF_DISCONNECT | (reuse ? TF_REUSE_SOCKET : 0), TRUE); -#endif /* HAVE_API_SUPPORT_WIN32_TRANSMIT_FILE */ - - return ret; -} -#elif !HAVE_EXTERN_DEFINED_WIN32_DISCONNECT_EX -gint -mono_w32socket_disconnect (SOCKET sock, gboolean reuse) -{ - g_unsupported_api ("DisconnectEx"); - SetLastError (ERROR_NOT_SUPPORTED); - return ERROR_NOT_SUPPORTED; -} -#endif /* HAVE_API_SUPPORT_WIN32_DISCONNECT_EX */ - -gint -mono_w32socket_set_blocking (SOCKET sock, gboolean blocking) -{ - gint ret; - gulong nonblocking_long = !blocking; - MONO_ENTER_GC_SAFE; - ret = ioctlsocket (sock, FIONBIO, &nonblocking_long); - MONO_EXIT_GC_SAFE; - return ret; -} - -gint -mono_w32socket_get_available (SOCKET sock, guint64 *amount) -{ - gint ret; - u_long amount_long = 0; - MONO_ENTER_GC_SAFE; - ret = ioctlsocket (sock, FIONREAD, &amount_long); - *amount = amount_long; - MONO_EXIT_GC_SAFE; - return ret; -} - -void -mono_w32socket_set_last_error (gint32 error) -{ - WSASetLastError (error); -} - -gint32 -mono_w32socket_get_last_error (void) -{ - return WSAGetLastError (); -} - -gint32 -mono_w32socket_convert_error (gint error) -{ - return (error > 0 && error < WSABASEERR) ? error + WSABASEERR : error; -} - -gboolean -mono_w32socket_duplicate (gpointer handle, gint32 targetProcessId, gpointer *duplicate_handle) -{ - gboolean ret; - - MONO_ENTER_GC_SAFE; - ret = DuplicateHandle (GetCurrentProcess(), handle, GINT_TO_POINTER(targetProcessId), duplicate_handle, 0, 0, 0x00000002 /* DUPLICATE_SAME_ACCESS */); - MONO_EXIT_GC_SAFE; - - return ret; -} diff --git a/src/mono/mono/metadata/w32socket.h b/src/mono/mono/metadata/w32socket.h deleted file mode 100644 index 650e64d6f3411a..00000000000000 --- a/src/mono/mono/metadata/w32socket.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * \file - * System.Net.Sockets.Socket support - * - * Author: - * Dick Porter (dick@ximian.com) - * - * (C) 2001 Ximian, Inc. - */ - -#ifndef _MONO_METADATA_W32SOCKET_H_ -#define _MONO_METADATA_W32SOCKET_H_ - -#include -#include -#include -#include - -#ifndef HOST_WIN32 -#define INVALID_SOCKET ((SOCKET)(guint32)(~0)) -#define SOCKET_ERROR (-1) - -typedef gint SOCKET; - -typedef struct { - guint32 len; - gpointer buf; -} WSABUF, *LPWSABUF; -#endif - -#endif /* _MONO_METADATA_W32SOCKET_H_ */ diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index b3b4b609df9c77..410c445501146a 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -68,7 +68,6 @@ #include #include #include -#include #include #include #include diff --git a/src/mono/mono/mini/mini-wasm.c b/src/mono/mono/mini/mini-wasm.c index b87b6caf990696..582bb6fbff1e09 100644 --- a/src/mono/mono/mini/mini-wasm.c +++ b/src/mono/mono/mini/mini-wasm.c @@ -634,11 +634,6 @@ mono_arch_patch_code_new (MonoCompile *cfg, guint8 *code, MonoJumpInfo *ji, gpoi #ifdef HOST_WASM -/* -The following functions don't belong here, but are due to laziness. -*/ -gboolean mono_w32file_get_file_system_type (const gunichar2 *path, gunichar2 *fsbuffer, gint fsbuffersize); - G_BEGIN_DECLS void * getgrnam (const char *name); @@ -650,25 +645,6 @@ int sem_timedwait (sem_t *sem, const struct timespec *abs_timeout); G_END_DECLS -//w32file-wasm.c -gboolean -mono_w32file_get_file_system_type (const gunichar2 *path, gunichar2 *fsbuffer, gint fsbuffersize) -{ - glong len; - gboolean status = FALSE; - - gunichar2 *ret = g_utf8_to_utf16 ("memfs", -1, NULL, &len, NULL); - if (ret != NULL && len < fsbuffersize) { - memcpy (fsbuffer, ret, len * sizeof (gunichar2)); - fsbuffer [len] = 0; - status = TRUE; - } - if (ret != NULL) - g_free (ret); - - return status; -} - G_BEGIN_DECLS //llvm builtin's that we should not have used in the first place From bb3ae83483e26a4dfe453f8b35da04561bcf066f Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Fri, 26 Feb 2021 01:09:06 -0500 Subject: [PATCH 29/36] Disable another test --- src/libraries/System.Threading/tests/MutexTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Threading/tests/MutexTests.cs b/src/libraries/System.Threading/tests/MutexTests.cs index aa88080a11530a..a893662df15195 100644 --- a/src/libraries/System.Threading/tests/MutexTests.cs +++ b/src/libraries/System.Threading/tests/MutexTests.cs @@ -530,6 +530,7 @@ public void NamedMutex_ThreadExitDisposeRaceTest() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] public void NamedMutex_DisposeWhenLockedRaceTest() { var mutexName = Guid.NewGuid().ToString("N"); From 696fc100e35e135c46a8dc69e1f9f873eb70c300 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Fri, 26 Feb 2021 01:11:37 -0500 Subject: [PATCH 30/36] Windows build fix --- src/mono/mono/metadata/w32file-win32.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mono/mono/metadata/w32file-win32.c b/src/mono/mono/metadata/w32file-win32.c index 70405c9eac2af7..124b2bbbd5f6f6 100644 --- a/src/mono/mono/metadata/w32file-win32.c +++ b/src/mono/mono/metadata/w32file-win32.c @@ -43,6 +43,11 @@ mono_w32file_close (gpointer handle) return res; } +static void +win32_io_interrupt_handler (gpointer ignored) +{ +} + gboolean mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error) { From 65801bd5eedb8dc595cb1be44fafa45efb739be9 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Fri, 12 Mar 2021 00:33:37 -0500 Subject: [PATCH 31/36] Disable InterruptTest on Windows --- src/libraries/System.Threading.Thread/tests/ThreadTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Threading.Thread/tests/ThreadTests.cs b/src/libraries/System.Threading.Thread/tests/ThreadTests.cs index c3545ca12cc6b0..e083072a133a30 100644 --- a/src/libraries/System.Threading.Thread/tests/ThreadTests.cs +++ b/src/libraries/System.Threading.Thread/tests/ThreadTests.cs @@ -913,6 +913,7 @@ public static void LocalDataSlotTest() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/49521", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] public static void InterruptTest() { // Interrupting a thread that is not blocked does not do anything, but once the thread starts blocking, it gets From 3472b0b7d548c6f7b4cc644cf4f6069a68e48550 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Fri, 12 Mar 2021 00:34:01 -0500 Subject: [PATCH 32/36] Add link to issue on reentrant wait support for Windows --- .../src/System/Threading/WaitHandle.Windows.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs index 2115e6b6e818f0..af3a8a38461c81 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitHandle.Windows.cs @@ -26,7 +26,7 @@ private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr* pHan if (numHandles == 1) waitAll = false; -#if !MONO // TODO: reentrant wait support +#if CORERT // TODO: reentrant wait support https://github.com/dotnet/runtime/issues/49518 bool reentrantWait = Thread.ReentrantWaitsEnabled; if (reentrantWait) @@ -48,7 +48,7 @@ private static unsafe int WaitForMultipleObjectsIgnoringSyncContext(IntPtr* pHan Thread currentThread = Thread.CurrentThread; currentThread.SetWaitSleepJoinState(); -#if !MONO +#if CORERT int result; if (reentrantWait) { From def05abde3ac452d167192d57eebcf87fbb2607a Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Fri, 12 Mar 2021 00:45:46 -0500 Subject: [PATCH 33/36] Move mutex abandoning to the managed Thread object's finalizer I originally implemented Zoltan's suggestion, but this seems to work and is significantly cleaner. Pre-jitting is also an option here, so if this doesn't work try that next. --- .../src/System/Threading/Thread.Mono.cs | 6 ++++-- src/mono/mono/metadata/threads.c | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs index e24fcb58d2fded..c1978eab5f1114 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs @@ -81,6 +81,9 @@ private Thread() ~Thread() { +#if TARGET_UNIX || TARGET_BROWSER + WaitSubsystem.OnThreadExiting(this); +#endif FreeInternal(); } @@ -193,7 +196,7 @@ public static int GetCurrentProcessorId() public void Interrupt() { -#if TARGET_UNIX || TARGET_BROWSER +#if TARGET_UNIX || TARGET_BROWSER // TODO: https://github.com/dotnet/runtime/issues/49521 WaitSubsystem.Interrupt(this); #endif InterruptInternal(this); @@ -212,7 +215,6 @@ public bool Join(int millisecondsTimeout) private void Initialize() { InitInternal(this); - #if TARGET_UNIX || TARGET_BROWSER _waitInfo = new WaitSubsystem.ThreadWaitInfo(this); #endif diff --git a/src/mono/mono/metadata/threads.c b/src/mono/mono/metadata/threads.c index 58e4bfb290aecf..98956c4a1d0d76 100644 --- a/src/mono/mono/metadata/threads.c +++ b/src/mono/mono/metadata/threads.c @@ -863,7 +863,8 @@ static GENERATE_GET_CLASS_WITH_CACHE (wait_subsystem, "System.Threading", "WaitS static void abandon_mutexes (MonoInternalThread *internal) { - ERROR_DECL (error); + // TODO: delete me if we decide not to prejit +/* ERROR_DECL (error); MONO_STATIC_POINTER_INIT (MonoMethod, thread_exiting) @@ -889,7 +890,7 @@ abandon_mutexes (MonoInternalThread *internal) mono_error_cleanup (error); - HANDLE_FUNCTION_RETURN (); + HANDLE_FUNCTION_RETURN ();*/ } #endif From 891987beefc9d314db5385f8005492a724c3fdb4 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Fri, 12 Mar 2021 00:46:49 -0500 Subject: [PATCH 34/36] Rethrow with InvalidOperationException when called from WaitHandle I think it would make much more sense to always throw SemaphoreFullException instead of sometimes throwing InvalidOperationException saying the semaphore is full, but this preserves the old behavior. --- .../src/System/Threading/WaitSubsystem.Unix.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs index be05d6c7bc497c..bd622d9f69401b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs @@ -375,7 +375,14 @@ public static int SignalAndWait( throw new ThreadInterruptedException(); } - waitableObjectToSignal.Signal(1); + try + { + waitableObjectToSignal.Signal(1); + } + catch (SemaphoreFullException ex) + { + throw new InvalidOperationException(SR.Threading_WaitHandleTooManyPosts, ex); + } waitCalled = true; return waitableObjectToWaitOn.Wait_Locked(waitInfo, timeoutMilliseconds, interruptible, prioritize); } From a9dd5c3ff6d42acdcd8717b4055fe3b1b21b7938 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Fri, 12 Mar 2021 05:44:35 -0500 Subject: [PATCH 35/36] Another ActiveIssue on Windows --- src/libraries/System.Threading.Thread/tests/ThreadTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Threading.Thread/tests/ThreadTests.cs b/src/libraries/System.Threading.Thread/tests/ThreadTests.cs index e083072a133a30..4e680e0c2b07d3 100644 --- a/src/libraries/System.Threading.Thread/tests/ThreadTests.cs +++ b/src/libraries/System.Threading.Thread/tests/ThreadTests.cs @@ -963,6 +963,7 @@ public static void InterruptTest() } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/49521", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] public static void InterruptInFinallyBlockTest_SkipOnDesktopFramework() { // A wait in a finally block can be interrupted. The .NET Framework applies the same rules as thread abort, and From cc1478836fca2a1cb940e7f3a01d98416637cd23 Mon Sep 17 00:00:00 2001 From: Ryan Lucia Date: Fri, 12 Mar 2021 05:44:49 -0500 Subject: [PATCH 36/36] Linker exclusion no longer needed --- .../System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml index d43b86f838267f..f066b8f010d43d 100644 --- a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml +++ b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml @@ -611,10 +611,6 @@ - - - -