1222198abSDmitry Chagin /*- 2222198abSDmitry Chagin * Copyright (c) 2004 Tim J. Robbins 3222198abSDmitry Chagin * Copyright (c) 2002 Doug Rabson 4222198abSDmitry Chagin * Copyright (c) 2000 Marcel Moolenaar 5222198abSDmitry Chagin * All rights reserved. 6222198abSDmitry Chagin * 7222198abSDmitry Chagin * Redistribution and use in source and binary forms, with or without 8222198abSDmitry Chagin * modification, are permitted provided that the following conditions 9222198abSDmitry Chagin * are met: 10222198abSDmitry Chagin * 1. Redistributions of source code must retain the above copyright 11222198abSDmitry Chagin * notice, this list of conditions and the following disclaimer 12222198abSDmitry Chagin * in this position and unchanged. 13222198abSDmitry Chagin * 2. Redistributions in binary form must reproduce the above copyright 14222198abSDmitry Chagin * notice, this list of conditions and the following disclaimer in the 15222198abSDmitry Chagin * documentation and/or other materials provided with the distribution. 16222198abSDmitry Chagin * 17222198abSDmitry Chagin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18222198abSDmitry Chagin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19222198abSDmitry Chagin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20222198abSDmitry Chagin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21222198abSDmitry Chagin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22222198abSDmitry Chagin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23222198abSDmitry Chagin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24222198abSDmitry Chagin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25222198abSDmitry Chagin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26222198abSDmitry Chagin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27222198abSDmitry Chagin */ 28222198abSDmitry Chagin 29222198abSDmitry Chagin #include <sys/cdefs.h> 30222198abSDmitry Chagin __FBSDID("$FreeBSD$"); 31222198abSDmitry Chagin 32222198abSDmitry Chagin #include "opt_compat.h" 33222198abSDmitry Chagin 34222198abSDmitry Chagin #include <sys/param.h> 35222198abSDmitry Chagin #include <sys/systm.h> 36222198abSDmitry Chagin #include <sys/imgact.h> 3781338031SDmitry Chagin #include <sys/ktr.h> 38222198abSDmitry Chagin #include <sys/lock.h> 39222198abSDmitry Chagin #include <sys/mutex.h> 40222198abSDmitry Chagin #include <sys/proc.h> 4181338031SDmitry Chagin #include <sys/racct.h> 42222198abSDmitry Chagin #include <sys/sched.h> 4381338031SDmitry Chagin #include <sys/syscallsubr.h> 44222198abSDmitry Chagin #include <sys/sx.h> 452a339d9eSKonstantin Belousov #include <sys/umtx.h> 46222198abSDmitry Chagin #include <sys/unistd.h> 47161acbb6SDmitry Chagin #include <sys/wait.h> 48222198abSDmitry Chagin 4981338031SDmitry Chagin #include <vm/vm.h> 5081338031SDmitry Chagin #include <vm/pmap.h> 5181338031SDmitry Chagin #include <vm/vm_map.h> 5281338031SDmitry Chagin 53222198abSDmitry Chagin #ifdef COMPAT_LINUX32 54222198abSDmitry Chagin #include <machine/../linux32/linux.h> 55222198abSDmitry Chagin #include <machine/../linux32/linux32_proto.h> 56222198abSDmitry Chagin #else 57222198abSDmitry Chagin #include <machine/../linux/linux.h> 58222198abSDmitry Chagin #include <machine/../linux/linux_proto.h> 59222198abSDmitry Chagin #endif 60222198abSDmitry Chagin #include <compat/linux/linux_emul.h> 61bc273677SDmitry Chagin #include <compat/linux/linux_futex.h> 62d825ce0aSJohn Baldwin #include <compat/linux/linux_misc.h> 6381338031SDmitry Chagin #include <compat/linux/linux_util.h> 64222198abSDmitry Chagin 65222198abSDmitry Chagin int 66222198abSDmitry Chagin linux_fork(struct thread *td, struct linux_fork_args *args) 67222198abSDmitry Chagin { 6833fd9b9aSMateusz Guzik struct fork_req fr; 69222198abSDmitry Chagin int error; 70222198abSDmitry Chagin struct proc *p2; 71222198abSDmitry Chagin struct thread *td2; 72222198abSDmitry Chagin 73222198abSDmitry Chagin #ifdef DEBUG 74222198abSDmitry Chagin if (ldebug(fork)) 75222198abSDmitry Chagin printf(ARGS(fork, "")); 76222198abSDmitry Chagin #endif 77222198abSDmitry Chagin 7833fd9b9aSMateusz Guzik bzero(&fr, sizeof(fr)); 7933fd9b9aSMateusz Guzik fr.fr_flags = RFFDG | RFPROC | RFSTOPPED; 8033fd9b9aSMateusz Guzik fr.fr_procp = &p2; 8133fd9b9aSMateusz Guzik if ((error = fork1(td, &fr)) != 0) 82222198abSDmitry Chagin return (error); 83222198abSDmitry Chagin 84222198abSDmitry Chagin td2 = FIRST_THREAD_IN_PROC(p2); 85222198abSDmitry Chagin 8681338031SDmitry Chagin linux_proc_init(td, td2, 0); 8781338031SDmitry Chagin 8881338031SDmitry Chagin td->td_retval[0] = p2->p_pid; 8981338031SDmitry Chagin 90222198abSDmitry Chagin /* 91222198abSDmitry Chagin * Make this runnable after we are finished with it. 92222198abSDmitry Chagin */ 93222198abSDmitry Chagin thread_lock(td2); 94222198abSDmitry Chagin TD_SET_CAN_RUN(td2); 95222198abSDmitry Chagin sched_add(td2, SRQ_BORING); 96222198abSDmitry Chagin thread_unlock(td2); 97222198abSDmitry Chagin 98222198abSDmitry Chagin return (0); 99222198abSDmitry Chagin } 100222198abSDmitry Chagin 101222198abSDmitry Chagin int 102222198abSDmitry Chagin linux_vfork(struct thread *td, struct linux_vfork_args *args) 103222198abSDmitry Chagin { 10433fd9b9aSMateusz Guzik struct fork_req fr; 105222198abSDmitry Chagin int error; 106222198abSDmitry Chagin struct proc *p2; 107222198abSDmitry Chagin struct thread *td2; 108222198abSDmitry Chagin 109222198abSDmitry Chagin #ifdef DEBUG 110222198abSDmitry Chagin if (ldebug(vfork)) 111222198abSDmitry Chagin printf(ARGS(vfork, "")); 112222198abSDmitry Chagin #endif 113222198abSDmitry Chagin 11433fd9b9aSMateusz Guzik bzero(&fr, sizeof(fr)); 11533fd9b9aSMateusz Guzik fr.fr_flags = RFFDG | RFPROC | RFMEM | RFPPWAIT | RFSTOPPED; 11633fd9b9aSMateusz Guzik fr.fr_procp = &p2; 11733fd9b9aSMateusz Guzik if ((error = fork1(td, &fr)) != 0) 118222198abSDmitry Chagin return (error); 119cfa57401SDmitry Chagin 12081338031SDmitry Chagin td2 = FIRST_THREAD_IN_PROC(p2); 12181338031SDmitry Chagin 12281338031SDmitry Chagin linux_proc_init(td, td2, 0); 123222198abSDmitry Chagin 12481338031SDmitry Chagin td->td_retval[0] = p2->p_pid; 125222198abSDmitry Chagin 126222198abSDmitry Chagin /* 127222198abSDmitry Chagin * Make this runnable after we are finished with it. 128222198abSDmitry Chagin */ 129222198abSDmitry Chagin thread_lock(td2); 130222198abSDmitry Chagin TD_SET_CAN_RUN(td2); 131222198abSDmitry Chagin sched_add(td2, SRQ_BORING); 132222198abSDmitry Chagin thread_unlock(td2); 133222198abSDmitry Chagin 134222198abSDmitry Chagin return (0); 135222198abSDmitry Chagin } 136222198abSDmitry Chagin 13781338031SDmitry Chagin static int 13881338031SDmitry Chagin linux_clone_proc(struct thread *td, struct linux_clone_args *args) 139222198abSDmitry Chagin { 14033fd9b9aSMateusz Guzik struct fork_req fr; 141222198abSDmitry Chagin int error, ff = RFPROC | RFSTOPPED; 142222198abSDmitry Chagin struct proc *p2; 143222198abSDmitry Chagin struct thread *td2; 144222198abSDmitry Chagin int exit_signal; 145222198abSDmitry Chagin struct linux_emuldata *em; 146222198abSDmitry Chagin 147222198abSDmitry Chagin #ifdef DEBUG 148222198abSDmitry Chagin if (ldebug(clone)) { 149222198abSDmitry Chagin printf(ARGS(clone, "flags %x, stack %p, parent tid: %p, " 150222198abSDmitry Chagin "child tid: %p"), (unsigned)args->flags, 151222198abSDmitry Chagin args->stack, args->parent_tidptr, args->child_tidptr); 152222198abSDmitry Chagin } 153222198abSDmitry Chagin #endif 154222198abSDmitry Chagin 155222198abSDmitry Chagin exit_signal = args->flags & 0x000000ff; 156222198abSDmitry Chagin if (LINUX_SIG_VALID(exit_signal)) { 1574ab7403bSDmitry Chagin exit_signal = linux_to_bsd_signal(exit_signal); 158222198abSDmitry Chagin } else if (exit_signal != 0) 159222198abSDmitry Chagin return (EINVAL); 160222198abSDmitry Chagin 161222198abSDmitry Chagin if (args->flags & LINUX_CLONE_VM) 162222198abSDmitry Chagin ff |= RFMEM; 163222198abSDmitry Chagin if (args->flags & LINUX_CLONE_SIGHAND) 164222198abSDmitry Chagin ff |= RFSIGSHARE; 165222198abSDmitry Chagin /* 166222198abSDmitry Chagin * XXX: In Linux, sharing of fs info (chroot/cwd/umask) 1671ce4275dSPedro F. Giffuni * and open files is independent. In FreeBSD, its in one 168222198abSDmitry Chagin * structure but in reality it does not cause any problems 169222198abSDmitry Chagin * because both of these flags are usually set together. 170222198abSDmitry Chagin */ 171222198abSDmitry Chagin if (!(args->flags & (LINUX_CLONE_FILES | LINUX_CLONE_FS))) 172222198abSDmitry Chagin ff |= RFFDG; 173222198abSDmitry Chagin 174222198abSDmitry Chagin if (args->flags & LINUX_CLONE_PARENT_SETTID) 175222198abSDmitry Chagin if (args->parent_tidptr == NULL) 176222198abSDmitry Chagin return (EINVAL); 177222198abSDmitry Chagin 178a7306730SBryan Drewery if (args->flags & LINUX_CLONE_VFORK) 179a7306730SBryan Drewery ff |= RFPPWAIT; 180a7306730SBryan Drewery 18133fd9b9aSMateusz Guzik bzero(&fr, sizeof(fr)); 18233fd9b9aSMateusz Guzik fr.fr_flags = ff; 18333fd9b9aSMateusz Guzik fr.fr_procp = &p2; 18433fd9b9aSMateusz Guzik error = fork1(td, &fr); 185222198abSDmitry Chagin if (error) 186222198abSDmitry Chagin return (error); 187222198abSDmitry Chagin 18881338031SDmitry Chagin td2 = FIRST_THREAD_IN_PROC(p2); 189222198abSDmitry Chagin 190222198abSDmitry Chagin /* create the emuldata */ 19181338031SDmitry Chagin linux_proc_init(td, td2, args->flags); 192222198abSDmitry Chagin 19381338031SDmitry Chagin em = em_find(td2); 19481338031SDmitry Chagin KASSERT(em != NULL, ("clone_proc: emuldata not found.\n")); 195222198abSDmitry Chagin 196222198abSDmitry Chagin if (args->flags & LINUX_CLONE_CHILD_SETTID) 197222198abSDmitry Chagin em->child_set_tid = args->child_tidptr; 198222198abSDmitry Chagin else 199222198abSDmitry Chagin em->child_set_tid = NULL; 200222198abSDmitry Chagin 201222198abSDmitry Chagin if (args->flags & LINUX_CLONE_CHILD_CLEARTID) 202222198abSDmitry Chagin em->child_clear_tid = args->child_tidptr; 203222198abSDmitry Chagin else 204222198abSDmitry Chagin em->child_clear_tid = NULL; 205222198abSDmitry Chagin 206222198abSDmitry Chagin if (args->flags & LINUX_CLONE_PARENT_SETTID) { 207222198abSDmitry Chagin error = copyout(&p2->p_pid, args->parent_tidptr, 208222198abSDmitry Chagin sizeof(p2->p_pid)); 209222198abSDmitry Chagin if (error) 210222198abSDmitry Chagin printf(LMSG("copyout failed!")); 211222198abSDmitry Chagin } 212222198abSDmitry Chagin 213222198abSDmitry Chagin PROC_LOCK(p2); 214222198abSDmitry Chagin p2->p_sigparent = exit_signal; 215222198abSDmitry Chagin PROC_UNLOCK(p2); 216222198abSDmitry Chagin /* 217222198abSDmitry Chagin * In a case of stack = NULL, we are supposed to COW calling process 218222198abSDmitry Chagin * stack. This is what normal fork() does, so we just keep tf_rsp arg 219222198abSDmitry Chagin * intact. 220222198abSDmitry Chagin */ 221222198abSDmitry Chagin linux_set_upcall_kse(td2, PTROUT(args->stack)); 222222198abSDmitry Chagin 223222198abSDmitry Chagin if (args->flags & LINUX_CLONE_SETTLS) 224222198abSDmitry Chagin linux_set_cloned_tls(td2, args->tls); 225222198abSDmitry Chagin 2269f4e66afSDmitry Chagin /* 2279f4e66afSDmitry Chagin * If CLONE_PARENT is set, then the parent of the new process will be 2289f4e66afSDmitry Chagin * the same as that of the calling process. 2299f4e66afSDmitry Chagin */ 2309f4e66afSDmitry Chagin if (args->flags & LINUX_CLONE_PARENT) { 2319f4e66afSDmitry Chagin sx_xlock(&proctree_lock); 2329f4e66afSDmitry Chagin PROC_LOCK(p2); 2339f4e66afSDmitry Chagin proc_reparent(p2, td->td_proc->p_pptr); 2349f4e66afSDmitry Chagin PROC_UNLOCK(p2); 2359f4e66afSDmitry Chagin sx_xunlock(&proctree_lock); 2369f4e66afSDmitry Chagin } 2379f4e66afSDmitry Chagin 238222198abSDmitry Chagin #ifdef DEBUG 239222198abSDmitry Chagin if (ldebug(clone)) 240222198abSDmitry Chagin printf(LMSG("clone: successful rfork to %d, " 241222198abSDmitry Chagin "stack %p sig = %d"), (int)p2->p_pid, args->stack, 242222198abSDmitry Chagin exit_signal); 243222198abSDmitry Chagin #endif 24481338031SDmitry Chagin 245222198abSDmitry Chagin /* 246222198abSDmitry Chagin * Make this runnable after we are finished with it. 247222198abSDmitry Chagin */ 248222198abSDmitry Chagin thread_lock(td2); 249222198abSDmitry Chagin TD_SET_CAN_RUN(td2); 250222198abSDmitry Chagin sched_add(td2, SRQ_BORING); 251222198abSDmitry Chagin thread_unlock(td2); 252222198abSDmitry Chagin 253222198abSDmitry Chagin td->td_retval[0] = p2->p_pid; 254222198abSDmitry Chagin 255222198abSDmitry Chagin return (0); 256222198abSDmitry Chagin } 257161acbb6SDmitry Chagin 25881338031SDmitry Chagin static int 25981338031SDmitry Chagin linux_clone_thread(struct thread *td, struct linux_clone_args *args) 26081338031SDmitry Chagin { 26181338031SDmitry Chagin struct linux_emuldata *em; 26281338031SDmitry Chagin struct thread *newtd; 26381338031SDmitry Chagin struct proc *p; 26481338031SDmitry Chagin int error; 26581338031SDmitry Chagin 26681338031SDmitry Chagin #ifdef DEBUG 26781338031SDmitry Chagin if (ldebug(clone)) { 26881338031SDmitry Chagin printf(ARGS(clone, "thread: flags %x, stack %p, parent tid: %p, " 26981338031SDmitry Chagin "child tid: %p"), (unsigned)args->flags, 27081338031SDmitry Chagin args->stack, args->parent_tidptr, args->child_tidptr); 27181338031SDmitry Chagin } 27281338031SDmitry Chagin #endif 27381338031SDmitry Chagin 2747d96520bSDmitry Chagin LINUX_CTR4(clone_thread, "thread(%d) flags %x ptid %p ctid %p", 27581338031SDmitry Chagin td->td_tid, (unsigned)args->flags, 27681338031SDmitry Chagin args->parent_tidptr, args->child_tidptr); 27781338031SDmitry Chagin 27881338031SDmitry Chagin if (args->flags & LINUX_CLONE_PARENT_SETTID) 27981338031SDmitry Chagin if (args->parent_tidptr == NULL) 28081338031SDmitry Chagin return (EINVAL); 28181338031SDmitry Chagin 28281338031SDmitry Chagin /* Threads should be created with own stack */ 28381338031SDmitry Chagin if (args->stack == NULL) 28481338031SDmitry Chagin return (EINVAL); 28581338031SDmitry Chagin 28681338031SDmitry Chagin p = td->td_proc; 28781338031SDmitry Chagin 288089d3293SEdward Tomasz Napierala #ifdef RACCT 289089d3293SEdward Tomasz Napierala if (racct_enable) { 290089d3293SEdward Tomasz Napierala PROC_LOCK(p); 291089d3293SEdward Tomasz Napierala error = racct_add(p, RACCT_NTHR, 1); 292089d3293SEdward Tomasz Napierala PROC_UNLOCK(p); 293089d3293SEdward Tomasz Napierala if (error != 0) 294089d3293SEdward Tomasz Napierala return (EPROCLIM); 295089d3293SEdward Tomasz Napierala } 296089d3293SEdward Tomasz Napierala #endif 297089d3293SEdward Tomasz Napierala 29881338031SDmitry Chagin /* Initialize our td */ 29981338031SDmitry Chagin error = kern_thr_alloc(p, 0, &newtd); 30081338031SDmitry Chagin if (error) 301089d3293SEdward Tomasz Napierala goto fail; 30281338031SDmitry Chagin 303*5c2cf818SKonstantin Belousov cpu_copy_thread(newtd, td); 30481338031SDmitry Chagin 30581338031SDmitry Chagin bzero(&newtd->td_startzero, 30681338031SDmitry Chagin __rangeof(struct thread, td_startzero, td_endzero)); 30781338031SDmitry Chagin bcopy(&td->td_startcopy, &newtd->td_startcopy, 30881338031SDmitry Chagin __rangeof(struct thread, td_startcopy, td_endcopy)); 30981338031SDmitry Chagin 31081338031SDmitry Chagin newtd->td_proc = p; 3116871c7c3SMateusz Guzik thread_cow_get(newtd, td); 31281338031SDmitry Chagin 31381338031SDmitry Chagin /* create the emuldata */ 31481338031SDmitry Chagin linux_proc_init(td, newtd, args->flags); 31581338031SDmitry Chagin 31681338031SDmitry Chagin em = em_find(newtd); 31781338031SDmitry Chagin KASSERT(em != NULL, ("clone_thread: emuldata not found.\n")); 31881338031SDmitry Chagin 31981338031SDmitry Chagin if (args->flags & LINUX_CLONE_SETTLS) 32081338031SDmitry Chagin linux_set_cloned_tls(newtd, args->tls); 32181338031SDmitry Chagin 32281338031SDmitry Chagin if (args->flags & LINUX_CLONE_CHILD_SETTID) 32381338031SDmitry Chagin em->child_set_tid = args->child_tidptr; 32481338031SDmitry Chagin else 32581338031SDmitry Chagin em->child_set_tid = NULL; 32681338031SDmitry Chagin 32781338031SDmitry Chagin if (args->flags & LINUX_CLONE_CHILD_CLEARTID) 32881338031SDmitry Chagin em->child_clear_tid = args->child_tidptr; 32981338031SDmitry Chagin else 33081338031SDmitry Chagin em->child_clear_tid = NULL; 33181338031SDmitry Chagin 33281338031SDmitry Chagin cpu_thread_clean(newtd); 33381338031SDmitry Chagin 33481338031SDmitry Chagin linux_set_upcall_kse(newtd, PTROUT(args->stack)); 33581338031SDmitry Chagin 33681338031SDmitry Chagin PROC_LOCK(p); 33781338031SDmitry Chagin p->p_flag |= P_HADTHREADS; 33881338031SDmitry Chagin bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name)); 33981338031SDmitry Chagin 34081338031SDmitry Chagin if (args->flags & LINUX_CLONE_PARENT) 34181338031SDmitry Chagin thread_link(newtd, p->p_pptr); 34281338031SDmitry Chagin else 34381338031SDmitry Chagin thread_link(newtd, p); 34481338031SDmitry Chagin 34581338031SDmitry Chagin thread_lock(td); 34681338031SDmitry Chagin /* let the scheduler know about these things. */ 34781338031SDmitry Chagin sched_fork_thread(td, newtd); 34881338031SDmitry Chagin thread_unlock(td); 34981338031SDmitry Chagin if (P_SHOULDSTOP(p)) 35081338031SDmitry Chagin newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK; 35181338031SDmitry Chagin PROC_UNLOCK(p); 35281338031SDmitry Chagin 35381338031SDmitry Chagin tidhash_add(newtd); 35481338031SDmitry Chagin 35581338031SDmitry Chagin #ifdef DEBUG 35681338031SDmitry Chagin if (ldebug(clone)) 35781338031SDmitry Chagin printf(ARGS(clone, "successful clone to %d, stack %p"), 35881338031SDmitry Chagin (int)newtd->td_tid, args->stack); 35981338031SDmitry Chagin #endif 36081338031SDmitry Chagin 3617d96520bSDmitry Chagin LINUX_CTR2(clone_thread, "thread(%d) successful clone to %d", 36281338031SDmitry Chagin td->td_tid, newtd->td_tid); 36381338031SDmitry Chagin 36481338031SDmitry Chagin if (args->flags & LINUX_CLONE_PARENT_SETTID) { 36581338031SDmitry Chagin error = copyout(&newtd->td_tid, args->parent_tidptr, 36681338031SDmitry Chagin sizeof(newtd->td_tid)); 36781338031SDmitry Chagin if (error) 36881338031SDmitry Chagin printf(LMSG("clone_thread: copyout failed!")); 36981338031SDmitry Chagin } 37081338031SDmitry Chagin 37181338031SDmitry Chagin /* 37281338031SDmitry Chagin * Make this runnable after we are finished with it. 37381338031SDmitry Chagin */ 37481338031SDmitry Chagin thread_lock(newtd); 37581338031SDmitry Chagin TD_SET_CAN_RUN(newtd); 37681338031SDmitry Chagin sched_add(newtd, SRQ_BORING); 37781338031SDmitry Chagin thread_unlock(newtd); 37881338031SDmitry Chagin 37981338031SDmitry Chagin td->td_retval[0] = newtd->td_tid; 38081338031SDmitry Chagin 38181338031SDmitry Chagin return (0); 382089d3293SEdward Tomasz Napierala 383089d3293SEdward Tomasz Napierala fail: 384089d3293SEdward Tomasz Napierala #ifdef RACCT 385089d3293SEdward Tomasz Napierala if (racct_enable) { 386089d3293SEdward Tomasz Napierala PROC_LOCK(p); 387089d3293SEdward Tomasz Napierala racct_sub(p, RACCT_NTHR, 1); 388089d3293SEdward Tomasz Napierala PROC_UNLOCK(p); 389089d3293SEdward Tomasz Napierala } 390089d3293SEdward Tomasz Napierala #endif 391089d3293SEdward Tomasz Napierala return (error); 39281338031SDmitry Chagin } 39381338031SDmitry Chagin 39481338031SDmitry Chagin int 39581338031SDmitry Chagin linux_clone(struct thread *td, struct linux_clone_args *args) 39681338031SDmitry Chagin { 39781338031SDmitry Chagin 39881338031SDmitry Chagin if (args->flags & LINUX_CLONE_THREAD) 39981338031SDmitry Chagin return (linux_clone_thread(td, args)); 40081338031SDmitry Chagin else 40181338031SDmitry Chagin return (linux_clone_proc(td, args)); 40281338031SDmitry Chagin } 40381338031SDmitry Chagin 404161acbb6SDmitry Chagin int 405161acbb6SDmitry Chagin linux_exit(struct thread *td, struct linux_exit_args *args) 406161acbb6SDmitry Chagin { 40781338031SDmitry Chagin struct linux_emuldata *em; 408161acbb6SDmitry Chagin 40981338031SDmitry Chagin em = em_find(td); 41081338031SDmitry Chagin KASSERT(em != NULL, ("exit: emuldata not found.\n")); 411161acbb6SDmitry Chagin 41281338031SDmitry Chagin LINUX_CTR2(exit, "thread(%d) (%d)", em->em_tid, args->rval); 41381338031SDmitry Chagin 4142a339d9eSKonstantin Belousov umtx_thread_exit(td); 4152a339d9eSKonstantin Belousov 41681338031SDmitry Chagin linux_thread_detach(td); 41781338031SDmitry Chagin 41881338031SDmitry Chagin /* 41981338031SDmitry Chagin * XXX. When the last two threads of a process 42081338031SDmitry Chagin * exit via pthread_exit() try thr_exit() first. 42181338031SDmitry Chagin */ 42281338031SDmitry Chagin kern_thr_exit(td); 423b4490c6eSKonstantin Belousov exit1(td, args->rval, 0); 424161acbb6SDmitry Chagin /* NOTREACHED */ 425161acbb6SDmitry Chagin } 426bc273677SDmitry Chagin 427bc273677SDmitry Chagin int 428bc273677SDmitry Chagin linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args) 429bc273677SDmitry Chagin { 430bc273677SDmitry Chagin struct linux_emuldata *em; 431bc273677SDmitry Chagin 432bc273677SDmitry Chagin em = em_find(td); 433bc273677SDmitry Chagin KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n")); 434bc273677SDmitry Chagin 435bc273677SDmitry Chagin em->child_clear_tid = args->tidptr; 436bc273677SDmitry Chagin 437bc273677SDmitry Chagin td->td_retval[0] = em->em_tid; 438bc273677SDmitry Chagin 439bc273677SDmitry Chagin LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d", 440bc273677SDmitry Chagin em->em_tid, args->tidptr, td->td_retval[0]); 441bc273677SDmitry Chagin 442bc273677SDmitry Chagin return (0); 443bc273677SDmitry Chagin } 444bc273677SDmitry Chagin 445bc273677SDmitry Chagin void 446bc273677SDmitry Chagin linux_thread_detach(struct thread *td) 447bc273677SDmitry Chagin { 448bc273677SDmitry Chagin struct linux_sys_futex_args cup; 449bc273677SDmitry Chagin struct linux_emuldata *em; 450bc273677SDmitry Chagin int *child_clear_tid; 451bc273677SDmitry Chagin int error; 452bc273677SDmitry Chagin 453bc273677SDmitry Chagin em = em_find(td); 454bc273677SDmitry Chagin KASSERT(em != NULL, ("thread_detach: emuldata not found.\n")); 455bc273677SDmitry Chagin 4567d96520bSDmitry Chagin LINUX_CTR1(thread_detach, "thread(%d)", em->em_tid); 457bc273677SDmitry Chagin 458bc273677SDmitry Chagin release_futexes(td, em); 459bc273677SDmitry Chagin 460bc273677SDmitry Chagin child_clear_tid = em->child_clear_tid; 461bc273677SDmitry Chagin 462bc273677SDmitry Chagin if (child_clear_tid != NULL) { 463bc273677SDmitry Chagin 4647d96520bSDmitry Chagin LINUX_CTR2(thread_detach, "thread(%d) %p", 465bc273677SDmitry Chagin em->em_tid, child_clear_tid); 466bc273677SDmitry Chagin 467bc273677SDmitry Chagin error = suword32(child_clear_tid, 0); 468bc273677SDmitry Chagin if (error != 0) 469bc273677SDmitry Chagin return; 470bc273677SDmitry Chagin 471bc273677SDmitry Chagin cup.uaddr = child_clear_tid; 472bc273677SDmitry Chagin cup.op = LINUX_FUTEX_WAKE; 473bc273677SDmitry Chagin cup.val = 1; /* wake one */ 474bc273677SDmitry Chagin cup.timeout = NULL; 475bc273677SDmitry Chagin cup.uaddr2 = NULL; 476bc273677SDmitry Chagin cup.val3 = 0; 477bc273677SDmitry Chagin error = linux_sys_futex(td, &cup); 478bc273677SDmitry Chagin /* 479bc273677SDmitry Chagin * this cannot happen at the moment and if this happens it 480bc273677SDmitry Chagin * probably means there is a user space bug 481bc273677SDmitry Chagin */ 482bc273677SDmitry Chagin if (error != 0) 483bc273677SDmitry Chagin linux_msg(td, "futex stuff in thread_detach failed."); 484bc273677SDmitry Chagin } 485bc273677SDmitry Chagin } 486