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/linux_fork.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 /*-
    2  * Copyright (c) 2004 Tim J. Robbins
    3  * Copyright (c) 2002 Doug Rabson
    4  * Copyright (c) 2000 Marcel Moolenaar
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer
   12  *    in this position and unchanged.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/11.0/sys/compat/linux/linux_fork.c 301961 2016-06-16 12:05:44Z kib $");
   31 
   32 #include "opt_compat.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/imgact.h>
   37 #include <sys/ktr.h>
   38 #include <sys/lock.h>
   39 #include <sys/mutex.h>
   40 #include <sys/proc.h>
   41 #include <sys/racct.h>
   42 #include <sys/sched.h>
   43 #include <sys/syscallsubr.h>
   44 #include <sys/sx.h>
   45 #include <sys/umtx.h>
   46 #include <sys/unistd.h>
   47 #include <sys/wait.h>
   48 
   49 #include <vm/vm.h>
   50 #include <vm/pmap.h>
   51 #include <vm/vm_map.h>
   52 
   53 #ifdef COMPAT_LINUX32
   54 #include <machine/../linux32/linux.h>
   55 #include <machine/../linux32/linux32_proto.h>
   56 #else
   57 #include <machine/../linux/linux.h>
   58 #include <machine/../linux/linux_proto.h>
   59 #endif
   60 #include <compat/linux/linux_emul.h>
   61 #include <compat/linux/linux_futex.h>
   62 #include <compat/linux/linux_misc.h>
   63 #include <compat/linux/linux_util.h>
   64 
   65 int
   66 linux_fork(struct thread *td, struct linux_fork_args *args)
   67 {
   68         struct fork_req fr;
   69         int error;
   70         struct proc *p2;
   71         struct thread *td2;
   72 
   73 #ifdef DEBUG
   74         if (ldebug(fork))
   75                 printf(ARGS(fork, ""));
   76 #endif
   77 
   78         bzero(&fr, sizeof(fr));
   79         fr.fr_flags = RFFDG | RFPROC | RFSTOPPED;
   80         fr.fr_procp = &p2;
   81         if ((error = fork1(td, &fr)) != 0)
   82                 return (error);
   83 
   84         td2 = FIRST_THREAD_IN_PROC(p2);
   85 
   86         linux_proc_init(td, td2, 0);
   87 
   88         td->td_retval[0] = p2->p_pid;
   89 
   90         /*
   91          * Make this runnable after we are finished with it.
   92          */
   93         thread_lock(td2);
   94         TD_SET_CAN_RUN(td2);
   95         sched_add(td2, SRQ_BORING);
   96         thread_unlock(td2);
   97 
   98         return (0);
   99 }
  100 
  101 int
  102 linux_vfork(struct thread *td, struct linux_vfork_args *args)
  103 {
  104         struct fork_req fr;
  105         int error;
  106         struct proc *p2;
  107         struct thread *td2;
  108 
  109 #ifdef DEBUG
  110         if (ldebug(vfork))
  111                 printf(ARGS(vfork, ""));
  112 #endif
  113 
  114         bzero(&fr, sizeof(fr));
  115         fr.fr_flags = RFFDG | RFPROC | RFMEM | RFPPWAIT | RFSTOPPED;
  116         fr.fr_procp = &p2;
  117         if ((error = fork1(td, &fr)) != 0)
  118                 return (error);
  119 
  120         td2 = FIRST_THREAD_IN_PROC(p2);
  121 
  122         linux_proc_init(td, td2, 0);
  123 
  124         td->td_retval[0] = p2->p_pid;
  125 
  126         /*
  127          * Make this runnable after we are finished with it.
  128          */
  129         thread_lock(td2);
  130         TD_SET_CAN_RUN(td2);
  131         sched_add(td2, SRQ_BORING);
  132         thread_unlock(td2);
  133 
  134         return (0);
  135 }
  136 
  137 static int
  138 linux_clone_proc(struct thread *td, struct linux_clone_args *args)
  139 {
  140         struct fork_req fr;
  141         int error, ff = RFPROC | RFSTOPPED;
  142         struct proc *p2;
  143         struct thread *td2;
  144         int exit_signal;
  145         struct linux_emuldata *em;
  146 
  147 #ifdef DEBUG
  148         if (ldebug(clone)) {
  149                 printf(ARGS(clone, "flags %x, stack %p, parent tid: %p, "
  150                     "child tid: %p"), (unsigned)args->flags,
  151                     args->stack, args->parent_tidptr, args->child_tidptr);
  152         }
  153 #endif
  154 
  155         exit_signal = args->flags & 0x000000ff;
  156         if (LINUX_SIG_VALID(exit_signal)) {
  157                 exit_signal = linux_to_bsd_signal(exit_signal);
  158         } else if (exit_signal != 0)
  159                 return (EINVAL);
  160 
  161         if (args->flags & LINUX_CLONE_VM)
  162                 ff |= RFMEM;
  163         if (args->flags & LINUX_CLONE_SIGHAND)
  164                 ff |= RFSIGSHARE;
  165         /*
  166          * XXX: In Linux, sharing of fs info (chroot/cwd/umask)
  167          * and open files is independent.  In FreeBSD, its in one
  168          * structure but in reality it does not cause any problems
  169          * because both of these flags are usually set together.
  170          */
  171         if (!(args->flags & (LINUX_CLONE_FILES | LINUX_CLONE_FS)))
  172                 ff |= RFFDG;
  173 
  174         if (args->flags & LINUX_CLONE_PARENT_SETTID)
  175                 if (args->parent_tidptr == NULL)
  176                         return (EINVAL);
  177 
  178         if (args->flags & LINUX_CLONE_VFORK)
  179                 ff |= RFPPWAIT;
  180 
  181         bzero(&fr, sizeof(fr));
  182         fr.fr_flags = ff;
  183         fr.fr_procp = &p2;
  184         error = fork1(td, &fr);
  185         if (error)
  186                 return (error);
  187 
  188         td2 = FIRST_THREAD_IN_PROC(p2);
  189 
  190         /* create the emuldata */
  191         linux_proc_init(td, td2, args->flags);
  192 
  193         em = em_find(td2);
  194         KASSERT(em != NULL, ("clone_proc: emuldata not found.\n"));
  195 
  196         if (args->flags & LINUX_CLONE_CHILD_SETTID)
  197                 em->child_set_tid = args->child_tidptr;
  198         else
  199                 em->child_set_tid = NULL;
  200 
  201         if (args->flags & LINUX_CLONE_CHILD_CLEARTID)
  202                 em->child_clear_tid = args->child_tidptr;
  203         else
  204                 em->child_clear_tid = NULL;
  205 
  206         if (args->flags & LINUX_CLONE_PARENT_SETTID) {
  207                 error = copyout(&p2->p_pid, args->parent_tidptr,
  208                     sizeof(p2->p_pid));
  209                 if (error)
  210                         printf(LMSG("copyout failed!"));
  211         }
  212 
  213         PROC_LOCK(p2);
  214         p2->p_sigparent = exit_signal;
  215         PROC_UNLOCK(p2);
  216         /*
  217          * In a case of stack = NULL, we are supposed to COW calling process
  218          * stack. This is what normal fork() does, so we just keep tf_rsp arg
  219          * intact.
  220          */
  221         linux_set_upcall_kse(td2, PTROUT(args->stack));
  222 
  223         if (args->flags & LINUX_CLONE_SETTLS)
  224                 linux_set_cloned_tls(td2, args->tls);
  225 
  226         /*
  227          * If CLONE_PARENT is set, then the parent of the new process will be 
  228          * the same as that of the calling process.
  229          */
  230         if (args->flags & LINUX_CLONE_PARENT) {
  231                 sx_xlock(&proctree_lock);
  232                 PROC_LOCK(p2);
  233                 proc_reparent(p2, td->td_proc->p_pptr);
  234                 PROC_UNLOCK(p2);
  235                 sx_xunlock(&proctree_lock);
  236         }
  237 
  238 #ifdef DEBUG
  239         if (ldebug(clone))
  240                 printf(LMSG("clone: successful rfork to %d, "
  241                     "stack %p sig = %d"), (int)p2->p_pid, args->stack,
  242                     exit_signal);
  243 #endif
  244 
  245         /*
  246          * Make this runnable after we are finished with it.
  247          */
  248         thread_lock(td2);
  249         TD_SET_CAN_RUN(td2);
  250         sched_add(td2, SRQ_BORING);
  251         thread_unlock(td2);
  252 
  253         td->td_retval[0] = p2->p_pid;
  254 
  255         return (0);
  256 }
  257 
  258 static int
  259 linux_clone_thread(struct thread *td, struct linux_clone_args *args)
  260 {
  261         struct linux_emuldata *em;
  262         struct thread *newtd;
  263         struct proc *p;
  264         int error;
  265 
  266 #ifdef DEBUG
  267         if (ldebug(clone)) {
  268                 printf(ARGS(clone, "thread: flags %x, stack %p, parent tid: %p, "
  269                     "child tid: %p"), (unsigned)args->flags,
  270                     args->stack, args->parent_tidptr, args->child_tidptr);
  271         }
  272 #endif
  273 
  274         LINUX_CTR4(clone_thread, "thread(%d) flags %x ptid %p ctid %p",
  275             td->td_tid, (unsigned)args->flags,
  276             args->parent_tidptr, args->child_tidptr);
  277 
  278         if (args->flags & LINUX_CLONE_PARENT_SETTID)
  279                 if (args->parent_tidptr == NULL)
  280                         return (EINVAL);
  281 
  282         /* Threads should be created with own stack */
  283         if (args->stack == NULL)
  284                 return (EINVAL);
  285 
  286         p = td->td_proc;
  287 
  288 #ifdef RACCT
  289         if (racct_enable) {
  290                 PROC_LOCK(p);
  291                 error = racct_add(p, RACCT_NTHR, 1);
  292                 PROC_UNLOCK(p);
  293                 if (error != 0)
  294                         return (EPROCLIM);
  295         }
  296 #endif
  297 
  298         /* Initialize our td */
  299         error = kern_thr_alloc(p, 0, &newtd);
  300         if (error)
  301                 goto fail;
  302 
  303         cpu_copy_thread(newtd, td);
  304 
  305         bzero(&newtd->td_startzero,
  306             __rangeof(struct thread, td_startzero, td_endzero));
  307         bcopy(&td->td_startcopy, &newtd->td_startcopy,
  308             __rangeof(struct thread, td_startcopy, td_endcopy));
  309 
  310         newtd->td_proc = p;
  311         thread_cow_get(newtd, td);
  312 
  313         /* create the emuldata */
  314         linux_proc_init(td, newtd, args->flags);
  315 
  316         em = em_find(newtd);
  317         KASSERT(em != NULL, ("clone_thread: emuldata not found.\n"));
  318 
  319         if (args->flags & LINUX_CLONE_SETTLS)
  320                 linux_set_cloned_tls(newtd, args->tls);
  321 
  322         if (args->flags & LINUX_CLONE_CHILD_SETTID)
  323                 em->child_set_tid = args->child_tidptr;
  324         else
  325                 em->child_set_tid = NULL;
  326 
  327         if (args->flags & LINUX_CLONE_CHILD_CLEARTID)
  328                 em->child_clear_tid = args->child_tidptr;
  329         else
  330                 em->child_clear_tid = NULL;
  331 
  332         cpu_thread_clean(newtd);
  333         
  334         linux_set_upcall_kse(newtd, PTROUT(args->stack));
  335 
  336         PROC_LOCK(p);
  337         p->p_flag |= P_HADTHREADS;
  338         bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name));
  339 
  340         if (args->flags & LINUX_CLONE_PARENT)
  341                 thread_link(newtd, p->p_pptr);
  342         else
  343                 thread_link(newtd, p);
  344 
  345         thread_lock(td);
  346         /* let the scheduler know about these things. */
  347         sched_fork_thread(td, newtd);
  348         thread_unlock(td);
  349         if (P_SHOULDSTOP(p))
  350                 newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
  351         PROC_UNLOCK(p);
  352 
  353         tidhash_add(newtd);
  354 
  355 #ifdef DEBUG
  356         if (ldebug(clone))
  357                 printf(ARGS(clone, "successful clone to %d, stack %p"),
  358                 (int)newtd->td_tid, args->stack);
  359 #endif
  360 
  361         LINUX_CTR2(clone_thread, "thread(%d) successful clone to %d",
  362             td->td_tid, newtd->td_tid);
  363 
  364         if (args->flags & LINUX_CLONE_PARENT_SETTID) {
  365                 error = copyout(&newtd->td_tid, args->parent_tidptr,
  366                     sizeof(newtd->td_tid));
  367                 if (error)
  368                         printf(LMSG("clone_thread: copyout failed!"));
  369         }
  370 
  371         /*
  372          * Make this runnable after we are finished with it.
  373          */
  374         thread_lock(newtd);
  375         TD_SET_CAN_RUN(newtd);
  376         sched_add(newtd, SRQ_BORING);
  377         thread_unlock(newtd);
  378 
  379         td->td_retval[0] = newtd->td_tid;
  380 
  381         return (0);
  382 
  383 fail:
  384 #ifdef RACCT
  385         if (racct_enable) {
  386                 PROC_LOCK(p);
  387                 racct_sub(p, RACCT_NTHR, 1);
  388                 PROC_UNLOCK(p);
  389         }
  390 #endif
  391         return (error);
  392 }
  393 
  394 int
  395 linux_clone(struct thread *td, struct linux_clone_args *args)
  396 {
  397 
  398         if (args->flags & LINUX_CLONE_THREAD)
  399                 return (linux_clone_thread(td, args));
  400         else
  401                 return (linux_clone_proc(td, args));
  402 }
  403 
  404 int
  405 linux_exit(struct thread *td, struct linux_exit_args *args)
  406 {
  407         struct linux_emuldata *em;
  408 
  409         em = em_find(td);
  410         KASSERT(em != NULL, ("exit: emuldata not found.\n"));
  411 
  412         LINUX_CTR2(exit, "thread(%d) (%d)", em->em_tid, args->rval);
  413 
  414         umtx_thread_exit(td);
  415 
  416         linux_thread_detach(td);
  417 
  418         /*
  419          * XXX. When the last two threads of a process
  420          * exit via pthread_exit() try thr_exit() first.
  421          */
  422         kern_thr_exit(td);
  423         exit1(td, args->rval, 0);
  424                 /* NOTREACHED */
  425 }
  426 
  427 int
  428 linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args)
  429 {
  430         struct linux_emuldata *em;
  431 
  432         em = em_find(td);
  433         KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n"));
  434 
  435         em->child_clear_tid = args->tidptr;
  436 
  437         td->td_retval[0] = em->em_tid;
  438 
  439         LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d",
  440             em->em_tid, args->tidptr, td->td_retval[0]);
  441 
  442         return (0);
  443 }
  444 
  445 void
  446 linux_thread_detach(struct thread *td)
  447 {
  448         struct linux_sys_futex_args cup;
  449         struct linux_emuldata *em;
  450         int *child_clear_tid;
  451         int error;
  452 
  453         em = em_find(td);
  454         KASSERT(em != NULL, ("thread_detach: emuldata not found.\n"));
  455 
  456         LINUX_CTR1(thread_detach, "thread(%d)", em->em_tid);
  457 
  458         release_futexes(td, em);
  459 
  460         child_clear_tid = em->child_clear_tid;
  461 
  462         if (child_clear_tid != NULL) {
  463 
  464                 LINUX_CTR2(thread_detach, "thread(%d) %p",
  465                     em->em_tid, child_clear_tid);
  466         
  467                 error = suword32(child_clear_tid, 0);
  468                 if (error != 0)
  469                         return;
  470 
  471                 cup.uaddr = child_clear_tid;
  472                 cup.op = LINUX_FUTEX_WAKE;
  473                 cup.val = 1;            /* wake one */
  474                 cup.timeout = NULL;
  475                 cup.uaddr2 = NULL;
  476                 cup.val3 = 0;
  477                 error = linux_sys_futex(td, &cup);
  478                 /*
  479                  * this cannot happen at the moment and if this happens it
  480                  * probably means there is a user space bug
  481                  */
  482                 if (error != 0)
  483                         linux_msg(td, "futex stuff in thread_detach failed.");
  484         }
  485 }

Cache object: 62b803286e9d13cc7ce6d87b42677bf3


[ 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.