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