kern_thr.c revision 218967
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 218967 2011-02-23 12:56:25Z jhb $");
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/rwlock.h>
41#include <sys/sched.h>
42#include <sys/sysctl.h>
43#include <sys/smp.h>
44#include <sys/syscallsubr.h>
45#include <sys/sysent.h>
46#include <sys/systm.h>
47#include <sys/sysproto.h>
48#include <sys/signalvar.h>
49#include <sys/ucontext.h>
50#include <sys/thr.h>
51#include <sys/rtprio.h>
52#include <sys/umtx.h>
53#include <sys/limits.h>
54
55#include <machine/frame.h>
56
57#include <security/audit/audit.h>
58
59#ifdef COMPAT_FREEBSD32
60
61static inline int
62suword_lwpid(void *addr, lwpid_t lwpid)
63{
64	int error;
65
66	if (SV_CURPROC_FLAG(SV_LP64))
67		error = suword(addr, lwpid);
68	else
69		error = suword32(addr, lwpid);
70	return (error);
71}
72
73#else
74#define suword_lwpid	suword
75#endif
76
77extern int max_threads_per_proc;
78extern int max_threads_hits;
79
80static int create_thread(struct thread *td, mcontext_t *ctx,
81			 void (*start_func)(void *), void *arg,
82			 char *stack_base, size_t stack_size,
83			 char *tls_base,
84			 long *child_tid, long *parent_tid,
85			 int flags, struct rtprio *rtp);
86
87/*
88 * System call interface.
89 */
90int
91thr_create(struct thread *td, struct thr_create_args *uap)
92    /* ucontext_t *ctx, long *id, int flags */
93{
94	ucontext_t ctx;
95	int error;
96
97	if ((error = copyin(uap->ctx, &ctx, sizeof(ctx))))
98		return (error);
99
100	error = create_thread(td, &ctx.uc_mcontext, NULL, NULL,
101		NULL, 0, NULL, uap->id, NULL, uap->flags, NULL);
102	return (error);
103}
104
105int
106thr_new(struct thread *td, struct thr_new_args *uap)
107    /* struct thr_param * */
108{
109	struct thr_param param;
110	int error;
111
112	if (uap->param_size < 0 || uap->param_size > sizeof(param))
113		return (EINVAL);
114	bzero(&param, sizeof(param));
115	if ((error = copyin(uap->param, &param, uap->param_size)))
116		return (error);
117	return (kern_thr_new(td, &param));
118}
119
120int
121kern_thr_new(struct thread *td, struct thr_param *param)
122{
123	struct rtprio rtp, *rtpp;
124	int error;
125
126	rtpp = NULL;
127	if (param->rtp != 0) {
128		error = copyin(param->rtp, &rtp, sizeof(struct rtprio));
129		if (error)
130			return (error);
131		rtpp = &rtp;
132	}
133	error = create_thread(td, NULL, param->start_func, param->arg,
134		param->stack_base, param->stack_size, param->tls_base,
135		param->child_tid, param->parent_tid, param->flags,
136		rtpp);
137	return (error);
138}
139
140static int
141create_thread(struct thread *td, mcontext_t *ctx,
142	    void (*start_func)(void *), void *arg,
143	    char *stack_base, size_t stack_size,
144	    char *tls_base,
145	    long *child_tid, long *parent_tid,
146	    int flags, struct rtprio *rtp)
147{
148	stack_t stack;
149	struct thread *newtd;
150	struct proc *p;
151	int error;
152
153	p = td->td_proc;
154
155	/* Have race condition but it is cheap. */
156	if (p->p_numthreads > max_threads_per_proc) {
157		++max_threads_hits;
158		return (EPROCLIM);
159	}
160
161	if (rtp != NULL) {
162		switch(rtp->type) {
163		case RTP_PRIO_REALTIME:
164		case RTP_PRIO_FIFO:
165			/* Only root can set scheduler policy */
166			if (priv_check(td, PRIV_SCHED_SETPOLICY) != 0)
167				return (EPERM);
168			if (rtp->prio > RTP_PRIO_MAX)
169				return (EINVAL);
170			break;
171		case RTP_PRIO_NORMAL:
172			rtp->prio = 0;
173			break;
174		default:
175			return (EINVAL);
176		}
177	}
178
179	/* Initialize our td */
180	newtd = thread_alloc(0);
181	if (newtd == NULL)
182		return (ENOMEM);
183
184	/*
185	 * Try the copyout as soon as we allocate the td so we don't
186	 * have to tear things down in a failure case below.
187	 * Here we copy out tid to two places, one for child and one
188	 * for parent, because pthread can create a detached thread,
189	 * if parent wants to safely access child tid, it has to provide
190	 * its storage, because child thread may exit quickly and
191	 * memory is freed before parent thread can access it.
192	 */
193	if ((child_tid != NULL &&
194	    suword_lwpid(child_tid, newtd->td_tid)) ||
195	    (parent_tid != NULL &&
196	    suword_lwpid(parent_tid, newtd->td_tid))) {
197		thread_free(newtd);
198		return (EFAULT);
199	}
200
201	bzero(&newtd->td_startzero,
202	    __rangeof(struct thread, td_startzero, td_endzero));
203	bcopy(&td->td_startcopy, &newtd->td_startcopy,
204	    __rangeof(struct thread, td_startcopy, td_endcopy));
205	newtd->td_proc = td->td_proc;
206	newtd->td_ucred = crhold(td->td_ucred);
207
208	cpu_set_upcall(newtd, td);
209
210	if (ctx != NULL) { /* old way to set user context */
211		error = set_mcontext(newtd, ctx);
212		if (error != 0) {
213			thread_free(newtd);
214			crfree(td->td_ucred);
215			return (error);
216		}
217	} else {
218		/* Set up our machine context. */
219		stack.ss_sp = stack_base;
220		stack.ss_size = stack_size;
221		/* Set upcall address to user thread entry function. */
222		cpu_set_upcall_kse(newtd, start_func, arg, &stack);
223		/* Setup user TLS address and TLS pointer register. */
224		error = cpu_set_user_tls(newtd, tls_base);
225		if (error != 0) {
226			thread_free(newtd);
227			crfree(td->td_ucred);
228			return (error);
229		}
230	}
231
232	PROC_LOCK(td->td_proc);
233	td->td_proc->p_flag |= P_HADTHREADS;
234	newtd->td_sigmask = td->td_sigmask;
235	thread_link(newtd, p);
236	bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name));
237	thread_lock(td);
238	/* let the scheduler know about these things. */
239	sched_fork_thread(td, newtd);
240	thread_unlock(td);
241	if (P_SHOULDSTOP(p))
242		newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
243	PROC_UNLOCK(p);
244
245	tidhash_add(newtd);
246
247	thread_lock(newtd);
248	if (rtp != NULL) {
249		if (!(td->td_pri_class == PRI_TIMESHARE &&
250		      rtp->type == RTP_PRIO_NORMAL)) {
251			rtp_to_pri(rtp, newtd);
252			sched_prio(newtd, newtd->td_user_pri);
253		} /* ignore timesharing class */
254	}
255	TD_SET_CAN_RUN(newtd);
256	sched_add(newtd, SRQ_BORING);
257	thread_unlock(newtd);
258
259	return (0);
260}
261
262int
263thr_self(struct thread *td, struct thr_self_args *uap)
264    /* long *id */
265{
266	int error;
267
268	error = suword_lwpid(uap->id, (unsigned)td->td_tid);
269	if (error == -1)
270		return (EFAULT);
271	return (0);
272}
273
274int
275thr_exit(struct thread *td, struct thr_exit_args *uap)
276    /* long *state */
277{
278	struct proc *p;
279
280	p = td->td_proc;
281
282	/* Signal userland that it can free the stack. */
283	if ((void *)uap->state != NULL) {
284		suword_lwpid(uap->state, 1);
285		kern_umtx_wake(td, uap->state, INT_MAX, 0);
286	}
287
288	rw_wlock(&tidhash_lock);
289	PROC_LOCK(p);
290	/*
291	 * Shutting down last thread in the proc.  This will actually
292	 * call exit() in the trampoline when it returns.
293	 */
294	if (p->p_numthreads != 1) {
295		LIST_REMOVE(td, td_hash);
296		rw_wunlock(&tidhash_lock);
297		tdsigcleanup(td);
298		PROC_SLOCK(p);
299		thread_stopped(p);
300		thread_exit();
301		/* NOTREACHED */
302	}
303	PROC_UNLOCK(p);
304	rw_wunlock(&tidhash_lock);
305	return (0);
306}
307
308int
309thr_kill(struct thread *td, struct thr_kill_args *uap)
310    /* long id, int sig */
311{
312	ksiginfo_t ksi;
313	struct thread *ttd;
314	struct proc *p;
315	int error;
316
317	p = td->td_proc;
318	ksiginfo_init(&ksi);
319	ksi.ksi_signo = uap->sig;
320	ksi.ksi_code = SI_LWP;
321	ksi.ksi_pid = p->p_pid;
322	ksi.ksi_uid = td->td_ucred->cr_ruid;
323	if (uap->id == -1) {
324		if (uap->sig != 0 && !_SIG_VALID(uap->sig)) {
325			error = EINVAL;
326		} else {
327			error = ESRCH;
328			PROC_LOCK(p);
329			FOREACH_THREAD_IN_PROC(p, ttd) {
330				if (ttd != td) {
331					error = 0;
332					if (uap->sig == 0)
333						break;
334					tdksignal(ttd, uap->sig, &ksi);
335				}
336			}
337			PROC_UNLOCK(p);
338		}
339	} else {
340		error = 0;
341		ttd = tdfind((lwpid_t)uap->id, p->p_pid);
342		if (ttd == NULL)
343			return (ESRCH);
344		if (uap->sig == 0)
345			;
346		else if (!_SIG_VALID(uap->sig))
347			error = EINVAL;
348		else
349			tdksignal(ttd, uap->sig, &ksi);
350		PROC_UNLOCK(ttd->td_proc);
351	}
352	return (error);
353}
354
355int
356thr_kill2(struct thread *td, struct thr_kill2_args *uap)
357    /* pid_t pid, long id, int sig */
358{
359	ksiginfo_t ksi;
360	struct thread *ttd;
361	struct proc *p;
362	int error;
363
364	AUDIT_ARG_SIGNUM(uap->sig);
365
366	ksiginfo_init(&ksi);
367	ksi.ksi_signo = uap->sig;
368	ksi.ksi_code = SI_LWP;
369	ksi.ksi_pid = td->td_proc->p_pid;
370	ksi.ksi_uid = td->td_ucred->cr_ruid;
371	if (uap->id == -1) {
372		if ((p = pfind(uap->pid)) == NULL)
373			return (ESRCH);
374		AUDIT_ARG_PROCESS(p);
375		error = p_cansignal(td, p, uap->sig);
376		if (error) {
377			PROC_UNLOCK(p);
378			return (error);
379		}
380		if (uap->sig != 0 && !_SIG_VALID(uap->sig)) {
381			error = EINVAL;
382		} else {
383			error = ESRCH;
384			FOREACH_THREAD_IN_PROC(p, ttd) {
385				if (ttd != td) {
386					error = 0;
387					if (uap->sig == 0)
388						break;
389					tdksignal(ttd, uap->sig, &ksi);
390				}
391			}
392		}
393		PROC_UNLOCK(p);
394	} else {
395		ttd = tdfind((lwpid_t)uap->id, uap->pid);
396		if (ttd == NULL)
397			return (ESRCH);
398		p = ttd->td_proc;
399		AUDIT_ARG_PROCESS(p);
400		error = p_cansignal(td, p, uap->sig);
401		if (uap->sig == 0)
402			;
403		else if (!_SIG_VALID(uap->sig))
404			error = EINVAL;
405		else
406			tdksignal(ttd, uap->sig, &ksi);
407		PROC_UNLOCK(p);
408	}
409	return (error);
410}
411
412int
413thr_suspend(struct thread *td, struct thr_suspend_args *uap)
414	/* const struct timespec *timeout */
415{
416	struct timespec ts, *tsp;
417	int error;
418
419	tsp = NULL;
420	if (uap->timeout != NULL) {
421		error = copyin((const void *)uap->timeout, (void *)&ts,
422		    sizeof(struct timespec));
423		if (error != 0)
424			return (error);
425		tsp = &ts;
426	}
427
428	return (kern_thr_suspend(td, tsp));
429}
430
431int
432kern_thr_suspend(struct thread *td, struct timespec *tsp)
433{
434	struct proc *p = td->td_proc;
435	struct timeval tv;
436	int error = 0;
437	int timo = 0;
438
439	if (td->td_pflags & TDP_WAKEUP) {
440		td->td_pflags &= ~TDP_WAKEUP;
441		return (0);
442	}
443
444	if (tsp != NULL) {
445		if (tsp->tv_nsec < 0 || tsp->tv_nsec > 1000000000)
446			return (EINVAL);
447		if (tsp->tv_sec == 0 && tsp->tv_nsec == 0)
448			error = EWOULDBLOCK;
449		else {
450			TIMESPEC_TO_TIMEVAL(&tv, tsp);
451			timo = tvtohz(&tv);
452		}
453	}
454
455	PROC_LOCK(p);
456	if (error == 0 && (td->td_flags & TDF_THRWAKEUP) == 0)
457		error = msleep((void *)td, &p->p_mtx,
458			 PCATCH, "lthr", timo);
459
460	if (td->td_flags & TDF_THRWAKEUP) {
461		thread_lock(td);
462		td->td_flags &= ~TDF_THRWAKEUP;
463		thread_unlock(td);
464		PROC_UNLOCK(p);
465		return (0);
466	}
467	PROC_UNLOCK(p);
468	if (error == EWOULDBLOCK)
469		error = ETIMEDOUT;
470	else if (error == ERESTART) {
471		if (timo != 0)
472			error = EINTR;
473	}
474	return (error);
475}
476
477int
478thr_wake(struct thread *td, struct thr_wake_args *uap)
479	/* long id */
480{
481	struct proc *p;
482	struct thread *ttd;
483
484	if (uap->id == td->td_tid) {
485		td->td_pflags |= TDP_WAKEUP;
486		return (0);
487	}
488
489	p = td->td_proc;
490	ttd = tdfind((lwpid_t)uap->id, p->p_pid);
491	if (ttd == NULL)
492		return (ESRCH);
493	thread_lock(ttd);
494	ttd->td_flags |= TDF_THRWAKEUP;
495	thread_unlock(ttd);
496	wakeup((void *)ttd);
497	PROC_UNLOCK(p);
498	return (0);
499}
500
501int
502thr_set_name(struct thread *td, struct thr_set_name_args *uap)
503{
504	struct proc *p;
505	char name[MAXCOMLEN + 1];
506	struct thread *ttd;
507	int error;
508
509	error = 0;
510	name[0] = '\0';
511	if (uap->name != NULL) {
512		error = copyinstr(uap->name, name, sizeof(name),
513			NULL);
514		if (error)
515			return (error);
516	}
517	p = td->td_proc;
518	ttd = tdfind((lwpid_t)uap->id, p->p_pid);
519	if (ttd == NULL)
520		return (ESRCH);
521	strcpy(ttd->td_name, name);
522	PROC_UNLOCK(p);
523	return (error);
524}
525