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> 45a0712c99SDavid Xu #include <sys/rtprio.h> 46a0712c99SDavid Xu #include <posix4/sched.h> 474938faa6SDavid Xu #include <sys/umtx.h> 484938faa6SDavid Xu #include <sys/limits.h> 4989bb1cefSJeff Roberson 5089bb1cefSJeff Roberson #include <machine/frame.h> 5189bb1cefSJeff Roberson 52ed062c8dSJulian Elischer extern int max_threads_per_proc; 53a8b491c1SJulian Elischer 54c4bd610fSDavid Xu static int create_thread(struct thread *td, mcontext_t *ctx, 55c4bd610fSDavid Xu void (*start_func)(void *), void *arg, 56c4bd610fSDavid Xu char *stack_base, size_t stack_size, 57c4bd610fSDavid Xu char *tls_base, 58c4bd610fSDavid Xu long *child_tid, long *parent_tid, 59a0712c99SDavid Xu int flags, struct thr_sched_param *sched); 60c4bd610fSDavid Xu 6189bb1cefSJeff Roberson /* 6289bb1cefSJeff Roberson * System call interface. 6389bb1cefSJeff Roberson */ 6489bb1cefSJeff Roberson int 6589bb1cefSJeff Roberson thr_create(struct thread *td, struct thr_create_args *uap) 66cd28f17dSMarcel Moolenaar /* ucontext_t *ctx, long *id, int flags */ 6789bb1cefSJeff Roberson { 6889bb1cefSJeff Roberson ucontext_t ctx; 6989bb1cefSJeff Roberson int error; 7089bb1cefSJeff Roberson 7189bb1cefSJeff Roberson if ((error = copyin(uap->ctx, &ctx, sizeof(ctx)))) 7289bb1cefSJeff Roberson return (error); 7389bb1cefSJeff Roberson 74c4bd610fSDavid Xu error = create_thread(td, &ctx.uc_mcontext, NULL, NULL, 75a0712c99SDavid Xu NULL, 0, NULL, uap->id, NULL, uap->flags, NULL); 76c4bd610fSDavid Xu return (error); 77c4bd610fSDavid Xu } 78c4bd610fSDavid Xu 79c4bd610fSDavid Xu int 80c4bd610fSDavid Xu thr_new(struct thread *td, struct thr_new_args *uap) 81c4bd610fSDavid Xu /* struct thr_param * */ 82c4bd610fSDavid Xu { 83c4bd610fSDavid Xu struct thr_param param; 84a0712c99SDavid Xu struct thr_sched_param sched_param, *sched; 85c4bd610fSDavid Xu int error; 86c4bd610fSDavid Xu 87c4bd610fSDavid Xu if (uap->param_size < sizeof(param)) 88c4bd610fSDavid Xu return (EINVAL); 89c4bd610fSDavid Xu if ((error = copyin(uap->param, ¶m, sizeof(param)))) 90c4bd610fSDavid Xu return (error); 91a0712c99SDavid Xu sched = NULL; 92a0712c99SDavid Xu if (param.sched != NULL) { 93a0712c99SDavid Xu error = copyin(param.sched, &sched_param, 94a0712c99SDavid Xu sizeof(sched_param)); 95a0712c99SDavid Xu if (error) 96a0712c99SDavid Xu return (error); 97a0712c99SDavid Xu sched = &sched_param; 98a0712c99SDavid Xu } 99a0712c99SDavid Xu 100c4bd610fSDavid Xu error = create_thread(td, NULL, param.start_func, param.arg, 101c4bd610fSDavid Xu param.stack_base, param.stack_size, param.tls_base, 102a0712c99SDavid Xu param.child_tid, param.parent_tid, param.flags, 103a0712c99SDavid Xu sched); 104c4bd610fSDavid Xu return (error); 105c4bd610fSDavid Xu } 106c4bd610fSDavid Xu 107c4bd610fSDavid Xu static int 108c4bd610fSDavid Xu create_thread(struct thread *td, mcontext_t *ctx, 109c4bd610fSDavid Xu void (*start_func)(void *), void *arg, 110c4bd610fSDavid Xu char *stack_base, size_t stack_size, 111c4bd610fSDavid Xu char *tls_base, 112c4bd610fSDavid Xu long *child_tid, long *parent_tid, 113a0712c99SDavid Xu int flags, struct thr_sched_param *sched) 114c4bd610fSDavid Xu { 115c4bd610fSDavid Xu stack_t stack; 116c4bd610fSDavid Xu struct thread *newtd; 117c4bd610fSDavid Xu struct ksegrp *kg, *newkg; 118c4bd610fSDavid Xu struct proc *p; 119c4bd610fSDavid Xu long id; 120adc9c950SDavid Xu int error; 121c4bd610fSDavid Xu 122c4bd610fSDavid Xu error = 0; 123c4bd610fSDavid Xu p = td->td_proc; 124c4bd610fSDavid Xu kg = td->td_ksegrp; 125c4bd610fSDavid Xu 126c4bd610fSDavid Xu /* Have race condition but it is cheap. */ 127adc9c950SDavid Xu if (p->p_numthreads >= max_threads_per_proc) 128ed062c8dSJulian Elischer return (EPROCLIM); 129c4bd610fSDavid Xu 130a0712c99SDavid Xu if (sched != NULL) { 131a0712c99SDavid Xu /* Only root can set scheduler policy */ 132a0712c99SDavid Xu if (sched->policy != SCHED_OTHER) { 133a0712c99SDavid Xu if (suser(td) != 0) 134a0712c99SDavid Xu return (EPERM); 135a0712c99SDavid Xu 136a0712c99SDavid Xu if (sched->policy != SCHED_FIFO && 137a0712c99SDavid Xu sched->policy != SCHED_RR) 138a0712c99SDavid Xu return (EINVAL); 139a0712c99SDavid Xu 140a0712c99SDavid Xu if (sched->param.sched_priority < RTP_PRIO_MIN || 141a0712c99SDavid Xu sched->param.sched_priority > RTP_PRIO_MAX) 142a0712c99SDavid Xu return (EINVAL); 143a0712c99SDavid Xu } 144a0712c99SDavid Xu } 145a0712c99SDavid Xu 146ed062c8dSJulian Elischer /* Initialize our td and new ksegrp.. */ 147ed062c8dSJulian Elischer newtd = thread_alloc(); 148c4bd610fSDavid Xu 14989bb1cefSJeff Roberson /* 150c4bd610fSDavid Xu * Try the copyout as soon as we allocate the td so we don't 151c4bd610fSDavid Xu * have to tear things down in a failure case below. 152c4bd610fSDavid Xu * Here we copy out tid to two places, one for child and one 153c4bd610fSDavid Xu * for parent, because pthread can create a detached thread, 154c4bd610fSDavid Xu * if parent wants to safely access child tid, it has to provide 155c4bd610fSDavid Xu * its storage, because child thread may exit quickly and 156c4bd610fSDavid Xu * memory is freed before parent thread can access it. 15789bb1cefSJeff Roberson */ 158ed062c8dSJulian Elischer id = newtd->td_tid; 159c4bd610fSDavid Xu if ((child_tid != NULL && 160c4bd610fSDavid Xu (error = copyout(&id, child_tid, sizeof(long)))) || 161c4bd610fSDavid Xu (parent_tid != NULL && 162c4bd610fSDavid Xu (error = copyout(&id, parent_tid, sizeof(long))))) { 163ed062c8dSJulian Elischer thread_free(newtd); 16489bb1cefSJeff Roberson return (error); 16589bb1cefSJeff Roberson } 166ed062c8dSJulian Elischer bzero(&newtd->td_startzero, 1676db36923SDavid Schultz __rangeof(struct thread, td_startzero, td_endzero)); 168ed062c8dSJulian Elischer bcopy(&td->td_startcopy, &newtd->td_startcopy, 1696db36923SDavid Schultz __rangeof(struct thread, td_startcopy, td_endcopy)); 170c4bd610fSDavid Xu newtd->td_proc = td->td_proc; 171c4bd610fSDavid Xu newtd->td_ucred = crhold(td->td_ucred); 17289bb1cefSJeff Roberson 173c4bd610fSDavid Xu cpu_set_upcall(newtd, td); 174c4bd610fSDavid Xu 175c4bd610fSDavid Xu if (ctx != NULL) { /* old way to set user context */ 176c4bd610fSDavid Xu error = set_mcontext(newtd, ctx); 177c4bd610fSDavid Xu if (error != 0) { 178c4bd610fSDavid Xu thread_free(newtd); 179c4bd610fSDavid Xu crfree(td->td_ucred); 180c4bd610fSDavid Xu return (error); 181c4bd610fSDavid Xu } 182c4bd610fSDavid Xu } else { 183c4bd610fSDavid Xu /* Set up our machine context. */ 184c4bd610fSDavid Xu stack.ss_sp = stack_base; 185c4bd610fSDavid Xu stack.ss_size = stack_size; 186c4bd610fSDavid Xu /* Set upcall address to user thread entry function. */ 187c4bd610fSDavid Xu cpu_set_upcall_kse(newtd, start_func, arg, &stack); 188c4bd610fSDavid Xu /* Setup user TLS address and TLS pointer register. */ 189740fd64dSDavid Xu error = cpu_set_user_tls(newtd, tls_base); 190740fd64dSDavid Xu if (error != 0) { 191740fd64dSDavid Xu thread_free(newtd); 192740fd64dSDavid Xu crfree(td->td_ucred); 193740fd64dSDavid Xu return (error); 194740fd64dSDavid Xu } 195c4bd610fSDavid Xu } 196c4bd610fSDavid Xu 197c4bd610fSDavid Xu newkg = ksegrp_alloc(); 198ed062c8dSJulian Elischer bzero(&newkg->kg_startzero, 1996db36923SDavid Schultz __rangeof(struct ksegrp, kg_startzero, kg_endzero)); 200ed062c8dSJulian Elischer bcopy(&kg->kg_startcopy, &newkg->kg_startcopy, 2016db36923SDavid Schultz __rangeof(struct ksegrp, kg_startcopy, kg_endcopy)); 202a8b491c1SJulian Elischer sched_init_concurrency(newkg); 203c4bd610fSDavid Xu PROC_LOCK(td->td_proc); 204ed062c8dSJulian Elischer td->td_proc->p_flag |= P_HADTHREADS; 205ed062c8dSJulian Elischer newtd->td_sigmask = td->td_sigmask; 20689bb1cefSJeff Roberson mtx_lock_spin(&sched_lock); 207ed062c8dSJulian Elischer ksegrp_link(newkg, p); 208ed062c8dSJulian Elischer thread_link(newtd, newkg); 209ed062c8dSJulian Elischer PROC_UNLOCK(p); 21089bb1cefSJeff Roberson 211ed062c8dSJulian Elischer /* let the scheduler know about these things. */ 212ed062c8dSJulian Elischer sched_fork_ksegrp(td, newkg); 213ed062c8dSJulian Elischer sched_fork_thread(td, newtd); 214a0712c99SDavid Xu if (sched != NULL) { 215a0712c99SDavid Xu struct rtprio rtp; 216a0712c99SDavid Xu switch (sched->policy) { 217a0712c99SDavid Xu case SCHED_FIFO: 218a0712c99SDavid Xu rtp.type = PRI_FIFO; 219a0712c99SDavid Xu rtp.prio = sched->param.sched_priority; 220a0712c99SDavid Xu break; 221a0712c99SDavid Xu case SCHED_RR: 222a0712c99SDavid Xu rtp.type = PRI_REALTIME; 223a0712c99SDavid Xu rtp.prio = sched->param.sched_priority; 224a0712c99SDavid Xu break; 225a0712c99SDavid Xu case SCHED_OTHER: 226a0712c99SDavid Xu rtp.type = PRI_TIMESHARE; 227a0712c99SDavid Xu if (curthread->td_ksegrp->kg_pri_class == PRI_TIMESHARE) 228a0712c99SDavid Xu rtp.prio = curthread->td_ksegrp->kg_user_pri; 229a0712c99SDavid Xu else 230a0712c99SDavid Xu rtp.prio = 0; 231a0712c99SDavid Xu break; 232a0712c99SDavid Xu default: 233a0712c99SDavid Xu panic("sched policy"); 234a0712c99SDavid Xu } 235a0712c99SDavid Xu rtp_to_pri(&rtp, newkg); 236a0712c99SDavid Xu sched_prio(newtd, newkg->kg_user_pri); 237a0712c99SDavid Xu } 238ed062c8dSJulian Elischer TD_SET_CAN_RUN(newtd); 239c4bd610fSDavid Xu /* if ((flags & THR_SUSPENDED) == 0) */ 240ed062c8dSJulian Elischer setrunqueue(newtd, SRQ_BORING); 24189bb1cefSJeff Roberson mtx_unlock_spin(&sched_lock); 24289bb1cefSJeff Roberson 24389bb1cefSJeff Roberson return (error); 24489bb1cefSJeff Roberson } 24589bb1cefSJeff Roberson 24689bb1cefSJeff Roberson int 24789bb1cefSJeff Roberson thr_self(struct thread *td, struct thr_self_args *uap) 248cd28f17dSMarcel Moolenaar /* long *id */ 24989bb1cefSJeff Roberson { 250cd28f17dSMarcel Moolenaar long id; 25189bb1cefSJeff Roberson int error; 25289bb1cefSJeff Roberson 253cd28f17dSMarcel Moolenaar id = td->td_tid; 254cd28f17dSMarcel Moolenaar if ((error = copyout(&id, uap->id, sizeof(long)))) 25589bb1cefSJeff Roberson return (error); 25689bb1cefSJeff Roberson 25789bb1cefSJeff Roberson return (0); 25889bb1cefSJeff Roberson } 25989bb1cefSJeff Roberson 26089bb1cefSJeff Roberson int 26189bb1cefSJeff Roberson thr_exit(struct thread *td, struct thr_exit_args *uap) 262401901acSMike Makonnen /* long *state */ 26389bb1cefSJeff Roberson { 26489bb1cefSJeff Roberson struct proc *p; 26589bb1cefSJeff Roberson 26689bb1cefSJeff Roberson p = td->td_proc; 26789bb1cefSJeff Roberson 268401901acSMike Makonnen /* Signal userland that it can free the stack. */ 2694938faa6SDavid Xu if ((void *)uap->state != NULL) { 270401901acSMike Makonnen suword((void *)uap->state, 1); 2714938faa6SDavid Xu kern_umtx_wake(td, uap->state, INT_MAX); 2724938faa6SDavid Xu } 273401901acSMike Makonnen 27489bb1cefSJeff Roberson PROC_LOCK(p); 2759104847fSDavid Xu sigqueue_flush(&td->td_sigqueue); 27689bb1cefSJeff Roberson mtx_lock_spin(&sched_lock); 27789bb1cefSJeff Roberson 27889bb1cefSJeff Roberson /* 279ed062c8dSJulian Elischer * Shutting down last thread in the proc. This will actually 280ed062c8dSJulian Elischer * call exit() in the trampoline when it returns. 28189bb1cefSJeff Roberson */ 282ed062c8dSJulian Elischer if (p->p_numthreads != 1) { 28371b7afb2SDavid Xu thread_stopped(p); 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); 3030a5cd498SDavid Xu if (uap->id == -1) { 3040a5cd498SDavid Xu if (uap->sig != 0 && !_SIG_VALID(uap->sig)) { 30589bb1cefSJeff Roberson error = EINVAL; 3060a5cd498SDavid Xu } else { 3070a5cd498SDavid Xu error = ESRCH; 3080a5cd498SDavid Xu FOREACH_THREAD_IN_PROC(p, ttd) { 3090a5cd498SDavid Xu if (ttd != td) { 3100a5cd498SDavid Xu error = 0; 3110a5cd498SDavid Xu if (uap->sig == 0) 3120a5cd498SDavid Xu break; 3136d7b314bSDavid Xu tdsignal(p, ttd, uap->sig, NULL); 3140a5cd498SDavid Xu } 3150a5cd498SDavid Xu } 3160a5cd498SDavid Xu } 3170a5cd498SDavid Xu } else { 3180a5cd498SDavid Xu if (uap->id != td->td_tid) 3190a5cd498SDavid Xu ttd = thread_find(p, uap->id); 3200a5cd498SDavid Xu else 3210a5cd498SDavid Xu ttd = td; 3220a5cd498SDavid Xu if (ttd == NULL) 3230a5cd498SDavid Xu error = ESRCH; 3240a5cd498SDavid Xu else if (uap->sig == 0) 3250a5cd498SDavid Xu ; 3260a5cd498SDavid Xu else if (!_SIG_VALID(uap->sig)) 3270a5cd498SDavid Xu error = EINVAL; 3280a5cd498SDavid Xu else 3290a5cd498SDavid Xu tdsignal(p, ttd, uap->sig, NULL); 3300a5cd498SDavid Xu } 33189bb1cefSJeff Roberson PROC_UNLOCK(p); 33289bb1cefSJeff Roberson return (error); 33389bb1cefSJeff Roberson } 3341713a516SMike Makonnen 3351713a516SMike Makonnen int 3361713a516SMike Makonnen thr_suspend(struct thread *td, struct thr_suspend_args *uap) 3371713a516SMike Makonnen /* const struct timespec *timeout */ 3381713a516SMike Makonnen { 3391713a516SMike Makonnen struct timespec ts; 3401713a516SMike Makonnen struct timeval tv; 3411713a516SMike Makonnen int error; 3421713a516SMike Makonnen int hz; 3431713a516SMike Makonnen 3441713a516SMike Makonnen hz = 0; 3451713a516SMike Makonnen error = 0; 3461713a516SMike Makonnen if (uap->timeout != NULL) { 3471713a516SMike Makonnen error = copyin((const void *)uap->timeout, (void *)&ts, 3481713a516SMike Makonnen sizeof(struct timespec)); 3491713a516SMike Makonnen if (error != 0) 3501713a516SMike Makonnen return (error); 3511713a516SMike Makonnen if (ts.tv_nsec < 0 || ts.tv_nsec > 1000000000) 3521713a516SMike Makonnen return (EINVAL); 3531713a516SMike Makonnen if (ts.tv_sec == 0 && ts.tv_nsec == 0) 3541713a516SMike Makonnen return (ETIMEDOUT); 3551713a516SMike Makonnen TIMESPEC_TO_TIMEVAL(&tv, &ts); 3561713a516SMike Makonnen hz = tvtohz(&tv); 3571713a516SMike Makonnen } 3581713a516SMike Makonnen PROC_LOCK(td->td_proc); 359c21e3b38SMike Makonnen if ((td->td_flags & TDF_THRWAKEUP) == 0) 3600f180a7cSJohn Baldwin error = msleep((void *)td, &td->td_proc->p_mtx, PCATCH, "lthr", 3610f180a7cSJohn Baldwin hz); 362c1df5a1aSDavid Xu if (td->td_flags & TDF_THRWAKEUP) { 3631713a516SMike Makonnen mtx_lock_spin(&sched_lock); 3641713a516SMike Makonnen td->td_flags &= ~TDF_THRWAKEUP; 3651713a516SMike Makonnen mtx_unlock_spin(&sched_lock); 3661713a516SMike Makonnen PROC_UNLOCK(td->td_proc); 367c1df5a1aSDavid Xu return (0); 368c1df5a1aSDavid Xu } 369c1df5a1aSDavid Xu PROC_UNLOCK(td->td_proc); 370c1df5a1aSDavid Xu if (error == EWOULDBLOCK) 371c1df5a1aSDavid Xu error = ETIMEDOUT; 372c1df5a1aSDavid Xu else if (error == ERESTART) { 373c1df5a1aSDavid Xu if (hz != 0) 374c1df5a1aSDavid Xu error = EINTR; 375c1df5a1aSDavid Xu } 376c1df5a1aSDavid Xu return (error); 3771713a516SMike Makonnen } 3781713a516SMike Makonnen 3791713a516SMike Makonnen int 3801713a516SMike Makonnen thr_wake(struct thread *td, struct thr_wake_args *uap) 381cd28f17dSMarcel Moolenaar /* long id */ 3821713a516SMike Makonnen { 38344355392SDavid Xu struct proc *p; 384cd28f17dSMarcel Moolenaar struct thread *ttd; 3851713a516SMike Makonnen 38644355392SDavid Xu p = td->td_proc; 38744355392SDavid Xu PROC_LOCK(p); 38844355392SDavid Xu ttd = thread_find(p, uap->id); 3891713a516SMike Makonnen if (ttd == NULL) { 39044355392SDavid Xu PROC_UNLOCK(p); 3911713a516SMike Makonnen return (ESRCH); 3921713a516SMike Makonnen } 3931713a516SMike Makonnen mtx_lock_spin(&sched_lock); 394cd28f17dSMarcel Moolenaar ttd->td_flags |= TDF_THRWAKEUP; 3951713a516SMike Makonnen mtx_unlock_spin(&sched_lock); 396c1df5a1aSDavid Xu wakeup((void *)ttd); 39744355392SDavid Xu PROC_UNLOCK(p); 3981713a516SMike Makonnen return (0); 3991713a516SMike Makonnen } 4009e7d7224SDavid Xu 4019e7d7224SDavid Xu int 4029e7d7224SDavid Xu thr_set_name(struct thread *td, struct thr_set_name_args *uap) 4039e7d7224SDavid Xu { 4049e7d7224SDavid Xu struct proc *p = td->td_proc; 4059e7d7224SDavid Xu char name[MAXCOMLEN + 1]; 4069e7d7224SDavid Xu struct thread *ttd; 4079e7d7224SDavid Xu int error; 4089e7d7224SDavid Xu 4099e7d7224SDavid Xu error = 0; 4109e7d7224SDavid Xu name[0] = '\0'; 4119e7d7224SDavid Xu if (uap->name != NULL) { 4129e7d7224SDavid Xu error = copyinstr(uap->name, name, sizeof(name), 4139e7d7224SDavid Xu NULL); 4149e7d7224SDavid Xu if (error) 4159e7d7224SDavid Xu return (error); 4169e7d7224SDavid Xu } 4179e7d7224SDavid Xu PROC_LOCK(p); 4189e7d7224SDavid Xu if (uap->id == td->td_tid) 4199e7d7224SDavid Xu ttd = td; 4209e7d7224SDavid Xu else 4219e7d7224SDavid Xu ttd = thread_find(p, uap->id); 4229e7d7224SDavid Xu if (ttd != NULL) 4239e7d7224SDavid Xu strcpy(ttd->td_name, name); 4249e7d7224SDavid Xu else 4259e7d7224SDavid Xu error = ESRCH; 4269e7d7224SDavid Xu PROC_UNLOCK(p); 4279e7d7224SDavid Xu return (error); 4289e7d7224SDavid Xu } 429