Created
November 6, 2014 07:59
-
-
Save aasimon/c8ae6fc3cf5d9b82b6ca to your computer and use it in GitHub Desktop.
Patch for SetThreadPriority support in mono-3.2.8
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/mcs/class/corlib/System.Threading/Thread.cs b/mcs/class/corlib/System.Threading/Thread.cs | |
index 5af6800..112751d 100644 | |
--- a/mcs/class/corlib/System.Threading/Thread.cs | |
+++ b/mcs/class/corlib/System.Threading/Thread.cs | |
@@ -98,13 +98,13 @@ namespace System.Threading { | |
private IntPtr android_tid; | |
private IntPtr thread_pinning_ref; | |
private int ignore_next_signal; | |
+ private int thread_priority; | |
/* | |
* These fields are used to avoid having to increment corlib versions | |
* when a new field is added to the unmanaged MonoThread structure. | |
*/ | |
private IntPtr unused0; | |
private IntPtr unused1; | |
- private IntPtr unused2; | |
#endregion | |
#pragma warning restore 169, 414, 649 | |
@@ -585,13 +585,19 @@ namespace System.Threading { | |
} | |
} | |
+ [MethodImplAttribute(MethodImplOptions.InternalCall)] | |
+ private extern static ThreadPriority GetPriority_internal (InternalThread thread); | |
+ | |
+ [MethodImplAttribute(MethodImplOptions.InternalCall)] | |
+ private extern static void SetPriority_internal (InternalThread thread, ThreadPriority priority); | |
+ | |
public ThreadPriority Priority { | |
get { | |
- return(ThreadPriority.Lowest); | |
+ return GetPriority_internal (Internal); | |
} | |
set { | |
- // FIXME: Implement setter. | |
+ SetPriority_internal (Internal, value); | |
} | |
} | |
diff --git a/mono/io-layer/thread-private.h b/mono/io-layer/thread-private.h | |
index 1c62618..53467b8 100644 | |
--- a/mono/io-layer/thread-private.h | |
+++ b/mono/io-layer/thread-private.h | |
@@ -37,6 +37,7 @@ struct _WapiHandle_thread | |
guint32 create_flags; | |
/* Fields below this point are only valid for the owning process */ | |
pthread_t id; | |
+ pid_t pid; | |
GPtrArray *owned_mutexes; | |
gpointer handle; | |
/* | |
diff --git a/mono/io-layer/threads.h b/mono/io-layer/threads.h | |
index 12b7c0c..7b21556 100644 | |
--- a/mono/io-layer/threads.h | |
+++ b/mono/io-layer/threads.h | |
@@ -59,6 +59,8 @@ extern void Sleep(guint32 ms); | |
extern guint32 SleepEx(guint32 ms, gboolean alertable); | |
extern guint32 QueueUserAPC (WapiApcProc apc_callback, gpointer thread_handle, | |
gpointer param); | |
+extern gint32 GetThreadPriority (gpointer handle, gint32 *thread_priority); | |
+extern gboolean SetThreadPriority (gpointer handle, gint32 *thread_priorit, gint32 priority); | |
/* Kludge alert! Making this visible outside io-layer is broken, but I | |
* can't find any w32 call that will let me do this. | |
diff --git a/mono/io-layer/wthreads.c b/mono/io-layer/wthreads.c | |
index e623d71..dfa1aac 100644 | |
--- a/mono/io-layer/wthreads.c | |
+++ b/mono/io-layer/wthreads.c | |
@@ -20,6 +20,7 @@ | |
#include <errno.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
+#include <sys/resource.h> | |
#include <mono/io-layer/wapi.h> | |
#include <mono/io-layer/wapi-private.h> | |
@@ -70,6 +71,14 @@ struct _WapiHandleOps _wapi_thread_ops = { | |
NULL /* prewait */ | |
}; | |
+typedef enum { | |
+ THREAD_PRIORITY_LOWEST = -2, | |
+ THREAD_PRIORITY_BELOW_NORMAL = -1, | |
+ THREAD_PRIORITY_NORMAL = 0, | |
+ THREAD_PRIORITY_ABOVE_NORMAL = 1, | |
+ THREAD_PRIORITY_HIGHEST = 2 | |
+} WapiThreadPriority; | |
+ | |
static mono_once_t thread_ops_once=MONO_ONCE_INIT; | |
static void thread_ops_init (void) | |
@@ -1306,3 +1315,118 @@ void _wapi_thread_disown_mutex (gpointer mutex) | |
g_ptr_array_remove (thread_handle->owned_mutexes, mutex); | |
} | |
+ | |
+/** | |
+ * _wapi_posix_priority_to_thread_priority: | |
+ * | |
+ * Convert a POSIX priority to a WapiThreadPriority. | |
+ * @sched_priority The POSIX priority to covert ( see getpriority(2) ) | |
+ * Returns the corresponding WapiThreadPriority. | |
+ */ | |
+static WapiThreadPriority _wapi_posix_priority_to_thread_priority (int sched_priority) | |
+{ | |
+/* Necessary to get valid priority range */ | |
+#ifdef _POSIX_PRIORITY_SCHEDULING | |
+ switch(sched_priority) { | |
+ case -20 ... -11: return (THREAD_PRIORITY_HIGHEST); | |
+ case -10 ... -1: return (THREAD_PRIORITY_ABOVE_NORMAL); | |
+ case 0: return (THREAD_PRIORITY_NORMAL); | |
+ case 1 ... 10: return (THREAD_PRIORITY_BELOW_NORMAL); | |
+ case 11 ... 19: return (THREAD_PRIORITY_LOWEST); | |
+ default: break; | |
+ } | |
+#endif | |
+ | |
+ return (THREAD_PRIORITY_NORMAL); | |
+} | |
+ | |
+/** | |
+ * _wapi_thread_priority_to_posix_priority: | |
+ * | |
+ * Convert a WapiThreadPriority to a POSIX priority. | |
+ * | |
+ * @sched_priority The WapiThreadPriorityThe covert. | |
+ * | |
+ * Returns the corresponding POSIX priority ( see getpriority(2) ) | |
+ */ | |
+static int _wapi_thread_priority_to_posix_priority (WapiThreadPriority priority) | |
+{ | |
+/* Necessary to get valid priority range */ | |
+#ifdef _POSIX_PRIORITY_SCHEDULING | |
+ switch(priority) { | |
+ case THREAD_PRIORITY_HIGHEST: return (-20); | |
+ case THREAD_PRIORITY_ABOVE_NORMAL: return (-10); | |
+ case THREAD_PRIORITY_NORMAL: return ( 0); | |
+ case THREAD_PRIORITY_BELOW_NORMAL: return ( 10); | |
+ case THREAD_PRIORITY_LOWEST: return ( 19); | |
+ } | |
+ | |
+#endif | |
+ return (0); | |
+} | |
+ | |
+/** | |
+ * GetThreadPriority: | |
+ * Gets the priority of the given thread. | |
+ * | |
+ * @handle: The thread handle to query. | |
+ * | |
+ * Returns a MonoThreadPriority approximating the current POSIX | |
+ * thread priority, or THREAD_PRIORITY_NORMAL on error. | |
+ */ | |
+gint32 GetThreadPriority (gpointer handle, gint32 *thread_priority) | |
+{ | |
+ struct _WapiHandle_thread *thread_handle; | |
+ int prio; | |
+ gboolean ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD, (gpointer *)&thread_handle); | |
+ | |
+ if (ok == FALSE) return (THREAD_PRIORITY_NORMAL); | |
+ | |
+ if (thread_handle->pid == 0) { | |
+ /* Thread not yet started; return intended priority. */ | |
+ return *thread_priority; | |
+ } | |
+ | |
+ errno = 0; | |
+ prio = getpriority (PRIO_PROCESS, thread_handle->pid); | |
+ if (prio == -1) { | |
+ g_warning ("%s: getpriority could not get priority: %s", __func__, strerror (errno)); | |
+ return (THREAD_PRIORITY_NORMAL); | |
+ } | |
+ | |
+ return _wapi_posix_priority_to_thread_priority (prio); | |
+} | |
+ | |
+/** | |
+ * SetThreadPriority: | |
+ * Sets the priority of the given thread. | |
+ * | |
+ * @handle: The thread handle to query. | |
+ * @priority: The priority to give to the thread. | |
+ * | |
+ * Returns TRUE on success, FALSE on failure or error. | |
+ */ | |
+gboolean SetThreadPriority (gpointer handle, gint32 *thread_priority, gint32 priority) | |
+{ | |
+ struct _WapiHandle_thread *thread_handle; | |
+ int ret; | |
+ gboolean ok; | |
+ | |
+ *thread_priority = _wapi_thread_priority_to_posix_priority (priority); | |
+ | |
+ ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD, (gpointer *)&thread_handle); | |
+ | |
+ if (ok == FALSE) return (FALSE); | |
+ | |
+ if (thread_handle->pid != 0) { | |
+ /* Thread already running; set priority now. */ | |
+ errno = 0; | |
+ ret = setpriority (PRIO_PROCESS, thread_handle->pid, *thread_priority); | |
+ if (ret == -1) { | |
+ g_warning ("%s: setpriority could not set priority %d: %s", __func__, *thread_priority, strerror (errno)); | |
+ return (FALSE); | |
+ } | |
+ } | |
+ | |
+ return (TRUE); | |
+} | |
diff --git a/mono/metadata/icall-def.h b/mono/metadata/icall-def.h | |
index 63fb708..bb5ecdf 100644 | |
--- a/mono/metadata/icall-def.h | |
+++ b/mono/metadata/icall-def.h | |
@@ -871,6 +871,7 @@ ICALL(THREAD_4, "FreeLocalSlotValues", mono_thread_free_local_slot_values) | |
ICALL(THREAD_55, "GetAbortExceptionState", ves_icall_System_Threading_Thread_GetAbortExceptionState) | |
ICALL(THREAD_7, "GetDomainID", ves_icall_System_Threading_Thread_GetDomainID) | |
ICALL(THREAD_8, "GetName_internal(System.Threading.InternalThread)", ves_icall_System_Threading_Thread_GetName_internal) | |
+ICALL(THREAD_56, "GetPriority_internal(System.Threading.InternalThread)", ves_icall_System_Threading_Thread_GetPriority_internal) | |
ICALL(THREAD_11, "GetState(System.Threading.InternalThread)", ves_icall_System_Threading_Thread_GetState) | |
ICALL(THREAD_53, "Interrupt_internal(System.Threading.InternalThread)", ves_icall_System_Threading_Thread_Interrupt_internal) | |
ICALL(THREAD_12, "Join_internal(System.Threading.InternalThread,int,intptr)", ves_icall_System_Threading_Thread_Join_internal) | |
@@ -878,6 +879,7 @@ ICALL(THREAD_13, "MemoryBarrier", ves_icall_System_Threading_Thread_MemoryBarrie | |
ICALL(THREAD_14, "ResetAbort_internal()", ves_icall_System_Threading_Thread_ResetAbort) | |
ICALL(THREAD_15, "Resume_internal()", ves_icall_System_Threading_Thread_Resume) | |
ICALL(THREAD_18, "SetName_internal(System.Threading.InternalThread,string)", ves_icall_System_Threading_Thread_SetName_internal) | |
+ICALL(THREAD_57, "SetPriority_internal(System.Threading.InternalThread,System.Threading.ThreadPriority)", ves_icall_System_Threading_Thread_SetPriority_internal) | |
ICALL(THREAD_21, "SetState(System.Threading.InternalThread,System.Threading.ThreadState)", ves_icall_System_Threading_Thread_SetState) | |
ICALL(THREAD_22, "Sleep_internal", ves_icall_System_Threading_Thread_Sleep_internal) | |
ICALL(THREAD_54, "SpinWait_nop", ves_icall_System_Threading_Thread_SpinWait_nop) | |
diff --git a/mono/metadata/object-internals.h b/mono/metadata/object-internals.h | |
index d969533..4c3d914 100644 | |
--- a/mono/metadata/object-internals.h | |
+++ b/mono/metadata/object-internals.h | |
@@ -436,6 +436,7 @@ struct _MonoInternalThread { | |
gpointer thread_pinning_ref; | |
gint32 ignore_next_signal; | |
MonoMethod *async_invoke_method; | |
+ int thread_priority; /* Used by Get/SetThreadPriority */ | |
/* | |
* These fields are used to avoid having to increment corlib versions | |
* when a new field is added to this structure. | |
@@ -443,7 +444,6 @@ struct _MonoInternalThread { | |
* same field there. | |
*/ | |
gpointer unused1; | |
- gpointer unused2; | |
}; | |
struct _MonoThread { | |
diff --git a/mono/metadata/threads-types.h b/mono/metadata/threads-types.h | |
index b090fcb..edb6bcf 100644 | |
--- a/mono/metadata/threads-types.h | |
+++ b/mono/metadata/threads-types.h | |
@@ -67,6 +67,8 @@ gint32 ves_icall_System_Threading_Thread_GetDomainID (void) MONO_INTERNAL; | |
gboolean ves_icall_System_Threading_Thread_Yield (void) MONO_INTERNAL; | |
MonoString* ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj) MONO_INTERNAL; | |
void ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name) MONO_INTERNAL; | |
+gint32 ves_icall_System_Threading_Thread_GetPriority_internal (MonoInternalThread *this_obj) MONO_INTERNAL; | |
+void ves_icall_System_Threading_Thread_SetPriority_internal (MonoInternalThread *this_obj, gint32 priority) MONO_INTERNAL; | |
MonoObject* ves_icall_System_Threading_Thread_GetCachedCurrentCulture (MonoInternalThread *this_obj) MONO_INTERNAL; | |
void ves_icall_System_Threading_Thread_SetCachedCurrentCulture (MonoThread *this_obj, MonoObject *culture) MONO_INTERNAL; | |
MonoObject* ves_icall_System_Threading_Thread_GetCachedCurrentUICulture (MonoInternalThread *this_obj) MONO_INTERNAL; | |
diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c | |
index 1b421c4..3727d82 100755 | |
--- a/mono/metadata/threads.c | |
+++ b/mono/metadata/threads.c | |
@@ -37,6 +37,11 @@ | |
#include <mono/io-layer/io-layer.h> | |
#ifndef HOST_WIN32 | |
#include <mono/io-layer/threads.h> | |
+#include <mono/io-layer/wapi-private.h> | |
+#include <mono/io-layer/handles-private.h> | |
+#include <sys/syscall.h> | |
+#include <sys/time.h> | |
+#include <sys/resource.h> | |
#endif | |
#include <mono/metadata/object-internals.h> | |
#include <mono/metadata/mono-debug-debugger.h> | |
@@ -550,6 +555,11 @@ static guint32 WINAPI start_wrapper_internal(void *data) | |
guint32 (*start_func)(void *); | |
void *start_arg; | |
gsize tid; | |
+#ifndef HOST_WIN32 | |
+ gboolean ok; | |
+ struct _WapiHandle_thread *thread_handle; | |
+ int ret; | |
+#endif | |
/* | |
* We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a | |
* GC stack walk. | |
@@ -606,6 +616,23 @@ static guint32 WINAPI start_wrapper_internal(void *data) | |
THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal)); | |
+#ifndef HOST_WIN32 | |
+ ok = _wapi_lookup_handle (internal->handle, WAPI_HANDLE_THREAD, (gpointer *)&thread_handle); | |
+ | |
+ if (ok != FALSE) { | |
+ thread_handle->pid = syscall(SYS_gettid); | |
+ | |
+ if(internal->thread_priority != 0) { | |
+ /* Thread running; set priority now. */ | |
+ errno = 0; | |
+ ret = setpriority (PRIO_PROCESS, thread_handle->pid,internal->thread_priority); | |
+ if (ret == -1) { | |
+ g_warning ("%s: setpriority could not set priority %d: %s", __func__, internal->thread_priority, strerror (errno)); | |
+ } | |
+ } | |
+ } | |
+#endif | |
+ | |
/* On 2.0 profile (and higher), set explicitly since state might have been | |
Unknown */ | |
if (internal->apartment_state == ThreadApartmentState_Unknown) | |
@@ -847,7 +874,7 @@ mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gb | |
/* Check that the managed and unmanaged layout of MonoInternalThread matches */ | |
if (mono_check_corlib_version () == NULL) | |
- g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset); | |
+ g_assert (((char*)&internal->unused1 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset); | |
return internal; | |
} | |
@@ -1342,6 +1369,41 @@ ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj | |
mono_thread_set_name_internal (this_obj, name, TRUE); | |
} | |
+/* | |
+ * ves_icall_System_Threading_Thread_GetPriority_internal: | |
+ * @param this_obj: The MonoInternalThread on which to operate. | |
+ * | |
+ * Gets the priority of the given thread. | |
+ * @return: The priority of the given thread. | |
+ */ | |
+gint32 | |
+ves_icall_System_Threading_Thread_GetPriority_internal (MonoInternalThread *this_obj) | |
+{ | |
+ gint32 priority; | |
+ | |
+ ensure_synch_cs_set (this_obj); | |
+ EnterCriticalSection (this_obj->synch_cs); | |
+ priority = GetThreadPriority (this_obj->handle, &this_obj->thread_priority) + 2; /* convert to [-2; 2] range to [0;4] */ | |
+ LeaveCriticalSection (this_obj->synch_cs); | |
+ return priority; | |
+} | |
+ | |
+/* | |
+ * ves_icall_System_Threading_Thread_SetPriority_internal: | |
+ * @param this_obj: The MonoInternalThread on which to operate. | |
+ * @param priority: The priority to set. | |
+ * | |
+ * Sets the priority of the given thread. | |
+ */ | |
+void | |
+ves_icall_System_Threading_Thread_SetPriority_internal (MonoInternalThread *this_obj, gint32 priority) | |
+{ | |
+ ensure_synch_cs_set (this_obj); | |
+ EnterCriticalSection (this_obj->synch_cs); | |
+ SetThreadPriority (this_obj->handle, &this_obj->thread_priority, priority - 2); /* convert from [0; 4] range to [-2; 2]. */ | |
+ LeaveCriticalSection (this_obj->synch_cs); | |
+} | |
+ | |
/* If the array is already in the requested domain, we just return it, | |
otherwise we return a copy in that domain. */ | |
static MonoArray* |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In the patch I added "int thread_priority" to the struct _MonoInternalThread in mono/metadata/object-internals.h and I'm a bit uncertain about the consequences...
It states in a comment:
I removed gpointer unused2; to retain binary compatibility, but since I added an int (32 bit) and removed a pointer (32 bits on 32bit system, 64 bits on 64bit systems) it will break binary compatibility on 64bit systems.
This could be addressed using a union {int thread_priority; gpointer unused2;} foobar; instead, but this will clutter the code...