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/8.3/sys/compat/linux/linux_fork.c 219205 2011-03-02 20:08:52Z dchagin $");
   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/lock.h>
   38 #include <sys/mutex.h>
   39 #include <sys/proc.h>
   40 #include <sys/sched.h>
   41 #include <sys/sx.h>
   42 #include <sys/unistd.h>
   43 
   44 #ifdef COMPAT_LINUX32
   45 #include <machine/../linux32/linux.h>
   46 #include <machine/../linux32/linux32_proto.h>
   47 #else
   48 #include <machine/../linux/linux.h>
   49 #include <machine/../linux/linux_proto.h>
   50 #endif
   51 #include <compat/linux/linux_signal.h>
   52 #include <compat/linux/linux_emul.h>
   53 
   54 
   55 int
   56 linux_fork(struct thread *td, struct linux_fork_args *args)
   57 {
   58         int error;
   59         struct proc *p2;
   60         struct thread *td2;
   61 
   62 #ifdef DEBUG
   63         if (ldebug(fork))
   64                 printf(ARGS(fork, ""));
   65 #endif
   66 
   67         if ((error = fork1(td, RFFDG | RFPROC | RFSTOPPED, 0, &p2)) != 0)
   68                 return (error);
   69 
   70         td->td_retval[0] = p2->p_pid;
   71         td->td_retval[1] = 0;
   72 
   73         error = linux_proc_init(td, td->td_retval[0], 0);
   74         if (error)
   75                 return (error);
   76 
   77         td2 = FIRST_THREAD_IN_PROC(p2);
   78 
   79         /*
   80          * Make this runnable after we are finished with it.
   81          */
   82         thread_lock(td2);
   83         TD_SET_CAN_RUN(td2);
   84         sched_add(td2, SRQ_BORING);
   85         thread_unlock(td2);
   86 
   87         return (0);
   88 }
   89 
   90 int
   91 linux_vfork(struct thread *td, struct linux_vfork_args *args)
   92 {
   93         int error;
   94         struct proc *p2;
   95         struct thread *td2;
   96 
   97 #ifdef DEBUG
   98         if (ldebug(vfork))
   99                 printf(ARGS(vfork, ""));
  100 #endif
  101 
  102         /* Exclude RFPPWAIT */
  103         if ((error = fork1(td, RFFDG | RFPROC | RFMEM | RFSTOPPED, 0, &p2)) != 0)
  104                 return (error);
  105 
  106         td->td_retval[0] = p2->p_pid;
  107 
  108         error = linux_proc_init(td, td->td_retval[0], 0);
  109         if (error)
  110                 return (error);
  111 
  112         PROC_LOCK(p2);
  113         p2->p_flag |= P_PPWAIT;
  114         PROC_UNLOCK(p2);
  115 
  116         td2 = FIRST_THREAD_IN_PROC(p2);
  117 
  118         /*
  119          * Make this runnable after we are finished with it.
  120          */
  121         thread_lock(td2);
  122         TD_SET_CAN_RUN(td2);
  123         sched_add(td2, SRQ_BORING);
  124         thread_unlock(td2);
  125 
  126         /* wait for the children to exit, ie. emulate vfork */
  127         PROC_LOCK(p2);
  128         while (p2->p_flag & P_PPWAIT)
  129                 cv_wait(&p2->p_pwait, &p2->p_mtx);
  130         PROC_UNLOCK(p2);
  131 
  132         return (0);
  133 }
  134 
  135 int
  136 linux_clone(struct thread *td, struct linux_clone_args *args)
  137 {
  138         int error, ff = RFPROC | RFSTOPPED;
  139         struct proc *p2;
  140         struct thread *td2;
  141         int exit_signal;
  142         struct linux_emuldata *em;
  143 
  144 #ifdef DEBUG
  145         if (ldebug(clone)) {
  146                 printf(ARGS(clone, "flags %x, stack %p, parent tid: %p, "
  147                     "child tid: %p"), (unsigned)args->flags,
  148                     args->stack, args->parent_tidptr, args->child_tidptr);
  149         }
  150 #endif
  151 
  152         exit_signal = args->flags & 0x000000ff;
  153         if (LINUX_SIG_VALID(exit_signal)) {
  154                 if (exit_signal <= LINUX_SIGTBLSZ)
  155                         exit_signal =
  156                             linux_to_bsd_signal[_SIG_IDX(exit_signal)];
  157         } else if (exit_signal != 0)
  158                 return (EINVAL);
  159 
  160         if (args->flags & LINUX_CLONE_VM)
  161                 ff |= RFMEM;
  162         if (args->flags & LINUX_CLONE_SIGHAND)
  163                 ff |= RFSIGSHARE;
  164         /*
  165          * XXX: In Linux, sharing of fs info (chroot/cwd/umask)
  166          * and open files is independant.  In FreeBSD, its in one
  167          * structure but in reality it does not cause any problems
  168          * because both of these flags are usually set together.
  169          */
  170         if (!(args->flags & (LINUX_CLONE_FILES | LINUX_CLONE_FS)))
  171                 ff |= RFFDG;
  172 
  173         /*
  174          * Attempt to detect when linux_clone(2) is used for creating
  175          * kernel threads. Unfortunately despite the existence of the
  176          * CLONE_THREAD flag, version of linuxthreads package used in
  177          * most popular distros as of beginning of 2005 doesn't make
  178          * any use of it. Therefore, this detection relies on
  179          * empirical observation that linuxthreads sets certain
  180          * combination of flags, so that we can make more or less
  181          * precise detection and notify the FreeBSD kernel that several
  182          * processes are in fact part of the same threading group, so
  183          * that special treatment is necessary for signal delivery
  184          * between those processes and fd locking.
  185          */
  186         if ((args->flags & 0xffffff00) == LINUX_THREADING_FLAGS)
  187                 ff |= RFTHREAD;
  188 
  189         if (args->flags & LINUX_CLONE_PARENT_SETTID)
  190                 if (args->parent_tidptr == NULL)
  191                         return (EINVAL);
  192 
  193         error = fork1(td, ff, 0, &p2);
  194         if (error)
  195                 return (error);
  196 
  197         if (args->flags & (LINUX_CLONE_PARENT | LINUX_CLONE_THREAD)) {
  198                 sx_xlock(&proctree_lock);
  199                 PROC_LOCK(p2);
  200                 proc_reparent(p2, td->td_proc->p_pptr);
  201                 PROC_UNLOCK(p2);
  202                 sx_xunlock(&proctree_lock);
  203         }
  204 
  205         /* create the emuldata */
  206         error = linux_proc_init(td, p2->p_pid, args->flags);
  207         /* reference it - no need to check this */
  208         em = em_find(p2, EMUL_DOLOCK);
  209         KASSERT(em != NULL, ("clone: emuldata not found."));
  210         /* and adjust it */
  211 
  212         if (args->flags & LINUX_CLONE_THREAD) {
  213 #ifdef notyet
  214                 PROC_LOCK(p2);
  215                 p2->p_pgrp = td->td_proc->p_pgrp;
  216                 PROC_UNLOCK(p2);
  217 #endif
  218                 exit_signal = 0;
  219         }
  220 
  221         if (args->flags & LINUX_CLONE_CHILD_SETTID)
  222                 em->child_set_tid = args->child_tidptr;
  223         else
  224                 em->child_set_tid = NULL;
  225 
  226         if (args->flags & LINUX_CLONE_CHILD_CLEARTID)
  227                 em->child_clear_tid = args->child_tidptr;
  228         else
  229                 em->child_clear_tid = NULL;
  230 
  231         EMUL_UNLOCK(&emul_lock);
  232 
  233         if (args->flags & LINUX_CLONE_PARENT_SETTID) {
  234                 error = copyout(&p2->p_pid, args->parent_tidptr,
  235                     sizeof(p2->p_pid));
  236                 if (error)
  237                         printf(LMSG("copyout failed!"));
  238         }
  239 
  240         PROC_LOCK(p2);
  241         p2->p_sigparent = exit_signal;
  242         PROC_UNLOCK(p2);
  243         td2 = FIRST_THREAD_IN_PROC(p2);
  244         /*
  245          * In a case of stack = NULL, we are supposed to COW calling process
  246          * stack. This is what normal fork() does, so we just keep tf_rsp arg
  247          * intact.
  248          */
  249         if (args->stack)
  250                 linux_set_upcall_kse(td2, PTROUT(args->stack));
  251 
  252         if (args->flags & LINUX_CLONE_SETTLS)
  253                 linux_set_cloned_tls(td2, args->tls);
  254 
  255 #ifdef DEBUG
  256         if (ldebug(clone))
  257                 printf(LMSG("clone: successful rfork to %d, "
  258                     "stack %p sig = %d"), (int)p2->p_pid, args->stack,
  259                     exit_signal);
  260 #endif
  261         if (args->flags & LINUX_CLONE_VFORK) {
  262                 PROC_LOCK(p2);
  263                 p2->p_flag |= P_PPWAIT;
  264                 PROC_UNLOCK(p2);
  265         }
  266 
  267         /*
  268          * Make this runnable after we are finished with it.
  269          */
  270         thread_lock(td2);
  271         TD_SET_CAN_RUN(td2);
  272         sched_add(td2, SRQ_BORING);
  273         thread_unlock(td2);
  274 
  275         td->td_retval[0] = p2->p_pid;
  276         td->td_retval[1] = 0;
  277 
  278         if (args->flags & LINUX_CLONE_VFORK) {
  279                 /* wait for the children to exit, ie. emulate vfork */
  280                 PROC_LOCK(p2);
  281                 while (p2->p_flag & P_PPWAIT)
  282                         cv_wait(&p2->p_pwait, &p2->p_mtx);
  283                 PROC_UNLOCK(p2);
  284         }
  285 
  286         return (0);
  287 }

Cache object: 3c4aad7d1ad2fa7b13f0deaf130ff1df


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