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/emulation/linux/linux_emuldata.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) 2010 The DragonFly Project.  All rights reserved.
    3  *
    4  * This code is derived from software contributed to The DragonFly Project
    5  * by Alex Hornung <ahornung@gmail.com>
    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  *
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in
   15  *    the documentation and/or other materials provided with the
   16  *    distribution.
   17  * 3. Neither the name of The DragonFly Project nor the names of its
   18  *    contributors may be used to endorse or promote products derived
   19  *    from this software without specific, prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
   25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  */
   34 
   35 #include "opt_compat.h"
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/imgact.h>
   40 #include <sys/imgact_aout.h>
   41 #include <sys/imgact_elf.h>
   42 #include <sys/kern_syscall.h>
   43 #include <sys/lock.h>
   44 #include <sys/mplock2.h>
   45 #include <sys/malloc.h>
   46 #include <sys/ptrace.h>
   47 #include <sys/proc.h>
   48 #include <sys/signalvar.h>
   49 #include <sys/sysent.h>
   50 #include <sys/sysproto.h>
   51 
   52 #include <vm/vm.h>
   53 #include <vm/vm_param.h>
   54 #include <vm/vm_page.h>
   55 #include <vm/vm_extern.h>
   56 #include <sys/exec.h>
   57 #include <sys/kernel.h>
   58 #include <sys/module.h>
   59 #include <machine/cpu.h>
   60 
   61 #include "i386/linux.h"
   62 #include "i386/linux_proto.h"
   63 #include "linux_signal.h"
   64 #include "linux_util.h"
   65 #include "linux_emuldata.h"
   66 
   67 
   68 struct lock emul_lock;
   69 
   70 struct linux_emuldata *
   71 emuldata_get(struct proc *p)
   72 {
   73         struct linux_emuldata *em;
   74 
   75         EMUL_LOCK();
   76 
   77         em = p->p_emuldata;
   78 
   79         EMUL_UNLOCK();
   80         return (em);
   81 }
   82 
   83 void
   84 emuldata_set_robust(struct proc *p, struct linux_robust_list_head *robust_ftx)
   85 {
   86         struct linux_emuldata *em;
   87 
   88         EMUL_LOCK();
   89 
   90         em = emuldata_get(p);
   91         KKASSERT(em != NULL);
   92 
   93         em->robust_futexes = robust_ftx;
   94         EMUL_UNLOCK();
   95 }
   96 
   97 int
   98 emuldata_init(struct proc *p, struct proc *pchild, int flags)
   99 {
  100         struct linux_emuldata_shared *s;
  101         struct linux_emuldata *em, *ep;
  102         int error = 0;
  103 
  104         EMUL_LOCK();
  105 
  106         em = emuldata_get(p);
  107 
  108         if (pchild == NULL) {
  109                 ep = NULL;
  110                 /* This is the execv* case, where a process gets overwritten */
  111                 KKASSERT(em != NULL);
  112                 KKASSERT(em->s != NULL);
  113                 if (atomic_fetchadd_int(&em->s->refs, -1) == 1) {
  114                         kfree(em->s, M_LINUX); 
  115                         em->s = NULL;
  116                 }
  117                 if (em->s)
  118                         KKASSERT(em->s->refs >= 0);
  119                 
  120                 em->parent_tidptr = NULL;
  121                 em->child_tidptr = NULL;
  122                 em->clone_flags = 0;
  123                 em->clear_tid = NULL;
  124                 em->set_tls = NULL;
  125                 em->proc = p;
  126         } else {
  127                 ep = em;
  128                 em = kmalloc(sizeof(*em), M_LINUX, M_WAITOK | M_ZERO);
  129         }
  130 
  131         if (flags & LINUX_CLONE_THREAD) {
  132                 /*
  133                  * If CLONE_THREAD is set, the child is placed in the same
  134                  * thread group as the calling process.
  135                  */
  136                 KKASSERT(ep != NULL);
  137                 em->s = ep->s;
  138                 s = em->s;
  139         } else {
  140                 /* new thread group */
  141                 s = kmalloc(sizeof(*s), M_LINUX, M_WAITOK | M_ZERO);
  142                 LIST_INIT(&s->threads);
  143                 if (pchild)
  144                         s->group_pid = pchild->p_pid;
  145                 else
  146                         s->group_pid = p->p_pid;
  147         }
  148 
  149         if (ep != NULL) {
  150                 em->parent_tidptr = ep->parent_tidptr;
  151                 em->child_tidptr = ep->child_tidptr;
  152 #if 0
  153                 em->clone_flags = ep->clone_flags;
  154 #endif
  155         }
  156 
  157         em->clone_flags = flags;
  158 
  159         atomic_add_int(&s->refs, 1);
  160         KKASSERT(s->refs >= 0);
  161         em->s = s;
  162         LIST_INSERT_HEAD(&s->threads, em, threads);
  163 
  164         
  165         if (pchild != NULL) {
  166                 em->proc = pchild;
  167                 pchild->p_emuldata = em;
  168         }
  169 
  170         EMUL_UNLOCK();
  171         return (error);
  172 }
  173 
  174 /* emuldata_exit is modelled after NetBSD's */
  175 void
  176 emuldata_exit(void *unused, struct proc *p)
  177 {
  178         struct linux_sys_futex_args cup;
  179         struct linux_emuldata *em;
  180         int error = 0;
  181 
  182         if (__predict_true(p->p_sysent != &elf_linux_sysvec))
  183                 return;
  184 
  185         release_futexes(p);
  186         EMUL_LOCK();
  187 
  188         em = emuldata_get(p);
  189         if (em == NULL) {
  190                 EMUL_UNLOCK();
  191                 return;
  192         }
  193 
  194         LIST_REMOVE(em, threads);
  195         p->p_emuldata = NULL;
  196 
  197         /*
  198          * Members of the thread groups others than the leader should
  199          * exit quietely: no zombie stage, no signal. We do that by
  200          * reparenting to init. init will collect us and nobody will
  201          * notice what happened.
  202          */
  203         if ((em->s->group_pid != p->p_pid) &&
  204             (em->clone_flags & LINUX_CLONE_THREAD)) {
  205                 p->p_sigparent = SIGCHLD;
  206 
  207                 proc_reparent(p, initproc);
  208                 wakeup((caddr_t)initproc); /* kern_exit seems to do this */
  209         }
  210 
  211         if ((em->s->group_pid == p->p_pid) &&
  212             (em->s->flags & LINUX_LES_INEXITGROUP)) {
  213                 p->p_xstat = em->s->xstat;
  214         }
  215 
  216         if (atomic_fetchadd_int(&em->s->refs, -1) == 1) {
  217                 kfree(em->s, M_LINUX);
  218                 em->s = NULL;
  219         }
  220         if (em->s)
  221                 KKASSERT(em->s->refs >= 0);
  222 
  223         EMUL_UNLOCK();
  224 
  225         if (em->clear_tid != NULL) {
  226                 int tid = 0;
  227                 copyout(&tid, em->clear_tid, sizeof(tid));
  228                 cup.uaddr = em->clear_tid;
  229                 cup.op = LINUX_FUTEX_WAKE;
  230                 cup.val = 0x7fffffff;   /* Awake everyone */
  231                 cup.timeout = NULL;
  232                 cup.uaddr2 = NULL;
  233                 cup.val3 = 0;
  234                 error = sys_linux_sys_futex(&cup);
  235                 if (error)
  236                         kprintf("emuldata_exit futex stuff failed miserably\n");
  237         }
  238 
  239         kfree(em, M_LINUX);
  240 }
  241 
  242 void
  243 linux_proc_transition(void *unused, struct image_params *imgp)
  244 {
  245         struct proc *p;
  246 
  247         p = imgp->proc;
  248         if (__predict_false(imgp->proc->p_sysent == &elf_linux_sysvec &&
  249             imgp->proc->p_emuldata == NULL)) {
  250 #ifdef LINUX_DEBUG
  251                 kprintf("timidly hello from proc_transition\n");
  252 #endif
  253                 emuldata_init(p, p, 0);
  254         }
  255 }
  256 
  257 static void
  258 linux_proc_userret(void)
  259 {
  260         struct proc *p = curproc;
  261         struct linux_emuldata *em;
  262 
  263         em = emuldata_get(p);
  264         KKASSERT(em != NULL);
  265 
  266         if (em->clone_flags & LINUX_CLONE_CHILD_SETTID) {
  267                 copyout(&p->p_pid, (int *)em->child_tidptr,
  268                     sizeof(p->p_pid));
  269         }
  270 
  271         return;
  272 }
  273 
  274 void
  275 linux_proc_fork(struct proc *p, struct proc *parent, void *child_tidptr)
  276 {
  277         struct linux_emuldata *em;
  278 
  279         em = emuldata_get(p);
  280         KKASSERT(em != NULL);
  281 
  282         if (child_tidptr != NULL)
  283                 em->child_tidptr = child_tidptr;
  284 
  285         /* LINUX_CLONE_CHILD_CLEARTID: clear TID in child's memory on exit() */
  286         if (em->clone_flags & LINUX_CLONE_CHILD_CLEARTID)
  287                 em->clear_tid = em->child_tidptr;
  288 
  289         if (em->clone_flags & LINUX_CLONE_CHILD_SETTID)
  290                 p->p_userret = linux_proc_userret;
  291 
  292         return;
  293 }
  294 
  295 int
  296 sys_linux_set_tid_address(struct linux_set_tid_address_args *args)
  297 {
  298         struct linux_emuldata *em;
  299 
  300         EMUL_LOCK();
  301 
  302         em = emuldata_get(curproc);
  303         KKASSERT(em != NULL);
  304 
  305         em->clear_tid = args->tidptr;
  306         args->sysmsg_iresult = curproc->p_pid;
  307 
  308         EMUL_UNLOCK();
  309         return 0;
  310 }

Cache object: c04ddfc4ec3a17b11e990df8ab8517c4


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