wok-current view wine-rt/stuff/wine-rt-101107.patch @ rev 13542

sudo-pam: fix (by xj); wine-rt: add (by xj); qjackctl: up 0.3.9
author Aleksej Bobylev <al.bobylev@gmail.com>
date Tue Oct 30 04:33:32 2012 +0000 (2012-10-30)
parents
children
line source
1 From 1dceb627db51a239a63ed5276f7e8911be6751bc Mon Sep 17 00:00:00 2001
2 From: Joakim B Hernberg <jhernberg@alchemy.lu>
3 Date: Sun, 7 Nov 2010 19:10:49 +0100
4 Subject: [PATCH] 3:rd wine-rt patch 101107
6 ---
7 README.WINE-RT | 27 +++++++++++++++++
8 server/main.c | 60 ++++++++++++++++++++++++++++++++++++++
9 server/thread.c | 87 ++++++++++++++++++++++++++++++++++++++++++------------
10 3 files changed, 154 insertions(+), 20 deletions(-)
11 create mode 100644 README.WINE-RT
13 diff --git a/README.WINE-RT b/README.WINE-RT
14 new file mode 100644
15 index 0000000..3f3f2c1
16 --- /dev/null
17 +++ b/README.WINE-RT
18 @@ -0,0 +1,27 @@
19 +What is it?
20 +The Wine-RT patch allows programs that use windows' concept of thread priority to gain similar functionality under linux. It maps windows priority levels to linux scheduling policies. THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST and THREAD_PRIORITY_TIME_CRITICAL levels which are made to run as linux SCHED_FIFO threads at priority levels that are defined by the WINERT variable. THREAD_PRIORITY_NORMAL threads are run as normal linux threads (as all threads are without the patch), and the priorities below normal (THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_LOWEST) are run as SCHED_BATCH. THREAD_PRIORITY_IDLE threads are run as SCHED_IDLE.
21 +Windows' concept of priority classes is not implemented at all.
22 +
23 +Please note that threads running SCHED_FIFO might hang your entire system, so please exercise caution!
24 +
25 +How does it work?
26 +When a windows program asks for a thread to be run at a higher priority, Wine will ask the linux system to schedule it as a SCHED_FIFO thread, which means that the tread will keep on executing until it has either finished, voluntarily yields execution or gets preempted by a higher priority SCHED_FIFO thread. This is already done by many linux audio applications, to ensure less xruns on lower buffer sizes. With Wine-RT, the same thing can be done for Wine applications.
27 +
28 +How to use it?
29 +The Wine-RT functionality is not enabled by default. Instead it is controlled by 2 environment variables "WINE_RT" and "WINE_SRV_RT".
30 +
31 +The "WINE_RT" variable has 2 purposes, it has to be set in order to activate the patch, and it determines the priority of the SCHED_FIFO threads, Its value can be set from 1 to your system's rtprio max value minus 10, as set in limits.conf or limits.d/audio.conf. (In Debian, Ubuntu and KXStudio this value is 99). THREAD_PRIORITY_ABOVE_NORMAL threads will run at this priority level, THREAD_PRIORITY_HIGHEST threads at this level + 5, and THREAD_PRIORITY_TIME_CRITICAL threads at this level + 10.
32 +
33 +WINE_SRV_RT makes the wineserver main thread run SCHED_FIFO. Valid values range from 1 to your system's rtprio max value.
34 +
35 +We can set these variables in 2 simple ways.
36 +First one is using a terminal with "exports", like this:
37 +export WINE_RT=#
38 +export WINE_SRV_RT=#
39 +wine <app>
40 +
41 +or just prefix your application with 'env VARIABLE=value', like this:
42 +env WINE_RT=# WINE_SRV_RT=# wine <app>
43 +
44 +A recommended starting point might be "env WINE_RT=15 WINE_SRV_RT=10 wine appname.exe".
45 +
46 diff --git a/server/main.c b/server/main.c
47 index 2d841e8..a89d1e0 100644
48 --- a/server/main.c
49 +++ b/server/main.c
50 @@ -27,10 +27,18 @@
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <sys/time.h>
54 +#include <sys/resource.h>
55 +#include <sys/mman.h>
56 #include <unistd.h>
57 #ifdef HAVE_GETOPT_H
58 # include <getopt.h>
59 #endif
60 +#ifdef HAVE_SCHED_H
61 +#include <sched.h>
62 +#ifndef SCHED_NORMAL
63 +#define SCHED_NORMAL SCHED_OTHER
64 +#endif
65 +#endif
67 #include "object.h"
68 #include "file.h"
69 @@ -44,6 +52,9 @@ int foreground = 0;
70 timeout_t master_socket_timeout = 3 * -TICKS_PER_SEC; /* master socket timeout, default is 3 seconds */
71 const char *server_argv0;
73 +/* global variable used here and in thread.c to determine whether wine runs with rt threads and at what base value */
74 +int base_rt_priority = -1;
75 +
76 /* parse-line args */
78 static void usage(void)
79 @@ -125,6 +136,51 @@ static void sigterm_handler( int signum )
80 exit(1); /* make sure atexit functions get called */
81 }
83 +#ifdef HAVE_SCHED_H
84 +void init_rt_scheduling( void )
85 +{
86 + struct sched_param param;
87 + struct rlimit limit;
88 + int priority_max, policy, wine_server_rt_priority;
89 + char *enviroment, *endptr;
90 +
91 + getrlimit( RLIMIT_RTPRIO, &limit );
92 + priority_max = limit.rlim_max;
93 +
94 + /* check for realtime mode and set the base priority level */
95 +
96 + if (!(enviroment = getenv( "WINE_RT" )))
97 + return;
98 + base_rt_priority = (int) strtol( enviroment, &endptr, 10 );
99 + if (enviroment == endptr || base_rt_priority == 0 || base_rt_priority > priority_max - 10)
100 + {
101 + fprintf( stderr, "Unable to run WINE in rt mode, WINE_RT values supported on this system range from 1 to %i\n", priority_max - 10 );
102 + base_rt_priority = -1;
103 + return;
104 + }
105 + fprintf( stderr, "WINE realtime scheduling hack enabled, realtime base priority has been set to %i\n", base_rt_priority );
106 +
107 + /* determine scheduling policy for the main wineserver thread */
108 +
109 + if (!(enviroment = getenv( "WINE_SRV_RT" )))
110 + {
111 + fprintf( stderr, "wineserver running SCHED_NORMAL\n" );
112 + return;
113 + }
114 + wine_server_rt_priority = (int) strtol( enviroment, &endptr, 10 );
115 + if (enviroment == endptr || wine_server_rt_priority == 0 || wine_server_rt_priority > priority_max)
116 + {
117 + fprintf( stderr, "Unable to run the wineserver SCHED_FIFO, valid WINE_SRV_RT values range from 1 to %i\n", priority_max );
118 + return;
119 + }
120 + fprintf( stderr, "wineserver running SCHED_FIFO at priority %i\n", wine_server_rt_priority );
121 + policy = SCHED_FIFO;
122 + param.sched_priority = wine_server_rt_priority;
123 + if (sched_setscheduler ( 0, policy, &param) != 0)
124 + fprintf (stderr, "Error scheduling wineserver as SCHED_FIFO\n");
125 +}
126 +#endif
127 +
128 int main( int argc, char *argv[] )
129 {
130 setvbuf( stderr, NULL, _IOLBF, 0 );
131 @@ -138,6 +194,10 @@ int main( int argc, char *argv[] )
132 signal( SIGTERM, sigterm_handler );
133 signal( SIGABRT, sigterm_handler );
135 +#ifdef HAVE_SCHED_H
136 + init_rt_scheduling();
137 +#endif
138 + mlockall(MCL_FUTURE);
139 sock_init();
140 open_master_socket();
142 diff --git a/server/thread.c b/server/thread.c
143 index 05e4121..2d103b4 100644
144 --- a/server/thread.c
145 +++ b/server/thread.c
146 @@ -32,11 +32,18 @@
147 #include <sys/types.h>
148 #include <unistd.h>
149 #include <time.h>
150 -#ifdef HAVE_POLL_H
151 -#include <poll.h>
152 -#endif
153 #ifdef HAVE_SCHED_H
154 #include <sched.h>
155 +#ifndef SCHED_NORMAL
156 +#define SCHED_NORMAL SCHED_OTHER
157 +#endif
158 +#ifndef SCHED_IDLE
159 +#define SCHED_IDLE 5 /* missing from my glibc, taken from linux/sched.h */
160 +#endif
161 +#endif
162 +
163 +#ifdef HAVE_POLL_H
164 +#include <poll.h>
165 #endif
167 #include "ntstatus.h"
168 @@ -164,6 +171,8 @@ static const struct fd_ops thread_fd_ops =
170 static struct list thread_list = LIST_INIT(thread_list);
172 +extern int base_rt_priority;
173 +
174 /* initialize the structure for a newly allocated thread */
175 static inline void init_thread_structure( struct thread *thread )
176 {
177 @@ -432,29 +441,67 @@ int set_thread_affinity( struct thread *thread, affinity_t affinity )
178 return ret;
179 }
181 -#define THREAD_PRIORITY_REALTIME_HIGHEST 6
182 -#define THREAD_PRIORITY_REALTIME_LOWEST -7
183 +void set_thread_priority( struct thread *thread, int priority )
184 +{
185 +#ifdef HAVE_SCHED_H
186 + struct sched_param param;
187 + int policy;
188 +
189 + if (base_rt_priority == -1 || (thread->unix_tid == -1)) return;
190 +
191 + switch (priority)
192 + {
193 + case THREAD_PRIORITY_TIME_CRITICAL:
194 + param.sched_priority = base_rt_priority + 10;
195 + policy = SCHED_FIFO;
196 + fprintf( stderr, "Thread %i at THREAD_PRIORITY_TIME_CRITICAL set to SCHED_FIFO - priority %i\n", thread->unix_tid, param.sched_priority );
197 + break;
198 + case THREAD_PRIORITY_HIGHEST:
199 + param.sched_priority = base_rt_priority + 5;
200 + policy = SCHED_FIFO;
201 + fprintf( stderr, "Thread %i at THREAD_PRIORITY_HIGHEST set to SCHED_FIFO - priority %i\n", thread->unix_tid, param.sched_priority );
202 + break;
203 + case THREAD_PRIORITY_ABOVE_NORMAL:
204 + param.sched_priority = base_rt_priority;
205 + policy = SCHED_FIFO;
206 + fprintf( stderr, "Thread %i at THREAD_PRIORITY_ABOVE_NORMAL set to SCHED_FIFO - priority %i\n", thread->unix_tid, param.sched_priority );
207 + break;
208 + case THREAD_PRIORITY_NORMAL:
209 + param.sched_priority = 0;
210 + policy = SCHED_NORMAL;
211 + fprintf( stderr, "Setting thread %i at level THREAD_PRIORITY_NORMAL to SCHED_NORMAL\n", thread->unix_tid );
212 + break;
213 + case THREAD_PRIORITY_BELOW_NORMAL:
214 + param.sched_priority = 0;
215 + policy = SCHED_BATCH;
216 + fprintf( stderr, "Setting thread %i at level THREAD_PRIORITY_BELOW_NORMAL to SCHED_BATCH\n", thread->unix_tid );
217 + break;
218 + case THREAD_PRIORITY_LOWEST:
219 + param.sched_priority = 0;
220 + policy = SCHED_BATCH;
221 + fprintf( stderr, "Setting thread %i at THREAD_PRIORITY_LOWEST level to SCHED_BATCH\n", thread->unix_tid );
222 + break;
223 + case THREAD_PRIORITY_IDLE:
224 + param.sched_priority = 0;
225 + policy = SCHED_IDLE;
226 + fprintf( stderr, "Setting thread %i with level THREAD_PRIORITY_IDLE to SCHED_IDLE\n", thread->unix_tid );
227 + break;
228 + default:
229 + fprintf( stderr, "Error setting scheduling priority level, unknown should never come here\n" );
230 + return;
231 + }
232 + if (sched_setscheduler (thread->unix_tid, policy, &param) != 0) fprintf (stderr, "Error setting priorities\n");
233 + thread->priority = priority;
234 + return;
235 +#endif
236 +}
238 /* set all information about a thread */
239 static void set_thread_info( struct thread *thread,
240 const struct set_thread_info_request *req )
241 {
242 if (req->mask & SET_THREAD_INFO_PRIORITY)
243 - {
244 - int max = THREAD_PRIORITY_HIGHEST;
245 - int min = THREAD_PRIORITY_LOWEST;
246 - if (thread->process->priority == PROCESS_PRIOCLASS_REALTIME)
247 - {
248 - max = THREAD_PRIORITY_REALTIME_HIGHEST;
249 - min = THREAD_PRIORITY_REALTIME_LOWEST;
250 - }
251 - if ((req->priority >= min && req->priority <= max) ||
252 - req->priority == THREAD_PRIORITY_IDLE ||
253 - req->priority == THREAD_PRIORITY_TIME_CRITICAL)
254 - thread->priority = req->priority;
255 - else
256 - set_error( STATUS_INVALID_PARAMETER );
257 - }
258 + set_thread_priority( thread, req->priority );
259 if (req->mask & SET_THREAD_INFO_AFFINITY)
260 {
261 if ((req->affinity & thread->process->affinity) != req->affinity)
262 --
263 1.7.3.2