]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/sched.cc
* Merge in cygwin-64bit-branch.
[newlib-cygwin.git] / winsup / cygwin / sched.cc
CommitLineData
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
49extern "C"
50{
51
52/* max priority for policy */
53int
54sched_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 */
65int
66sched_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 */
77int
f0227ea3 78valid_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*/
94int
95sched_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*/
233int
234sched_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
243int
244sched_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 */
306int
307sched_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 372int
f0227ea3 373sched_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 */
398int
399sched_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 */
408int
2f9ae2ed 409sched_yield ()
6b2a2aa4 410{
5e6a9154 411 SwitchToThread ();
6b2a2aa4
CF
412 return 0;
413}
414}
This page took 0.466385 seconds and 5 git commands to generate.