kern_thr.c revision 164188
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 164188 2006-11-11 16:46:31Z trhodes $"); 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/sysent.h> 44#include <sys/systm.h> 45#include <sys/sysproto.h> 46#include <sys/signalvar.h> 47#include <sys/ucontext.h> 48#include <sys/thr.h> 49#include <sys/rtprio.h> 50#include <sys/umtx.h> 51#include <sys/limits.h> 52 53#include <machine/frame.h> 54 55#ifdef COMPAT_IA32 56 57extern struct sysentvec ia32_freebsd_sysvec; 58 59static inline int 60suword_lwpid(void *addr, lwpid_t lwpid) 61{ 62 int error; 63 64 if (curproc->p_sysent != &ia32_freebsd_sysvec) 65 error = suword(addr, lwpid); 66 else 67 error = suword32(addr, lwpid); 68 return (error); 69} 70 71#else 72#define suword_lwpid suword 73#endif 74 75extern int max_threads_per_proc; 76 77static int create_thread(struct thread *td, mcontext_t *ctx, 78 void (*start_func)(void *), void *arg, 79 char *stack_base, size_t stack_size, 80 char *tls_base, 81 long *child_tid, long *parent_tid, 82 int flags, struct rtprio *rtp); 83 84/* 85 * System call interface. 86 */ 87int 88thr_create(struct thread *td, struct thr_create_args *uap) 89 /* ucontext_t *ctx, long *id, int flags */ 90{ 91 ucontext_t ctx; 92 int error; 93 94 if ((error = copyin(uap->ctx, &ctx, sizeof(ctx)))) 95 return (error); 96 97 error = create_thread(td, &ctx.uc_mcontext, NULL, NULL, 98 NULL, 0, NULL, uap->id, NULL, uap->flags, NULL); 99 return (error); 100} 101 102int 103thr_new(struct thread *td, struct thr_new_args *uap) 104 /* struct thr_param * */ 105{ 106 struct thr_param param; 107 int error; 108 109 if (uap->param_size < 0 || uap->param_size > sizeof(param)) 110 return (EINVAL); 111 bzero(¶m, sizeof(param)); 112 if ((error = copyin(uap->param, ¶m, uap->param_size))) 113 return (error); 114 return (kern_thr_new(td, ¶m)); 115} 116 117int 118kern_thr_new(struct thread *td, struct thr_param *param) 119{ 120 struct rtprio rtp, *rtpp; 121 int error; 122 123 rtpp = NULL; 124 if (param->rtp != 0) { 125 error = copyin(param->rtp, &rtp, sizeof(struct rtprio)); 126 rtpp = &rtp; 127 } 128 error = create_thread(td, NULL, param->start_func, param->arg, 129 param->stack_base, param->stack_size, param->tls_base, 130 param->child_tid, param->parent_tid, param->flags, 131 rtpp); 132 return (error); 133} 134 135static int 136create_thread(struct thread *td, mcontext_t *ctx, 137 void (*start_func)(void *), void *arg, 138 char *stack_base, size_t stack_size, 139 char *tls_base, 140 long *child_tid, long *parent_tid, 141 int flags, struct rtprio *rtp) 142{ 143 stack_t stack; 144 struct thread *newtd; 145#ifdef KSE 146 struct ksegrp *kg, *newkg; 147#endif 148 struct proc *p; 149 long id; 150 int error; 151 152 error = 0; 153 p = td->td_proc; 154#ifdef KSE 155 kg = td->td_ksegrp; 156#endif 157 158 /* Have race condition but it is cheap. */ 159 if (p->p_numthreads >= max_threads_per_proc) 160 return (EPROCLIM); 161 162 if (rtp != NULL) { 163 switch(rtp->type) { 164 case RTP_PRIO_REALTIME: 165 case RTP_PRIO_FIFO: 166 /* Only root can set scheduler policy */ 167 if (priv_check(td, PRIV_SCHED_SETPOLICY) != 0) 168 return (EPERM); 169 if (rtp->prio > RTP_PRIO_MAX) 170 return (EINVAL); 171 break; 172 case RTP_PRIO_NORMAL: 173 rtp->prio = 0; 174 break; 175 default: 176 return (EINVAL); 177 } 178 } 179 180 /* Initialize our td and new ksegrp.. */ 181 newtd = thread_alloc(); 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 id = newtd->td_tid; 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#ifdef KSE 233 newkg = ksegrp_alloc(); 234 bzero(&newkg->kg_startzero, 235 __rangeof(struct ksegrp, kg_startzero, kg_endzero)); 236 bcopy(&kg->kg_startcopy, &newkg->kg_startcopy, 237 __rangeof(struct ksegrp, kg_startcopy, kg_endcopy)); 238 sched_init_concurrency(newkg); 239 PROC_LOCK(td->td_proc); 240 td->td_proc->p_flag |= P_HADTHREADS; 241 newtd->td_sigmask = td->td_sigmask; 242 mtx_lock_spin(&sched_lock); 243 ksegrp_link(newkg, p); 244 thread_link(newtd, newkg); 245 PROC_UNLOCK(p); 246#else 247 PROC_LOCK(td->td_proc); 248 td->td_proc->p_flag |= P_HADTHREADS; 249 newtd->td_sigmask = td->td_sigmask; 250 mtx_lock_spin(&sched_lock); 251 thread_link(newtd, p); 252 PROC_UNLOCK(p); 253#endif 254 255#ifdef KSE 256 /* let the scheduler know about these things. */ 257 sched_fork_ksegrp(td, newkg); 258 sched_fork_thread(td, newtd); 259 if (rtp != NULL) { 260 if (!(kg->kg_pri_class == PRI_TIMESHARE && 261 rtp->type == RTP_PRIO_NORMAL)) { 262 rtp_to_pri(rtp, newkg); 263 sched_prio(newtd, newkg->kg_user_pri); 264 } /* ignore timesharing class */ 265 } 266#else 267 sched_fork(td, newtd); 268 if (rtp != NULL) { 269 if (!(td->td_pri_class == PRI_TIMESHARE && 270 rtp->type == RTP_PRIO_NORMAL)) { 271 rtp_to_pri(rtp, newtd); 272 sched_prio(newtd, newtd->td_user_pri); 273 } /* ignore timesharing class */ 274 } 275#endif 276 TD_SET_CAN_RUN(newtd); 277 /* if ((flags & THR_SUSPENDED) == 0) */ 278 setrunqueue(newtd, SRQ_BORING); 279 mtx_unlock_spin(&sched_lock); 280 281 return (error); 282} 283 284int 285thr_self(struct thread *td, struct thr_self_args *uap) 286 /* long *id */ 287{ 288 int error; 289 290 error = suword_lwpid(uap->id, (unsigned)td->td_tid); 291 if (error == -1) 292 return (EFAULT); 293 return (0); 294} 295 296int 297thr_exit(struct thread *td, struct thr_exit_args *uap) 298 /* long *state */ 299{ 300 struct proc *p; 301 302 p = td->td_proc; 303 304 /* Signal userland that it can free the stack. */ 305 if ((void *)uap->state != NULL) { 306 suword_lwpid(uap->state, 1); 307 kern_umtx_wake(td, uap->state, INT_MAX); 308 } 309 310 PROC_LOCK(p); 311 sigqueue_flush(&td->td_sigqueue); 312 mtx_lock_spin(&sched_lock); 313 314 /* 315 * Shutting down last thread in the proc. This will actually 316 * call exit() in the trampoline when it returns. 317 */ 318 if (p->p_numthreads != 1) { 319 thread_stopped(p); 320 thread_exit(); 321 /* NOTREACHED */ 322 } 323 mtx_unlock_spin(&sched_lock); 324 PROC_UNLOCK(p); 325 return (0); 326} 327 328int 329thr_kill(struct thread *td, struct thr_kill_args *uap) 330 /* long id, int sig */ 331{ 332 struct thread *ttd; 333 struct proc *p; 334 int error; 335 336 p = td->td_proc; 337 error = 0; 338 PROC_LOCK(p); 339 if (uap->id == -1) { 340 if (uap->sig != 0 && !_SIG_VALID(uap->sig)) { 341 error = EINVAL; 342 } else { 343 error = ESRCH; 344 FOREACH_THREAD_IN_PROC(p, ttd) { 345 if (ttd != td) { 346 error = 0; 347 if (uap->sig == 0) 348 break; 349 tdsignal(p, ttd, uap->sig, NULL); 350 } 351 } 352 } 353 } else { 354 if (uap->id != td->td_tid) 355 ttd = thread_find(p, uap->id); 356 else 357 ttd = td; 358 if (ttd == NULL) 359 error = ESRCH; 360 else if (uap->sig == 0) 361 ; 362 else if (!_SIG_VALID(uap->sig)) 363 error = EINVAL; 364 else 365 tdsignal(p, ttd, uap->sig, NULL); 366 } 367 PROC_UNLOCK(p); 368 return (error); 369} 370 371int 372thr_suspend(struct thread *td, struct thr_suspend_args *uap) 373 /* const struct timespec *timeout */ 374{ 375 struct timespec ts, *tsp; 376 int error; 377 378 error = 0; 379 tsp = NULL; 380 if (uap->timeout != NULL) { 381 error = copyin((const void *)uap->timeout, (void *)&ts, 382 sizeof(struct timespec)); 383 if (error != 0) 384 return (error); 385 tsp = &ts; 386 } 387 388 return (kern_thr_suspend(td, tsp)); 389} 390 391int 392kern_thr_suspend(struct thread *td, struct timespec *tsp) 393{ 394 struct timeval tv; 395 int error = 0, hz = 0; 396 397 if (tsp != NULL) { 398 if (tsp->tv_nsec < 0 || tsp->tv_nsec > 1000000000) 399 return (EINVAL); 400 if (tsp->tv_sec == 0 && tsp->tv_nsec == 0) 401 return (ETIMEDOUT); 402 TIMESPEC_TO_TIMEVAL(&tv, tsp); 403 hz = tvtohz(&tv); 404 } 405 PROC_LOCK(td->td_proc); 406 if ((td->td_flags & TDF_THRWAKEUP) == 0) 407 error = msleep((void *)td, &td->td_proc->p_mtx, PCATCH, "lthr", 408 hz); 409 if (td->td_flags & TDF_THRWAKEUP) { 410 mtx_lock_spin(&sched_lock); 411 td->td_flags &= ~TDF_THRWAKEUP; 412 mtx_unlock_spin(&sched_lock); 413 PROC_UNLOCK(td->td_proc); 414 return (0); 415 } 416 PROC_UNLOCK(td->td_proc); 417 if (error == EWOULDBLOCK) 418 error = ETIMEDOUT; 419 else if (error == ERESTART) { 420 if (hz != 0) 421 error = EINTR; 422 } 423 return (error); 424} 425 426int 427thr_wake(struct thread *td, struct thr_wake_args *uap) 428 /* long id */ 429{ 430 struct proc *p; 431 struct thread *ttd; 432 433 p = td->td_proc; 434 PROC_LOCK(p); 435 ttd = thread_find(p, uap->id); 436 if (ttd == NULL) { 437 PROC_UNLOCK(p); 438 return (ESRCH); 439 } 440 mtx_lock_spin(&sched_lock); 441 ttd->td_flags |= TDF_THRWAKEUP; 442 mtx_unlock_spin(&sched_lock); 443 wakeup((void *)ttd); 444 PROC_UNLOCK(p); 445 return (0); 446} 447 448int 449thr_set_name(struct thread *td, struct thr_set_name_args *uap) 450{ 451 struct proc *p = td->td_proc; 452 char name[MAXCOMLEN + 1]; 453 struct thread *ttd; 454 int error; 455 456 error = 0; 457 name[0] = '\0'; 458 if (uap->name != NULL) { 459 error = copyinstr(uap->name, name, sizeof(name), 460 NULL); 461 if (error) 462 return (error); 463 } 464 PROC_LOCK(p); 465 if (uap->id == td->td_tid) 466 ttd = td; 467 else 468 ttd = thread_find(p, uap->id); 469 if (ttd != NULL) 470 strcpy(ttd->td_name, name); 471 else 472 error = ESRCH; 473 PROC_UNLOCK(p); 474 return (error); 475} 476