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