linux_sched.c revision 1.12.2.4 1 /* $NetBSD: linux_sched.c,v 1.12.2.4 2005/12/11 10:28:46 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center; by Matthias Scheler.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * Linux compatibility module. Try to deal with scheduler related syscalls.
42 */
43
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: linux_sched.c,v 1.12.2.4 2005/12/11 10:28:46 christos Exp $");
46
47 #include <sys/param.h>
48 #include <sys/mount.h>
49 #include <sys/proc.h>
50 #include <sys/systm.h>
51 #include <sys/sysctl.h>
52 #include <sys/malloc.h>
53 #include <sys/sa.h>
54 #include <sys/syscallargs.h>
55 #include <sys/wait.h>
56
57 #include <machine/cpu.h>
58
59 #include <compat/linux/common/linux_types.h>
60 #include <compat/linux/common/linux_signal.h>
61 #include <compat/linux/common/linux_machdep.h> /* For LINUX_NPTL */
62 #include <compat/linux/common/linux_emuldata.h>
63
64 #include <compat/linux/linux_syscallargs.h>
65
66 #include <compat/linux/common/linux_sched.h>
67
68 int
69 linux_sys_clone(l, v, retval)
70 struct lwp *l;
71 void *v;
72 register_t *retval;
73 {
74 struct linux_sys_clone_args /* {
75 syscallarg(int) flags;
76 syscallarg(void *) stack;
77 #ifdef LINUX_NPTL
78 syscallarg(void *) parent_tidptr;
79 syscallarg(void *) child_tidptr;
80 #endif
81 } */ *uap = v;
82 int flags, sig;
83 int error;
84 #ifdef LINUX_NPTL
85 struct linux_emuldata *led;
86 #endif
87
88 /*
89 * We don't support the Linux CLONE_PID or CLONE_PTRACE flags.
90 */
91 if (SCARG(uap, flags) & (LINUX_CLONE_PID|LINUX_CLONE_PTRACE))
92 return (EINVAL);
93
94 /*
95 * Thread group implies shared signals. Shared signals
96 * imply shared VM. This matches what Linux kernel does.
97 */
98 if (SCARG(uap, flags) & LINUX_CLONE_THREAD
99 && (SCARG(uap, flags) & LINUX_CLONE_SIGHAND) == 0)
100 return (EINVAL);
101 if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND
102 && (SCARG(uap, flags) & LINUX_CLONE_VM) == 0)
103 return (EINVAL);
104
105 flags = 0;
106
107 if (SCARG(uap, flags) & LINUX_CLONE_VM)
108 flags |= FORK_SHAREVM;
109 if (SCARG(uap, flags) & LINUX_CLONE_FS)
110 flags |= FORK_SHARECWD;
111 if (SCARG(uap, flags) & LINUX_CLONE_FILES)
112 flags |= FORK_SHAREFILES;
113 if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND)
114 flags |= FORK_SHARESIGS;
115 if (SCARG(uap, flags) & LINUX_CLONE_VFORK)
116 flags |= FORK_PPWAIT;
117
118 /* Thread should not issue a SIGCHLD on termination */
119 if (SCARG(uap, flags) & LINUX_CLONE_THREAD) {
120 sig = 0;
121 } else {
122 sig = SCARG(uap, flags) & LINUX_CLONE_CSIGNAL;
123 if (sig < 0 || sig >= LINUX__NSIG)
124 return (EINVAL);
125 sig = linux_to_native_signo[sig];
126 }
127
128 #ifdef LINUX_NPTL
129 led = (struct linux_emuldata *)l->l_proc->p_emuldata;
130
131 if (SCARG(uap, flags) & LINUX_CLONE_PARENT_SETTID) {
132 if (SCARG(uap, parent_tidptr) == NULL) {
133 printf("linux_sys_clone: NULL parent_tidptr\n");
134 return EINVAL;
135 }
136
137 if ((error = copyout(&l->l_proc->p_pid,
138 SCARG(uap, parent_tidptr),
139 sizeof(l->l_proc->p_pid))) != 0)
140 return error;
141 }
142
143 /* CLONE_CHILD_CLEARTID: TID clear in the child on exit() */
144 if (SCARG(uap, flags) & LINUX_CLONE_CHILD_CLEARTID)
145 led->child_clear_tid = SCARG(uap, child_tidptr);
146 else
147 led->child_clear_tid = NULL;
148
149 /* CLONE_CHILD_SETTID: TID set in the child on clone() */
150 if (SCARG(uap, flags) & LINUX_CLONE_CHILD_SETTID)
151 led->child_set_tid = SCARG(uap, child_tidptr);
152 else
153 led->child_set_tid = NULL;
154
155 /* CLONE_SETTLS: new Thread Local Storage in the child */
156 if (SCARG(uap, flags) & LINUX_CLONE_SETTLS)
157 led->set_tls = linux_get_newtls(l);
158 else
159 led->set_tls = 0;
160 #endif /* LINUX_NPTL */
161 /*
162 * Note that Linux does not provide a portable way of specifying
163 * the stack area; the caller must know if the stack grows up
164 * or down. So, we pass a stack size of 0, so that the code
165 * that makes this adjustment is a noop.
166 */
167 if ((error = fork1(l, flags, sig, SCARG(uap, stack), 0,
168 NULL, NULL, retval, NULL)) != 0)
169 return error;
170
171 return 0;
172 }
173
174 int
175 linux_sys_sched_setparam(cl, v, retval)
176 struct lwp *cl;
177 void *v;
178 register_t *retval;
179 {
180 struct linux_sys_sched_setparam_args /* {
181 syscallarg(linux_pid_t) pid;
182 syscallarg(const struct linux_sched_param *) sp;
183 } */ *uap = v;
184 struct proc *cp = cl->l_proc;
185 int error;
186 struct linux_sched_param lp;
187 struct proc *p;
188
189 /*
190 * We only check for valid parameters and return afterwards.
191 */
192
193 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
194 return EINVAL;
195
196 error = copyin(SCARG(uap, sp), &lp, sizeof(lp));
197 if (error)
198 return error;
199
200 if (SCARG(uap, pid) != 0) {
201 struct pcred *pc = cp->p_cred;
202
203 if ((p = pfind(SCARG(uap, pid))) == NULL)
204 return ESRCH;
205 if (!(cp == p ||
206 pc->pc_ucred->cr_uid == 0 ||
207 pc->p_ruid == p->p_cred->p_ruid ||
208 pc->pc_ucred->cr_uid == p->p_cred->p_ruid ||
209 pc->p_ruid == p->p_ucred->cr_uid ||
210 pc->pc_ucred->cr_uid == p->p_ucred->cr_uid))
211 return EPERM;
212 }
213
214 return 0;
215 }
216
217 int
218 linux_sys_sched_getparam(cl, v, retval)
219 struct lwp *cl;
220 void *v;
221 register_t *retval;
222 {
223 struct linux_sys_sched_getparam_args /* {
224 syscallarg(linux_pid_t) pid;
225 syscallarg(struct linux_sched_param *) sp;
226 } */ *uap = v;
227 struct proc *cp = cl->l_proc;
228 struct proc *p;
229 struct linux_sched_param lp;
230
231 /*
232 * We only check for valid parameters and return a dummy priority afterwards.
233 */
234 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
235 return EINVAL;
236
237 if (SCARG(uap, pid) != 0) {
238 struct pcred *pc = cp->p_cred;
239
240 if ((p = pfind(SCARG(uap, pid))) == NULL)
241 return ESRCH;
242 if (!(cp == p ||
243 pc->pc_ucred->cr_uid == 0 ||
244 pc->p_ruid == p->p_cred->p_ruid ||
245 pc->pc_ucred->cr_uid == p->p_cred->p_ruid ||
246 pc->p_ruid == p->p_ucred->cr_uid ||
247 pc->pc_ucred->cr_uid == p->p_ucred->cr_uid))
248 return EPERM;
249 }
250
251 lp.sched_priority = 0;
252 return copyout(&lp, SCARG(uap, sp), sizeof(lp));
253 }
254
255 int
256 linux_sys_sched_setscheduler(cl, v, retval)
257 struct lwp *cl;
258 void *v;
259 register_t *retval;
260 {
261 struct linux_sys_sched_setscheduler_args /* {
262 syscallarg(linux_pid_t) pid;
263 syscallarg(int) policy;
264 syscallarg(cont struct linux_sched_scheduler *) sp;
265 } */ *uap = v;
266 struct proc *cp = cl->l_proc;
267 int error;
268 struct linux_sched_param lp;
269 struct proc *p;
270
271 /*
272 * We only check for valid parameters and return afterwards.
273 */
274
275 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
276 return EINVAL;
277
278 error = copyin(SCARG(uap, sp), &lp, sizeof(lp));
279 if (error)
280 return error;
281
282 if (SCARG(uap, pid) != 0) {
283 struct pcred *pc = cp->p_cred;
284
285 if ((p = pfind(SCARG(uap, pid))) == NULL)
286 return ESRCH;
287 if (!(cp == p ||
288 pc->pc_ucred->cr_uid == 0 ||
289 pc->p_ruid == p->p_cred->p_ruid ||
290 pc->pc_ucred->cr_uid == p->p_cred->p_ruid ||
291 pc->p_ruid == p->p_ucred->cr_uid ||
292 pc->pc_ucred->cr_uid == p->p_ucred->cr_uid))
293 return EPERM;
294 }
295
296 /*
297 * We can't emulate anything put the default scheduling policy.
298 */
299 if (SCARG(uap, policy) != LINUX_SCHED_OTHER || lp.sched_priority != 0)
300 return EINVAL;
301
302 return 0;
303 }
304
305 int
306 linux_sys_sched_getscheduler(cl, v, retval)
307 struct lwp *cl;
308 void *v;
309 register_t *retval;
310 {
311 struct linux_sys_sched_getscheduler_args /* {
312 syscallarg(linux_pid_t) pid;
313 } */ *uap = v;
314 struct proc *cp = cl->l_proc;
315 struct proc *p;
316
317 *retval = -1;
318 /*
319 * We only check for valid parameters and return afterwards.
320 */
321
322 if (SCARG(uap, pid) != 0) {
323 struct pcred *pc = cp->p_cred;
324
325 if ((p = pfind(SCARG(uap, pid))) == NULL)
326 return ESRCH;
327 if (!(cp == p ||
328 pc->pc_ucred->cr_uid == 0 ||
329 pc->p_ruid == p->p_cred->p_ruid ||
330 pc->pc_ucred->cr_uid == p->p_cred->p_ruid ||
331 pc->p_ruid == p->p_ucred->cr_uid ||
332 pc->pc_ucred->cr_uid == p->p_ucred->cr_uid))
333 return EPERM;
334 }
335
336 /*
337 * We can't emulate anything put the default scheduling policy.
338 */
339 *retval = LINUX_SCHED_OTHER;
340 return 0;
341 }
342
343 int
344 linux_sys_sched_yield(cl, v, retval)
345 struct lwp *cl;
346 void *v;
347 register_t *retval;
348 {
349
350 yield();
351 return 0;
352 }
353
354 int
355 linux_sys_sched_get_priority_max(cl, v, retval)
356 struct lwp *cl;
357 void *v;
358 register_t *retval;
359 {
360 struct linux_sys_sched_get_priority_max_args /* {
361 syscallarg(int) policy;
362 } */ *uap = v;
363
364 /*
365 * We can't emulate anything put the default scheduling policy.
366 */
367 if (SCARG(uap, policy) != LINUX_SCHED_OTHER) {
368 *retval = -1;
369 return EINVAL;
370 }
371
372 *retval = 0;
373 return 0;
374 }
375
376 int
377 linux_sys_sched_get_priority_min(cl, v, retval)
378 struct lwp *cl;
379 void *v;
380 register_t *retval;
381 {
382 struct linux_sys_sched_get_priority_min_args /* {
383 syscallarg(int) policy;
384 } */ *uap = v;
385
386 /*
387 * We can't emulate anything put the default scheduling policy.
388 */
389 if (SCARG(uap, policy) != LINUX_SCHED_OTHER) {
390 *retval = -1;
391 return EINVAL;
392 }
393
394 *retval = 0;
395 return 0;
396 }
397
398 #ifndef __m68k__
399 /* Present on everything but m68k */
400 int
401 linux_sys_exit_group(l, v, retval)
402 struct lwp *l;
403 void *v;
404 register_t *retval;
405 {
406 struct linux_sys_exit_group_args /* {
407 syscallarg(int) error_code;
408 } */ *uap = v;
409
410 /*
411 * XXX The calling thread is supposed to kill all threads
412 * in the same thread group (i.e. all threads created
413 * via clone(2) with CLONE_THREAD flag set). This appears
414 * to not be used yet, so the thread group handling
415 * is currently not implemented.
416 */
417
418 exit1(l, W_EXITCODE(SCARG(uap, error_code), 0));
419 /* NOTREACHED */
420 return 0;
421 }
422 #endif /* !__m68k__ */
423
424 #ifdef LINUX_NPTL
425 int
426 linux_sys_set_tid_address(l, v, retval)
427 struct lwp *l;
428 void *v;
429 register_t *retval;
430 {
431 struct linux_sys_set_tid_address_args /* {
432 syscallarg(int *) tidptr;
433 } */ *uap = v;
434 struct linux_emuldata *led;
435
436 led = (struct linux_emuldata *)l->l_proc->p_emuldata;
437 led->clear_tid = SCARG(uap, tid);
438
439 *retval = l->l_proc->p_pid;
440
441 return 0;
442 }
443
444 /* ARGUSED1 */
445 int
446 linux_sys_gettid(l, v, retval)
447 struct lwp *l;
448 void *v;
449 register_t *retval;
450 {
451 *retval = l->l_proc->p_pid;
452 return 0;
453 }
454
455 int
456 linux_sys_sched_getaffinity(l, v, retval)
457 struct lwp *l;
458 void *v;
459 register_t *retval;
460 {
461 struct linux_sys_sched_getaffinity_args /* {
462 syscallarg(pid_t) pid;
463 syscallarg(unsigned int) len;
464 syscallarg(unsigned long *) mask;
465 } */ *uap = v;
466 int error;
467 int ret;
468 int ncpu;
469 int name[2];
470 size_t sz;
471 char *data;
472 int *retp;
473
474 if (SCARG(uap, mask) == NULL)
475 return EINVAL;
476
477 if (SCARG(uap, len) < sizeof(int))
478 return EINVAL;
479
480 if (pfind(SCARG(uap, pid)) == NULL)
481 return ESRCH;
482
483 /*
484 * return the actual number of CPU, tag all of them as available
485 * The result is a mask, the first CPU being in the least significant
486 * bit.
487 */
488 name[0] = CTL_HW;
489 name[1] = HW_NCPU;
490 sz = sizeof(ncpu);
491
492 if ((error = old_sysctl(&name[0], 2, &ncpu, &sz, NULL, 0, NULL)) != 0)
493 return error;
494
495 ret = (1 << ncpu) - 1;
496
497 data = malloc(SCARG(uap, len), M_TEMP, M_WAITOK|M_ZERO);
498 retp = (int *)&data[SCARG(uap, len) - sizeof(ret)];
499 *retp = ret;
500
501 if ((error = copyout(data, SCARG(uap, mask), SCARG(uap, len))) != 0)
502 return error;
503
504 free(data, M_TEMP);
505
506 return 0;
507
508 }
509
510 int
511 linux_sys_sched_setaffinity(l, v, retval)
512 struct lwp *l;
513 void *v;
514 register_t *retval;
515 {
516 struct linux_sys_sched_setaffinity_args /* {
517 syscallarg(pid_t) pid;
518 syscallarg(unsigned int) len;
519 syscallarg(unsigned long *) mask;
520 } */ *uap = v;
521
522 if (pfind(SCARG(uap, pid)) == NULL)
523 return ESRCH;
524
525 /* Let's ignore it */
526 #ifdef DEBUG_LINUX
527 printf("linux_sys_sched_setaffinity\n");
528 #endif
529 return 0;
530 };
531 #endif /* LINUX_NPTL */
532