xref: /freebsd/sys/compat/linux/linux_fork.c (revision 5c2cf818454375536fda522ba83cf67c50929e6b)
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