kern_thr.c revision 211733
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 211733 2010-08-24 07:29:55Z davidxu $");
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_FREEBSD32
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(0);
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	tdsigcleanup(td);
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	ksiginfo_t ksi;
307	struct thread *ttd;
308	struct proc *p;
309	int error;
310
311	p = td->td_proc;
312	error = 0;
313	ksiginfo_init(&ksi);
314	ksi.ksi_signo = uap->sig;
315	ksi.ksi_code = SI_LWP;
316	ksi.ksi_pid = p->p_pid;
317	ksi.ksi_uid = td->td_ucred->cr_ruid;
318	PROC_LOCK(p);
319	if (uap->id == -1) {
320		if (uap->sig != 0 && !_SIG_VALID(uap->sig)) {
321			error = EINVAL;
322		} else {
323			error = ESRCH;
324			FOREACH_THREAD_IN_PROC(p, ttd) {
325				if (ttd != td) {
326					error = 0;
327					if (uap->sig == 0)
328						break;
329					tdksignal(ttd, uap->sig, &ksi);
330				}
331			}
332		}
333	} else {
334		if (uap->id != td->td_tid)
335			ttd = thread_find(p, uap->id);
336		else
337			ttd = td;
338		if (ttd == NULL)
339			error = ESRCH;
340		else if (uap->sig == 0)
341			;
342		else if (!_SIG_VALID(uap->sig))
343			error = EINVAL;
344		else
345			tdksignal(ttd, uap->sig, &ksi);
346	}
347	PROC_UNLOCK(p);
348	return (error);
349}
350
351int
352thr_kill2(struct thread *td, struct thr_kill2_args *uap)
353    /* pid_t pid, long id, int sig */
354{
355	ksiginfo_t ksi;
356	struct thread *ttd;
357	struct proc *p;
358	int error;
359
360	AUDIT_ARG_SIGNUM(uap->sig);
361
362	if (uap->pid == td->td_proc->p_pid) {
363		p = td->td_proc;
364		PROC_LOCK(p);
365	} else if ((p = pfind(uap->pid)) == NULL) {
366		return (ESRCH);
367	}
368	AUDIT_ARG_PROCESS(p);
369
370	error = p_cansignal(td, p, uap->sig);
371	if (error == 0) {
372		ksiginfo_init(&ksi);
373		ksi.ksi_signo = uap->sig;
374		ksi.ksi_code = SI_LWP;
375		ksi.ksi_pid = td->td_proc->p_pid;
376		ksi.ksi_uid = td->td_ucred->cr_ruid;
377		if (uap->id == -1) {
378			if (uap->sig != 0 && !_SIG_VALID(uap->sig)) {
379				error = EINVAL;
380			} else {
381				error = ESRCH;
382				FOREACH_THREAD_IN_PROC(p, ttd) {
383					if (ttd != td) {
384						error = 0;
385						if (uap->sig == 0)
386							break;
387						tdksignal(ttd, uap->sig, &ksi);
388					}
389				}
390			}
391		} else {
392			if (uap->id != td->td_tid)
393				ttd = thread_find(p, uap->id);
394			else
395				ttd = td;
396			if (ttd == NULL)
397				error = ESRCH;
398			else if (uap->sig == 0)
399				;
400			else if (!_SIG_VALID(uap->sig))
401				error = EINVAL;
402			else
403				tdksignal(ttd, uap->sig, &ksi);
404		}
405	}
406	PROC_UNLOCK(p);
407	return (error);
408}
409
410int
411thr_suspend(struct thread *td, struct thr_suspend_args *uap)
412	/* const struct timespec *timeout */
413{
414	struct timespec ts, *tsp;
415	int error;
416
417	tsp = NULL;
418	if (uap->timeout != NULL) {
419		error = copyin((const void *)uap->timeout, (void *)&ts,
420		    sizeof(struct timespec));
421		if (error != 0)
422			return (error);
423		tsp = &ts;
424	}
425
426	return (kern_thr_suspend(td, tsp));
427}
428
429int
430kern_thr_suspend(struct thread *td, struct timespec *tsp)
431{
432	struct timeval tv;
433	int error = 0;
434	int timo = 0;
435
436	if (tsp != NULL) {
437		if (tsp->tv_nsec < 0 || tsp->tv_nsec > 1000000000)
438			return (EINVAL);
439	}
440
441	if (td->td_pflags & TDP_WAKEUP) {
442		td->td_pflags &= ~TDP_WAKEUP;
443		return (0);
444	}
445
446	PROC_LOCK(td->td_proc);
447	if ((td->td_flags & TDF_THRWAKEUP) == 0) {
448		if (tsp->tv_sec == 0 && tsp->tv_nsec == 0)
449			error = EWOULDBLOCK;
450		else {
451			TIMESPEC_TO_TIMEVAL(&tv, tsp);
452			timo = tvtohz(&tv);
453			error = msleep((void *)td, &td->td_proc->p_mtx,
454				 PCATCH, "lthr", timo);
455		}
456	}
457
458	if (td->td_flags & TDF_THRWAKEUP) {
459		thread_lock(td);
460		td->td_flags &= ~TDF_THRWAKEUP;
461		thread_unlock(td);
462		PROC_UNLOCK(td->td_proc);
463		return (0);
464	}
465	PROC_UNLOCK(td->td_proc);
466	if (error == EWOULDBLOCK)
467		error = ETIMEDOUT;
468	else if (error == ERESTART) {
469		if (timo != 0)
470			error = EINTR;
471	}
472	return (error);
473}
474
475int
476thr_wake(struct thread *td, struct thr_wake_args *uap)
477	/* long id */
478{
479	struct proc *p;
480	struct thread *ttd;
481
482	if (uap->id == td->td_tid) {
483		td->td_pflags |= TDP_WAKEUP;
484		return (0);
485	}
486
487	p = td->td_proc;
488	PROC_LOCK(p);
489	ttd = thread_find(p, uap->id);
490	if (ttd == NULL) {
491		PROC_UNLOCK(p);
492		return (ESRCH);
493	}
494	thread_lock(ttd);
495	ttd->td_flags |= TDF_THRWAKEUP;
496	thread_unlock(ttd);
497	wakeup((void *)ttd);
498	PROC_UNLOCK(p);
499	return (0);
500}
501
502int
503thr_set_name(struct thread *td, struct thr_set_name_args *uap)
504{
505	struct proc *p = td->td_proc;
506	char name[MAXCOMLEN + 1];
507	struct thread *ttd;
508	int error;
509
510	error = 0;
511	name[0] = '\0';
512	if (uap->name != NULL) {
513		error = copyinstr(uap->name, name, sizeof(name),
514			NULL);
515		if (error)
516			return (error);
517	}
518	PROC_LOCK(p);
519	if (uap->id == td->td_tid)
520		ttd = td;
521	else
522		ttd = thread_find(p, uap->id);
523	if (ttd != NULL)
524		strcpy(ttd->td_name, name);
525	else
526		error = ESRCH;
527	PROC_UNLOCK(p);
528	return (error);
529}
530