1139804Simp/*-
2112899Sjeff * Copyright (c) 2003, Jeffrey Roberson <jeff@freebsd.org>
3112899Sjeff * All rights reserved.
4112899Sjeff *
5112899Sjeff * Redistribution and use in source and binary forms, with or without
6112899Sjeff * modification, are permitted provided that the following conditions
7112899Sjeff * are met:
8112899Sjeff * 1. Redistributions of source code must retain the above copyright
9112899Sjeff *    notice unmodified, this list of conditions, and the following
10112899Sjeff *    disclaimer.
11112899Sjeff * 2. Redistributions in binary form must reproduce the above copyright
12112899Sjeff *    notice, this list of conditions and the following disclaimer in the
13112899Sjeff *    documentation and/or other materials provided with the distribution.
14112899Sjeff *
15112899Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16112899Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17112899Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18112899Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19112899Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20112899Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21112899Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22112899Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23112899Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24112899Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25112899Sjeff */
26112899Sjeff
27116182Sobrien#include <sys/cdefs.h>
28116182Sobrien__FBSDID("$FreeBSD: stable/10/sys/kern/kern_thr.c 337258 2018-08-03 14:45:53Z asomers $");
29116182Sobrien
30162551Sdavidxu#include "opt_compat.h"
31160319Sdavidxu#include "opt_posix.h"
32112899Sjeff#include <sys/param.h>
33112899Sjeff#include <sys/kernel.h>
34112899Sjeff#include <sys/lock.h>
35112899Sjeff#include <sys/mutex.h>
36164033Srwatson#include <sys/priv.h>
37112899Sjeff#include <sys/proc.h>
38164188Strhodes#include <sys/posix4.h>
39304188Sjhb#include <sys/ptrace.h>
40220222Strasz#include <sys/racct.h>
41112899Sjeff#include <sys/resourcevar.h>
42214238Sdavidxu#include <sys/rwlock.h>
43113373Sjeff#include <sys/sched.h>
44134886Sjulian#include <sys/sysctl.h>
45134791Sjulian#include <sys/smp.h>
46170404Sjhb#include <sys/syscallsubr.h>
47112899Sjeff#include <sys/sysent.h>
48112899Sjeff#include <sys/systm.h>
49112899Sjeff#include <sys/sysproto.h>
50112899Sjeff#include <sys/signalvar.h>
51218972Skib#include <sys/sysctl.h>
52112899Sjeff#include <sys/ucontext.h>
53112899Sjeff#include <sys/thr.h>
54160254Sdavidxu#include <sys/rtprio.h>
55151692Sdavidxu#include <sys/umtx.h>
56151692Sdavidxu#include <sys/limits.h>
57112899Sjeff
58112899Sjeff#include <machine/frame.h>
59112899Sjeff
60171859Sdavidxu#include <security/audit/audit.h>
61171859Sdavidxu
62227309Sedstatic SYSCTL_NODE(_kern, OID_AUTO, threads, CTLFLAG_RW, 0,
63227309Sed    "thread allocation");
64218972Skib
65218972Skibstatic int max_threads_per_proc = 1500;
66218972SkibSYSCTL_INT(_kern_threads, OID_AUTO, max_threads_per_proc, CTLFLAG_RW,
67228449Seadler    &max_threads_per_proc, 0, "Limit on threads per proc");
68218972Skib
69218972Skibstatic int max_threads_hits;
70218972SkibSYSCTL_INT(_kern_threads, OID_AUTO, max_threads_hits, CTLFLAG_RD,
71228449Seadler    &max_threads_hits, 0, "kern.threads.max_threads_per_proc hit count");
72218972Skib
73205014Snwhitehorn#ifdef COMPAT_FREEBSD32
74162551Sdavidxu
75162551Sdavidxustatic inline int
76162551Sdavidxusuword_lwpid(void *addr, lwpid_t lwpid)
77162551Sdavidxu{
78162551Sdavidxu	int error;
79162551Sdavidxu
80185169Skib	if (SV_CURPROC_FLAG(SV_LP64))
81162551Sdavidxu		error = suword(addr, lwpid);
82162551Sdavidxu	else
83162551Sdavidxu		error = suword32(addr, lwpid);
84162551Sdavidxu	return (error);
85162551Sdavidxu}
86162551Sdavidxu
87162551Sdavidxu#else
88162551Sdavidxu#define suword_lwpid	suword
89162551Sdavidxu#endif
90162551Sdavidxu
91112899Sjeff/*
92112899Sjeff * System call interface.
93112899Sjeff */
94286843Sed
95286843Sedstruct thr_create_initthr_args {
96286843Sed	ucontext_t ctx;
97286843Sed	long *tid;
98286843Sed};
99286843Sed
100286843Sedstatic int
101286843Sedthr_create_initthr(struct thread *td, void *thunk)
102286843Sed{
103286843Sed	struct thr_create_initthr_args *args;
104286843Sed
105286843Sed	/* Copy out the child tid. */
106286843Sed	args = thunk;
107286843Sed	if (args->tid != NULL && suword_lwpid(args->tid, td->td_tid))
108286843Sed		return (EFAULT);
109286843Sed
110286843Sed	return (set_mcontext(td, &args->ctx.uc_mcontext));
111286843Sed}
112286843Sed
113112899Sjeffint
114225617Skmacysys_thr_create(struct thread *td, struct thr_create_args *uap)
115131431Smarcel    /* ucontext_t *ctx, long *id, int flags */
116112899Sjeff{
117286843Sed	struct thr_create_initthr_args args;
118112899Sjeff	int error;
119145434Sdavidxu
120286843Sed	if ((error = copyin(uap->ctx, &args.ctx, sizeof(args.ctx))))
121145434Sdavidxu		return (error);
122286843Sed	args.tid = uap->id;
123286843Sed	return (thread_create(td, NULL, thr_create_initthr, &args));
124145434Sdavidxu}
125145434Sdavidxu
126145434Sdavidxuint
127225617Skmacysys_thr_new(struct thread *td, struct thr_new_args *uap)
128145434Sdavidxu    /* struct thr_param * */
129145434Sdavidxu{
130145434Sdavidxu	struct thr_param param;
131145434Sdavidxu	int error;
132145434Sdavidxu
133162551Sdavidxu	if (uap->param_size < 0 || uap->param_size > sizeof(param))
134145434Sdavidxu		return (EINVAL);
135162497Sdavidxu	bzero(&param, sizeof(param));
136162551Sdavidxu	if ((error = copyin(uap->param, &param, uap->param_size)))
137145434Sdavidxu		return (error);
138162551Sdavidxu	return (kern_thr_new(td, &param));
139162551Sdavidxu}
140162551Sdavidxu
141286843Sedstatic int
142286843Sedthr_new_initthr(struct thread *td, void *thunk)
143286843Sed{
144286843Sed	stack_t stack;
145286843Sed	struct thr_param *param;
146286843Sed
147286843Sed	/*
148286843Sed	 * Here we copy out tid to two places, one for child and one
149286843Sed	 * for parent, because pthread can create a detached thread,
150286843Sed	 * if parent wants to safely access child tid, it has to provide
151286843Sed	 * its storage, because child thread may exit quickly and
152286843Sed	 * memory is freed before parent thread can access it.
153286843Sed	 */
154286843Sed	param = thunk;
155286843Sed	if ((param->child_tid != NULL &&
156286843Sed	    suword_lwpid(param->child_tid, td->td_tid)) ||
157286843Sed	    (param->parent_tid != NULL &&
158286843Sed	    suword_lwpid(param->parent_tid, td->td_tid)))
159286843Sed		return (EFAULT);
160286843Sed
161286843Sed	/* Set up our machine context. */
162286843Sed	stack.ss_sp = param->stack_base;
163286843Sed	stack.ss_size = param->stack_size;
164286843Sed	/* Set upcall address to user thread entry function. */
165286843Sed	cpu_set_upcall_kse(td, param->start_func, param->arg, &stack);
166286843Sed	/* Setup user TLS address and TLS pointer register. */
167286843Sed	return (cpu_set_user_tls(td, param->tls_base));
168286843Sed}
169286843Sed
170162551Sdavidxuint
171162551Sdavidxukern_thr_new(struct thread *td, struct thr_param *param)
172162551Sdavidxu{
173162551Sdavidxu	struct rtprio rtp, *rtpp;
174162551Sdavidxu	int error;
175162551Sdavidxu
176162497Sdavidxu	rtpp = NULL;
177162551Sdavidxu	if (param->rtp != 0) {
178162551Sdavidxu		error = copyin(param->rtp, &rtp, sizeof(struct rtprio));
179183846Srdivacky		if (error)
180183846Srdivacky			return (error);
181162497Sdavidxu		rtpp = &rtp;
182160254Sdavidxu	}
183286843Sed	return (thread_create(td, rtpp, thr_new_initthr, param));
184145434Sdavidxu}
185145434Sdavidxu
186286843Sedint
187286843Sedthread_create(struct thread *td, struct rtprio *rtp,
188286843Sed    int (*initialize_thread)(struct thread *, void *), void *thunk)
189145434Sdavidxu{
190145434Sdavidxu	struct thread *newtd;
191134791Sjulian	struct proc *p;
192160252Sdavidxu	int error;
193112899Sjeff
194134791Sjulian	p = td->td_proc;
195112899Sjeff
196162497Sdavidxu	if (rtp != NULL) {
197162497Sdavidxu		switch(rtp->type) {
198162497Sdavidxu		case RTP_PRIO_REALTIME:
199162497Sdavidxu		case RTP_PRIO_FIFO:
200160259Sdavidxu			/* Only root can set scheduler policy */
201164033Srwatson			if (priv_check(td, PRIV_SCHED_SETPOLICY) != 0)
202160254Sdavidxu				return (EPERM);
203162497Sdavidxu			if (rtp->prio > RTP_PRIO_MAX)
204160254Sdavidxu				return (EINVAL);
205160259Sdavidxu			break;
206162497Sdavidxu		case RTP_PRIO_NORMAL:
207162497Sdavidxu			rtp->prio = 0;
208160259Sdavidxu			break;
209160259Sdavidxu		default:
210160259Sdavidxu			return (EINVAL);
211160254Sdavidxu		}
212160254Sdavidxu	}
213160254Sdavidxu
214223825Strasz#ifdef RACCT
215220222Strasz	PROC_LOCK(td->td_proc);
216220222Strasz	error = racct_add(p, RACCT_NTHR, 1);
217220222Strasz	PROC_UNLOCK(td->td_proc);
218220222Strasz	if (error != 0)
219220222Strasz		return (EPROCLIM);
220223825Strasz#endif
221220222Strasz
222164936Sjulian	/* Initialize our td */
223293481Sdchagin	error = kern_thr_alloc(p, 0, &newtd);
224293481Sdchagin	if (error)
225220222Strasz		goto fail;
226145434Sdavidxu
227228360Spho	cpu_set_upcall(newtd, td);
228228360Spho
229134791Sjulian	bzero(&newtd->td_startzero,
230137946Sdas	    __rangeof(struct thread, td_startzero, td_endzero));
231284199Skib	newtd->td_su = NULL;
232304905Skib	newtd->td_sleeptimo = 0;
233134791Sjulian	bcopy(&td->td_startcopy, &newtd->td_startcopy,
234137946Sdas	    __rangeof(struct thread, td_startcopy, td_endcopy));
235134791Sjulian	newtd->td_proc = td->td_proc;
236134791Sjulian	newtd->td_ucred = crhold(td->td_ucred);
237289780Sjhb	newtd->td_dbg_sc_code = td->td_dbg_sc_code;
238289780Sjhb	newtd->td_dbg_sc_narg = td->td_dbg_sc_narg;
239112899Sjeff
240286843Sed	error = initialize_thread(newtd, thunk);
241286843Sed	if (error != 0) {
242286843Sed		thread_free(newtd);
243286843Sed		crfree(td->td_ucred);
244286843Sed		goto fail;
245131431Smarcel	}
246112899Sjeff
247160252Sdavidxu	PROC_LOCK(td->td_proc);
248145434Sdavidxu	td->td_proc->p_flag |= P_HADTHREADS;
249163709Sjb	thread_link(newtd, p);
250173625Sjulian	bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name));
251170307Sjeff	thread_lock(td);
252134791Sjulian	/* let the scheduler know about these things. */
253134791Sjulian	sched_fork_thread(td, newtd);
254170307Sjeff	thread_unlock(td);
255177471Sjeff	if (P_SHOULDSTOP(p))
256177471Sjeff		newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
257304188Sjhb	if (p->p_ptevents & PTRACE_LWP)
258304017Sjhb		newtd->td_dbgflags |= TDB_BORN;
259170307Sjeff	PROC_UNLOCK(p);
260213642Sdavidxu
261213642Sdavidxu	tidhash_add(newtd);
262213642Sdavidxu
263170307Sjeff	thread_lock(newtd);
264162497Sdavidxu	if (rtp != NULL) {
265163709Sjb		if (!(td->td_pri_class == PRI_TIMESHARE &&
266163709Sjb		      rtp->type == RTP_PRIO_NORMAL)) {
267163709Sjb			rtp_to_pri(rtp, newtd);
268163709Sjb			sched_prio(newtd, newtd->td_user_pri);
269163709Sjb		} /* ignore timesharing class */
270163709Sjb	}
271134791Sjulian	TD_SET_CAN_RUN(newtd);
272177514Sdavidxu	sched_add(newtd, SRQ_BORING);
273170307Sjeff	thread_unlock(newtd);
274112899Sjeff
275189074Sed	return (0);
276220222Strasz
277220222Straszfail:
278223825Strasz#ifdef RACCT
279284665Strasz	if (racct_enable) {
280284665Strasz		PROC_LOCK(p);
281284665Strasz		racct_sub(p, RACCT_NTHR, 1);
282284665Strasz		PROC_UNLOCK(p);
283284665Strasz	}
284223825Strasz#endif
285220222Strasz	return (error);
286112899Sjeff}
287112899Sjeff
288112899Sjeffint
289225617Skmacysys_thr_self(struct thread *td, struct thr_self_args *uap)
290131431Smarcel    /* long *id */
291112899Sjeff{
292112899Sjeff	int error;
293112899Sjeff
294162551Sdavidxu	error = suword_lwpid(uap->id, (unsigned)td->td_tid);
295162551Sdavidxu	if (error == -1)
296162551Sdavidxu		return (EFAULT);
297112899Sjeff	return (0);
298112899Sjeff}
299112899Sjeff
300112899Sjeffint
301225617Skmacysys_thr_exit(struct thread *td, struct thr_exit_args *uap)
302136192Smtm    /* long *state */
303112899Sjeff{
304112899Sjeff
305136192Smtm	/* Signal userland that it can free the stack. */
306151692Sdavidxu	if ((void *)uap->state != NULL) {
307162551Sdavidxu		suword_lwpid(uap->state, 1);
308178648Sdavidxu		kern_umtx_wake(td, uap->state, INT_MAX, 0);
309151692Sdavidxu	}
310136192Smtm
311293480Sdchagin	return (kern_thr_exit(td));
312293480Sdchagin}
313293480Sdchagin
314293480Sdchaginint
315293480Sdchaginkern_thr_exit(struct thread *td)
316293480Sdchagin{
317293480Sdchagin	struct proc *p;
318293480Sdchagin
319293480Sdchagin	p = td->td_proc;
320293480Sdchagin
321304017Sjhb	/*
322304017Sjhb	 * If all of the threads in a process call this routine to
323304017Sjhb	 * exit (e.g. all threads call pthread_exit()), exactly one
324304017Sjhb	 * thread should return to the caller to terminate the process
325304017Sjhb	 * instead of the thread.
326304017Sjhb	 *
327304017Sjhb	 * Checking p_numthreads alone is not sufficient since threads
328304017Sjhb	 * might be committed to terminating while the PROC_LOCK is
329304017Sjhb	 * dropped in either ptracestop() or while removing this thread
330304017Sjhb	 * from the tidhash.  Instead, the p_pendingexits field holds
331304017Sjhb	 * the count of threads in either of those states and a thread
332304017Sjhb	 * is considered the "last" thread if all of the other threads
333304017Sjhb	 * in a process are already terminating.
334304017Sjhb	 */
335112899Sjeff	PROC_LOCK(p);
336304017Sjhb	if (p->p_numthreads == p->p_pendingexits + 1) {
337304017Sjhb		/*
338304017Sjhb		 * Ignore attempts to shut down last thread in the
339304017Sjhb		 * proc.  This will actually call _exit(2) in the
340304017Sjhb		 * usermode trampoline when it returns.
341304017Sjhb		 */
342304017Sjhb		PROC_UNLOCK(p);
343304017Sjhb		return (0);
344134791Sjulian	}
345274339Skib
346304017Sjhb	p->p_pendingexits++;
347304017Sjhb	td->td_dbgflags |= TDB_EXIT;
348304188Sjhb	if (p->p_ptevents & PTRACE_LWP)
349315949Sbadger		ptracestop(td, SIGTRAP, NULL);
350304017Sjhb	PROC_UNLOCK(p);
351304017Sjhb	tidhash_remove(td);
352304017Sjhb	PROC_LOCK(p);
353304017Sjhb	p->p_pendingexits--;
354304017Sjhb
355274339Skib	/*
356304017Sjhb	 * The check above should prevent all other threads from this
357304017Sjhb	 * process from exiting while the PROC_LOCK is dropped, so
358304017Sjhb	 * there must be at least one other thread other than the
359304017Sjhb	 * current thread.
360274339Skib	 */
361304017Sjhb	KASSERT(p->p_numthreads > 1, ("too few threads"));
362304017Sjhb	racct_sub(p, RACCT_NTHR, 1);
363304017Sjhb	tdsigcleanup(td);
364304017Sjhb	umtx_thread_exit(td);
365337258Sasomers
366337258Sasomers#ifdef AUDIT
367337258Sasomers	AUDIT_SYSCALL_EXIT(0, td);
368337258Sasomers#endif
369337258Sasomers
370304017Sjhb	PROC_SLOCK(p);
371304017Sjhb	thread_stopped(p);
372304017Sjhb	thread_exit();
373304017Sjhb	/* NOTREACHED */
374112899Sjeff}
375112899Sjeff
376112899Sjeffint
377225617Skmacysys_thr_kill(struct thread *td, struct thr_kill_args *uap)
378131431Smarcel    /* long id, int sig */
379112899Sjeff{
380204519Sbruno	ksiginfo_t ksi;
381112899Sjeff	struct thread *ttd;
382112899Sjeff	struct proc *p;
383112899Sjeff	int error;
384112899Sjeff
385112899Sjeff	p = td->td_proc;
386204519Sbruno	ksiginfo_init(&ksi);
387204519Sbruno	ksi.ksi_signo = uap->sig;
388211732Sdavidxu	ksi.ksi_code = SI_LWP;
389204519Sbruno	ksi.ksi_pid = p->p_pid;
390204519Sbruno	ksi.ksi_uid = td->td_ucred->cr_ruid;
391154093Sdavidxu	if (uap->id == -1) {
392154093Sdavidxu		if (uap->sig != 0 && !_SIG_VALID(uap->sig)) {
393154093Sdavidxu			error = EINVAL;
394154093Sdavidxu		} else {
395154093Sdavidxu			error = ESRCH;
396213642Sdavidxu			PROC_LOCK(p);
397154093Sdavidxu			FOREACH_THREAD_IN_PROC(p, ttd) {
398154093Sdavidxu				if (ttd != td) {
399154093Sdavidxu					error = 0;
400154093Sdavidxu					if (uap->sig == 0)
401154093Sdavidxu						break;
402209592Sjhb					tdksignal(ttd, uap->sig, &ksi);
403154093Sdavidxu				}
404154093Sdavidxu			}
405213642Sdavidxu			PROC_UNLOCK(p);
406154093Sdavidxu		}
407154093Sdavidxu	} else {
408213642Sdavidxu		error = 0;
409213642Sdavidxu		ttd = tdfind((lwpid_t)uap->id, p->p_pid);
410154093Sdavidxu		if (ttd == NULL)
411213642Sdavidxu			return (ESRCH);
412213642Sdavidxu		if (uap->sig == 0)
413154093Sdavidxu			;
414154093Sdavidxu		else if (!_SIG_VALID(uap->sig))
415154093Sdavidxu			error = EINVAL;
416213642Sdavidxu		else
417209592Sjhb			tdksignal(ttd, uap->sig, &ksi);
418213642Sdavidxu		PROC_UNLOCK(ttd->td_proc);
419112899Sjeff	}
420112899Sjeff	return (error);
421112899Sjeff}
422127482Smtm
423127482Smtmint
424225617Skmacysys_thr_kill2(struct thread *td, struct thr_kill2_args *uap)
425171859Sdavidxu    /* pid_t pid, long id, int sig */
426171859Sdavidxu{
427204519Sbruno	ksiginfo_t ksi;
428171859Sdavidxu	struct thread *ttd;
429171859Sdavidxu	struct proc *p;
430171859Sdavidxu	int error;
431171859Sdavidxu
432195104Srwatson	AUDIT_ARG_SIGNUM(uap->sig);
433171859Sdavidxu
434213642Sdavidxu	ksiginfo_init(&ksi);
435213642Sdavidxu	ksi.ksi_signo = uap->sig;
436213642Sdavidxu	ksi.ksi_code = SI_LWP;
437213642Sdavidxu	ksi.ksi_pid = td->td_proc->p_pid;
438213642Sdavidxu	ksi.ksi_uid = td->td_ucred->cr_ruid;
439213642Sdavidxu	if (uap->id == -1) {
440213642Sdavidxu		if ((p = pfind(uap->pid)) == NULL)
441213642Sdavidxu			return (ESRCH);
442213642Sdavidxu		AUDIT_ARG_PROCESS(p);
443213642Sdavidxu		error = p_cansignal(td, p, uap->sig);
444213642Sdavidxu		if (error) {
445213642Sdavidxu			PROC_UNLOCK(p);
446213642Sdavidxu			return (error);
447213642Sdavidxu		}
448213642Sdavidxu		if (uap->sig != 0 && !_SIG_VALID(uap->sig)) {
449213642Sdavidxu			error = EINVAL;
450213642Sdavidxu		} else {
451213642Sdavidxu			error = ESRCH;
452213642Sdavidxu			FOREACH_THREAD_IN_PROC(p, ttd) {
453213642Sdavidxu				if (ttd != td) {
454213642Sdavidxu					error = 0;
455213642Sdavidxu					if (uap->sig == 0)
456213642Sdavidxu						break;
457213642Sdavidxu					tdksignal(ttd, uap->sig, &ksi);
458171859Sdavidxu				}
459171859Sdavidxu			}
460171859Sdavidxu		}
461213642Sdavidxu		PROC_UNLOCK(p);
462213642Sdavidxu	} else {
463213642Sdavidxu		ttd = tdfind((lwpid_t)uap->id, uap->pid);
464213642Sdavidxu		if (ttd == NULL)
465213642Sdavidxu			return (ESRCH);
466213642Sdavidxu		p = ttd->td_proc;
467213642Sdavidxu		AUDIT_ARG_PROCESS(p);
468213642Sdavidxu		error = p_cansignal(td, p, uap->sig);
469213642Sdavidxu		if (uap->sig == 0)
470213642Sdavidxu			;
471213642Sdavidxu		else if (!_SIG_VALID(uap->sig))
472213642Sdavidxu			error = EINVAL;
473213642Sdavidxu		else
474213642Sdavidxu			tdksignal(ttd, uap->sig, &ksi);
475213642Sdavidxu		PROC_UNLOCK(p);
476171859Sdavidxu	}
477171859Sdavidxu	return (error);
478171859Sdavidxu}
479171859Sdavidxu
480171859Sdavidxuint
481225617Skmacysys_thr_suspend(struct thread *td, struct thr_suspend_args *uap)
482127482Smtm	/* const struct timespec *timeout */
483127482Smtm{
484162551Sdavidxu	struct timespec ts, *tsp;
485127482Smtm	int error;
486127482Smtm
487162551Sdavidxu	tsp = NULL;
488127482Smtm	if (uap->timeout != NULL) {
489228221Spho		error = umtx_copyin_timeout(uap->timeout, &ts);
490127482Smtm		if (error != 0)
491127482Smtm			return (error);
492162551Sdavidxu		tsp = &ts;
493162551Sdavidxu	}
494162551Sdavidxu
495162551Sdavidxu	return (kern_thr_suspend(td, tsp));
496162551Sdavidxu}
497162551Sdavidxu
498162551Sdavidxuint
499162551Sdavidxukern_thr_suspend(struct thread *td, struct timespec *tsp)
500162551Sdavidxu{
501214091Sdavidxu	struct proc *p = td->td_proc;
502162551Sdavidxu	struct timeval tv;
503211733Sdavidxu	int error = 0;
504211733Sdavidxu	int timo = 0;
505162551Sdavidxu
506164876Sdavidxu	if (td->td_pflags & TDP_WAKEUP) {
507164876Sdavidxu		td->td_pflags &= ~TDP_WAKEUP;
508164876Sdavidxu		return (0);
509164876Sdavidxu	}
510164876Sdavidxu
511214091Sdavidxu	if (tsp != NULL) {
512211733Sdavidxu		if (tsp->tv_sec == 0 && tsp->tv_nsec == 0)
513211733Sdavidxu			error = EWOULDBLOCK;
514211733Sdavidxu		else {
515211733Sdavidxu			TIMESPEC_TO_TIMEVAL(&tv, tsp);
516211733Sdavidxu			timo = tvtohz(&tv);
517211733Sdavidxu		}
518211733Sdavidxu	}
519211733Sdavidxu
520214091Sdavidxu	PROC_LOCK(p);
521214091Sdavidxu	if (error == 0 && (td->td_flags & TDF_THRWAKEUP) == 0)
522214091Sdavidxu		error = msleep((void *)td, &p->p_mtx,
523214091Sdavidxu			 PCATCH, "lthr", timo);
524214091Sdavidxu
525138272Sdavidxu	if (td->td_flags & TDF_THRWAKEUP) {
526170307Sjeff		thread_lock(td);
527138272Sdavidxu		td->td_flags &= ~TDF_THRWAKEUP;
528170307Sjeff		thread_unlock(td);
529214091Sdavidxu		PROC_UNLOCK(p);
530138272Sdavidxu		return (0);
531138272Sdavidxu	}
532214091Sdavidxu	PROC_UNLOCK(p);
533138272Sdavidxu	if (error == EWOULDBLOCK)
534138272Sdavidxu		error = ETIMEDOUT;
535138272Sdavidxu	else if (error == ERESTART) {
536211733Sdavidxu		if (timo != 0)
537138272Sdavidxu			error = EINTR;
538138272Sdavidxu	}
539138272Sdavidxu	return (error);
540127482Smtm}
541127482Smtm
542127482Smtmint
543225617Skmacysys_thr_wake(struct thread *td, struct thr_wake_args *uap)
544131431Smarcel	/* long id */
545127482Smtm{
546151990Sdavidxu	struct proc *p;
547131431Smarcel	struct thread *ttd;
548127482Smtm
549164876Sdavidxu	if (uap->id == td->td_tid) {
550164876Sdavidxu		td->td_pflags |= TDP_WAKEUP;
551164876Sdavidxu		return (0);
552164876Sdavidxu	}
553164876Sdavidxu
554151990Sdavidxu	p = td->td_proc;
555213642Sdavidxu	ttd = tdfind((lwpid_t)uap->id, p->p_pid);
556213642Sdavidxu	if (ttd == NULL)
557127482Smtm		return (ESRCH);
558170307Sjeff	thread_lock(ttd);
559131431Smarcel	ttd->td_flags |= TDF_THRWAKEUP;
560170307Sjeff	thread_unlock(ttd);
561138272Sdavidxu	wakeup((void *)ttd);
562151990Sdavidxu	PROC_UNLOCK(p);
563127482Smtm	return (0);
564127482Smtm}
565155327Sdavidxu
566155327Sdavidxuint
567225617Skmacysys_thr_set_name(struct thread *td, struct thr_set_name_args *uap)
568155327Sdavidxu{
569213642Sdavidxu	struct proc *p;
570155327Sdavidxu	char name[MAXCOMLEN + 1];
571155327Sdavidxu	struct thread *ttd;
572155327Sdavidxu	int error;
573155327Sdavidxu
574155327Sdavidxu	error = 0;
575155327Sdavidxu	name[0] = '\0';
576155327Sdavidxu	if (uap->name != NULL) {
577310099Svangyzen		error = copyinstr(uap->name, name, sizeof(name), NULL);
578310099Svangyzen		if (error == ENAMETOOLONG) {
579310099Svangyzen			error = copyin(uap->name, name, sizeof(name) - 1);
580310099Svangyzen			name[sizeof(name) - 1] = '\0';
581310099Svangyzen		}
582155327Sdavidxu		if (error)
583155327Sdavidxu			return (error);
584155327Sdavidxu	}
585213642Sdavidxu	p = td->td_proc;
586213642Sdavidxu	ttd = tdfind((lwpid_t)uap->id, p->p_pid);
587213642Sdavidxu	if (ttd == NULL)
588213642Sdavidxu		return (ESRCH);
589213642Sdavidxu	strcpy(ttd->td_name, name);
590232700Sjhb#ifdef KTR
591232700Sjhb	sched_clear_tdname(ttd);
592232700Sjhb#endif
593155327Sdavidxu	PROC_UNLOCK(p);
594155327Sdavidxu	return (error);
595155327Sdavidxu}
596293481Sdchagin
597293481Sdchaginint
598293481Sdchaginkern_thr_alloc(struct proc *p, int pages, struct thread **ntd)
599293481Sdchagin{
600293481Sdchagin
601293481Sdchagin	/* Have race condition but it is cheap. */
602293481Sdchagin	if (p->p_numthreads >= max_threads_per_proc) {
603293481Sdchagin		++max_threads_hits;
604293481Sdchagin		return (EPROCLIM);
605293481Sdchagin	}
606293481Sdchagin
607293481Sdchagin	*ntd = thread_alloc(pages);
608293481Sdchagin	if (*ntd == NULL)
609293481Sdchagin		return (ENOMEM);
610293481Sdchagin
611293481Sdchagin	return (0);
612293481Sdchagin}
613