Home | History | Annotate | Line # | Download | only in common
linux_sched.c revision 1.66.4.1.4.1
      1  1.66.4.1.4.1     skrll /*	$NetBSD: linux_sched.c,v 1.66.4.1.4.1 2017/01/18 08:46:26 skrll Exp $	*/
      2           1.1      tron 
      3           1.1      tron /*-
      4           1.1      tron  * Copyright (c) 1999 The NetBSD Foundation, Inc.
      5           1.1      tron  * All rights reserved.
      6           1.1      tron  *
      7           1.1      tron  * This code is derived from software contributed to The NetBSD Foundation
      8           1.2   thorpej  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
      9           1.1      tron  * NASA Ames Research Center; by Matthias Scheler.
     10           1.1      tron  *
     11           1.1      tron  * Redistribution and use in source and binary forms, with or without
     12           1.1      tron  * modification, are permitted provided that the following conditions
     13           1.1      tron  * are met:
     14           1.1      tron  * 1. Redistributions of source code must retain the above copyright
     15           1.1      tron  *    notice, this list of conditions and the following disclaimer.
     16           1.1      tron  * 2. Redistributions in binary form must reproduce the above copyright
     17           1.1      tron  *    notice, this list of conditions and the following disclaimer in the
     18           1.1      tron  *    documentation and/or other materials provided with the distribution.
     19           1.1      tron  *
     20           1.1      tron  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21           1.1      tron  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22           1.1      tron  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23           1.1      tron  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24           1.1      tron  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25           1.1      tron  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26           1.1      tron  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27           1.1      tron  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28           1.1      tron  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29           1.1      tron  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30           1.1      tron  * POSSIBILITY OF SUCH DAMAGE.
     31           1.1      tron  */
     32           1.1      tron 
     33           1.1      tron /*
     34           1.1      tron  * Linux compatibility module. Try to deal with scheduler related syscalls.
     35           1.1      tron  */
     36           1.8     lukem 
     37           1.8     lukem #include <sys/cdefs.h>
     38  1.66.4.1.4.1     skrll __KERNEL_RCSID(0, "$NetBSD: linux_sched.c,v 1.66.4.1.4.1 2017/01/18 08:46:26 skrll Exp $");
     39           1.1      tron 
     40           1.1      tron #include <sys/param.h>
     41           1.1      tron #include <sys/mount.h>
     42           1.1      tron #include <sys/proc.h>
     43           1.1      tron #include <sys/systm.h>
     44          1.22      manu #include <sys/sysctl.h>
     45           1.1      tron #include <sys/syscallargs.h>
     46          1.14  jdolecek #include <sys/wait.h>
     47          1.30      elad #include <sys/kauth.h>
     48          1.34      manu #include <sys/ptrace.h>
     49          1.63       chs #include <sys/atomic.h>
     50           1.3     itohy 
     51          1.43        ad #include <sys/cpu.h>
     52           1.1      tron 
     53           1.1      tron #include <compat/linux/common/linux_types.h>
     54           1.1      tron #include <compat/linux/common/linux_signal.h>
     55          1.19      manu #include <compat/linux/common/linux_emuldata.h>
     56          1.44     njoly #include <compat/linux/common/linux_ipc.h>
     57          1.44     njoly #include <compat/linux/common/linux_sem.h>
     58          1.58  christos #include <compat/linux/common/linux_exec.h>
     59          1.63       chs #include <compat/linux/common/linux_machdep.h>
     60           1.1      tron 
     61           1.1      tron #include <compat/linux/linux_syscallargs.h>
     62           1.1      tron 
     63           1.1      tron #include <compat/linux/common/linux_sched.h>
     64           1.1      tron 
     65          1.65  christos static int linux_clone_nptl(struct lwp *, const struct linux_sys_clone_args *,
     66          1.65  christos     register_t *);
     67          1.65  christos 
     68  1.66.4.1.4.1     skrll /* Unlike Linux, dynamically calculate CPU mask size */
     69  1.66.4.1.4.1     skrll #define	LINUX_CPU_MASK_SIZE (sizeof(long) * ((ncpu + LONG_BIT - 1) / LONG_BIT))
     70  1.66.4.1.4.1     skrll 
     71          1.65  christos #if DEBUG_LINUX
     72          1.65  christos #define DPRINTF(x) uprintf x
     73          1.65  christos #else
     74          1.65  christos #define DPRINTF(x)
     75          1.65  christos #endif
     76          1.63       chs 
     77          1.63       chs static void
     78          1.63       chs linux_child_return(void *arg)
     79          1.63       chs {
     80          1.63       chs 	struct lwp *l = arg;
     81          1.63       chs 	struct proc *p = l->l_proc;
     82          1.63       chs 	struct linux_emuldata *led = l->l_emuldata;
     83          1.63       chs 	void *ctp = led->led_child_tidptr;
     84          1.65  christos 	int error;
     85          1.63       chs 
     86          1.63       chs 	if (ctp) {
     87          1.65  christos 		if ((error = copyout(&p->p_pid, ctp, sizeof(p->p_pid))) != 0)
     88          1.63       chs 			printf("%s: LINUX_CLONE_CHILD_SETTID "
     89          1.65  christos 			    "failed (child_tidptr = %p, tid = %d error =%d)\n",
     90          1.65  christos 			    __func__, ctp, p->p_pid, error);
     91          1.63       chs 	}
     92          1.63       chs 	child_return(arg);
     93          1.63       chs }
     94          1.63       chs 
     95           1.1      tron int
     96          1.65  christos linux_sys_clone(struct lwp *l, const struct linux_sys_clone_args *uap,
     97          1.65  christos     register_t *retval)
     98           1.1      tron {
     99          1.46       dsl 	/* {
    100           1.1      tron 		syscallarg(int) flags;
    101           1.1      tron 		syscallarg(void *) stack;
    102          1.19      manu 		syscallarg(void *) parent_tidptr;
    103          1.63       chs 		syscallarg(void *) tls;
    104          1.19      manu 		syscallarg(void *) child_tidptr;
    105          1.46       dsl 	} */
    106          1.58  christos 	struct proc *p;
    107          1.19      manu 	struct linux_emuldata *led;
    108          1.63       chs 	int flags, sig, error;
    109           1.1      tron 
    110           1.1      tron 	/*
    111           1.1      tron 	 * We don't support the Linux CLONE_PID or CLONE_PTRACE flags.
    112           1.1      tron 	 */
    113           1.1      tron 	if (SCARG(uap, flags) & (LINUX_CLONE_PID|LINUX_CLONE_PTRACE))
    114          1.65  christos 		return EINVAL;
    115           1.1      tron 
    116          1.13  jdolecek 	/*
    117          1.13  jdolecek 	 * Thread group implies shared signals. Shared signals
    118          1.13  jdolecek 	 * imply shared VM. This matches what Linux kernel does.
    119          1.13  jdolecek 	 */
    120          1.13  jdolecek 	if (SCARG(uap, flags) & LINUX_CLONE_THREAD
    121          1.13  jdolecek 	    && (SCARG(uap, flags) & LINUX_CLONE_SIGHAND) == 0)
    122          1.65  christos 		return EINVAL;
    123          1.13  jdolecek 	if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND
    124          1.13  jdolecek 	    && (SCARG(uap, flags) & LINUX_CLONE_VM) == 0)
    125          1.65  christos 		return EINVAL;
    126          1.13  jdolecek 
    127          1.63       chs 	/*
    128          1.63       chs 	 * The thread group flavor is implemented totally differently.
    129          1.63       chs 	 */
    130          1.65  christos 	if (SCARG(uap, flags) & LINUX_CLONE_THREAD)
    131          1.63       chs 		return linux_clone_nptl(l, uap, retval);
    132          1.63       chs 
    133           1.1      tron 	flags = 0;
    134           1.1      tron 	if (SCARG(uap, flags) & LINUX_CLONE_VM)
    135           1.1      tron 		flags |= FORK_SHAREVM;
    136           1.1      tron 	if (SCARG(uap, flags) & LINUX_CLONE_FS)
    137           1.1      tron 		flags |= FORK_SHARECWD;
    138           1.1      tron 	if (SCARG(uap, flags) & LINUX_CLONE_FILES)
    139           1.1      tron 		flags |= FORK_SHAREFILES;
    140           1.1      tron 	if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND)
    141           1.1      tron 		flags |= FORK_SHARESIGS;
    142           1.1      tron 	if (SCARG(uap, flags) & LINUX_CLONE_VFORK)
    143           1.1      tron 		flags |= FORK_PPWAIT;
    144           1.1      tron 
    145          1.34      manu 	sig = SCARG(uap, flags) & LINUX_CLONE_CSIGNAL;
    146          1.34      manu 	if (sig < 0 || sig >= LINUX__NSIG)
    147          1.65  christos 		return EINVAL;
    148          1.34      manu 	sig = linux_to_native_signo[sig];
    149           1.1      tron 
    150          1.63       chs 	if (SCARG(uap, flags) & LINUX_CLONE_CHILD_SETTID) {
    151          1.63       chs 		led = l->l_emuldata;
    152          1.63       chs 		led->led_child_tidptr = SCARG(uap, child_tidptr);
    153          1.63       chs 	}
    154          1.19      manu 
    155           1.1      tron 	/*
    156           1.1      tron 	 * Note that Linux does not provide a portable way of specifying
    157           1.1      tron 	 * the stack area; the caller must know if the stack grows up
    158           1.1      tron 	 * or down.  So, we pass a stack size of 0, so that the code
    159           1.1      tron 	 * that makes this adjustment is a noop.
    160           1.1      tron 	 */
    161          1.19      manu 	if ((error = fork1(l, flags, sig, SCARG(uap, stack), 0,
    162          1.65  christos 	    linux_child_return, NULL, retval, &p)) != 0) {
    163          1.65  christos 		DPRINTF(("%s: fork1: error %d\n", __func__, error));
    164          1.63       chs 		return error;
    165          1.65  christos 	}
    166          1.63       chs 
    167          1.63       chs 	return 0;
    168          1.63       chs }
    169          1.63       chs 
    170          1.63       chs static int
    171          1.63       chs linux_clone_nptl(struct lwp *l, const struct linux_sys_clone_args *uap, register_t *retval)
    172          1.63       chs {
    173          1.63       chs 	/* {
    174          1.63       chs 		syscallarg(int) flags;
    175          1.63       chs 		syscallarg(void *) stack;
    176          1.63       chs 		syscallarg(void *) parent_tidptr;
    177          1.63       chs 		syscallarg(void *) tls;
    178          1.63       chs 		syscallarg(void *) child_tidptr;
    179          1.63       chs 	} */
    180          1.63       chs 	struct proc *p;
    181          1.63       chs 	struct lwp *l2;
    182          1.63       chs 	struct linux_emuldata *led;
    183          1.63       chs 	void *parent_tidptr, *tls, *child_tidptr;
    184          1.63       chs 	struct schedstate_percpu *spc;
    185          1.63       chs 	vaddr_t uaddr;
    186          1.63       chs 	lwpid_t lid;
    187          1.63       chs 	int flags, tnprocs, error;
    188          1.63       chs 
    189          1.63       chs 	p = l->l_proc;
    190          1.63       chs 	flags = SCARG(uap, flags);
    191          1.63       chs 	parent_tidptr = SCARG(uap, parent_tidptr);
    192          1.63       chs 	tls = SCARG(uap, tls);
    193          1.63       chs 	child_tidptr = SCARG(uap, child_tidptr);
    194          1.63       chs 
    195          1.63       chs 	tnprocs = atomic_inc_uint_nv(&nprocs);
    196          1.63       chs 	if (__predict_false(tnprocs >= maxproc) ||
    197          1.63       chs 	    kauth_authorize_process(l->l_cred, KAUTH_PROCESS_FORK, p,
    198          1.65  christos 	    KAUTH_ARG(tnprocs), NULL, NULL) != 0) {
    199          1.63       chs 		atomic_dec_uint(&nprocs);
    200          1.63       chs 		return EAGAIN;
    201          1.63       chs 	}
    202          1.63       chs 
    203          1.63       chs 	uaddr = uvm_uarea_alloc();
    204          1.63       chs 	if (__predict_false(uaddr == 0)) {
    205          1.63       chs 		atomic_dec_uint(&nprocs);
    206          1.63       chs 		return ENOMEM;
    207          1.63       chs 	}
    208          1.63       chs 
    209          1.63       chs 	error = lwp_create(l, p, uaddr, LWP_DETACHED | LWP_PIDLID,
    210          1.65  christos 	    SCARG(uap, stack), 0, child_return, NULL, &l2, l->l_class);
    211          1.63       chs 	if (__predict_false(error)) {
    212          1.65  christos 		DPRINTF(("%s: lwp_create error=%d\n", __func__, error));
    213          1.63       chs 		atomic_dec_uint(&nprocs);
    214          1.63       chs 		uvm_uarea_free(uaddr);
    215          1.19      manu 		return error;
    216          1.63       chs 	}
    217          1.63       chs 	lid = l2->l_lid;
    218          1.19      manu 
    219          1.63       chs 	/* LINUX_CLONE_CHILD_CLEARTID: clear TID in child's memory on exit() */
    220          1.63       chs 	if (flags & LINUX_CLONE_CHILD_CLEARTID) {
    221          1.63       chs 		led = l2->l_emuldata;
    222          1.63       chs 		led->led_clear_tid = child_tidptr;
    223          1.63       chs 	}
    224          1.63       chs 
    225          1.63       chs 	/* LINUX_CLONE_PARENT_SETTID: store child's TID in parent's memory */
    226          1.63       chs 	if (flags & LINUX_CLONE_PARENT_SETTID) {
    227          1.65  christos 		if ((error = copyout(&lid, parent_tidptr, sizeof(lid))) != 0)
    228          1.63       chs 			printf("%s: LINUX_CLONE_PARENT_SETTID "
    229          1.65  christos 			    "failed (parent_tidptr = %p tid = %d error=%d)\n",
    230          1.65  christos 			    __func__, parent_tidptr, lid, error);
    231          1.63       chs 	}
    232          1.63       chs 
    233          1.63       chs 	/* LINUX_CLONE_CHILD_SETTID: store child's TID in child's memory  */
    234          1.63       chs 	if (flags & LINUX_CLONE_CHILD_SETTID) {
    235          1.65  christos 		if ((error = copyout(&lid, child_tidptr, sizeof(lid))) != 0)
    236          1.63       chs 			printf("%s: LINUX_CLONE_CHILD_SETTID "
    237          1.65  christos 			    "failed (child_tidptr = %p, tid = %d error=%d)\n",
    238          1.65  christos 			    __func__, child_tidptr, lid, error);
    239          1.63       chs 	}
    240          1.63       chs 
    241          1.63       chs 	if (flags & LINUX_CLONE_SETTLS) {
    242          1.63       chs 		error = LINUX_LWP_SETPRIVATE(l2, tls);
    243          1.63       chs 		if (error) {
    244          1.65  christos 			DPRINTF(("%s: LINUX_LWP_SETPRIVATE %d\n", __func__,
    245          1.65  christos 			    error));
    246          1.63       chs 			lwp_exit(l2);
    247          1.63       chs 			return error;
    248          1.63       chs 		}
    249          1.63       chs 	}
    250          1.63       chs 
    251          1.63       chs 	/*
    252          1.63       chs 	 * Set the new LWP running, unless the process is stopping,
    253          1.63       chs 	 * then the LWP is created stopped.
    254          1.63       chs 	 */
    255          1.63       chs 	mutex_enter(p->p_lock);
    256          1.63       chs 	lwp_lock(l2);
    257          1.63       chs 	spc = &l2->l_cpu->ci_schedstate;
    258          1.63       chs 	if ((l->l_flag & (LW_WREBOOT | LW_WSUSPEND | LW_WEXIT)) == 0) {
    259          1.63       chs 	    	if (p->p_stat == SSTOP || (p->p_sflag & PS_STOPPING) != 0) {
    260          1.63       chs 			KASSERT(l2->l_wchan == NULL);
    261          1.63       chs 	    		l2->l_stat = LSSTOP;
    262          1.63       chs 			p->p_nrlwps--;
    263          1.63       chs 			lwp_unlock_to(l2, spc->spc_lwplock);
    264          1.63       chs 		} else {
    265          1.63       chs 			KASSERT(lwp_locked(l2, spc->spc_mutex));
    266          1.63       chs 			l2->l_stat = LSRUN;
    267          1.63       chs 			sched_enqueue(l2, false);
    268          1.63       chs 			lwp_unlock(l2);
    269          1.63       chs 		}
    270          1.63       chs 	} else {
    271          1.63       chs 		l2->l_stat = LSSUSPENDED;
    272          1.63       chs 		p->p_nrlwps--;
    273          1.63       chs 		lwp_unlock_to(l2, spc->spc_lwplock);
    274          1.63       chs 	}
    275          1.63       chs 	mutex_exit(p->p_lock);
    276          1.58  christos 
    277          1.63       chs 	retval[0] = lid;
    278          1.63       chs 	retval[1] = 0;
    279          1.19      manu 	return 0;
    280           1.1      tron }
    281           1.1      tron 
    282          1.49      elad /*
    283          1.49      elad  * linux realtime priority
    284          1.49      elad  *
    285          1.49      elad  * - SCHED_RR and SCHED_FIFO tasks have priorities [1,99].
    286          1.49      elad  *
    287          1.49      elad  * - SCHED_OTHER tasks don't have realtime priorities.
    288          1.49      elad  *   in particular, sched_param::sched_priority is always 0.
    289          1.49      elad  */
    290          1.49      elad 
    291          1.49      elad #define	LINUX_SCHED_RTPRIO_MIN	1
    292          1.49      elad #define	LINUX_SCHED_RTPRIO_MAX	99
    293          1.49      elad 
    294          1.49      elad static int
    295          1.49      elad sched_linux2native(int linux_policy, struct linux_sched_param *linux_params,
    296          1.49      elad     int *native_policy, struct sched_param *native_params)
    297          1.49      elad {
    298          1.49      elad 
    299          1.49      elad 	switch (linux_policy) {
    300          1.49      elad 	case LINUX_SCHED_OTHER:
    301          1.49      elad 		if (native_policy != NULL) {
    302          1.49      elad 			*native_policy = SCHED_OTHER;
    303          1.49      elad 		}
    304          1.49      elad 		break;
    305          1.49      elad 
    306          1.49      elad 	case LINUX_SCHED_FIFO:
    307          1.49      elad 		if (native_policy != NULL) {
    308          1.49      elad 			*native_policy = SCHED_FIFO;
    309          1.49      elad 		}
    310          1.49      elad 		break;
    311          1.49      elad 
    312          1.49      elad 	case LINUX_SCHED_RR:
    313          1.49      elad 		if (native_policy != NULL) {
    314          1.49      elad 			*native_policy = SCHED_RR;
    315          1.49      elad 		}
    316          1.49      elad 		break;
    317          1.49      elad 
    318          1.49      elad 	default:
    319          1.49      elad 		return EINVAL;
    320          1.49      elad 	}
    321          1.49      elad 
    322          1.49      elad 	if (linux_params != NULL) {
    323          1.49      elad 		int prio = linux_params->sched_priority;
    324          1.49      elad 
    325          1.49      elad 		KASSERT(native_params != NULL);
    326          1.49      elad 
    327          1.49      elad 		if (linux_policy == LINUX_SCHED_OTHER) {
    328          1.49      elad 			if (prio != 0) {
    329          1.49      elad 				return EINVAL;
    330          1.49      elad 			}
    331          1.49      elad 			native_params->sched_priority = PRI_NONE; /* XXX */
    332          1.49      elad 		} else {
    333          1.49      elad 			if (prio < LINUX_SCHED_RTPRIO_MIN ||
    334          1.49      elad 			    prio > LINUX_SCHED_RTPRIO_MAX) {
    335          1.49      elad 				return EINVAL;
    336          1.49      elad 			}
    337          1.49      elad 			native_params->sched_priority =
    338          1.49      elad 			    (prio - LINUX_SCHED_RTPRIO_MIN)
    339          1.49      elad 			    * (SCHED_PRI_MAX - SCHED_PRI_MIN)
    340          1.49      elad 			    / (LINUX_SCHED_RTPRIO_MAX - LINUX_SCHED_RTPRIO_MIN)
    341          1.49      elad 			    + SCHED_PRI_MIN;
    342          1.49      elad 		}
    343          1.49      elad 	}
    344          1.49      elad 
    345          1.49      elad 	return 0;
    346          1.49      elad }
    347          1.49      elad 
    348          1.49      elad static int
    349          1.49      elad sched_native2linux(int native_policy, struct sched_param *native_params,
    350          1.49      elad     int *linux_policy, struct linux_sched_param *linux_params)
    351          1.49      elad {
    352          1.49      elad 
    353          1.49      elad 	switch (native_policy) {
    354          1.49      elad 	case SCHED_OTHER:
    355          1.49      elad 		if (linux_policy != NULL) {
    356          1.49      elad 			*linux_policy = LINUX_SCHED_OTHER;
    357          1.49      elad 		}
    358          1.49      elad 		break;
    359          1.49      elad 
    360          1.49      elad 	case SCHED_FIFO:
    361          1.49      elad 		if (linux_policy != NULL) {
    362          1.49      elad 			*linux_policy = LINUX_SCHED_FIFO;
    363          1.49      elad 		}
    364          1.49      elad 		break;
    365          1.49      elad 
    366          1.49      elad 	case SCHED_RR:
    367          1.49      elad 		if (linux_policy != NULL) {
    368          1.49      elad 			*linux_policy = LINUX_SCHED_RR;
    369          1.49      elad 		}
    370          1.49      elad 		break;
    371          1.49      elad 
    372          1.49      elad 	default:
    373          1.49      elad 		panic("%s: unknown policy %d\n", __func__, native_policy);
    374          1.49      elad 	}
    375          1.49      elad 
    376          1.49      elad 	if (native_params != NULL) {
    377          1.49      elad 		int prio = native_params->sched_priority;
    378          1.49      elad 
    379          1.49      elad 		KASSERT(prio >= SCHED_PRI_MIN);
    380          1.49      elad 		KASSERT(prio <= SCHED_PRI_MAX);
    381          1.49      elad 		KASSERT(linux_params != NULL);
    382          1.56  jmcneill 
    383          1.65  christos 		DPRINTF(("%s: native: policy %d, priority %d\n",
    384          1.65  christos 		    __func__, native_policy, prio));
    385          1.49      elad 
    386          1.49      elad 		if (native_policy == SCHED_OTHER) {
    387          1.49      elad 			linux_params->sched_priority = 0;
    388          1.49      elad 		} else {
    389          1.49      elad 			linux_params->sched_priority =
    390          1.49      elad 			    (prio - SCHED_PRI_MIN)
    391          1.49      elad 			    * (LINUX_SCHED_RTPRIO_MAX - LINUX_SCHED_RTPRIO_MIN)
    392          1.49      elad 			    / (SCHED_PRI_MAX - SCHED_PRI_MIN)
    393          1.49      elad 			    + LINUX_SCHED_RTPRIO_MIN;
    394          1.49      elad 		}
    395          1.65  christos 		DPRINTF(("%s: linux: policy %d, priority %d\n",
    396          1.65  christos 		    __func__, -1, linux_params->sched_priority));
    397          1.49      elad 	}
    398          1.49      elad 
    399          1.49      elad 	return 0;
    400          1.49      elad }
    401          1.49      elad 
    402           1.1      tron int
    403          1.46       dsl linux_sys_sched_setparam(struct lwp *l, const struct linux_sys_sched_setparam_args *uap, register_t *retval)
    404           1.1      tron {
    405          1.46       dsl 	/* {
    406           1.1      tron 		syscallarg(linux_pid_t) pid;
    407           1.1      tron 		syscallarg(const struct linux_sched_param *) sp;
    408          1.46       dsl 	} */
    409          1.49      elad 	int error, policy;
    410           1.1      tron 	struct linux_sched_param lp;
    411          1.49      elad 	struct sched_param sp;
    412          1.49      elad 
    413          1.49      elad 	if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL) {
    414          1.49      elad 		error = EINVAL;
    415          1.49      elad 		goto out;
    416          1.49      elad 	}
    417           1.1      tron 
    418          1.49      elad 	error = copyin(SCARG(uap, sp), &lp, sizeof(lp));
    419          1.49      elad 	if (error)
    420          1.49      elad 		goto out;
    421           1.1      tron 
    422          1.49      elad 	/* We need the current policy in Linux terms. */
    423          1.66     njoly 	error = do_sched_getparam(SCARG(uap, pid), 0, &policy, NULL);
    424          1.49      elad 	if (error)
    425          1.49      elad 		goto out;
    426          1.49      elad 	error = sched_native2linux(policy, NULL, &policy, NULL);
    427          1.49      elad 	if (error)
    428          1.49      elad 		goto out;
    429           1.1      tron 
    430          1.49      elad 	error = sched_linux2native(policy, &lp, &policy, &sp);
    431           1.1      tron 	if (error)
    432          1.49      elad 		goto out;
    433           1.1      tron 
    434          1.66     njoly 	error = do_sched_setparam(SCARG(uap, pid), 0, policy, &sp);
    435          1.49      elad 	if (error)
    436          1.49      elad 		goto out;
    437           1.1      tron 
    438          1.49      elad  out:
    439          1.49      elad 	return error;
    440           1.1      tron }
    441           1.1      tron 
    442           1.1      tron int
    443          1.46       dsl linux_sys_sched_getparam(struct lwp *l, const struct linux_sys_sched_getparam_args *uap, register_t *retval)
    444           1.1      tron {
    445          1.46       dsl 	/* {
    446           1.1      tron 		syscallarg(linux_pid_t) pid;
    447           1.1      tron 		syscallarg(struct linux_sched_param *) sp;
    448          1.46       dsl 	} */
    449           1.1      tron 	struct linux_sched_param lp;
    450          1.49      elad 	struct sched_param sp;
    451          1.50      elad 	int error, policy;
    452          1.49      elad 
    453          1.49      elad 	if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL) {
    454          1.49      elad 		error = EINVAL;
    455          1.49      elad 		goto out;
    456          1.49      elad 	}
    457           1.1      tron 
    458          1.66     njoly 	error = do_sched_getparam(SCARG(uap, pid), 0, &policy, &sp);
    459          1.49      elad 	if (error)
    460          1.49      elad 		goto out;
    461          1.65  christos 	DPRINTF(("%s: native: policy %d, priority %d\n",
    462          1.65  christos 	    __func__, policy, sp.sched_priority));
    463           1.1      tron 
    464          1.50      elad 	error = sched_native2linux(policy, &sp, NULL, &lp);
    465          1.49      elad 	if (error)
    466          1.49      elad 		goto out;
    467          1.65  christos 	DPRINTF(("%s: linux: policy %d, priority %d\n",
    468          1.65  christos 	    __func__, policy, lp.sched_priority));
    469          1.47      elad 
    470          1.49      elad 	error = copyout(&lp, SCARG(uap, sp), sizeof(lp));
    471          1.49      elad 	if (error)
    472          1.49      elad 		goto out;
    473           1.1      tron 
    474          1.49      elad  out:
    475          1.49      elad 	return error;
    476           1.1      tron }
    477           1.1      tron 
    478           1.1      tron int
    479          1.46       dsl linux_sys_sched_setscheduler(struct lwp *l, const struct linux_sys_sched_setscheduler_args *uap, register_t *retval)
    480           1.1      tron {
    481          1.46       dsl 	/* {
    482           1.1      tron 		syscallarg(linux_pid_t) pid;
    483           1.1      tron 		syscallarg(int) policy;
    484          1.61     njoly 		syscallarg(cont struct linux_sched_param *) sp;
    485          1.46       dsl 	} */
    486          1.49      elad 	int error, policy;
    487           1.1      tron 	struct linux_sched_param lp;
    488          1.49      elad 	struct sched_param sp;
    489           1.1      tron 
    490          1.49      elad 	if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL) {
    491          1.49      elad 		error = EINVAL;
    492          1.49      elad 		goto out;
    493          1.49      elad 	}
    494           1.1      tron 
    495           1.1      tron 	error = copyin(SCARG(uap, sp), &lp, sizeof(lp));
    496           1.1      tron 	if (error)
    497          1.49      elad 		goto out;
    498          1.65  christos 	DPRINTF(("%s: linux: policy %d, priority %d\n",
    499          1.65  christos 	    __func__, SCARG(uap, policy), lp.sched_priority));
    500           1.1      tron 
    501          1.49      elad 	error = sched_linux2native(SCARG(uap, policy), &lp, &policy, &sp);
    502          1.49      elad 	if (error)
    503          1.49      elad 		goto out;
    504          1.65  christos 	DPRINTF(("%s: native: policy %d, priority %d\n",
    505          1.65  christos 	    __func__, policy, sp.sched_priority));
    506           1.1      tron 
    507          1.66     njoly 	error = do_sched_setparam(SCARG(uap, pid), 0, policy, &sp);
    508          1.49      elad 	if (error)
    509          1.49      elad 		goto out;
    510           1.1      tron 
    511          1.49      elad  out:
    512          1.49      elad 	return error;
    513           1.1      tron }
    514           1.1      tron 
    515           1.1      tron int
    516          1.46       dsl linux_sys_sched_getscheduler(struct lwp *l, const struct linux_sys_sched_getscheduler_args *uap, register_t *retval)
    517           1.1      tron {
    518          1.46       dsl 	/* {
    519           1.1      tron 		syscallarg(linux_pid_t) pid;
    520          1.46       dsl 	} */
    521          1.49      elad 	int error, policy;
    522           1.1      tron 
    523           1.1      tron 	*retval = -1;
    524           1.1      tron 
    525          1.66     njoly 	error = do_sched_getparam(SCARG(uap, pid), 0, &policy, NULL);
    526          1.49      elad 	if (error)
    527          1.49      elad 		goto out;
    528          1.49      elad 
    529          1.49      elad 	error = sched_native2linux(policy, NULL, &policy, NULL);
    530          1.49      elad 	if (error)
    531          1.49      elad 		goto out;
    532          1.49      elad 
    533          1.49      elad 	*retval = policy;
    534           1.1      tron 
    535          1.49      elad  out:
    536          1.49      elad 	return error;
    537           1.1      tron }
    538           1.1      tron 
    539           1.1      tron int
    540          1.46       dsl linux_sys_sched_yield(struct lwp *l, const void *v, register_t *retval)
    541           1.1      tron {
    542          1.11  gmcgarry 
    543          1.11  gmcgarry 	yield();
    544           1.1      tron 	return 0;
    545           1.1      tron }
    546           1.1      tron 
    547           1.1      tron int
    548          1.46       dsl linux_sys_sched_get_priority_max(struct lwp *l, const struct linux_sys_sched_get_priority_max_args *uap, register_t *retval)
    549           1.1      tron {
    550          1.46       dsl 	/* {
    551           1.1      tron 		syscallarg(int) policy;
    552          1.46       dsl 	} */
    553           1.1      tron 
    554          1.55     njoly 	switch (SCARG(uap, policy)) {
    555          1.55     njoly 	case LINUX_SCHED_OTHER:
    556          1.55     njoly 		*retval = 0;
    557          1.55     njoly 		break;
    558          1.55     njoly 	case LINUX_SCHED_FIFO:
    559          1.55     njoly 	case LINUX_SCHED_RR:
    560          1.55     njoly 		*retval = LINUX_SCHED_RTPRIO_MAX;
    561          1.55     njoly 		break;
    562          1.55     njoly 	default:
    563           1.1      tron 		return EINVAL;
    564           1.1      tron 	}
    565           1.1      tron 
    566           1.1      tron 	return 0;
    567           1.1      tron }
    568           1.1      tron 
    569           1.1      tron int
    570          1.46       dsl linux_sys_sched_get_priority_min(struct lwp *l, const struct linux_sys_sched_get_priority_min_args *uap, register_t *retval)
    571           1.1      tron {
    572          1.46       dsl 	/* {
    573           1.1      tron 		syscallarg(int) policy;
    574          1.46       dsl 	} */
    575           1.1      tron 
    576          1.55     njoly 	switch (SCARG(uap, policy)) {
    577          1.55     njoly 	case LINUX_SCHED_OTHER:
    578          1.55     njoly 		*retval = 0;
    579          1.55     njoly 		break;
    580          1.55     njoly 	case LINUX_SCHED_FIFO:
    581          1.55     njoly 	case LINUX_SCHED_RR:
    582          1.55     njoly 		*retval = LINUX_SCHED_RTPRIO_MIN;
    583          1.55     njoly 		break;
    584          1.55     njoly 	default:
    585           1.1      tron 		return EINVAL;
    586           1.1      tron 	}
    587           1.1      tron 
    588           1.1      tron 	return 0;
    589           1.1      tron }
    590          1.14  jdolecek 
    591          1.63       chs int
    592          1.63       chs linux_sys_exit(struct lwp *l, const struct linux_sys_exit_args *uap, register_t *retval)
    593          1.63       chs {
    594          1.63       chs 
    595          1.63       chs 	lwp_exit(l);
    596          1.63       chs 	return 0;
    597          1.63       chs }
    598          1.63       chs 
    599          1.14  jdolecek #ifndef __m68k__
    600          1.14  jdolecek /* Present on everything but m68k */
    601          1.14  jdolecek int
    602          1.46       dsl linux_sys_exit_group(struct lwp *l, const struct linux_sys_exit_group_args *uap, register_t *retval)
    603          1.14  jdolecek {
    604          1.14  jdolecek 
    605          1.46       dsl 	return sys_exit(l, (const void *)uap, retval);
    606          1.14  jdolecek }
    607          1.14  jdolecek #endif /* !__m68k__ */
    608          1.19      manu 
    609          1.19      manu int
    610          1.46       dsl linux_sys_set_tid_address(struct lwp *l, const struct linux_sys_set_tid_address_args *uap, register_t *retval)
    611          1.19      manu {
    612          1.46       dsl 	/* {
    613          1.19      manu 		syscallarg(int *) tidptr;
    614          1.46       dsl 	} */
    615          1.19      manu 	struct linux_emuldata *led;
    616          1.19      manu 
    617          1.63       chs 	led = (struct linux_emuldata *)l->l_emuldata;
    618          1.63       chs 	led->led_clear_tid = SCARG(uap, tid);
    619          1.63       chs 	*retval = l->l_lid;
    620          1.19      manu 
    621          1.19      manu 	return 0;
    622          1.19      manu }
    623          1.20      manu 
    624          1.20      manu /* ARGUSED1 */
    625          1.20      manu int
    626          1.46       dsl linux_sys_gettid(struct lwp *l, const void *v, register_t *retval)
    627          1.20      manu {
    628          1.31      manu 
    629          1.63       chs 	*retval = l->l_lid;
    630          1.31      manu 	return 0;
    631          1.31      manu }
    632          1.31      manu 
    633  1.66.4.1.4.1     skrll /*
    634  1.66.4.1.4.1     skrll  * The affinity syscalls assume that the layout of our cpu kcpuset is
    635  1.66.4.1.4.1     skrll  * the same as linux's: a linear bitmask.
    636  1.66.4.1.4.1     skrll  */
    637          1.22      manu int
    638          1.46       dsl linux_sys_sched_getaffinity(struct lwp *l, const struct linux_sys_sched_getaffinity_args *uap, register_t *retval)
    639          1.22      manu {
    640          1.46       dsl 	/* {
    641          1.63       chs 		syscallarg(linux_pid_t) pid;
    642          1.22      manu 		syscallarg(unsigned int) len;
    643          1.22      manu 		syscallarg(unsigned long *) mask;
    644          1.46       dsl 	} */
    645  1.66.4.1.4.1     skrll 	struct lwp *t;
    646  1.66.4.1.4.1     skrll 	kcpuset_t *kcset;
    647  1.66.4.1.4.1     skrll 	size_t size;
    648  1.66.4.1.4.1     skrll 	cpuid_t i;
    649  1.66.4.1.4.1     skrll 	int error;
    650          1.22      manu 
    651  1.66.4.1.4.1     skrll 	size = LINUX_CPU_MASK_SIZE;
    652          1.60     njoly 	if (SCARG(uap, len) < size)
    653          1.22      manu 		return EINVAL;
    654          1.22      manu 
    655  1.66.4.1.4.1     skrll 	/* Lock the LWP */
    656  1.66.4.1.4.1     skrll 	t = lwp_find2(SCARG(uap, pid), l->l_lid);
    657  1.66.4.1.4.1     skrll 	if (t == NULL)
    658          1.22      manu 		return ESRCH;
    659          1.22      manu 
    660  1.66.4.1.4.1     skrll 	/* Check the permission */
    661  1.66.4.1.4.1     skrll 	if (kauth_authorize_process(l->l_cred,
    662  1.66.4.1.4.1     skrll 	    KAUTH_PROCESS_SCHEDULER_GETAFFINITY, t->l_proc, NULL, NULL, NULL)) {
    663  1.66.4.1.4.1     skrll 		mutex_exit(t->l_proc->p_lock);
    664  1.66.4.1.4.1     skrll 		return EPERM;
    665  1.66.4.1.4.1     skrll 	}
    666  1.66.4.1.4.1     skrll 
    667  1.66.4.1.4.1     skrll 	kcpuset_create(&kcset, true);
    668  1.66.4.1.4.1     skrll 	lwp_lock(t);
    669  1.66.4.1.4.1     skrll 	if (t->l_affinity != NULL)
    670  1.66.4.1.4.1     skrll 		kcpuset_copy(kcset, t->l_affinity);
    671  1.66.4.1.4.1     skrll 	else {
    672  1.66.4.1.4.1     skrll 		/*
    673  1.66.4.1.4.1     skrll 		 * All available CPUs should be masked when affinity has not
    674  1.66.4.1.4.1     skrll 		 * been set.
    675  1.66.4.1.4.1     skrll 		 */
    676  1.66.4.1.4.1     skrll 		kcpuset_zero(kcset);
    677  1.66.4.1.4.1     skrll 		for (i = 0; i < ncpu; i++)
    678  1.66.4.1.4.1     skrll 			kcpuset_set(kcset, i);
    679  1.66.4.1.4.1     skrll 	}
    680  1.66.4.1.4.1     skrll 	lwp_unlock(t);
    681  1.66.4.1.4.1     skrll 	mutex_exit(t->l_proc->p_lock);
    682  1.66.4.1.4.1     skrll 	error = kcpuset_copyout(kcset, (cpuset_t *)SCARG(uap, mask), size);
    683  1.66.4.1.4.1     skrll 	kcpuset_unuse(kcset, NULL);
    684          1.60     njoly 	*retval = size;
    685          1.59     njoly 	return error;
    686          1.22      manu }
    687          1.22      manu 
    688          1.22      manu int
    689          1.46       dsl linux_sys_sched_setaffinity(struct lwp *l, const struct linux_sys_sched_setaffinity_args *uap, register_t *retval)
    690          1.22      manu {
    691          1.46       dsl 	/* {
    692          1.63       chs 		syscallarg(linux_pid_t) pid;
    693          1.22      manu 		syscallarg(unsigned int) len;
    694          1.22      manu 		syscallarg(unsigned long *) mask;
    695          1.46       dsl 	} */
    696  1.66.4.1.4.1     skrll 	struct sys__sched_setaffinity_args ssa;
    697  1.66.4.1.4.1     skrll 	size_t size;
    698          1.22      manu 
    699  1.66.4.1.4.1     skrll 	size = LINUX_CPU_MASK_SIZE;
    700  1.66.4.1.4.1     skrll 	if (SCARG(uap, len) < size)
    701  1.66.4.1.4.1     skrll 		return EINVAL;
    702          1.22      manu 
    703  1.66.4.1.4.1     skrll 	SCARG(&ssa, pid) = SCARG(uap, pid);
    704  1.66.4.1.4.1     skrll 	SCARG(&ssa, lid) = l->l_lid;
    705  1.66.4.1.4.1     skrll 	SCARG(&ssa, size) = size;
    706  1.66.4.1.4.1     skrll 	SCARG(&ssa, cpuset) = (cpuset_t *)SCARG(uap, mask);
    707  1.66.4.1.4.1     skrll 
    708  1.66.4.1.4.1     skrll 	return sys__sched_setaffinity(l, &ssa, retval);
    709          1.64       dsl }
    710