X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fio-layer%2Fwthreads.c;h=16c5f0e50d216792013e68cce625bed5cd8fc06c;hb=01814d4a1979440872dc4841053ae7bb9e5c8855;hp=5245f6df9068787d302999c98bda374eee0e136b;hpb=66e33aa2ee25b9de6ff80e41aa7036b9a8352479;p=mono.git diff --git a/mono/io-layer/wthreads.c b/mono/io-layer/wthreads.c index 5245f6df906..16c5f0e50d2 100644 --- a/mono/io-layer/wthreads.c +++ b/mono/io-layer/wthreads.c @@ -7,6 +7,7 @@ * (C) 2002-2006 Ximian, Inc. * Copyright 2003-2011 Novell, Inc (http://www.novell.com) * Copyright 2011 Xamarin, Inc (http://www.xamarin.com) + * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ #include @@ -22,47 +23,60 @@ #include #include -#include #include #include +#include #include #include #include #include +#include +#include #ifdef HAVE_VALGRIND_MEMCHECK_H #include #endif -#if 0 -#define DEBUG(...) g_message(__VA_ARGS__) -#else -#define DEBUG(...) -#endif - -#if 0 -#define WAIT_DEBUG(code) do { code } while (0) -#else -#define WAIT_DEBUG(code) do { } while (0) -#endif +static void thread_details (gpointer data); +static const gchar* thread_typename (void); +static gsize thread_typesize (void); -struct _WapiHandleOps _wapi_thread_ops = { +static MonoW32HandleOps _wapi_thread_ops = { NULL, /* close */ NULL, /* signal */ NULL, /* own */ NULL, /* is_owned */ NULL, /* special_wait */ - NULL /* prewait */ + NULL, /* prewait */ + thread_details, /* details */ + thread_typename, /* typename */ + thread_typesize, /* typesize */ }; -static mono_once_t thread_ops_once = MONO_ONCE_INIT; +void +_wapi_thread_init (void) +{ + mono_w32handle_register_ops (MONO_W32HANDLE_THREAD, &_wapi_thread_ops); + + mono_w32handle_register_capabilities (MONO_W32HANDLE_THREAD, MONO_W32HANDLE_CAP_WAIT); +} + +static void thread_details (gpointer data) +{ + WapiHandle_thread *thread = (WapiHandle_thread*) data; + g_print ("id: %p, owned_mutexes: %d, priority: %d", + thread->id, thread->owned_mutexes->len, thread->priority); +} + +static const gchar* thread_typename (void) +{ + return "Thread"; +} -static void -thread_ops_init (void) +static gsize thread_typesize (void) { - _wapi_handle_register_capabilities (WAPI_HANDLE_THREAD, - WAPI_HANDLE_CAP_WAIT); + return sizeof (WapiHandle_thread); } void @@ -87,7 +101,7 @@ lookup_thread (HANDLE handle) WapiHandle_thread *thread; gboolean ok; - ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD, + ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_THREAD, (gpointer *)&thread); g_assert (ok); return thread; @@ -110,19 +124,19 @@ wapi_thread_handle_set_exited (gpointer handle, guint32 exitstatus) pid_t pid = _wapi_getpid (); pthread_t tid = pthread_self (); - if (_wapi_handle_issignalled (handle) || - _wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) { + if (mono_w32handle_issignalled (handle) || + mono_w32handle_get_type (handle) == MONO_W32HANDLE_UNUSED) { /* We must have already deliberately finished with * this thread, so don't do any more now */ return; } - DEBUG ("%s: Thread %p terminating", __func__, handle); + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Thread %p terminating", __func__, handle); thread_handle = lookup_thread (handle); - DEBUG ("%s: Thread %p abandoning held mutexes", __func__, handle); + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Thread %p abandoning held mutexes", __func__, handle); for (i = 0; i < thread_handle->owned_mutexes->len; i++) { gpointer mutex = g_ptr_array_index (thread_handle->owned_mutexes, i); @@ -132,19 +146,19 @@ wapi_thread_handle_set_exited (gpointer handle, guint32 exitstatus) } g_ptr_array_free (thread_handle->owned_mutexes, TRUE); - thr_ret = _wapi_handle_lock_handle (handle); + thr_ret = mono_w32handle_lock_handle (handle); g_assert (thr_ret == 0); - _wapi_handle_set_signal_state (handle, TRUE, TRUE); + mono_w32handle_set_signal_state (handle, TRUE, TRUE); - thr_ret = _wapi_handle_unlock_handle (handle); + thr_ret = mono_w32handle_unlock_handle (handle); g_assert (thr_ret == 0); - DEBUG("%s: Recording thread handle %p id %ld status as %d", + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Recording thread handle %p id %ld status as %d", __func__, handle, thread_handle->id, exitstatus); /* The thread is no longer active, so unref it */ - _wapi_handle_unref (handle); + mono_w32handle_unref (handle); } /* @@ -158,12 +172,10 @@ wapi_create_thread_handle (void) WapiHandle_thread thread_handle = {0}, *thread; gpointer handle; - mono_once (&thread_ops_once, thread_ops_init); - thread_handle.owned_mutexes = g_ptr_array_new (); - handle = _wapi_handle_new (WAPI_HANDLE_THREAD, &thread_handle); - if (handle == _WAPI_HANDLE_INVALID) { + handle = mono_w32handle_new (MONO_W32HANDLE_THREAD, &thread_handle); + if (handle == INVALID_HANDLE_VALUE) { g_warning ("%s: error creating thread handle", __func__); SetLastError (ERROR_GEN_FAILURE); @@ -178,9 +190,9 @@ wapi_create_thread_handle (void) * Hold a reference while the thread is active, because we use * the handle to store thread exit information */ - _wapi_handle_ref (handle); + mono_w32handle_ref (handle); - DEBUG ("%s: started thread id %ld", __func__, thread->id); + MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: started thread id %ld", __func__, thread->id); return handle; } @@ -188,7 +200,7 @@ wapi_create_thread_handle (void) void wapi_ref_thread_handle (gpointer handle) { - _wapi_handle_ref (handle); + mono_w32handle_ref (handle); } gpointer @@ -210,7 +222,7 @@ _wapi_thread_own_mutex (gpointer mutex) thread = get_current_thread (); - _wapi_handle_ref (mutex); + mono_w32handle_ref (mutex); g_ptr_array_add (thread->owned_mutexes, mutex); } @@ -222,11 +234,229 @@ _wapi_thread_disown_mutex (gpointer mutex) thread = get_current_thread (); - _wapi_handle_unref (mutex); + mono_w32handle_unref (mutex); g_ptr_array_remove (thread->owned_mutexes, mutex); } +/** + * wapi_init_thread_info_priority: + * @param handle: The thread handle to set. + * @param priority: Priority to initialize with + * + * Initialize the priority field of the thread info + */ +void +wapi_init_thread_info_priority (gpointer handle, gint32 priority) +{ + struct _WapiHandle_thread *thread_handle = NULL; + gboolean ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_THREAD, + (gpointer *)&thread_handle); + + if (ok == TRUE) + thread_handle->priority = priority; +} + +/** + * _wapi_thread_posix_priority_to_priority: + * + * Convert a POSIX priority to a WapiThreadPriority. + * sched_priority is a POSIX priority, + * policy is the current scheduling policy + */ +static WapiThreadPriority +_wapi_thread_posix_priority_to_priority (int sched_priority, int policy) +{ +/* Necessary to get valid priority range */ +#ifdef _POSIX_PRIORITY_SCHEDULING + int max, + min, + i, + priority, + chunk; + WapiThreadPriority priorities[] = { + THREAD_PRIORITY_LOWEST, + THREAD_PRIORITY_LOWEST, + THREAD_PRIORITY_BELOW_NORMAL, + THREAD_PRIORITY_NORMAL, + THREAD_PRIORITY_ABOVE_NORMAL, + THREAD_PRIORITY_HIGHEST, + THREAD_PRIORITY_HIGHEST + }; + + max = sched_get_priority_max (policy); + min = sched_get_priority_min (policy); + + /* Partition priority range linearly, + assign each partition a thread priority */ + if (max != min && 0 <= max && 0 <= min) { + for (i=1, priority=min, chunk=(max-min)/7; + i<6 && sched_priority > priority; + ++i) { + priority += chunk; + } + + if (max <= priority) + { + return (THREAD_PRIORITY_HIGHEST); + } + else + { + return (priorities[i-1]); + } + } +#endif + + return (THREAD_PRIORITY_NORMAL); +} + +/** + * wapi_thread_priority_to_posix_priority: + * + * Convert a WapiThreadPriority to a POSIX priority. + * priority is a WapiThreadPriority, + * policy is the current scheduling policy + */ +int +wapi_thread_priority_to_posix_priority (WapiThreadPriority priority, int policy) +{ +/* Necessary to get valid priority range */ +#ifdef _POSIX_PRIORITY_SCHEDULING + int max, + min, + posix_priority, + i; + WapiThreadPriority priorities[] = { + THREAD_PRIORITY_LOWEST, + THREAD_PRIORITY_LOWEST, + THREAD_PRIORITY_BELOW_NORMAL, + THREAD_PRIORITY_NORMAL, + THREAD_PRIORITY_ABOVE_NORMAL, + THREAD_PRIORITY_HIGHEST, + THREAD_PRIORITY_HIGHEST + }; + + max = sched_get_priority_max (policy); + min = sched_get_priority_min (policy); + + /* Partition priority range linearly, + numerically approximate matching ThreadPriority */ + if (max != min && 0 <= max && 0 <= min) { + for (i=0; i<7; ++i) { + if (priorities[i] == priority) { + posix_priority = min + ((max-min)/7) * i; + if (max < posix_priority) + { + return max; + } + else { + return posix_priority; + } + } + } + } +#endif + + switch (policy) { + case SCHED_FIFO: + case SCHED_RR: + return 50; +#ifdef SCHED_BATCH + case SCHED_BATCH: +#endif + case SCHED_OTHER: + return 0; + default: + return -1; + } +} + +/** + * GetThreadPriority: + * @param handle: The thread handle to query. + * + * Gets the priority of the given thread. + * @return: A MonoThreadPriority approximating the current POSIX + * thread priority, or THREAD_PRIORITY_NORMAL on error. + */ +gint32 +GetThreadPriority (gpointer handle) +{ + struct _WapiHandle_thread *thread_handle = NULL; + int policy; + struct sched_param param; + gboolean ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_THREAD, + (gpointer *)&thread_handle); + + if (ok == FALSE) + return (THREAD_PRIORITY_NORMAL); + + switch (pthread_getschedparam (thread_handle->id, &policy, ¶m)) { + case 0: + if ((policy == SCHED_FIFO) || (policy == SCHED_RR)) + return (_wapi_thread_posix_priority_to_priority (param.sched_priority, policy)); + else + return (thread_handle->priority); + case ESRCH: + g_warning ("pthread_getschedparam: error looking up thread id %x", (gsize)thread_handle->id); + } + + return (THREAD_PRIORITY_NORMAL); +} + +/** + * SetThreadPriority: + * @param handle: The thread handle to query. + * @param priority: The priority to give to the thread. + * + * Sets the priority of the given thread. + * @return: TRUE on success, FALSE on failure or error. + */ +gboolean +SetThreadPriority (gpointer handle, gint32 priority) +{ + struct _WapiHandle_thread *thread_handle = NULL; + int policy, + posix_priority, + rv; + struct sched_param param; + gboolean ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_THREAD, + (gpointer *)&thread_handle); + + if (ok == FALSE) { + return ok; + } + + rv = pthread_getschedparam (thread_handle->id, &policy, ¶m); + if (rv) { + if (ESRCH == rv) + g_warning ("pthread_getschedparam: error looking up thread id %x", (gsize)thread_handle->id); + return FALSE; + } + + posix_priority = wapi_thread_priority_to_posix_priority (priority, policy); + if (0 > posix_priority) + return FALSE; + + param.sched_priority = posix_priority; + switch (pthread_setschedparam (thread_handle->id, policy, ¶m)) { + case 0: + thread_handle->priority = priority; + return TRUE; + case ESRCH: + g_warning ("pthread_setschedprio: error looking up thread id %x", (gsize)thread_handle->id); + break; + case ENOTSUP: + g_warning ("%s: priority %d not supported", __func__, priority); + break; + case EPERM: + g_warning ("%s: permission denied", __func__); + break; + } + + return FALSE; +} + char* wapi_current_thread_desc (void) {