The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linux/common/linux_sched.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: linux_sched.c,v 1.37.2.2 2009/06/21 11:22:24 bouyer 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.37.2.2 2009/06/21 11:22:24 bouyer 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 #include <sys/kauth.h>
   57 #include <sys/ptrace.h>
   58 
   59 #include <machine/cpu.h>
   60 
   61 #include <compat/linux/common/linux_types.h>
   62 #include <compat/linux/common/linux_signal.h>
   63 #include <compat/linux/common/linux_machdep.h> /* For LINUX_NPTL */
   64 #include <compat/linux/common/linux_emuldata.h>
   65 
   66 #include <compat/linux/linux_syscallargs.h>
   67 
   68 #include <compat/linux/common/linux_sched.h>
   69 
   70 int
   71 linux_sys_clone(l, v, retval)
   72         struct lwp *l;
   73         void *v;
   74         register_t *retval;
   75 {
   76         struct linux_sys_clone_args /* {
   77                 syscallarg(int) flags;
   78                 syscallarg(void *) stack;
   79 #ifdef LINUX_NPTL
   80                 syscallarg(void *) parent_tidptr;
   81                 syscallarg(void *) child_tidptr;
   82 #endif
   83         } */ *uap = v;
   84         int flags, sig;
   85         int error;
   86 #ifdef LINUX_NPTL
   87         struct linux_emuldata *led;
   88 #endif
   89 
   90         /*
   91          * We don't support the Linux CLONE_PID or CLONE_PTRACE flags.
   92          */
   93         if (SCARG(uap, flags) & (LINUX_CLONE_PID|LINUX_CLONE_PTRACE))
   94                 return (EINVAL);
   95 
   96         /*
   97          * Thread group implies shared signals. Shared signals
   98          * imply shared VM. This matches what Linux kernel does.
   99          */
  100         if (SCARG(uap, flags) & LINUX_CLONE_THREAD
  101             && (SCARG(uap, flags) & LINUX_CLONE_SIGHAND) == 0)
  102                 return (EINVAL);
  103         if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND
  104             && (SCARG(uap, flags) & LINUX_CLONE_VM) == 0)
  105                 return (EINVAL);
  106 
  107         flags = 0;
  108 
  109         if (SCARG(uap, flags) & LINUX_CLONE_VM)
  110                 flags |= FORK_SHAREVM;
  111         if (SCARG(uap, flags) & LINUX_CLONE_FS)
  112                 flags |= FORK_SHARECWD;
  113         if (SCARG(uap, flags) & LINUX_CLONE_FILES)
  114                 flags |= FORK_SHAREFILES;
  115         if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND)
  116                 flags |= FORK_SHARESIGS;
  117         if (SCARG(uap, flags) & LINUX_CLONE_VFORK)
  118                 flags |= FORK_PPWAIT;
  119 
  120         sig = SCARG(uap, flags) & LINUX_CLONE_CSIGNAL;
  121         if (sig < 0 || sig >= LINUX__NSIG)
  122                 return (EINVAL);
  123         sig = linux_to_native_signo[sig];
  124 
  125 #ifdef LINUX_NPTL
  126         led = (struct linux_emuldata *)l->l_proc->p_emuldata;
  127 
  128         led->parent_tidptr = SCARG(uap, parent_tidptr);
  129         led->child_tidptr = SCARG(uap, child_tidptr);
  130         led->clone_flags = SCARG(uap, flags);
  131 #endif /* LINUX_NPTL */
  132 
  133         /*
  134          * Note that Linux does not provide a portable way of specifying
  135          * the stack area; the caller must know if the stack grows up
  136          * or down.  So, we pass a stack size of 0, so that the code
  137          * that makes this adjustment is a noop.
  138          */
  139         if ((error = fork1(l, flags, sig, SCARG(uap, stack), 0,
  140             NULL, NULL, retval, NULL)) != 0)
  141                 return error;
  142 
  143         return 0;
  144 }
  145 
  146 int
  147 linux_sys_sched_setparam(struct lwp *cl, void *v, register_t *retval)
  148 {
  149         struct linux_sys_sched_setparam_args /* {
  150                 syscallarg(linux_pid_t) pid;
  151                 syscallarg(const struct linux_sched_param *) sp;
  152         } */ *uap = v;
  153         int error;
  154         struct linux_sched_param lp;
  155         struct proc *p;
  156 
  157 /*
  158  * We only check for valid parameters and return afterwards.
  159  */
  160 
  161         if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
  162                 return EINVAL;
  163 
  164         error = copyin(SCARG(uap, sp), &lp, sizeof(lp));
  165         if (error)
  166                 return error;
  167 
  168         if (SCARG(uap, pid) != 0) {
  169                 kauth_cred_t pc = cl->l_cred;
  170 
  171                 if ((p = pfind(SCARG(uap, pid))) == NULL)
  172                         return ESRCH;
  173                 if (!(cl->l_proc == p ||
  174                       kauth_cred_geteuid(pc) == 0 ||
  175                       kauth_cred_getuid(pc) == kauth_cred_getuid(p->p_cred) ||
  176                       kauth_cred_geteuid(pc) == kauth_cred_getuid(p->p_cred) ||
  177                       kauth_cred_getuid(pc) == kauth_cred_geteuid(p->p_cred) ||
  178                       kauth_cred_geteuid(pc) == kauth_cred_geteuid(p->p_cred)))
  179                         return EPERM;
  180         }
  181 
  182         return 0;
  183 }
  184 
  185 int
  186 linux_sys_sched_getparam(struct lwp *cl, void *v, register_t *retval)
  187 {
  188         struct linux_sys_sched_getparam_args /* {
  189                 syscallarg(linux_pid_t) pid;
  190                 syscallarg(struct linux_sched_param *) sp;
  191         } */ *uap = v;
  192         struct proc *p;
  193         struct linux_sched_param lp;
  194 
  195 /*
  196  * We only check for valid parameters and return a dummy priority afterwards.
  197  */
  198         if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
  199                 return EINVAL;
  200 
  201         if (SCARG(uap, pid) != 0) {
  202                 kauth_cred_t pc = cl->l_cred;
  203 
  204                 if ((p = pfind(SCARG(uap, pid))) == NULL)
  205                         return ESRCH;
  206                 if (!(cl->l_proc == p ||
  207                       kauth_cred_geteuid(pc) == 0 ||
  208                       kauth_cred_getuid(pc) == kauth_cred_getuid(p->p_cred) ||
  209                       kauth_cred_geteuid(pc) == kauth_cred_getuid(p->p_cred) ||
  210                       kauth_cred_getuid(pc) == kauth_cred_geteuid(p->p_cred) ||
  211                       kauth_cred_geteuid(pc) == kauth_cred_geteuid(p->p_cred)))
  212                         return EPERM;
  213         }
  214 
  215         lp.sched_priority = 0;
  216         return copyout(&lp, SCARG(uap, sp), sizeof(lp));
  217 }
  218 
  219 int
  220 linux_sys_sched_setscheduler(struct lwp *cl, void *v,
  221     register_t *retval)
  222 {
  223         struct linux_sys_sched_setscheduler_args /* {
  224                 syscallarg(linux_pid_t) pid;
  225                 syscallarg(int) policy;
  226                 syscallarg(cont struct linux_sched_scheduler *) sp;
  227         } */ *uap = v;
  228         int error;
  229         struct linux_sched_param lp;
  230         struct proc *p;
  231 
  232 /*
  233  * We only check for valid parameters and return afterwards.
  234  */
  235 
  236         if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
  237                 return EINVAL;
  238 
  239         error = copyin(SCARG(uap, sp), &lp, sizeof(lp));
  240         if (error)
  241                 return error;
  242 
  243         if (SCARG(uap, pid) != 0) {
  244                 kauth_cred_t pc = cl->l_cred;
  245 
  246                 if ((p = pfind(SCARG(uap, pid))) == NULL)
  247                         return ESRCH;
  248                 if (!(cl->l_proc == p ||
  249                       kauth_cred_geteuid(pc) == 0 ||
  250                       kauth_cred_getuid(pc) == kauth_cred_getuid(p->p_cred) ||
  251                       kauth_cred_geteuid(pc) == kauth_cred_getuid(p->p_cred) ||
  252                       kauth_cred_getuid(pc) == kauth_cred_geteuid(p->p_cred) ||
  253                       kauth_cred_geteuid(pc) == kauth_cred_geteuid(p->p_cred)))
  254                         return EPERM;
  255         }
  256 
  257         return 0;
  258 /*
  259  * We can't emulate anything put the default scheduling policy.
  260  */
  261         if (SCARG(uap, policy) != LINUX_SCHED_OTHER || lp.sched_priority != 0)
  262                 return EINVAL;
  263 
  264         return 0;
  265 }
  266 
  267 int
  268 linux_sys_sched_getscheduler(cl, v, retval)
  269         struct lwp *cl;
  270         void *v;
  271         register_t *retval;
  272 {
  273         struct linux_sys_sched_getscheduler_args /* {
  274                 syscallarg(linux_pid_t) pid;
  275         } */ *uap = v;
  276         struct proc *p;
  277 
  278         *retval = -1;
  279 /*
  280  * We only check for valid parameters and return afterwards.
  281  */
  282 
  283         if (SCARG(uap, pid) != 0) {
  284                 kauth_cred_t pc = cl->l_cred;
  285 
  286                 if ((p = pfind(SCARG(uap, pid))) == NULL)
  287                         return ESRCH;
  288                 if (!(cl->l_proc == p ||
  289                       kauth_cred_geteuid(pc) == 0 ||
  290                       kauth_cred_getuid(pc) == kauth_cred_getuid(p->p_cred) ||
  291                       kauth_cred_geteuid(pc) == kauth_cred_getuid(p->p_cred) ||
  292                       kauth_cred_getuid(pc) == kauth_cred_geteuid(p->p_cred) ||
  293                       kauth_cred_geteuid(pc) == kauth_cred_geteuid(p->p_cred)))
  294                         return EPERM;
  295         }
  296 
  297 /*
  298  * We can't emulate anything put the default scheduling policy.
  299  */
  300         *retval = LINUX_SCHED_OTHER;
  301         return 0;
  302 }
  303 
  304 int
  305 linux_sys_sched_yield(struct lwp *cl, void *v,
  306     register_t *retval)
  307 {
  308 
  309         yield();
  310         return 0;
  311 }
  312 
  313 int
  314 linux_sys_sched_get_priority_max(struct lwp *cl, void *v,
  315     register_t *retval)
  316 {
  317         struct linux_sys_sched_get_priority_max_args /* {
  318                 syscallarg(int) policy;
  319         } */ *uap = v;
  320 
  321 /*
  322  * We can't emulate anything put the default scheduling policy.
  323  */
  324         if (SCARG(uap, policy) != LINUX_SCHED_OTHER) {
  325                 *retval = -1;
  326                 return EINVAL;
  327         }
  328 
  329         *retval = 0;
  330         return 0;
  331 }
  332 
  333 int
  334 linux_sys_sched_get_priority_min(struct lwp *cl, void *v,
  335     register_t *retval)
  336 {
  337         struct linux_sys_sched_get_priority_min_args /* {
  338                 syscallarg(int) policy;
  339         } */ *uap = v;
  340 
  341 /*
  342  * We can't emulate anything put the default scheduling policy.
  343  */
  344         if (SCARG(uap, policy) != LINUX_SCHED_OTHER) {
  345                 *retval = -1;
  346                 return EINVAL;
  347         }
  348 
  349         *retval = 0;
  350         return 0;
  351 }
  352 
  353 #ifndef __m68k__
  354 /* Present on everything but m68k */
  355 int
  356 linux_sys_exit_group(l, v, retval)
  357         struct lwp *l;
  358         void *v;
  359         register_t *retval;
  360 {
  361 #ifdef LINUX_NPTL
  362         struct linux_sys_exit_group_args /* {
  363                 syscallarg(int) error_code;
  364         } */ *uap = v;
  365         struct proc *p = l->l_proc;
  366         struct linux_emuldata *led = p->p_emuldata;
  367         struct linux_emuldata *e;
  368 
  369         if (led->s->flags & LINUX_LES_USE_NPTL) {
  370 
  371 #ifdef DEBUG_LINUX
  372                 printf("%s:%d, led->s->refs = %d\n", __func__, __LINE__,
  373                     led->s->refs);
  374 #endif
  375 
  376                 /*
  377                  * The calling thread is supposed to kill all threads
  378                  * in the same thread group (i.e. all threads created
  379                  * via clone(2) with CLONE_THREAD flag set).
  380                  *
  381                  * If there is only one thread, things are quite simple
  382                  */
  383                 if (led->s->refs == 1)
  384                         return sys_exit(l, v, retval);
  385 
  386 #ifdef DEBUG_LINUX
  387                 printf("%s:%d\n", __func__, __LINE__);
  388 #endif
  389 
  390                 led->s->flags |= LINUX_LES_INEXITGROUP;
  391                 led->s->xstat = W_EXITCODE(SCARG(uap, error_code), 0);
  392 
  393                 /*
  394                  * Kill all threads in the group. The emulation exit hook takes
  395                  * care of hiding the zombies and reporting the exit code
  396                  * properly.
  397                  */
  398                 LIST_FOREACH(e, &led->s->threads, threads) {
  399                         if (e->proc == p)
  400                                 continue;
  401 
  402 #ifdef DEBUG_LINUX
  403                         printf("%s: kill PID %d\n", __func__, e->proc->p_pid);
  404 #endif
  405                         psignal(e->proc, SIGKILL);
  406                 }
  407 
  408                 /* Now, kill ourselves */
  409                 psignal(p, SIGKILL);
  410                 return 0;
  411 
  412         }
  413 #endif /* LINUX_NPTL */
  414 
  415         return sys_exit(l, v, retval);
  416 }
  417 #endif /* !__m68k__ */
  418 
  419 #ifdef LINUX_NPTL
  420 int
  421 linux_sys_set_tid_address(l, v, retval)
  422         struct lwp *l;
  423         void *v;
  424         register_t *retval;
  425 {
  426         struct linux_sys_set_tid_address_args /* {
  427                 syscallarg(int *) tidptr;
  428         } */ *uap = v;
  429         struct linux_emuldata *led;
  430 
  431         led = (struct linux_emuldata *)l->l_proc->p_emuldata;
  432         led->clear_tid = SCARG(uap, tid);
  433 
  434         led->s->flags |= LINUX_LES_USE_NPTL;
  435 
  436         *retval = l->l_proc->p_pid;
  437 
  438         return 0;
  439 }
  440 
  441 /* ARGUSED1 */
  442 int
  443 linux_sys_gettid(l, v, retval)
  444         struct lwp *l;
  445         void *v;
  446         register_t *retval;
  447 {
  448         /* The Linux kernel does it exactly that way */
  449         *retval = l->l_proc->p_pid;
  450         return 0;
  451 }
  452 
  453 #ifdef LINUX_NPTL
  454 /* ARGUSED1 */
  455 int
  456 linux_sys_getpid(l, v, retval)
  457         struct lwp *l;
  458         void *v;
  459         register_t *retval;
  460 {
  461         struct linux_emuldata *led = l->l_proc->p_emuldata;
  462 
  463         if (led->s->flags & LINUX_LES_USE_NPTL) {
  464                 /* The Linux kernel does it exactly that way */
  465                 *retval = led->s->group_pid;
  466         } else {
  467                 *retval = l->l_proc->p_pid;
  468         }
  469 
  470         return 0;
  471 }
  472 
  473 /* ARGUSED1 */
  474 int
  475 linux_sys_getppid(l, v, retval)
  476         struct lwp *l;
  477         void *v;
  478         register_t *retval;
  479 {
  480         struct proc *p = l->l_proc;
  481         struct linux_emuldata *led = p->p_emuldata;
  482         struct proc *glp;
  483         struct proc *pp;
  484 
  485         if (led->s->flags & LINUX_LES_USE_NPTL) {
  486 
  487                 /* Find the thread group leader's parent */
  488                 if ((glp = pfind(led->s->group_pid)) == NULL) {
  489                         /* Maybe panic... */
  490                         printf("linux_sys_getppid: missing group leader PID"
  491                             " %d\n", led->s->group_pid); 
  492                         return -1;
  493                 }
  494                 pp = glp->p_pptr;
  495 
  496                 /* If this is a Linux process too, return thread group PID */
  497                 if (pp->p_emul == p->p_emul) {
  498                         struct linux_emuldata *pled;
  499 
  500                         pled = pp->p_emuldata;
  501                         *retval = pled->s->group_pid;
  502                 } else {
  503                         *retval = pp->p_pid;
  504                 }
  505 
  506         } else {
  507                 *retval = p->p_pptr->p_pid;
  508         }
  509 
  510         return 0;
  511 }
  512 #endif /* LINUX_NPTL */
  513 
  514 int
  515 linux_sys_sched_getaffinity(l, v, retval)
  516         struct lwp *l;
  517         void *v;
  518         register_t *retval;
  519 {
  520         struct linux_sys_sched_getaffinity_args /* {
  521                 syscallarg(pid_t) pid;
  522                 syscallarg(unsigned int) len;
  523                 syscallarg(unsigned long *) mask;
  524         } */ *uap = v;
  525         int error;
  526         int ret;
  527         int ncpu;
  528         int name[2];
  529         size_t sz;
  530         char *data;
  531         int *retp;
  532 
  533         if (SCARG(uap, mask) == NULL)
  534                 return EINVAL;
  535 
  536         if (SCARG(uap, len) < sizeof(int))
  537                 return EINVAL;
  538 
  539         if (pfind(SCARG(uap, pid)) == NULL)
  540                 return ESRCH;
  541 
  542         /* 
  543          * return the actual number of CPU, tag all of them as available 
  544          * The result is a mask, the first CPU being in the least significant
  545          * bit.
  546          */
  547         name[0] = CTL_HW;
  548         name[1] = HW_NCPU;
  549         sz = sizeof(ncpu);
  550 
  551         if ((error = old_sysctl(&name[0], 2, &ncpu, &sz, NULL, 0, NULL)) != 0)
  552                 return error;
  553 
  554         ret = (1 << ncpu) - 1;
  555 
  556         data = malloc(SCARG(uap, len), M_TEMP, M_WAITOK|M_ZERO);
  557         retp = (int *)&data[SCARG(uap, len) - sizeof(ret)];
  558         *retp = ret;
  559 
  560         error = copyout(data, SCARG(uap, mask), SCARG(uap, len));
  561 
  562         free(data, M_TEMP);
  563 
  564         return error;
  565 
  566 }
  567 
  568 int
  569 linux_sys_sched_setaffinity(l, v, retval)
  570         struct lwp *l;
  571         void *v;
  572         register_t *retval;
  573 {
  574         struct linux_sys_sched_setaffinity_args /* {
  575                 syscallarg(pid_t) pid;
  576                 syscallarg(unsigned int) len;
  577                 syscallarg(unsigned long *) mask;
  578         } */ *uap = v;
  579 
  580         if (pfind(SCARG(uap, pid)) == NULL)
  581                 return ESRCH;
  582 
  583         /* Let's ignore it */
  584 #ifdef DEBUG_LINUX
  585         printf("linux_sys_sched_setaffinity\n");
  586 #endif
  587         return 0;
  588 };
  589 #endif /* LINUX_NPTL */

Cache object: afca633995e6157ed36bc838e30a6540


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.