]>
Commit | Line | Data |
---|---|---|
6b2a2aa4 CF |
1 | /* sched.cc: scheduler interface for Cygwin |
2 | ||
61522196 CV |
3 | Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011, 2012, |
4 | 2013 Red Hat, Inc. | |
6b2a2aa4 CF |
5 | |
6 | Written by Robert Collins <rbtcollins@hotmail.com> | |
7 | ||
8 | This file is part of Cygwin. | |
9 | ||
10 | This software is a copyrighted work licensed under the terms of the | |
11 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
12 | details. */ | |
13 | ||
6b2a2aa4 | 14 | #include "winsup.h" |
ade47a34 | 15 | #include "miscfuncs.h" |
6b2a2aa4 | 16 | #include "cygerrno.h" |
6b2a2aa4 CF |
17 | #include "pinfo.h" |
18 | /* for getpid */ | |
19 | #include <unistd.h> | |
aff96307 CF |
20 | #include "registry.h" |
21 | ||
6b2a2aa4 | 22 | /* Win32 priority to UNIX priority Mapping. |
61522196 | 23 | |
6b2a2aa4 CF |
24 | For now, I'm just following the spec: any range of priorities is ok. |
25 | There are probably many many issues with this... | |
462f4eff | 26 | |
61522196 CV |
27 | FIXME: We don't support pre-Windows 2000 so we should fix the priority |
28 | computation. Here's the description for the current code: | |
462f4eff | 29 | |
61522196 CV |
30 | We don't want process's going realtime. Well, they probably could, but |
31 | the issues with avoiding the priority values 17-22 and 27-30 (not | |
32 | supported before win2k) make that inefficient. | |
462f4eff | 33 | |
61522196 | 34 | However to complicate things most unixes use lower is better priorities. |
462f4eff | 35 | |
61522196 CV |
36 | So we map -14 to 15, and 15 to 1 via (16- ((n+16) >> 1)). We then map 1 |
37 | to 15 to various process class and thread priority combinations. Then we | |
38 | need to look at the threads process priority. As win95, 98 and NT 4 | |
39 | don't support opening threads cross-process (unless a thread HANDLE is | |
40 | passed around) for now, we'll just use the priority class. | |
462f4eff | 41 | |
61522196 CV |
42 | The code and logic are present to calculate the priority for thread, if a |
43 | thread handle can be obtained. Alternatively, if the symbols wouldn't be | |
44 | resolved until they are used we could support this. | |
45 | ||
46 | Lastly, because we can't assume that the pid we're given are Windows pids, | |
47 | we can't alter non-cygwin started programs. */ | |
6b2a2aa4 CF |
48 | |
49 | extern "C" | |
50 | { | |
51 | ||
52 | /* max priority for policy */ | |
53 | int | |
54 | sched_get_priority_max (int policy) | |
55 | { | |
56 | if (policy < 1 || policy > 3) | |
57 | { | |
58 | set_errno (EINVAL); | |
59 | return -1; | |
60 | } | |
61 | return -14; | |
62 | } | |
63 | ||
64 | /* min priority for policy */ | |
65 | int | |
66 | sched_get_priority_min (int policy) | |
67 | { | |
68 | if (policy < 1 || policy > 3) | |
69 | { | |
70 | set_errno (EINVAL); | |
71 | return -1; | |
72 | } | |
73 | return 15; | |
74 | } | |
75 | ||
5c83f260 RC |
76 | /* Check a scheduler parameter struct for valid settings */ |
77 | int | |
f0227ea3 | 78 | valid_sched_parameters (const struct sched_param *param) |
5c83f260 RC |
79 | { |
80 | if (param->sched_priority < -14 || param->sched_priority > 15) | |
81 | { | |
82 | return 0; | |
83 | } | |
84 | return -1; | |
85 | ||
86 | } | |
87 | ||
6b2a2aa4 CF |
88 | /* get sched params for process |
89 | ||
462f4eff | 90 | Note, I'm never returning EPERM, |
6b2a2aa4 | 91 | Always ESRCH. This is by design (If cygwin ever looks at paranoid security |
462f4eff | 92 | Walking the pid values is a known hole in some os's) |
6b2a2aa4 CF |
93 | */ |
94 | int | |
95 | sched_getparam (pid_t pid, struct sched_param *param) | |
96 | { | |
97 | pid_t localpid; | |
98 | int winpri; | |
99 | if (!param || pid < 0) | |
100 | { | |
101 | set_errno (EINVAL); | |
102 | return -1; | |
103 | } | |
104 | ||
105 | localpid = pid ? pid : getpid (); | |
106 | ||
107 | DWORD Class; | |
108 | int ThreadPriority; | |
109 | HANDLE process; | |
110 | pinfo p (localpid); | |
111 | ||
112 | /* get the class */ | |
113 | ||
114 | if (!p) | |
115 | { | |
116 | set_errno (ESRCH); | |
117 | return -1; | |
118 | } | |
119 | process = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, p->dwProcessId); | |
120 | if (!process) | |
121 | { | |
122 | set_errno (ESRCH); | |
123 | return -1; | |
124 | } | |
125 | Class = GetPriorityClass (process); | |
126 | CloseHandle (process); | |
127 | if (!Class) | |
128 | { | |
129 | set_errno (ESRCH); | |
130 | return -1; | |
131 | } | |
132 | ThreadPriority = THREAD_PRIORITY_NORMAL; | |
133 | ||
61522196 | 134 | /* calculate the unix priority. */ |
6b2a2aa4 CF |
135 | |
136 | switch (Class) | |
137 | { | |
138 | case IDLE_PRIORITY_CLASS: | |
139 | switch (ThreadPriority) | |
140 | { | |
141 | case THREAD_PRIORITY_IDLE: | |
142 | winpri = 1; | |
143 | break; | |
144 | case THREAD_PRIORITY_LOWEST: | |
145 | winpri = 2; | |
146 | break; | |
147 | case THREAD_PRIORITY_BELOW_NORMAL: | |
148 | winpri = 3; | |
149 | break; | |
150 | case THREAD_PRIORITY_NORMAL: | |
151 | winpri = 4; | |
152 | break; | |
153 | case THREAD_PRIORITY_ABOVE_NORMAL: | |
154 | winpri = 5; | |
155 | break; | |
156 | case THREAD_PRIORITY_HIGHEST: | |
157 | default: | |
158 | winpri = 6; | |
159 | break; | |
160 | } | |
161 | break; | |
162 | case HIGH_PRIORITY_CLASS: | |
163 | switch (ThreadPriority) | |
164 | { | |
165 | case THREAD_PRIORITY_IDLE: | |
166 | winpri = 1; | |
167 | break; | |
168 | case THREAD_PRIORITY_LOWEST: | |
169 | winpri = 11; | |
170 | break; | |
171 | case THREAD_PRIORITY_BELOW_NORMAL: | |
172 | winpri = 12; | |
173 | break; | |
174 | case THREAD_PRIORITY_NORMAL: | |
175 | winpri = 13; | |
176 | break; | |
177 | case THREAD_PRIORITY_ABOVE_NORMAL: | |
178 | winpri = 14; | |
179 | break; | |
180 | case THREAD_PRIORITY_HIGHEST: | |
181 | default: | |
182 | winpri = 15; | |
183 | break; | |
184 | } | |
185 | break; | |
186 | case NORMAL_PRIORITY_CLASS: | |
187 | default: | |
188 | switch (ThreadPriority) | |
189 | { | |
190 | case THREAD_PRIORITY_IDLE: | |
191 | winpri = 1; | |
192 | break; | |
193 | case THREAD_PRIORITY_LOWEST: | |
194 | winpri = 7; | |
195 | break; | |
196 | case THREAD_PRIORITY_BELOW_NORMAL: | |
197 | winpri = 8; | |
198 | break; | |
199 | case THREAD_PRIORITY_NORMAL: | |
200 | winpri = 9; | |
201 | break; | |
202 | case THREAD_PRIORITY_ABOVE_NORMAL: | |
203 | winpri = 10; | |
204 | break; | |
205 | case THREAD_PRIORITY_HIGHEST: | |
206 | default: | |
207 | winpri = 11; | |
208 | break; | |
209 | } | |
210 | break; | |
211 | } | |
212 | ||
213 | /* reverse out winpri = (16- ((unixpri+16) >> 1)) */ | |
462f4eff | 214 | /* |
6b2a2aa4 CF |
215 | winpri-16 = - (unixpri +16 ) >> 1 |
216 | ||
217 | -(winpri-16) = unixpri +16 >> 1 | |
218 | (-(winpri-16)) << 1 = unixpri+16 | |
219 | ((-(winpri - 16)) << 1) - 16 = unixpri | |
220 | */ | |
221 | ||
222 | param->sched_priority = ((-(winpri - 16)) << 1) - 16; | |
223 | ||
224 | return 0; | |
225 | } | |
226 | ||
227 | /* get the scheduler for pid | |
228 | ||
229 | All process's on WIN32 run with SCHED_FIFO. | |
462f4eff | 230 | So we just give an answer. |
6b2a2aa4 CF |
231 | (WIN32 uses a multi queue FIFO). |
232 | */ | |
233 | int | |
234 | sched_getscheduler (pid_t pid) | |
235 | { | |
236 | if (pid < 0) | |
237 | return ESRCH; | |
238 | else | |
239 | return SCHED_FIFO; | |
240 | } | |
241 | ||
61522196 | 242 | /* get the time quantum for pid */ |
6b2a2aa4 CF |
243 | int |
244 | sched_rr_get_interval (pid_t pid, struct timespec *interval) | |
245 | { | |
aff96307 CF |
246 | static const char quantable[2][2][3] = |
247 | {{{12, 24, 36}, { 6, 12, 18}}, | |
248 | {{36, 36, 36}, {18, 18, 18}}}; | |
249 | /* FIXME: Clocktickinterval can be 15 ms for multi-processor system. */ | |
250 | static const int clocktickinterval = 10; | |
251 | static const int quantapertick = 3; | |
252 | ||
253 | HWND forwin; | |
254 | DWORD forprocid; | |
cca89be9 | 255 | DWORD vfindex, slindex, qindex, prisep; |
aff96307 CF |
256 | long nsec; |
257 | ||
aff96307 CF |
258 | forwin = GetForegroundWindow (); |
259 | if (!forwin) | |
260 | GetWindowThreadProcessId (forwin, &forprocid); | |
261 | else | |
262 | forprocid = 0; | |
263 | ||
b18cb86b CV |
264 | reg_key reg (HKEY_LOCAL_MACHINE, KEY_READ, L"SYSTEM", L"CurrentControlSet", |
265 | L"Control", L"PriorityControl", NULL); | |
aff96307 CF |
266 | if (reg.error ()) |
267 | { | |
268 | set_errno (ESRCH); | |
269 | return -1; | |
270 | } | |
cca89be9 | 271 | prisep = reg.get_dword (L"Win32PrioritySeparation", 2); |
aff96307 CF |
272 | pinfo pi (pid ? pid : myself->pid); |
273 | if (!pi) | |
274 | { | |
275 | set_errno (ESRCH); | |
276 | return -1; | |
277 | } | |
278 | ||
279 | if (pi->dwProcessId == forprocid) | |
280 | { | |
281 | qindex = prisep & 3; | |
282 | qindex = qindex == 3 ? 2 : qindex; | |
283 | } | |
284 | else | |
285 | qindex = 0; | |
286 | vfindex = ((prisep >> 2) & 3) % 3; | |
287 | if (vfindex == 0) | |
cb7e1879 | 288 | vfindex = wincap.is_server () || (prisep & 3) == 0 ? 1 : 0; |
aff96307 CF |
289 | else |
290 | vfindex -= 1; | |
291 | slindex = ((prisep >> 4) & 3) % 3; | |
292 | if (slindex == 0) | |
293 | slindex = wincap.is_server () ? 1 : 0; | |
294 | else | |
295 | slindex -= 1; | |
296 | ||
297 | nsec = quantable[vfindex][slindex][qindex] / quantapertick | |
298 | * clocktickinterval * 1000000; | |
299 | interval->tv_sec = nsec / 1000000000; | |
300 | interval->tv_nsec = nsec % 1000000000; | |
301 | ||
302 | return 0; | |
6b2a2aa4 CF |
303 | } |
304 | ||
305 | /* set the scheduling parameters */ | |
306 | int | |
307 | sched_setparam (pid_t pid, const struct sched_param *param) | |
308 | { | |
309 | pid_t localpid; | |
310 | int winpri; | |
311 | DWORD Class; | |
6b2a2aa4 CF |
312 | HANDLE process; |
313 | ||
314 | if (!param || pid < 0) | |
315 | { | |
316 | set_errno (EINVAL); | |
317 | return -1; | |
318 | } | |
319 | ||
f0227ea3 | 320 | if (!valid_sched_parameters (param)) |
6b2a2aa4 CF |
321 | { |
322 | set_errno (EINVAL); | |
323 | return -1; | |
324 | } | |
325 | ||
326 | /* winpri = (16- ((unixpri+16) >> 1)) */ | |
327 | winpri = 16 - ((param->sched_priority + 16) >> 1); | |
328 | ||
329 | /* calculate our desired priority class and thread priority */ | |
330 | ||
331 | if (winpri < 7) | |
332 | Class = IDLE_PRIORITY_CLASS; | |
333 | else if (winpri > 10) | |
334 | Class = HIGH_PRIORITY_CLASS; | |
335 | else | |
336 | Class = NORMAL_PRIORITY_CLASS; | |
337 | ||
6b2a2aa4 CF |
338 | localpid = pid ? pid : getpid (); |
339 | ||
340 | pinfo p (localpid); | |
341 | ||
342 | /* set the class */ | |
343 | ||
344 | if (!p) | |
345 | { | |
61522196 | 346 | set_errno (ESRCH); |
6b2a2aa4 CF |
347 | return -1; |
348 | } | |
349 | process = | |
350 | OpenProcess (PROCESS_SET_INFORMATION, FALSE, (DWORD) p->dwProcessId); | |
351 | if (!process) | |
352 | { | |
353 | set_errno (2); //ESRCH); | |
354 | return -1; | |
355 | } | |
356 | if (!SetPriorityClass (process, Class)) | |
357 | { | |
358 | CloseHandle (process); | |
359 | set_errno (EPERM); | |
360 | return -1; | |
361 | } | |
362 | CloseHandle (process); | |
363 | ||
364 | return 0; | |
365 | } | |
366 | ||
61522196 CV |
367 | /* we map -14 to 15, and 15 to 1 via (16- ((n+16) >> 1)). This lines up with |
368 | the allowed values we return elsewhere in the sched* functions. We then | |
369 | map in groups of three to allowed thread priority's. The reason for dropping | |
370 | accuracy while still returning a wide range of values is to allow more | |
371 | flexible code in the future. */ | |
5c83f260 | 372 | int |
f0227ea3 | 373 | sched_set_thread_priority (HANDLE thread, int priority) |
5c83f260 RC |
374 | { |
375 | int real_pri; | |
376 | real_pri = 16 - ((priority + 16) >> 1); | |
377 | if (real_pri <1 || real_pri > 15) | |
378 | return EINVAL; | |
462f4eff CF |
379 | |
380 | if (real_pri < 4) | |
5c83f260 RC |
381 | real_pri = THREAD_PRIORITY_LOWEST; |
382 | else if (real_pri < 7) | |
383 | real_pri = THREAD_PRIORITY_BELOW_NORMAL; | |
384 | else if (real_pri < 10) | |
385 | real_pri = THREAD_PRIORITY_NORMAL; | |
386 | else if (real_pri < 13) | |
387 | real_pri = THREAD_PRIORITY_ABOVE_NORMAL; | |
388 | else | |
389 | real_pri = THREAD_PRIORITY_HIGHEST; | |
390 | ||
f0227ea3 | 391 | if (!SetThreadPriority (thread, real_pri)) |
5c83f260 RC |
392 | /* invalid handle, no access are the only expected errors. */ |
393 | return EPERM; | |
394 | return 0; | |
395 | } | |
396 | ||
6b2a2aa4 CF |
397 | /* set the scheduler */ |
398 | int | |
399 | sched_setscheduler (pid_t pid, int policy, | |
400 | const struct sched_param *param) | |
401 | { | |
402 | /* on win32, you can't change the scheduler. Doh! */ | |
403 | set_errno (ENOSYS); | |
404 | return -1; | |
405 | } | |
406 | ||
407 | /* yield the cpu */ | |
408 | int | |
2f9ae2ed | 409 | sched_yield () |
6b2a2aa4 | 410 | { |
5e6a9154 | 411 | SwitchToThread (); |
6b2a2aa4 CF |
412 | return 0; |
413 | } | |
414 | } |