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 cpu_set_user_tls(newtd, tls_base); 180 } 181 182 if ((td->td_proc->p_flag & P_HADTHREADS) == 0) { 183 /* Treat initial thread as it has PTHREAD_SCOPE_PROCESS. */ 184 p->p_procscopegrp = kg; 185 mtx_lock_spin(&sched_lock); 186 sched_set_concurrency(kg, 187 thr_concurrency ? thr_concurrency : (2*mp_ncpus)); 188 mtx_unlock_spin(&sched_lock); 189 } 190 191 linkkg = 0; 192 if (scope_sys) { 193 linkkg = 1; 194 newkg = ksegrp_alloc(); 195 bzero(&newkg->kg_startzero, 196 __rangeof(struct ksegrp, kg_startzero, kg_endzero)); 197 bcopy(&kg->kg_startcopy, &newkg->kg_startcopy, 198 __rangeof(struct ksegrp, kg_startcopy, kg_endcopy)); 199 sched_init_concurrency(newkg); 200 PROC_LOCK(td->td_proc); 201 } else { 202 /* 203 * Try to create a KSE group which will be shared 204 * by all PTHREAD_SCOPE_PROCESS threads. 205 */ 206 retry: 207 PROC_LOCK(td->td_proc); 208 if ((newkg = p->p_procscopegrp) == NULL) { 209 PROC_UNLOCK(p); 210 newkg = ksegrp_alloc(); 211 bzero(&newkg->kg_startzero, 212 __rangeof(struct ksegrp, kg_startzero, kg_endzero)); 213 bcopy(&kg->kg_startcopy, &newkg->kg_startcopy, 214 __rangeof(struct ksegrp, kg_startcopy, kg_endcopy)); 215 PROC_LOCK(p); 216 if (p->p_procscopegrp == NULL) { 217 p->p_procscopegrp = newkg; 218 sched_init_concurrency(newkg); 219 sched_set_concurrency(newkg, 220 thr_concurrency ? thr_concurrency : (2*mp_ncpus)); 221 linkkg = 1; 222 } else { 223 PROC_UNLOCK(p); 224 ksegrp_free(newkg); 225 goto retry; 226 } 227 } 228 } 229 230 td->td_proc->p_flag |= P_HADTHREADS; 231 newtd->td_sigmask = td->td_sigmask; 232 mtx_lock_spin(&sched_lock); 233 if (linkkg) 234 ksegrp_link(newkg, p); 235 thread_link(newtd, newkg); 236 PROC_UNLOCK(p); 237 238 /* let the scheduler know about these things. */ 239 if (linkkg) 240 sched_fork_ksegrp(td, newkg); 241 sched_fork_thread(td, newtd); 242 TD_SET_CAN_RUN(newtd); 243 /* if ((flags & THR_SUSPENDED) == 0) */ 244 setrunqueue(newtd, SRQ_BORING); 245 mtx_unlock_spin(&sched_lock); 246 247 return (error); 248 } 249 250 int 251 thr_self(struct thread *td, struct thr_self_args *uap) 252 /* long *id */ 253 { 254 long id; 255 int error; 256 257 id = td->td_tid; 258 if ((error = copyout(&id, uap->id, sizeof(long)))) 259 return (error); 260 261 return (0); 262 } 263 264 int 265 thr_exit(struct thread *td, struct thr_exit_args *uap) 266 /* long *state */ 267 { 268 struct proc *p; 269 270 p = td->td_proc; 271 272 /* Signal userland that it can free the stack. */ 273 if ((void *)uap->state != NULL) 274 suword((void *)uap->state, 1); 275 276 PROC_LOCK(p); 277 mtx_lock_spin(&sched_lock); 278 279 /* 280 * Shutting down last thread in the proc. This will actually 281 * call exit() in the trampoline when it returns. 282 */ 283 if (p->p_numthreads != 1) { 284 thread_exit(); 285 /* NOTREACHED */ 286 } 287 mtx_unlock_spin(&sched_lock); 288 PROC_UNLOCK(p); 289 return (0); 290 } 291 292 int 293 thr_kill(struct thread *td, struct thr_kill_args *uap) 294 /* long id, int sig */ 295 { 296 struct thread *ttd; 297 struct proc *p; 298 int error; 299 300 p = td->td_proc; 301 error = 0; 302 PROC_LOCK(p); 303 FOREACH_THREAD_IN_PROC(p, ttd) { 304 if (ttd->td_tid == uap->id) 305 break; 306 } 307 if (ttd == NULL) { 308 error = ESRCH; 309 goto out; 310 } 311 if (uap->sig == 0) 312 goto out; 313 if (!_SIG_VALID(uap->sig)) { 314 error = EINVAL; 315 goto out; 316 } 317 tdsignal(ttd, uap->sig, SIGTARGET_TD); 318 out: 319 PROC_UNLOCK(p); 320 return (error); 321 } 322 323 int 324 thr_suspend(struct thread *td, struct thr_suspend_args *uap) 325 /* const struct timespec *timeout */ 326 { 327 struct timespec ts; 328 struct timeval tv; 329 int error; 330 int hz; 331 332 hz = 0; 333 error = 0; 334 if (uap->timeout != NULL) { 335 error = copyin((const void *)uap->timeout, (void *)&ts, 336 sizeof(struct timespec)); 337 if (error != 0) 338 return (error); 339 if (ts.tv_nsec < 0 || ts.tv_nsec > 1000000000) 340 return (EINVAL); 341 if (ts.tv_sec == 0 && ts.tv_nsec == 0) 342 return (ETIMEDOUT); 343 TIMESPEC_TO_TIMEVAL(&tv, &ts); 344 hz = tvtohz(&tv); 345 } 346 PROC_LOCK(td->td_proc); 347 if ((td->td_flags & TDF_THRWAKEUP) == 0) 348 error = msleep((void *)td, &td->td_proc->p_mtx, 349 td->td_priority | PCATCH, "lthr", hz); 350 if (td->td_flags & TDF_THRWAKEUP) { 351 mtx_lock_spin(&sched_lock); 352 td->td_flags &= ~TDF_THRWAKEUP; 353 mtx_unlock_spin(&sched_lock); 354 PROC_UNLOCK(td->td_proc); 355 return (0); 356 } 357 PROC_UNLOCK(td->td_proc); 358 if (error == EWOULDBLOCK) 359 error = ETIMEDOUT; 360 else if (error == ERESTART) { 361 if (hz != 0) 362 error = EINTR; 363 } 364 return (error); 365 } 366 367 int 368 thr_wake(struct thread *td, struct thr_wake_args *uap) 369 /* long id */ 370 { 371 struct thread *ttd; 372 373 PROC_LOCK(td->td_proc); 374 FOREACH_THREAD_IN_PROC(td->td_proc, ttd) { 375 if (ttd->td_tid == uap->id) 376 break; 377 } 378 if (ttd == NULL) { 379 PROC_UNLOCK(td->td_proc); 380 return (ESRCH); 381 } 382 mtx_lock_spin(&sched_lock); 383 ttd->td_flags |= TDF_THRWAKEUP; 384 mtx_unlock_spin(&sched_lock); 385 wakeup((void *)ttd); 386 PROC_UNLOCK(td->td_proc); 387 return (0); 388 } 389