Implement THREAD_PRIORITY_TIME_CRITICAL

Mike Hearn mh at codeweavers.com
Fri Mar 31 07:06:23 CST 2006


This patch gives me rock solid audio in Imperium Galactica 2, so now the 
game works perfectly.

There has been discussion around this issue with respect to security in 
the past, however, regardless of what approach is adopted this code will 
have to be written anyway.

thanks -mike
-------------- next part --------------
diff --git a/server/thread.c b/server/thread.c
index 1c00ce7..ed0d09a 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
@@ -314,12 +317,59 @@ struct thread *get_thread_from_pid( int 
     return NULL;
 }
 
+static void set_thread_priority( int unix_tid, int ntprio )
+{
+#ifdef HAVE_SCHED_H    
+    struct sched_param param;
+    int result, scheduler;
+
+    assert( unix_tid != -1 );
+
+    if (ntprio == THREAD_PRIORITY_TIME_CRITICAL)
+    {
+        param.sched_priority = 1;
+        scheduler = SCHED_FIFO;
+    }
+    else
+    {
+        param.sched_priority = 0;
+        scheduler = SCHED_OTHER;
+    }
+    
+    result = sched_setscheduler( unix_tid, scheduler, &param );
+
+    if (result == 0) return;
+    
+    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;
+        }
+
+        return;
+    }
+
+    perror( "wineserver: sched_setscheduler" );
+#endif    
+}
+
 /* set all information about a thread */
 static void set_thread_info( struct thread *thread,
                              const struct set_thread_info_request *req )
 {
     if (req->mask & SET_THREAD_INFO_PRIORITY)
+    {
+        if ((thread->priority != req->priority) && (thread->unix_tid != -1))
+            set_thread_priority( thread->unix_tid, req->priority );
+        
         thread->priority = req->priority;
+    }
+
     if (req->mask & SET_THREAD_INFO_AFFINITY)
     {
         if (req->affinity != 1) set_error( STATUS_INVALID_PARAMETER );
@@ -902,6 +952,10 @@ DECL_HANDLER(init_thread)
     }
     debug_level = max( debug_level, req->debug_level );
 
+    /* we may have raced with a SetThreadPriority call */
+    if (current->priority != THREAD_PRIORITY_NORMAL)
+        set_thread_priority( current->unix_tid, current->priority );
+    
     reply->pid     = get_process_id( process );
     reply->tid     = get_thread_id( current );
     reply->version = SERVER_PROTOCOL_VERSION;


More information about the wine-patches mailing list