19454b2d8SWarner Losh /*- 289bb1cefSJeff Roberson * Copyright (c) 2003, Jeffrey Roberson <jeff@freebsd.org> 389bb1cefSJeff Roberson * All rights reserved. 489bb1cefSJeff Roberson * 589bb1cefSJeff Roberson * Redistribution and use in source and binary forms, with or without 689bb1cefSJeff Roberson * modification, are permitted provided that the following conditions 789bb1cefSJeff Roberson * are met: 889bb1cefSJeff Roberson * 1. Redistributions of source code must retain the above copyright 989bb1cefSJeff Roberson * notice unmodified, this list of conditions, and the following 1089bb1cefSJeff Roberson * disclaimer. 1189bb1cefSJeff Roberson * 2. Redistributions in binary form must reproduce the above copyright 1289bb1cefSJeff Roberson * notice, this list of conditions and the following disclaimer in the 1389bb1cefSJeff Roberson * documentation and/or other materials provided with the distribution. 1489bb1cefSJeff Roberson * 1589bb1cefSJeff Roberson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1689bb1cefSJeff Roberson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1789bb1cefSJeff Roberson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1889bb1cefSJeff Roberson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1989bb1cefSJeff Roberson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2089bb1cefSJeff Roberson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2189bb1cefSJeff Roberson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2289bb1cefSJeff Roberson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2389bb1cefSJeff Roberson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2489bb1cefSJeff Roberson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2589bb1cefSJeff Roberson */ 2689bb1cefSJeff Roberson 27677b542eSDavid E. O'Brien #include <sys/cdefs.h> 28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 29677b542eSDavid E. O'Brien 3089bb1cefSJeff Roberson #include <sys/param.h> 3189bb1cefSJeff Roberson #include <sys/kernel.h> 3289bb1cefSJeff Roberson #include <sys/lock.h> 3389bb1cefSJeff Roberson #include <sys/mutex.h> 3489bb1cefSJeff Roberson #include <sys/proc.h> 3589bb1cefSJeff Roberson #include <sys/resourcevar.h> 36a22ec9d8SJeff Roberson #include <sys/sched.h> 37a8b491c1SJulian Elischer #include <sys/sysctl.h> 38ed062c8dSJulian Elischer #include <sys/smp.h> 3989bb1cefSJeff Roberson #include <sys/sysent.h> 4089bb1cefSJeff Roberson #include <sys/systm.h> 4189bb1cefSJeff Roberson #include <sys/sysproto.h> 4289bb1cefSJeff Roberson #include <sys/signalvar.h> 4389bb1cefSJeff Roberson #include <sys/ucontext.h> 4489bb1cefSJeff Roberson #include <sys/thr.h> 4589bb1cefSJeff Roberson 4689bb1cefSJeff Roberson #include <machine/frame.h> 4789bb1cefSJeff Roberson 48ed062c8dSJulian Elischer extern int max_threads_per_proc; 49ed062c8dSJulian Elischer extern int max_groups_per_proc; 50ed062c8dSJulian Elischer 51a8b491c1SJulian Elischer SYSCTL_DECL(_kern_threads); 52c4bd610fSDavid Xu static int thr_scope = 0; 53c4bd610fSDavid Xu SYSCTL_INT(_kern_threads, OID_AUTO, thr_scope, CTLFLAG_RW, 54c4bd610fSDavid Xu &thr_scope, 0, "sys or proc scope scheduling"); 55a8b491c1SJulian Elischer 5624640982SJulian Elischer static int thr_concurrency = 0; 57a8b491c1SJulian Elischer SYSCTL_INT(_kern_threads, OID_AUTO, thr_concurrency, CTLFLAG_RW, 58a8b491c1SJulian Elischer &thr_concurrency, 0, "a concurrency value if not default"); 59a8b491c1SJulian Elischer 60c4bd610fSDavid Xu static int create_thread(struct thread *td, mcontext_t *ctx, 61c4bd610fSDavid Xu void (*start_func)(void *), void *arg, 62c4bd610fSDavid Xu char *stack_base, size_t stack_size, 63c4bd610fSDavid Xu char *tls_base, 64c4bd610fSDavid Xu long *child_tid, long *parent_tid, 65c4bd610fSDavid Xu int flags); 66c4bd610fSDavid Xu 6789bb1cefSJeff Roberson /* 6889bb1cefSJeff Roberson * System call interface. 6989bb1cefSJeff Roberson */ 7089bb1cefSJeff Roberson int 7189bb1cefSJeff Roberson thr_create(struct thread *td, struct thr_create_args *uap) 72cd28f17dSMarcel Moolenaar /* ucontext_t *ctx, long *id, int flags */ 7389bb1cefSJeff Roberson { 7489bb1cefSJeff Roberson ucontext_t ctx; 7589bb1cefSJeff Roberson int error; 7689bb1cefSJeff Roberson 7789bb1cefSJeff Roberson if ((error = copyin(uap->ctx, &ctx, sizeof(ctx)))) 7889bb1cefSJeff Roberson return (error); 7989bb1cefSJeff Roberson 80c4bd610fSDavid Xu error = create_thread(td, &ctx.uc_mcontext, NULL, NULL, 81c4bd610fSDavid Xu NULL, 0, NULL, uap->id, NULL, uap->flags); 82c4bd610fSDavid Xu return (error); 83c4bd610fSDavid Xu } 84c4bd610fSDavid Xu 85c4bd610fSDavid Xu int 86c4bd610fSDavid Xu thr_new(struct thread *td, struct thr_new_args *uap) 87c4bd610fSDavid Xu /* struct thr_param * */ 88c4bd610fSDavid Xu { 89c4bd610fSDavid Xu struct thr_param param; 90c4bd610fSDavid Xu int error; 91c4bd610fSDavid Xu 92c4bd610fSDavid Xu if (uap->param_size < sizeof(param)) 93c4bd610fSDavid Xu return (EINVAL); 94c4bd610fSDavid Xu if ((error = copyin(uap->param, ¶m, sizeof(param)))) 95c4bd610fSDavid Xu return (error); 96c4bd610fSDavid Xu error = create_thread(td, NULL, param.start_func, param.arg, 97c4bd610fSDavid Xu param.stack_base, param.stack_size, param.tls_base, 98c4bd610fSDavid Xu param.child_tid, param.parent_tid, param.flags); 99c4bd610fSDavid Xu return (error); 100c4bd610fSDavid Xu } 101c4bd610fSDavid Xu 102c4bd610fSDavid Xu static int 103c4bd610fSDavid Xu create_thread(struct thread *td, mcontext_t *ctx, 104c4bd610fSDavid Xu void (*start_func)(void *), void *arg, 105c4bd610fSDavid Xu char *stack_base, size_t stack_size, 106c4bd610fSDavid Xu char *tls_base, 107c4bd610fSDavid Xu long *child_tid, long *parent_tid, 108c4bd610fSDavid Xu int flags) 109c4bd610fSDavid Xu { 110c4bd610fSDavid Xu stack_t stack; 111c4bd610fSDavid Xu struct thread *newtd; 112c4bd610fSDavid Xu struct ksegrp *kg, *newkg; 113c4bd610fSDavid Xu struct proc *p; 114c4bd610fSDavid Xu long id; 115c4bd610fSDavid Xu int error, scope_sys, linkkg; 116c4bd610fSDavid Xu 117c4bd610fSDavid Xu error = 0; 118c4bd610fSDavid Xu p = td->td_proc; 119c4bd610fSDavid Xu kg = td->td_ksegrp; 120c4bd610fSDavid Xu 121c4bd610fSDavid Xu /* Have race condition but it is cheap. */ 122ed062c8dSJulian Elischer if ((p->p_numksegrps >= max_groups_per_proc) || 123ed062c8dSJulian Elischer (p->p_numthreads >= max_threads_per_proc)) { 124ed062c8dSJulian Elischer return (EPROCLIM); 125ed062c8dSJulian Elischer } 126195f5806SDavid Xu 127c4bd610fSDavid Xu /* Check PTHREAD_SCOPE_SYSTEM */ 128c4bd610fSDavid Xu scope_sys = (flags & THR_SYSTEM_SCOPE) != 0; 129c4bd610fSDavid Xu 130c4bd610fSDavid Xu /* sysctl overrides user's flag */ 131c4bd610fSDavid Xu if (thr_scope == 1) 132c4bd610fSDavid Xu scope_sys = 0; 133c4bd610fSDavid Xu else if (thr_scope == 2) 134c4bd610fSDavid Xu scope_sys = 1; 135c4bd610fSDavid Xu 136ed062c8dSJulian Elischer /* Initialize our td and new ksegrp.. */ 137ed062c8dSJulian Elischer newtd = thread_alloc(); 138c4bd610fSDavid Xu 13989bb1cefSJeff Roberson /* 140c4bd610fSDavid Xu * Try the copyout as soon as we allocate the td so we don't 141c4bd610fSDavid Xu * have to tear things down in a failure case below. 142c4bd610fSDavid Xu * Here we copy out tid to two places, one for child and one 143c4bd610fSDavid Xu * for parent, because pthread can create a detached thread, 144c4bd610fSDavid Xu * if parent wants to safely access child tid, it has to provide 145c4bd610fSDavid Xu * its storage, because child thread may exit quickly and 146c4bd610fSDavid Xu * memory is freed before parent thread can access it. 14789bb1cefSJeff Roberson */ 148ed062c8dSJulian Elischer id = newtd->td_tid; 149c4bd610fSDavid Xu if ((child_tid != NULL && 150c4bd610fSDavid Xu (error = copyout(&id, child_tid, sizeof(long)))) || 151c4bd610fSDavid Xu (parent_tid != NULL && 152c4bd610fSDavid Xu (error = copyout(&id, parent_tid, sizeof(long))))) { 153ed062c8dSJulian Elischer thread_free(newtd); 15489bb1cefSJeff Roberson return (error); 15589bb1cefSJeff Roberson } 156ed062c8dSJulian Elischer bzero(&newtd->td_startzero, 1576db36923SDavid Schultz __rangeof(struct thread, td_startzero, td_endzero)); 158ed062c8dSJulian Elischer bcopy(&td->td_startcopy, &newtd->td_startcopy, 1596db36923SDavid Schultz __rangeof(struct thread, td_startcopy, td_endcopy)); 160c4bd610fSDavid Xu newtd->td_proc = td->td_proc; 161c4bd610fSDavid Xu newtd->td_ucred = crhold(td->td_ucred); 16289bb1cefSJeff Roberson 163c4bd610fSDavid Xu cpu_set_upcall(newtd, td); 164c4bd610fSDavid Xu 165c4bd610fSDavid Xu if (ctx != NULL) { /* old way to set user context */ 166c4bd610fSDavid Xu error = set_mcontext(newtd, ctx); 167c4bd610fSDavid Xu if (error != 0) { 168c4bd610fSDavid Xu thread_free(newtd); 169c4bd610fSDavid Xu crfree(td->td_ucred); 170c4bd610fSDavid Xu return (error); 171c4bd610fSDavid Xu } 172c4bd610fSDavid Xu } else { 173c4bd610fSDavid Xu /* Set up our machine context. */ 174c4bd610fSDavid Xu stack.ss_sp = stack_base; 175c4bd610fSDavid Xu stack.ss_size = stack_size; 176c4bd610fSDavid Xu /* Set upcall address to user thread entry function. */ 177c4bd610fSDavid Xu cpu_set_upcall_kse(newtd, start_func, arg, &stack); 178c4bd610fSDavid Xu /* Setup user TLS address and TLS pointer register. */ 179c4bd610fSDavid Xu cpu_set_user_tls(newtd, tls_base); 180c4bd610fSDavid Xu } 181c4bd610fSDavid Xu 182c4bd610fSDavid Xu if ((td->td_proc->p_flag & P_HADTHREADS) == 0) { 183c4bd610fSDavid Xu /* Treat initial thread as it has PTHREAD_SCOPE_PROCESS. */ 184c4bd610fSDavid Xu p->p_procscopegrp = kg; 185c4bd610fSDavid Xu mtx_lock_spin(&sched_lock); 186c4bd610fSDavid Xu sched_set_concurrency(kg, 187c4bd610fSDavid Xu thr_concurrency ? thr_concurrency : (2*mp_ncpus)); 188c4bd610fSDavid Xu mtx_unlock_spin(&sched_lock); 189c4bd610fSDavid Xu } 190c4bd610fSDavid Xu 191c4bd610fSDavid Xu linkkg = 0; 192195f5806SDavid Xu if (scope_sys) { 193c4bd610fSDavid Xu linkkg = 1; 194c4bd610fSDavid Xu newkg = ksegrp_alloc(); 195ed062c8dSJulian Elischer bzero(&newkg->kg_startzero, 1966db36923SDavid Schultz __rangeof(struct ksegrp, kg_startzero, kg_endzero)); 197ed062c8dSJulian Elischer bcopy(&kg->kg_startcopy, &newkg->kg_startcopy, 1986db36923SDavid Schultz __rangeof(struct ksegrp, kg_startcopy, kg_endcopy)); 199a8b491c1SJulian Elischer sched_init_concurrency(newkg); 200c4bd610fSDavid Xu PROC_LOCK(td->td_proc); 201a8b491c1SJulian Elischer } else { 202c4bd610fSDavid Xu /* 203c4bd610fSDavid Xu * Try to create a KSE group which will be shared 204c4bd610fSDavid Xu * by all PTHREAD_SCOPE_PROCESS threads. 205c4bd610fSDavid Xu */ 206c4bd610fSDavid Xu retry: 207c4bd610fSDavid Xu PROC_LOCK(td->td_proc); 208c4bd610fSDavid Xu if ((newkg = p->p_procscopegrp) == NULL) { 209c4bd610fSDavid Xu PROC_UNLOCK(p); 210c4bd610fSDavid Xu newkg = ksegrp_alloc(); 211c4bd610fSDavid Xu bzero(&newkg->kg_startzero, 212c4bd610fSDavid Xu __rangeof(struct ksegrp, kg_startzero, kg_endzero)); 213c4bd610fSDavid Xu bcopy(&kg->kg_startcopy, &newkg->kg_startcopy, 214c4bd610fSDavid Xu __rangeof(struct ksegrp, kg_startcopy, kg_endcopy)); 215c4bd610fSDavid Xu PROC_LOCK(p); 216c4bd610fSDavid Xu if (p->p_procscopegrp == NULL) { 217c4bd610fSDavid Xu p->p_procscopegrp = newkg; 218c4bd610fSDavid Xu sched_init_concurrency(newkg); 219c4bd610fSDavid Xu sched_set_concurrency(newkg, 220a8b491c1SJulian Elischer thr_concurrency ? thr_concurrency : (2*mp_ncpus)); 221c4bd610fSDavid Xu linkkg = 1; 222c4bd610fSDavid Xu } else { 223c4bd610fSDavid Xu PROC_UNLOCK(p); 224c4bd610fSDavid Xu ksegrp_free(newkg); 225c4bd610fSDavid Xu goto retry; 226c4bd610fSDavid Xu } 227a8b491c1SJulian Elischer } 228a8b491c1SJulian Elischer } 229a8b491c1SJulian Elischer 230ed062c8dSJulian Elischer td->td_proc->p_flag |= P_HADTHREADS; 231ed062c8dSJulian Elischer newtd->td_sigmask = td->td_sigmask; 23289bb1cefSJeff Roberson mtx_lock_spin(&sched_lock); 233c4bd610fSDavid Xu if (linkkg) 234ed062c8dSJulian Elischer ksegrp_link(newkg, p); 235ed062c8dSJulian Elischer thread_link(newtd, newkg); 236ed062c8dSJulian Elischer PROC_UNLOCK(p); 23789bb1cefSJeff Roberson 238ed062c8dSJulian Elischer /* let the scheduler know about these things. */ 239c4bd610fSDavid Xu if (linkkg) 240ed062c8dSJulian Elischer sched_fork_ksegrp(td, newkg); 241ed062c8dSJulian Elischer sched_fork_thread(td, newtd); 242ed062c8dSJulian Elischer TD_SET_CAN_RUN(newtd); 243c4bd610fSDavid Xu /* if ((flags & THR_SUSPENDED) == 0) */ 244ed062c8dSJulian Elischer setrunqueue(newtd, SRQ_BORING); 24589bb1cefSJeff Roberson mtx_unlock_spin(&sched_lock); 24689bb1cefSJeff Roberson 24789bb1cefSJeff Roberson return (error); 24889bb1cefSJeff Roberson } 24989bb1cefSJeff Roberson 25089bb1cefSJeff Roberson int 25189bb1cefSJeff Roberson thr_self(struct thread *td, struct thr_self_args *uap) 252cd28f17dSMarcel Moolenaar /* long *id */ 25389bb1cefSJeff Roberson { 254cd28f17dSMarcel Moolenaar long id; 25589bb1cefSJeff Roberson int error; 25689bb1cefSJeff Roberson 257cd28f17dSMarcel Moolenaar id = td->td_tid; 258cd28f17dSMarcel Moolenaar if ((error = copyout(&id, uap->id, sizeof(long)))) 25989bb1cefSJeff Roberson return (error); 26089bb1cefSJeff Roberson 26189bb1cefSJeff Roberson return (0); 26289bb1cefSJeff Roberson } 26389bb1cefSJeff Roberson 26489bb1cefSJeff Roberson int 26589bb1cefSJeff Roberson thr_exit(struct thread *td, struct thr_exit_args *uap) 266401901acSMike Makonnen /* long *state */ 26789bb1cefSJeff Roberson { 26889bb1cefSJeff Roberson struct proc *p; 26989bb1cefSJeff Roberson 27089bb1cefSJeff Roberson p = td->td_proc; 27189bb1cefSJeff Roberson 272401901acSMike Makonnen /* Signal userland that it can free the stack. */ 273401901acSMike Makonnen if ((void *)uap->state != NULL) 274401901acSMike Makonnen suword((void *)uap->state, 1); 275401901acSMike Makonnen 27689bb1cefSJeff Roberson PROC_LOCK(p); 27789bb1cefSJeff Roberson mtx_lock_spin(&sched_lock); 27889bb1cefSJeff Roberson 27989bb1cefSJeff Roberson /* 280ed062c8dSJulian Elischer * Shutting down last thread in the proc. This will actually 281ed062c8dSJulian Elischer * call exit() in the trampoline when it returns. 28289bb1cefSJeff Roberson */ 283ed062c8dSJulian Elischer if (p->p_numthreads != 1) { 284ed062c8dSJulian Elischer thread_exit(); 285ed062c8dSJulian Elischer /* NOTREACHED */ 286ed062c8dSJulian Elischer } 28789bb1cefSJeff Roberson mtx_unlock_spin(&sched_lock); 288ed062c8dSJulian Elischer PROC_UNLOCK(p); 28989bb1cefSJeff Roberson return (0); 29089bb1cefSJeff Roberson } 29189bb1cefSJeff Roberson 29289bb1cefSJeff Roberson int 29389bb1cefSJeff Roberson thr_kill(struct thread *td, struct thr_kill_args *uap) 294cd28f17dSMarcel Moolenaar /* long id, int sig */ 29589bb1cefSJeff Roberson { 29689bb1cefSJeff Roberson struct thread *ttd; 29789bb1cefSJeff Roberson struct proc *p; 29889bb1cefSJeff Roberson int error; 29989bb1cefSJeff Roberson 30089bb1cefSJeff Roberson p = td->td_proc; 30189bb1cefSJeff Roberson error = 0; 30289bb1cefSJeff Roberson PROC_LOCK(p); 30371cfaac0SMike Makonnen FOREACH_THREAD_IN_PROC(p, ttd) { 304cd28f17dSMarcel Moolenaar if (ttd->td_tid == uap->id) 30589bb1cefSJeff Roberson break; 30671cfaac0SMike Makonnen } 30789bb1cefSJeff Roberson if (ttd == NULL) { 30889bb1cefSJeff Roberson error = ESRCH; 30989bb1cefSJeff Roberson goto out; 31089bb1cefSJeff Roberson } 31189bb1cefSJeff Roberson if (uap->sig == 0) 31289bb1cefSJeff Roberson goto out; 31389bb1cefSJeff Roberson if (!_SIG_VALID(uap->sig)) { 31489bb1cefSJeff Roberson error = EINVAL; 31589bb1cefSJeff Roberson goto out; 31689bb1cefSJeff Roberson } 317c197abc4SMike Makonnen tdsignal(ttd, uap->sig, SIGTARGET_TD); 31889bb1cefSJeff Roberson out: 31989bb1cefSJeff Roberson PROC_UNLOCK(p); 32089bb1cefSJeff Roberson return (error); 32189bb1cefSJeff Roberson } 3221713a516SMike Makonnen 3231713a516SMike Makonnen int 3241713a516SMike Makonnen thr_suspend(struct thread *td, struct thr_suspend_args *uap) 3251713a516SMike Makonnen /* const struct timespec *timeout */ 3261713a516SMike Makonnen { 3271713a516SMike Makonnen struct timespec ts; 3281713a516SMike Makonnen struct timeval tv; 3291713a516SMike Makonnen int error; 3301713a516SMike Makonnen int hz; 3311713a516SMike Makonnen 3321713a516SMike Makonnen hz = 0; 3331713a516SMike Makonnen error = 0; 3341713a516SMike Makonnen if (uap->timeout != NULL) { 3351713a516SMike Makonnen error = copyin((const void *)uap->timeout, (void *)&ts, 3361713a516SMike Makonnen sizeof(struct timespec)); 3371713a516SMike Makonnen if (error != 0) 3381713a516SMike Makonnen return (error); 3391713a516SMike Makonnen if (ts.tv_nsec < 0 || ts.tv_nsec > 1000000000) 3401713a516SMike Makonnen return (EINVAL); 3411713a516SMike Makonnen if (ts.tv_sec == 0 && ts.tv_nsec == 0) 3421713a516SMike Makonnen return (ETIMEDOUT); 3431713a516SMike Makonnen TIMESPEC_TO_TIMEVAL(&tv, &ts); 3441713a516SMike Makonnen hz = tvtohz(&tv); 3451713a516SMike Makonnen } 3461713a516SMike Makonnen PROC_LOCK(td->td_proc); 347c21e3b38SMike Makonnen if ((td->td_flags & TDF_THRWAKEUP) == 0) 3481713a516SMike Makonnen error = msleep((void *)td, &td->td_proc->p_mtx, 3491713a516SMike Makonnen td->td_priority | PCATCH, "lthr", hz); 350c1df5a1aSDavid Xu if (td->td_flags & TDF_THRWAKEUP) { 3511713a516SMike Makonnen mtx_lock_spin(&sched_lock); 3521713a516SMike Makonnen td->td_flags &= ~TDF_THRWAKEUP; 3531713a516SMike Makonnen mtx_unlock_spin(&sched_lock); 3541713a516SMike Makonnen PROC_UNLOCK(td->td_proc); 355c1df5a1aSDavid Xu return (0); 356c1df5a1aSDavid Xu } 357c1df5a1aSDavid Xu PROC_UNLOCK(td->td_proc); 358c1df5a1aSDavid Xu if (error == EWOULDBLOCK) 359c1df5a1aSDavid Xu error = ETIMEDOUT; 360c1df5a1aSDavid Xu else if (error == ERESTART) { 361c1df5a1aSDavid Xu if (hz != 0) 362c1df5a1aSDavid Xu error = EINTR; 363c1df5a1aSDavid Xu } 364c1df5a1aSDavid Xu return (error); 3651713a516SMike Makonnen } 3661713a516SMike Makonnen 3671713a516SMike Makonnen int 3681713a516SMike Makonnen thr_wake(struct thread *td, struct thr_wake_args *uap) 369cd28f17dSMarcel Moolenaar /* long id */ 3701713a516SMike Makonnen { 371cd28f17dSMarcel Moolenaar struct thread *ttd; 3721713a516SMike Makonnen 373b9fb5d42SMike Makonnen PROC_LOCK(td->td_proc); 374b9fb5d42SMike Makonnen FOREACH_THREAD_IN_PROC(td->td_proc, ttd) { 375cd28f17dSMarcel Moolenaar if (ttd->td_tid == uap->id) 3761713a516SMike Makonnen break; 3771713a516SMike Makonnen } 3781713a516SMike Makonnen if (ttd == NULL) { 379b9fb5d42SMike Makonnen PROC_UNLOCK(td->td_proc); 3801713a516SMike Makonnen return (ESRCH); 3811713a516SMike Makonnen } 3821713a516SMike Makonnen mtx_lock_spin(&sched_lock); 383cd28f17dSMarcel Moolenaar ttd->td_flags |= TDF_THRWAKEUP; 3841713a516SMike Makonnen mtx_unlock_spin(&sched_lock); 385c1df5a1aSDavid Xu wakeup((void *)ttd); 386b9fb5d42SMike Makonnen PROC_UNLOCK(td->td_proc); 3871713a516SMike Makonnen return (0); 3881713a516SMike Makonnen } 389