Implement SetThreadPriority using sched_setscheduler()
Mike Hearn
mike at plan99.net
Thu Mar 30 17:05:51 CST 2006
This patch gives me rock solid audio in Imperium Galactica 2. No more
white noise, clicking or destabilising half way through.
It exposes a race that I'll send a fix for later, for now I am hacking
around it with a sleep(1) at the end of RtlUserCreateThread. The race is
that you can do this:
hthread = CreateThread(...);
SetThreadPriority(hthread ...);
and the set_thread_info server call will occur before the thread has
fully initialized, so, we don't know the UNIX tid and cannot set the
priority. My current idea is to fix the race by forcing
RtlUserCreateThread to wait for the thread to sync with the server using
an event.
This patch only implements support for TIME_CRITICAL threads. Mapping
priorities at a finer level of granularity is still on the todo list.
Final thing - there has been on/off discussion about the security
implications of this in the past. But, this code needs to be implemented
anyway, regardless of outcome, and on SuSE at least I think AppArmor can
be used to allow for thread prio raising without full root access. So
IMHO the permissions debate layers on top of this. Until an acceptable
solution is found some users may wish to just run Wine as root and play
their games, which they know are trustable.
thanks -mike
-------------- next part --------------
diff --git a/server/thread.c b/server/thread.c
index 1c00ce7..eeb9929 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -32,6 +32,9 @@
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
+#ifdef HAVE_SCHED_H
+#include <sched.h>
+#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
@@ -319,7 +322,36 @@ static void set_thread_info( struct thre
const struct set_thread_info_request *req )
{
if (req->mask & SET_THREAD_INFO_PRIORITY)
+ {
+#ifdef HAVE_SCHED_H
+ if ((req->priority == THREAD_PRIORITY_TIME_CRITICAL) && (thread->unix_tid != -1))
+ {
+ struct sched_param param;
+ int result;
+
+ param.sched_priority = 1;
+ result = sched_setscheduler(thread->unix_tid, SCHED_FIFO, ¶m);
+
+ if ((result < 0) && (result != -EPERM))
+ {
+ perror("wineserver: sched_setscheduler");
+ }
+ else if (result == -EPERM)
+ {
+ static int need_warning = 1;
+
+ if (need_warning)
+ {
+ fprintf(stderr, "\nwineserver: Failed to promote the priority of a time critical thread.\n");
+ fprintf(stderr, "Audio may destabilise. To fix this re-run the application as root.\n\n");
+ need_warning = 0;
+ }
+ }
+ }
+#endif
thread->priority = req->priority;
+ }
+
if (req->mask & SET_THREAD_INFO_AFFINITY)
{
if (req->affinity != 1) set_error( STATUS_INVALID_PARAMETER );
More information about the wine-patches
mailing list