kern_thr.c revision 196648
1/*-
2 * Copyright (c) 2003, Jeffrey Roberson <jeff@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice unmodified, this list of conditions, and the following
10 *    disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/kern/kern_thr.c 196648 2009-08-29 21:53:08Z kib $");
29
30#include "opt_compat.h"
31#include "opt_posix.h"
32#include <sys/param.h>
33#include <sys/kernel.h>
34#include <sys/lock.h>
35#include <sys/mutex.h>
36#include <sys/priv.h>
37#include <sys/proc.h>
38#include <sys/posix4.h>
39#include <sys/resourcevar.h>
40#include <sys/sched.h>
41#include <sys/sysctl.h>
42#include <sys/smp.h>
43#include <sys/syscallsubr.h>
44#include <sys/sysent.h>
45#include <sys/systm.h>
46#include <sys/sysproto.h>
47#include <sys/signalvar.h>
48#include <sys/ucontext.h>
49#include <sys/thr.h>
50#include <sys/rtprio.h>
51#include <sys/umtx.h>
52#include <sys/limits.h>
53
54#include <machine/frame.h>
55
56#include <security/audit/audit.h>
57
58#ifdef COMPAT_IA32
59
60static inline int
61suword_lwpid(void *addr, lwpid_t lwpid)
62{
63	int error;
64
65	if (SV_CURPROC_FLAG(SV_LP64))
66		error = suword(addr, lwpid);
67	else
68		error = suword32(addr, lwpid);
69	return (error);
70}
71
72#else
73#define suword_lwpid	suword
74#endif
75
76extern int max_threads_per_proc;
77extern int max_threads_hits;
78
79static int create_thread(struct thread *td, mcontext_t *ctx,
80			 void (*start_func)(void *), void *arg,
81			 char *stack_base, size_t stack_size,
82			 char *tls_base,
83			 long *child_tid, long *parent_tid,
84			 int flags, struct rtprio *rtp);
85
86/*
87 * System call interface.
88 */
89int
90thr_create(struct thread *td, struct thr_create_args *uap)
91    /* ucontext_t *ctx, long *id, int flags */
92{
93	ucontext_t ctx;
94	int error;
95
96	if ((error = copyin(uap->ctx, &ctx, sizeof(ctx))))
97		return (error);
98
99	error = create_thread(td, &ctx.uc_mcontext, NULL, NULL,
100		NULL, 0, NULL, uap->id, NULL, uap->flags, NULL);
101	return (error);
102}
103
104int
105thr_new(struct thread *td, struct thr_new_args *uap)
106    /* struct thr_param * */
107{
108	struct thr_param param;
109	int error;
110
111	if (uap->param_size < 0 || uap->param_size > sizeof(param))
112		return (EINVAL);
113	bzero(&param, sizeof(param));
114	if ((error = copyin(uap->param, &param, uap->param_size)))
115		return (error);
116	return (kern_thr_new(td, &param));
117}
118
119int
120kern_thr_new(struct thread *td, struct thr_param *param)
121{
122	struct rtprio rtp, *rtpp;
123	int error;
124
125	rtpp = NULL;
126	if (param->rtp != 0) {
127		error = copyin(param->rtp, &rtp, sizeof(struct rtprio));
128		if (error)
129			return (error);
130		rtpp = &rtp;
131	}
132	error = create_thread(td, NULL, param->start_func, param->arg,
133		param->stack_base, param->stack_size, param->tls_base,
134		param->child_tid, param->parent_tid, param->flags,
135		rtpp);
136	return (error);
137}
138
139static int
140create_thread(struct thread *td, mcontext_t *ctx,
141	    void (*start_func)(void *), void *arg,
142	    char *stack_base, size_t stack_size,
143	    char *tls_base,
144	    long *child_tid, long *parent_tid,
145	    int flags, struct rtprio *rtp)
146{
147	stack_t stack;
148	struct thread *newtd;
149	struct proc *p;
150	int error;
151
152	p = td->td_proc;
153
154	/* Have race condition but it is cheap. */
155	if (p->p_numthreads >= max_threads_per_proc) {
156		++max_threads_hits;
157		return (EPROCLIM);
158	}
159
160	if (rtp != NULL) {
161		switch(rtp->type) {
162		case RTP_PRIO_REALTIME:
163		case RTP_PRIO_FIFO:
164			/* Only root can set scheduler policy */
165			if (priv_check(td, PRIV_SCHED_SETPOLICY) != 0)
166				return (EPERM);
167			if (rtp->prio > RTP_PRIO_MAX)
168				return (EINVAL);
169			break;
170		case RTP_PRIO_NORMAL:
171			rtp->prio = 0;
172			break;
173		default:
174			return (EINVAL);
175		}
176	}
177
178	/* Initialize our td */
179	newtd = thread_alloc();
180	if (newtd == NULL)
181		return (ENOMEM);
182
183	/*
184	 * Try the copyout as soon as we allocate the td so we don't
185	 * have to tear things down in a failure case below.
186	 * Here we copy out tid to two places, one for child and one
187	 * for parent, because pthread can create a detached thread,
188	 * if parent wants to safely access child tid, it has to provide
189	 * its storage, because child thread may exit quickly and
190	 * memory is freed before parent thread can access it.
191	 */
192	if ((child_tid != NULL &&
193	    suword_lwpid(child_tid, newtd->td_tid)) ||
194	    (parent_tid != NULL &&
195	    suword_lwpid(parent_tid, newtd->td_tid))) {
196		thread_free(newtd);
197		return (EFAULT);
198	}
199
200	bzero(&newtd->td_startzero,
201	    __rangeof(struct thread, td_startzero, td_endzero));
202	bcopy(&td->td_startcopy, &newtd->td_startcopy,
203	    __rangeof(struct thread, td_startcopy, td_endcopy));
204	newtd->td_proc = td->td_proc;
205	newtd->td_ucred = crhold(td->td_ucred);
206
207	cpu_set_upcall(newtd, td);
208
209	if (ctx != NULL) { /* old way to set user context */
210		error = set_mcontext(newtd, ctx);
211		if (error != 0) {
212			thread_free(newtd);
213			crfree(td->td_ucred);
214			return (error);
215		}
216	} else {
217		/* Set up our machine context. */
218		stack.ss_sp = stack_base;
219		stack.ss_size = stack_size;
220		/* Set upcall address to user thread entry function. */
221		cpu_set_upcall_kse(newtd, start_func, arg, &stack);
222		/* Setup user TLS address and TLS pointer register. */
223		error = cpu_set_user_tls(newtd, tls_base);
224		if (error != 0) {
225			thread_free(newtd);
226			crfree(td->td_ucred);
227			return (error);
228		}
229	}
230
231	PROC_LOCK(td->td_proc);
232	td->td_proc->p_flag |= P_HADTHREADS;
233	newtd->td_sigmask = td->td_sigmask;
234	thread_link(newtd, p);
235	bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name));
236	thread_lock(td);
237	/* let the scheduler know about these things. */
238	sched_fork_thread(td, newtd);
239	thread_unlock(td);
240	if (P_SHOULDSTOP(p))
241		newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
242	PROC_UNLOCK(p);
243	thread_lock(newtd);
244	if (rtp != NULL) {
245		if (!(td->td_pri_class == PRI_TIMESHARE &&
246		      rtp->type == RTP_PRIO_NORMAL)) {
247			rtp_to_pri(rtp, newtd);
248			sched_prio(newtd, newtd->td_user_pri);
249		} /* ignore timesharing class */
250	}
251	TD_SET_CAN_RUN(newtd);
252	sched_add(newtd, SRQ_BORING);
253	thread_unlock(newtd);
254
255	return (0);
256}
257
258int
259thr_self(struct thread *td, struct thr_self_args *uap)
260    /* long *id */
261{
262	int error;
263
264	error = suword_lwpid(uap->id, (unsigned)td->td_tid);
265	if (error == -1)
266		return (EFAULT);
267	return (0);
268}
269
270int
271thr_exit(struct thread *td, struct thr_exit_args *uap)
272    /* long *state */
273{
274	struct proc *p;
275
276	p = td->td_proc;
277
278	/* Signal userland that it can free the stack. */
279	if ((void *)uap->state != NULL) {
280		suword_lwpid(uap->state, 1);
281		kern_umtx_wake(td, uap->state, INT_MAX, 0);
282	}
283
284	PROC_LOCK(p);
285	sigqueue_flush(&td->td_sigqueue);
286	PROC_SLOCK(p);
287
288	/*
289	 * Shutting down last thread in the proc.  This will actually
290	 * call exit() in the trampoline when it returns.
291	 */
292	if (p->p_numthreads != 1) {
293		thread_stopped(p);
294		thread_exit();
295		/* NOTREACHED */
296	}
297	PROC_SUNLOCK(p);
298	PROC_UNLOCK(p);
299	return (0);
300}
301
302int
303thr_kill(struct thread *td, struct thr_kill_args *uap)
304    /* long id, int sig */
305{
306	struct thread *ttd;
307	struct proc *p;
308	int error;
309
310	p = td->td_proc;
311	error = 0;
312	PROC_LOCK(p);
313	if (uap->id == -1) {
314		if (uap->sig != 0 && !_SIG_VALID(uap->sig)) {
315			error = EINVAL;
316		} else {
317			error = ESRCH;
318			FOREACH_THREAD_IN_PROC(p, ttd) {
319				if (ttd != td) {
320					error = 0;
321					if (uap->sig == 0)
322						break;
323					tdsignal(p, ttd, uap->sig, NULL);
324				}
325			}
326		}
327	} else {
328		if (uap->id != td->td_tid)
329			ttd = thread_find(p, uap->id);
330		else
331			ttd = td;
332		if (ttd == NULL)
333			error = ESRCH;
334		else if (uap->sig == 0)
335			;
336		else if (!_SIG_VALID(uap->sig))
337			error = EINVAL;
338		else
339			tdsignal(p, ttd, uap->sig, NULL);
340	}
341	PROC_UNLOCK(p);
342	return (error);
343}
344
345int
346thr_kill2(struct thread *td, struct thr_kill2_args *uap)
347    /* pid_t pid, long id, int sig */
348{
349	struct thread *ttd;
350	struct proc *p;
351	int error;
352
353	AUDIT_ARG_SIGNUM(uap->sig);
354
355	if (uap->pid == td->td_proc->p_pid) {
356		p = td->td_proc;
357		PROC_LOCK(p);
358	} else if ((p = pfind(uap->pid)) == NULL) {
359		return (ESRCH);
360	}
361	AUDIT_ARG_PROCESS(p);
362
363	error = p_cansignal(td, p, uap->sig);
364	if (error == 0) {
365		if (uap->id == -1) {
366			if (uap->sig != 0 && !_SIG_VALID(uap->sig)) {
367				error = EINVAL;
368			} else {
369				error = ESRCH;
370				FOREACH_THREAD_IN_PROC(p, ttd) {
371					if (ttd != td) {
372						error = 0;
373						if (uap->sig == 0)
374							break;
375						tdsignal(p, ttd, uap->sig, NULL);
376					}
377				}
378			}
379		} else {
380			if (uap->id != td->td_tid)
381				ttd = thread_find(p, uap->id);
382			else
383				ttd = td;
384			if (ttd == NULL)
385				error = ESRCH;
386			else if (uap->sig == 0)
387				;
388			else if (!_SIG_VALID(uap->sig))
389				error = EINVAL;
390			else
391				tdsignal(p, ttd, uap->sig, NULL);
392		}
393	}
394	PROC_UNLOCK(p);
395	return (error);
396}
397
398int
399thr_suspend(struct thread *td, struct thr_suspend_args *uap)
400	/* const struct timespec *timeout */
401{
402	struct timespec ts, *tsp;
403	int error;
404
405	tsp = NULL;
406	if (uap->timeout != NULL) {
407		error = copyin((const void *)uap->timeout, (void *)&ts,
408		    sizeof(struct timespec));
409		if (error != 0)
410			return (error);
411		tsp = &ts;
412	}
413
414	return (kern_thr_suspend(td, tsp));
415}
416
417int
418kern_thr_suspend(struct thread *td, struct timespec *tsp)
419{
420	struct timeval tv;
421	int error = 0, hz = 0;
422
423	if (tsp != NULL) {
424		if (tsp->tv_nsec < 0 || tsp->tv_nsec > 1000000000)
425			return (EINVAL);
426		if (tsp->tv_sec == 0 && tsp->tv_nsec == 0)
427			return (ETIMEDOUT);
428		TIMESPEC_TO_TIMEVAL(&tv, tsp);
429		hz = tvtohz(&tv);
430	}
431
432	if (td->td_pflags & TDP_WAKEUP) {
433		td->td_pflags &= ~TDP_WAKEUP;
434		return (0);
435	}
436
437	PROC_LOCK(td->td_proc);
438	if ((td->td_flags & TDF_THRWAKEUP) == 0)
439		error = msleep((void *)td, &td->td_proc->p_mtx, PCATCH, "lthr",
440		    hz);
441	if (td->td_flags & TDF_THRWAKEUP) {
442		thread_lock(td);
443		td->td_flags &= ~TDF_THRWAKEUP;
444		thread_unlock(td);
445		PROC_UNLOCK(td->td_proc);
446		return (0);
447	}
448	PROC_UNLOCK(td->td_proc);
449	if (error == EWOULDBLOCK)
450		error = ETIMEDOUT;
451	else if (error == ERESTART) {
452		if (hz != 0)
453			error = EINTR;
454	}
455	return (error);
456}
457
458int
459thr_wake(struct thread *td, struct thr_wake_args *uap)
460	/* long id */
461{
462	struct proc *p;
463	struct thread *ttd;
464
465	if (uap->id == td->td_tid) {
466		td->td_pflags |= TDP_WAKEUP;
467		return (0);
468	}
469
470	p = td->td_proc;
471	PROC_LOCK(p);
472	ttd = thread_find(p, uap->id);
473	if (ttd == NULL) {
474		PROC_UNLOCK(p);
475		return (ESRCH);
476	}
477	thread_lock(ttd);
478	ttd->td_flags |= TDF_THRWAKEUP;
479	thread_unlock(ttd);
480	wakeup((void *)ttd);
481	PROC_UNLOCK(p);
482	return (0);
483}
484
485int
486thr_set_name(struct thread *td, struct thr_set_name_args *uap)
487{
488	struct proc *p = td->td_proc;
489	char name[MAXCOMLEN + 1];
490	struct thread *ttd;
491	int error;
492
493	error = 0;
494	name[0] = '\0';
495	if (uap->name != NULL) {
496		error = copyinstr(uap->name, name, sizeof(name),
497			NULL);
498		if (error)
499			return (error);
500	}
501	PROC_LOCK(p);
502	if (uap->id == td->td_tid)
503		ttd = td;
504	else
505		ttd = thread_find(p, uap->id);
506	if (ttd != NULL)
507		strcpy(ttd->td_name, name);
508	else
509		error = ESRCH;
510	PROC_UNLOCK(p);
511	return (error);
512}
513