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