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$"); 29 30 #include <sys/param.h> 31 #include <sys/kernel.h> 32 #include <sys/lock.h> 33 #include <sys/mutex.h> 34 #include <sys/proc.h> 35 #include <sys/resourcevar.h> 36 #include <sys/sched.h> 37 #include <sys/sysctl.h> 38 #include <sys/smp.h> 39 #include <sys/sysent.h> 40 #include <sys/systm.h> 41 #include <sys/sysproto.h> 42 #include <sys/signalvar.h> 43 #include <sys/ucontext.h> 44 #include <sys/thr.h> 45 46 #include <machine/frame.h> 47 48 extern int max_threads_per_proc; 49 extern int max_groups_per_proc; 50 51 SYSCTL_DECL(_kern_threads); 52 static int thr_scope = 0; 53 SYSCTL_INT(_kern_threads, OID_AUTO, thr_scope, CTLFLAG_RW, 54 &thr_scope, 0, "sys or proc scope scheduling"); 55 56 static int thr_concurrency = 0; 57 SYSCTL_INT(_kern_threads, OID_AUTO, thr_concurrency, CTLFLAG_RW, 58 &thr_concurrency, 0, "a concurrency value if not default"); 59 60 static int create_thread(struct thread *td, mcontext_t *ctx, 61 void (*start_func)(void *), void *arg, 62 char *stack_base, size_t stack_size, 63 char *tls_base, 64 long *child_tid, long *parent_tid, 65 int flags); 66 67 /* 68 * System call interface. 69 */ 70 int 71 thr_create(struct thread *td, struct thr_create_args *uap) 72 /* ucontext_t *ctx, long *id, int flags */ 73 { 74 ucontext_t ctx; 75 int error; 76 77 if ((error = copyin(uap->ctx, &ctx, sizeof(ctx)))) 78 return (error); 79 80 error = create_thread(td, &ctx.uc_mcontext, NULL, NULL, 81 NULL, 0, NULL, uap->id, NULL, uap->flags); 82 return (error); 83 } 84 85 int 86 thr_new(struct thread *td, struct thr_new_args *uap) 87 /* struct thr_param * */ 88 { 89 struct thr_param param; 90 int error; 91 92 if (uap->param_size < sizeof(param)) 93 return (EINVAL); 94 if ((error = copyin(uap->param, ¶m, sizeof(param)))) 95 return (error); 96 error = create_thread(td, NULL, param.start_func, param.arg, 97 param.stack_base, param.stack_size, param.tls_base, 98 param.child_tid, param.parent_tid, param.flags); 99 return (error); 100 } 101 102 static int 103 create_thread(struct thread *td, mcontext_t *ctx, 104 void (*start_func)(void *), void *arg, 105 char *stack_base, size_t stack_size, 106 char *tls_base, 107 long *child_tid, long *parent_tid, 108 int flags) 109 { 110 stack_t stack; 111 struct thread *newtd; 112 struct ksegrp *kg, *newkg; 113 struct proc *p; 114 long id; 115 int error, scope_sys, linkkg; 116 117 error = 0; 118 p = td->td_proc; 119 kg = td->td_ksegrp; 120 121 /* Have race condition but it is cheap. */ 122 if ((p->p_numksegrps >= max_groups_per_proc) || 123 (p->p_numthreads >= max_threads_per_proc)) { 124 return (EPROCLIM); 125 } 126 127 /* Check PTHREAD_SCOPE_SYSTEM */ 128 scope_sys = (flags & THR_SYSTEM_SCOPE) != 0; 129 130 /* sysctl overrides user's flag */ 131 if (thr_scope == 1) 132 scope_sys = 0; 133 else if (thr_scope == 2) 134 scope_sys = 1; 135 136 /* Initialize our td and new ksegrp.. */ 137 newtd = thread_alloc(); 138 139 /* 140 * Try the copyout as soon as we allocate the td so we don't 141 * have to tear things down in a failure case below. 142 * Here we copy out tid to two places, one for child and one 143 * for parent, because pthread can create a detached thread, 144 * if parent wants to safely access child tid, it has to provide 145 * its storage, because child thread may exit quickly and 146 * memory is freed before parent thread can access it. 147 */ 148 id = newtd->td_tid; 149 if ((child_tid != NULL && 150 (error = copyout(&id, child_tid, sizeof(long)))) || 151 (parent_tid != NULL && 152 (error = copyout(&id, parent_tid, sizeof(long))))) { 153 thread_free(newtd); 154 return (error); 155 } 156 bzero(&newtd->td_startzero, 157 __rangeof(struct thread, td_startzero, td_endzero)); 158 bcopy(&td->td_startcopy, &newtd->td_startcopy, 159 __rangeof(struct thread, td_startcopy, td_endcopy)); 160 newtd->td_proc = td->td_proc; 161 newtd->td_ucred = crhold(td->td_ucred); 162 163 cpu_set_upcall(newtd, td); 164 165 if (ctx != NULL) { /* old way to set user context */ 166 error = set_mcontext(newtd, ctx); 167 if (error != 0) { 168 thread_free(newtd); 169 crfree(td->td_ucred); 170 return (error); 171 } 172 } else { 173 /* Set up our machine context. */ 174 stack.ss_sp = stack_base; 175 stack.ss_size = stack_size; 176 /* Set upcall address to user thread entry function. */ 177 cpu_set_upcall_kse(newtd, start_func, arg, &stack); 178 /* Setup user TLS address and TLS pointer register. */ 179 error = cpu_set_user_tls(newtd, tls_base); 180 if (error != 0) { 181 thread_free(newtd); 182 crfree(td->td_ucred); 183 return (error); 184 } 185 } 186 187 if ((td->td_proc->p_flag & P_HADTHREADS) == 0) { 188 /* Treat initial thread as it has PTHREAD_SCOPE_PROCESS. */ 189 p->p_procscopegrp = kg; 190 mtx_lock_spin(&sched_lock); 191 sched_set_concurrency(kg, 192 thr_concurrency ? thr_concurrency : (2*mp_ncpus)); 193 mtx_unlock_spin(&sched_lock); 194 } 195 196 linkkg = 0; 197 if (scope_sys) { 198 linkkg = 1; 199 newkg = ksegrp_alloc(); 200 bzero(&newkg->kg_startzero, 201 __rangeof(struct ksegrp, kg_startzero, kg_endzero)); 202 bcopy(&kg->kg_startcopy, &newkg->kg_startcopy, 203 __rangeof(struct ksegrp, kg_startcopy, kg_endcopy)); 204 sched_init_concurrency(newkg); 205 PROC_LOCK(td->td_proc); 206 } else { 207 /* 208 * Try to create a KSE group which will be shared 209 * by all PTHREAD_SCOPE_PROCESS threads. 210 */ 211 retry: 212 PROC_LOCK(td->td_proc); 213 if ((newkg = p->p_procscopegrp) == NULL) { 214 PROC_UNLOCK(p); 215 newkg = ksegrp_alloc(); 216 bzero(&newkg->kg_startzero, 217 __rangeof(struct ksegrp, kg_startzero, kg_endzero)); 218 bcopy(&kg->kg_startcopy, &newkg->kg_startcopy, 219 __rangeof(struct ksegrp, kg_startcopy, kg_endcopy)); 220 PROC_LOCK(p); 221 if (p->p_procscopegrp == NULL) { 222 p->p_procscopegrp = newkg; 223 sched_init_concurrency(newkg); 224 sched_set_concurrency(newkg, 225 thr_concurrency ? thr_concurrency : (2*mp_ncpus)); 226 linkkg = 1; 227 } else { 228 PROC_UNLOCK(p); 229 ksegrp_free(newkg); 230 goto retry; 231 } 232 } 233 } 234 235 td->td_proc->p_flag |= P_HADTHREADS; 236 newtd->td_sigmask = td->td_sigmask; 237 mtx_lock_spin(&sched_lock); 238 if (linkkg) 239 ksegrp_link(newkg, p); 240 thread_link(newtd, newkg); 241 PROC_UNLOCK(p); 242 243 /* let the scheduler know about these things. */ 244 if (linkkg) 245 sched_fork_ksegrp(td, newkg); 246 sched_fork_thread(td, newtd); 247 TD_SET_CAN_RUN(newtd); 248 /* if ((flags & THR_SUSPENDED) == 0) */ 249 setrunqueue(newtd, SRQ_BORING); 250 mtx_unlock_spin(&sched_lock); 251 252 return (error); 253 } 254 255 int 256 thr_self(struct thread *td, struct thr_self_args *uap) 257 /* long *id */ 258 { 259 long id; 260 int error; 261 262 id = td->td_tid; 263 if ((error = copyout(&id, uap->id, sizeof(long)))) 264 return (error); 265 266 return (0); 267 } 268 269 int 270 thr_exit(struct thread *td, struct thr_exit_args *uap) 271 /* long *state */ 272 { 273 struct proc *p; 274 275 p = td->td_proc; 276 277 /* Signal userland that it can free the stack. */ 278 if ((void *)uap->state != NULL) 279 suword((void *)uap->state, 1); 280 281 PROC_LOCK(p); 282 mtx_lock_spin(&sched_lock); 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_exit(); 290 /* NOTREACHED */ 291 } 292 mtx_unlock_spin(&sched_lock); 293 PROC_UNLOCK(p); 294 return (0); 295 } 296 297 int 298 thr_kill(struct thread *td, struct thr_kill_args *uap) 299 /* long id, int sig */ 300 { 301 struct thread *ttd; 302 struct proc *p; 303 int error; 304 305 p = td->td_proc; 306 error = 0; 307 PROC_LOCK(p); 308 FOREACH_THREAD_IN_PROC(p, ttd) { 309 if (ttd->td_tid == uap->id) 310 break; 311 } 312 if (ttd == NULL) { 313 error = ESRCH; 314 goto out; 315 } 316 if (uap->sig == 0) 317 goto out; 318 if (!_SIG_VALID(uap->sig)) { 319 error = EINVAL; 320 goto out; 321 } 322 tdsignal(ttd, uap->sig, SIGTARGET_TD); 323 out: 324 PROC_UNLOCK(p); 325 return (error); 326 } 327 328 int 329 thr_suspend(struct thread *td, struct thr_suspend_args *uap) 330 /* const struct timespec *timeout */ 331 { 332 struct timespec ts; 333 struct timeval tv; 334 int error; 335 int hz; 336 337 hz = 0; 338 error = 0; 339 if (uap->timeout != NULL) { 340 error = copyin((const void *)uap->timeout, (void *)&ts, 341 sizeof(struct timespec)); 342 if (error != 0) 343 return (error); 344 if (ts.tv_nsec < 0 || ts.tv_nsec > 1000000000) 345 return (EINVAL); 346 if (ts.tv_sec == 0 && ts.tv_nsec == 0) 347 return (ETIMEDOUT); 348 TIMESPEC_TO_TIMEVAL(&tv, &ts); 349 hz = tvtohz(&tv); 350 } 351 PROC_LOCK(td->td_proc); 352 if ((td->td_flags & TDF_THRWAKEUP) == 0) 353 error = msleep((void *)td, &td->td_proc->p_mtx, 354 td->td_priority | PCATCH, "lthr", hz); 355 if (td->td_flags & TDF_THRWAKEUP) { 356 mtx_lock_spin(&sched_lock); 357 td->td_flags &= ~TDF_THRWAKEUP; 358 mtx_unlock_spin(&sched_lock); 359 PROC_UNLOCK(td->td_proc); 360 return (0); 361 } 362 PROC_UNLOCK(td->td_proc); 363 if (error == EWOULDBLOCK) 364 error = ETIMEDOUT; 365 else if (error == ERESTART) { 366 if (hz != 0) 367 error = EINTR; 368 } 369 return (error); 370 } 371 372 int 373 thr_wake(struct thread *td, struct thr_wake_args *uap) 374 /* long id */ 375 { 376 struct thread *ttd; 377 378 PROC_LOCK(td->td_proc); 379 FOREACH_THREAD_IN_PROC(td->td_proc, ttd) { 380 if (ttd->td_tid == uap->id) 381 break; 382 } 383 if (ttd == NULL) { 384 PROC_UNLOCK(td->td_proc); 385 return (ESRCH); 386 } 387 mtx_lock_spin(&sched_lock); 388 ttd->td_flags |= TDF_THRWAKEUP; 389 mtx_unlock_spin(&sched_lock); 390 wakeup((void *)ttd); 391 PROC_UNLOCK(td->td_proc); 392 return (0); 393 } 394