Last active
August 29, 2015 14:06
-
-
Save justincc/31e52218d098529b4696 to your computer and use it in GitHub Desktop.
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
From 53d170e17ad6fd46f2d551e2df25277db6e4d4cf Mon Sep 17 00:00:00 2001 | |
From: Justin Clark-Casey <justincc@justincc.org> | |
Date: Tue, 16 Sep 2014 18:03:42 +0100 | |
Subject: [PATCH] This is a modified patch from | |
https://bugzilla.novell.com/show_bug.cgi?id=540524 updated to build against | |
mono 3.2.8 | |
This uses Thread.Priority to change RT thread priority if mono is run via "$ sudo chrt --rr 10 <exec>" or similar | |
For many reasons this is not a good approach - this patch is primarily for test purposes. | |
--- | |
mcs/class/corlib/System.Threading/Thread.cs | 10 +- | |
mono/io-layer/threads.h | 2 + | |
mono/io-layer/wthreads.c | 219 ++++++++++++++++++++++++++++ | |
mono/metadata/icall-def.h | 2 + | |
mono/metadata/threads-types.h | 2 + | |
mono/metadata/threads.c | 37 +++++ | |
6 files changed, 270 insertions(+), 2 deletions(-) | |
diff --git a/mcs/class/corlib/System.Threading/Thread.cs b/mcs/class/corlib/System.Threading/Thread.cs | |
index 5af6800..446af1f 100644 | |
--- a/mcs/class/corlib/System.Threading/Thread.cs | |
+++ b/mcs/class/corlib/System.Threading/Thread.cs | |
@@ -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/threads.h b/mono/io-layer/threads.h | |
index 12b7c0c..65ec7d8 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); | |
+extern gboolean SetThreadPriority (gpointer handle, 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..0bcffcd 100644 | |
--- a/mono/io-layer/wthreads.c | |
+++ b/mono/io-layer/wthreads.c | |
@@ -70,6 +70,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 +1314,214 @@ void _wapi_thread_disown_mutex (gpointer mutex) | |
g_ptr_array_remove (thread_handle->owned_mutexes, mutex); | |
} | |
+ | |
+/** | |
+ * _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) | |
+ { | |
+ g_debug("Get Using priority %i", THREAD_PRIORITY_HIGHEST); | |
+ return (THREAD_PRIORITY_HIGHEST); | |
+ } | |
+ else | |
+ { | |
+ g_debug("Get Using priority %i", priorities[i-1]); | |
+ 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 | |
+ */ | |
+static 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); | |
+ | |
+ g_debug("WAPI input in Set %i", priority); | |
+ g_debug("Min in Set %i", min); | |
+ g_debug("Max in Set %i", max); | |
+ g_debug("Policy in Set %i", 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) | |
+ { | |
+ g_debug("Set Using max priority %i", max); | |
+ return max; | |
+ } | |
+ else { | |
+ g_debug("Set Using priority %i",posix_priority); | |
+ return posix_priority; | |
+ } | |
+ } | |
+ } | |
+ } | |
+#endif | |
+ | |
+ switch (policy) { | |
+ case SCHED_FIFO: | |
+ case SCHED_RR: | |
+ return 50; | |
+ case SCHED_BATCH: | |
+ 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; | |
+ int policy; | |
+ struct sched_param param; | |
+ gboolean ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD, | |
+ (gpointer *)&thread_handle); | |
+ | |
+ if (ok == FALSE) { | |
+/* | |
+ g_warning ("%s: error looking up thread handle %p", __func__, | |
+ handle); | |
+*/ | |
+ | |
+ return (THREAD_PRIORITY_NORMAL); | |
+ } | |
+ | |
+ switch (pthread_getschedparam (thread_handle->id, &policy, ¶m)) { | |
+ case 0: | |
+ return (_wapi_thread_posix_priority_to_priority (param.sched_priority, policy)); | |
+ 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; | |
+ int policy, | |
+ posix_priority, | |
+ rv; | |
+ struct sched_param param; | |
+ gboolean ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD, | |
+ (gpointer *)&thread_handle); | |
+ | |
+ if (ok == FALSE) { | |
+/* | |
+ g_warning ("%s: error looking up thread handle %p", __func__, | |
+ handle); | |
+*/ | |
+ | |
+ 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: | |
+ return TRUE; | |
+ case ESRCH: | |
+ g_warning ("pthread_setschedparam: 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; | |
+} | |
+ | |
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/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..756d2c1 100755 | |
--- a/mono/metadata/threads.c | |
+++ b/mono/metadata/threads.c | |
@@ -1342,6 +1342,43 @@ 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) + 2; | |
+ | |
+ 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, priority - 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* | |
-- | |
1.9.1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A have completely rewritten the patch to use "nice" instead of pthread_setschedparam through the posix calls setpriority(2).
It even works for non-root users as long as the priority is only lowered.
I posted it here: https://gist.github.com/aasimon/c8ae6fc3cf5d9b82b6ca