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 3060088160SDavid Xu #include "opt_posix.h" 3189bb1cefSJeff Roberson #include <sys/param.h> 3289bb1cefSJeff Roberson #include <sys/kernel.h> 3389bb1cefSJeff Roberson #include <sys/lock.h> 3489bb1cefSJeff Roberson #include <sys/mutex.h> 3589bb1cefSJeff Roberson #include <sys/proc.h> 3689bb1cefSJeff Roberson #include <sys/resourcevar.h> 37a22ec9d8SJeff Roberson #include <sys/sched.h> 38a8b491c1SJulian Elischer #include <sys/sysctl.h> 39ed062c8dSJulian Elischer #include <sys/smp.h> 4089bb1cefSJeff Roberson #include <sys/sysent.h> 4189bb1cefSJeff Roberson #include <sys/systm.h> 4289bb1cefSJeff Roberson #include <sys/sysproto.h> 4389bb1cefSJeff Roberson #include <sys/signalvar.h> 4489bb1cefSJeff Roberson #include <sys/ucontext.h> 4589bb1cefSJeff Roberson #include <sys/thr.h> 46a0712c99SDavid Xu #include <sys/rtprio.h> 47a0712c99SDavid Xu #include <posix4/sched.h> 4860088160SDavid Xu #include <posix4/posix4.h> 494938faa6SDavid Xu #include <sys/umtx.h> 504938faa6SDavid Xu #include <sys/limits.h> 5189bb1cefSJeff Roberson 5289bb1cefSJeff Roberson #include <machine/frame.h> 5389bb1cefSJeff Roberson 54ed062c8dSJulian Elischer extern int max_threads_per_proc; 55a8b491c1SJulian Elischer 56c4bd610fSDavid Xu static int create_thread(struct thread *td, mcontext_t *ctx, 57c4bd610fSDavid Xu void (*start_func)(void *), void *arg, 58c4bd610fSDavid Xu char *stack_base, size_t stack_size, 59c4bd610fSDavid Xu char *tls_base, 60c4bd610fSDavid Xu long *child_tid, long *parent_tid, 61a0712c99SDavid Xu int flags, struct thr_sched_param *sched); 62c4bd610fSDavid Xu 6389bb1cefSJeff Roberson /* 6489bb1cefSJeff Roberson * System call interface. 6589bb1cefSJeff Roberson */ 6689bb1cefSJeff Roberson int 6789bb1cefSJeff Roberson thr_create(struct thread *td, struct thr_create_args *uap) 68cd28f17dSMarcel Moolenaar /* ucontext_t *ctx, long *id, int flags */ 6989bb1cefSJeff Roberson { 7089bb1cefSJeff Roberson ucontext_t ctx; 7189bb1cefSJeff Roberson int error; 7289bb1cefSJeff Roberson 7389bb1cefSJeff Roberson if ((error = copyin(uap->ctx, &ctx, sizeof(ctx)))) 7489bb1cefSJeff Roberson return (error); 7589bb1cefSJeff Roberson 76c4bd610fSDavid Xu error = create_thread(td, &ctx.uc_mcontext, NULL, NULL, 77a0712c99SDavid Xu NULL, 0, NULL, uap->id, NULL, uap->flags, NULL); 78c4bd610fSDavid Xu return (error); 79c4bd610fSDavid Xu } 80c4bd610fSDavid Xu 81c4bd610fSDavid Xu int 82c4bd610fSDavid Xu thr_new(struct thread *td, struct thr_new_args *uap) 83c4bd610fSDavid Xu /* struct thr_param * */ 84c4bd610fSDavid Xu { 85c4bd610fSDavid Xu struct thr_param param; 86a0712c99SDavid Xu struct thr_sched_param sched_param, *sched; 87c4bd610fSDavid Xu int error; 88c4bd610fSDavid Xu 89c4bd610fSDavid Xu if (uap->param_size < sizeof(param)) 90c4bd610fSDavid Xu return (EINVAL); 91c4bd610fSDavid Xu if ((error = copyin(uap->param, ¶m, sizeof(param)))) 92c4bd610fSDavid Xu return (error); 93a0712c99SDavid Xu sched = NULL; 9460088160SDavid Xu if (param.sched_param != NULL) { 9560088160SDavid Xu if (param.sched_param_size != sizeof(struct thr_sched_param)) 9660088160SDavid Xu return (EINVAL); 9760088160SDavid Xu 9860088160SDavid Xu error = copyin(param.sched_param, &sched_param, 99a0712c99SDavid Xu sizeof(sched_param)); 100a0712c99SDavid Xu if (error) 101a0712c99SDavid Xu return (error); 102a0712c99SDavid Xu sched = &sched_param; 103a0712c99SDavid Xu } 104a0712c99SDavid Xu 105c4bd610fSDavid Xu error = create_thread(td, NULL, param.start_func, param.arg, 106c4bd610fSDavid Xu param.stack_base, param.stack_size, param.tls_base, 107a0712c99SDavid Xu param.child_tid, param.parent_tid, param.flags, 108a0712c99SDavid Xu sched); 109c4bd610fSDavid Xu return (error); 110c4bd610fSDavid Xu } 111c4bd610fSDavid Xu 112c4bd610fSDavid Xu static int 113c4bd610fSDavid Xu create_thread(struct thread *td, mcontext_t *ctx, 114c4bd610fSDavid Xu void (*start_func)(void *), void *arg, 115c4bd610fSDavid Xu char *stack_base, size_t stack_size, 116c4bd610fSDavid Xu char *tls_base, 117c4bd610fSDavid Xu long *child_tid, long *parent_tid, 118a0712c99SDavid Xu int flags, struct thr_sched_param *sched) 119c4bd610fSDavid Xu { 120c4bd610fSDavid Xu stack_t stack; 121c4bd610fSDavid Xu struct thread *newtd; 122c4bd610fSDavid Xu struct ksegrp *kg, *newkg; 123c4bd610fSDavid Xu struct proc *p; 124c4bd610fSDavid Xu long id; 125adc9c950SDavid Xu int error; 126c4bd610fSDavid Xu 127c4bd610fSDavid Xu error = 0; 128c4bd610fSDavid Xu p = td->td_proc; 129c4bd610fSDavid Xu kg = td->td_ksegrp; 130c4bd610fSDavid Xu 131c4bd610fSDavid Xu /* Have race condition but it is cheap. */ 132adc9c950SDavid Xu if (p->p_numthreads >= max_threads_per_proc) 133ed062c8dSJulian Elischer return (EPROCLIM); 134c4bd610fSDavid Xu 135a0712c99SDavid Xu if (sched != NULL) { 1362dca4ca7SDavid Xu switch(sched->policy) { 1372dca4ca7SDavid Xu case SCHED_FIFO: 1382dca4ca7SDavid Xu case SCHED_RR: 139a0712c99SDavid Xu /* Only root can set scheduler policy */ 140a0712c99SDavid Xu if (suser(td) != 0) 141a0712c99SDavid Xu return (EPERM); 142a0712c99SDavid Xu if (sched->param.sched_priority < RTP_PRIO_MIN || 143a0712c99SDavid Xu sched->param.sched_priority > RTP_PRIO_MAX) 144a0712c99SDavid Xu return (EINVAL); 1452dca4ca7SDavid Xu break; 1462dca4ca7SDavid Xu case SCHED_OTHER: 1472dca4ca7SDavid Xu break; 1482dca4ca7SDavid Xu default: 1492dca4ca7SDavid Xu return (EINVAL); 150a0712c99SDavid Xu } 151a0712c99SDavid Xu } 152a0712c99SDavid Xu 153ed062c8dSJulian Elischer /* Initialize our td and new ksegrp.. */ 154ed062c8dSJulian Elischer newtd = thread_alloc(); 155c4bd610fSDavid Xu 15689bb1cefSJeff Roberson /* 157c4bd610fSDavid Xu * Try the copyout as soon as we allocate the td so we don't 158c4bd610fSDavid Xu * have to tear things down in a failure case below. 159c4bd610fSDavid Xu * Here we copy out tid to two places, one for child and one 160c4bd610fSDavid Xu * for parent, because pthread can create a detached thread, 161c4bd610fSDavid Xu * if parent wants to safely access child tid, it has to provide 162c4bd610fSDavid Xu * its storage, because child thread may exit quickly and 163c4bd610fSDavid Xu * memory is freed before parent thread can access it. 16489bb1cefSJeff Roberson */ 165ed062c8dSJulian Elischer id = newtd->td_tid; 166c4bd610fSDavid Xu if ((child_tid != NULL && 167c4bd610fSDavid Xu (error = copyout(&id, child_tid, sizeof(long)))) || 168c4bd610fSDavid Xu (parent_tid != NULL && 169c4bd610fSDavid Xu (error = copyout(&id, parent_tid, sizeof(long))))) { 170ed062c8dSJulian Elischer thread_free(newtd); 17189bb1cefSJeff Roberson return (error); 17289bb1cefSJeff Roberson } 173ed062c8dSJulian Elischer bzero(&newtd->td_startzero, 1746db36923SDavid Schultz __rangeof(struct thread, td_startzero, td_endzero)); 175ed062c8dSJulian Elischer bcopy(&td->td_startcopy, &newtd->td_startcopy, 1766db36923SDavid Schultz __rangeof(struct thread, td_startcopy, td_endcopy)); 177c4bd610fSDavid Xu newtd->td_proc = td->td_proc; 178c4bd610fSDavid Xu newtd->td_ucred = crhold(td->td_ucred); 17989bb1cefSJeff Roberson 180c4bd610fSDavid Xu cpu_set_upcall(newtd, td); 181c4bd610fSDavid Xu 182c4bd610fSDavid Xu if (ctx != NULL) { /* old way to set user context */ 183c4bd610fSDavid Xu error = set_mcontext(newtd, ctx); 184c4bd610fSDavid Xu if (error != 0) { 185c4bd610fSDavid Xu thread_free(newtd); 186c4bd610fSDavid Xu crfree(td->td_ucred); 187c4bd610fSDavid Xu return (error); 188c4bd610fSDavid Xu } 189c4bd610fSDavid Xu } else { 190c4bd610fSDavid Xu /* Set up our machine context. */ 191c4bd610fSDavid Xu stack.ss_sp = stack_base; 192c4bd610fSDavid Xu stack.ss_size = stack_size; 193c4bd610fSDavid Xu /* Set upcall address to user thread entry function. */ 194c4bd610fSDavid Xu cpu_set_upcall_kse(newtd, start_func, arg, &stack); 195c4bd610fSDavid Xu /* Setup user TLS address and TLS pointer register. */ 196740fd64dSDavid Xu error = cpu_set_user_tls(newtd, tls_base); 197740fd64dSDavid Xu if (error != 0) { 198740fd64dSDavid Xu thread_free(newtd); 199740fd64dSDavid Xu crfree(td->td_ucred); 200740fd64dSDavid Xu return (error); 201740fd64dSDavid Xu } 202c4bd610fSDavid Xu } 203c4bd610fSDavid Xu 204c4bd610fSDavid Xu newkg = ksegrp_alloc(); 205ed062c8dSJulian Elischer bzero(&newkg->kg_startzero, 2066db36923SDavid Schultz __rangeof(struct ksegrp, kg_startzero, kg_endzero)); 207ed062c8dSJulian Elischer bcopy(&kg->kg_startcopy, &newkg->kg_startcopy, 2086db36923SDavid Schultz __rangeof(struct ksegrp, kg_startcopy, kg_endcopy)); 209a8b491c1SJulian Elischer sched_init_concurrency(newkg); 210c4bd610fSDavid Xu PROC_LOCK(td->td_proc); 211ed062c8dSJulian Elischer td->td_proc->p_flag |= P_HADTHREADS; 212ed062c8dSJulian Elischer newtd->td_sigmask = td->td_sigmask; 21389bb1cefSJeff Roberson mtx_lock_spin(&sched_lock); 214ed062c8dSJulian Elischer ksegrp_link(newkg, p); 215ed062c8dSJulian Elischer thread_link(newtd, newkg); 216ed062c8dSJulian Elischer PROC_UNLOCK(p); 21789bb1cefSJeff Roberson 218ed062c8dSJulian Elischer /* let the scheduler know about these things. */ 219ed062c8dSJulian Elischer sched_fork_ksegrp(td, newkg); 220ed062c8dSJulian Elischer sched_fork_thread(td, newtd); 221a0712c99SDavid Xu if (sched != NULL) { 222a0712c99SDavid Xu struct rtprio rtp; 223a0712c99SDavid Xu switch (sched->policy) { 224a0712c99SDavid Xu case SCHED_FIFO: 225a0712c99SDavid Xu rtp.type = PRI_FIFO; 226a0712c99SDavid Xu rtp.prio = sched->param.sched_priority; 2272f26f4c6SDavid Xu rtp_to_pri(&rtp, newkg); 2282f26f4c6SDavid Xu sched_prio(newtd, newkg->kg_user_pri); 229a0712c99SDavid Xu break; 230a0712c99SDavid Xu case SCHED_RR: 231a0712c99SDavid Xu rtp.type = PRI_REALTIME; 232a0712c99SDavid Xu rtp.prio = sched->param.sched_priority; 2332f26f4c6SDavid Xu rtp_to_pri(&rtp, newkg); 2342f26f4c6SDavid Xu sched_prio(newtd, newkg->kg_user_pri); 235a0712c99SDavid Xu break; 236a0712c99SDavid Xu case SCHED_OTHER: 237a94d3e1fSDavid Xu if (newkg->kg_pri_class != PRI_TIMESHARE) { 238a0712c99SDavid Xu rtp.type = PRI_TIMESHARE; 239a0712c99SDavid Xu rtp.prio = 0; 2402f26f4c6SDavid Xu rtp_to_pri(&rtp, newkg); 2412f26f4c6SDavid Xu sched_prio(newtd, newkg->kg_user_pri); 2422f26f4c6SDavid Xu } 243a0712c99SDavid Xu break; 244a0712c99SDavid Xu default: 245a0712c99SDavid Xu panic("sched policy"); 246a0712c99SDavid Xu } 247a0712c99SDavid Xu } 248ed062c8dSJulian Elischer TD_SET_CAN_RUN(newtd); 249c4bd610fSDavid Xu /* if ((flags & THR_SUSPENDED) == 0) */ 250ed062c8dSJulian Elischer setrunqueue(newtd, SRQ_BORING); 25189bb1cefSJeff Roberson mtx_unlock_spin(&sched_lock); 25289bb1cefSJeff Roberson 25389bb1cefSJeff Roberson return (error); 25489bb1cefSJeff Roberson } 25589bb1cefSJeff Roberson 25689bb1cefSJeff Roberson int 25789bb1cefSJeff Roberson thr_self(struct thread *td, struct thr_self_args *uap) 258cd28f17dSMarcel Moolenaar /* long *id */ 25989bb1cefSJeff Roberson { 260cd28f17dSMarcel Moolenaar long id; 26189bb1cefSJeff Roberson int error; 26289bb1cefSJeff Roberson 263cd28f17dSMarcel Moolenaar id = td->td_tid; 264cd28f17dSMarcel Moolenaar if ((error = copyout(&id, uap->id, sizeof(long)))) 26589bb1cefSJeff Roberson return (error); 26689bb1cefSJeff Roberson 26789bb1cefSJeff Roberson return (0); 26889bb1cefSJeff Roberson } 26989bb1cefSJeff Roberson 27089bb1cefSJeff Roberson int 27189bb1cefSJeff Roberson thr_exit(struct thread *td, struct thr_exit_args *uap) 272401901acSMike Makonnen /* long *state */ 27389bb1cefSJeff Roberson { 27489bb1cefSJeff Roberson struct proc *p; 27589bb1cefSJeff Roberson 27689bb1cefSJeff Roberson p = td->td_proc; 27789bb1cefSJeff Roberson 278401901acSMike Makonnen /* Signal userland that it can free the stack. */ 2794938faa6SDavid Xu if ((void *)uap->state != NULL) { 280401901acSMike Makonnen suword((void *)uap->state, 1); 2814938faa6SDavid Xu kern_umtx_wake(td, uap->state, INT_MAX); 2824938faa6SDavid Xu } 283401901acSMike Makonnen 28489bb1cefSJeff Roberson PROC_LOCK(p); 2859104847fSDavid Xu sigqueue_flush(&td->td_sigqueue); 28689bb1cefSJeff Roberson mtx_lock_spin(&sched_lock); 28789bb1cefSJeff Roberson 28889bb1cefSJeff Roberson /* 289ed062c8dSJulian Elischer * Shutting down last thread in the proc. This will actually 290ed062c8dSJulian Elischer * call exit() in the trampoline when it returns. 29189bb1cefSJeff Roberson */ 292ed062c8dSJulian Elischer if (p->p_numthreads != 1) { 29371b7afb2SDavid Xu thread_stopped(p); 294ed062c8dSJulian Elischer thread_exit(); 295ed062c8dSJulian Elischer /* NOTREACHED */ 296ed062c8dSJulian Elischer } 29789bb1cefSJeff Roberson mtx_unlock_spin(&sched_lock); 298ed062c8dSJulian Elischer PROC_UNLOCK(p); 29989bb1cefSJeff Roberson return (0); 30089bb1cefSJeff Roberson } 30189bb1cefSJeff Roberson 30289bb1cefSJeff Roberson int 30389bb1cefSJeff Roberson thr_kill(struct thread *td, struct thr_kill_args *uap) 304cd28f17dSMarcel Moolenaar /* long id, int sig */ 30589bb1cefSJeff Roberson { 30689bb1cefSJeff Roberson struct thread *ttd; 30789bb1cefSJeff Roberson struct proc *p; 30889bb1cefSJeff Roberson int error; 30989bb1cefSJeff Roberson 31089bb1cefSJeff Roberson p = td->td_proc; 31189bb1cefSJeff Roberson error = 0; 31289bb1cefSJeff Roberson PROC_LOCK(p); 3130a5cd498SDavid Xu if (uap->id == -1) { 3140a5cd498SDavid Xu if (uap->sig != 0 && !_SIG_VALID(uap->sig)) { 31589bb1cefSJeff Roberson error = EINVAL; 3160a5cd498SDavid Xu } else { 3170a5cd498SDavid Xu error = ESRCH; 3180a5cd498SDavid Xu FOREACH_THREAD_IN_PROC(p, ttd) { 3190a5cd498SDavid Xu if (ttd != td) { 3200a5cd498SDavid Xu error = 0; 3210a5cd498SDavid Xu if (uap->sig == 0) 3220a5cd498SDavid Xu break; 3236d7b314bSDavid Xu tdsignal(p, ttd, uap->sig, NULL); 3240a5cd498SDavid Xu } 3250a5cd498SDavid Xu } 3260a5cd498SDavid Xu } 3270a5cd498SDavid Xu } else { 3280a5cd498SDavid Xu if (uap->id != td->td_tid) 3290a5cd498SDavid Xu ttd = thread_find(p, uap->id); 3300a5cd498SDavid Xu else 3310a5cd498SDavid Xu ttd = td; 3320a5cd498SDavid Xu if (ttd == NULL) 3330a5cd498SDavid Xu error = ESRCH; 3340a5cd498SDavid Xu else if (uap->sig == 0) 3350a5cd498SDavid Xu ; 3360a5cd498SDavid Xu else if (!_SIG_VALID(uap->sig)) 3370a5cd498SDavid Xu error = EINVAL; 3380a5cd498SDavid Xu else 3390a5cd498SDavid Xu tdsignal(p, ttd, uap->sig, NULL); 3400a5cd498SDavid Xu } 34189bb1cefSJeff Roberson PROC_UNLOCK(p); 34289bb1cefSJeff Roberson return (error); 34389bb1cefSJeff Roberson } 3441713a516SMike Makonnen 3451713a516SMike Makonnen int 3461713a516SMike Makonnen thr_suspend(struct thread *td, struct thr_suspend_args *uap) 3471713a516SMike Makonnen /* const struct timespec *timeout */ 3481713a516SMike Makonnen { 3491713a516SMike Makonnen struct timespec ts; 3501713a516SMike Makonnen struct timeval tv; 3511713a516SMike Makonnen int error; 3521713a516SMike Makonnen int hz; 3531713a516SMike Makonnen 3541713a516SMike Makonnen hz = 0; 3551713a516SMike Makonnen error = 0; 3561713a516SMike Makonnen if (uap->timeout != NULL) { 3571713a516SMike Makonnen error = copyin((const void *)uap->timeout, (void *)&ts, 3581713a516SMike Makonnen sizeof(struct timespec)); 3591713a516SMike Makonnen if (error != 0) 3601713a516SMike Makonnen return (error); 3611713a516SMike Makonnen if (ts.tv_nsec < 0 || ts.tv_nsec > 1000000000) 3621713a516SMike Makonnen return (EINVAL); 3631713a516SMike Makonnen if (ts.tv_sec == 0 && ts.tv_nsec == 0) 3641713a516SMike Makonnen return (ETIMEDOUT); 3651713a516SMike Makonnen TIMESPEC_TO_TIMEVAL(&tv, &ts); 3661713a516SMike Makonnen hz = tvtohz(&tv); 3671713a516SMike Makonnen } 3681713a516SMike Makonnen PROC_LOCK(td->td_proc); 369c21e3b38SMike Makonnen if ((td->td_flags & TDF_THRWAKEUP) == 0) 3700f180a7cSJohn Baldwin error = msleep((void *)td, &td->td_proc->p_mtx, PCATCH, "lthr", 3710f180a7cSJohn Baldwin hz); 372c1df5a1aSDavid Xu if (td->td_flags & TDF_THRWAKEUP) { 3731713a516SMike Makonnen mtx_lock_spin(&sched_lock); 3741713a516SMike Makonnen td->td_flags &= ~TDF_THRWAKEUP; 3751713a516SMike Makonnen mtx_unlock_spin(&sched_lock); 3761713a516SMike Makonnen PROC_UNLOCK(td->td_proc); 377c1df5a1aSDavid Xu return (0); 378c1df5a1aSDavid Xu } 379c1df5a1aSDavid Xu PROC_UNLOCK(td->td_proc); 380c1df5a1aSDavid Xu if (error == EWOULDBLOCK) 381c1df5a1aSDavid Xu error = ETIMEDOUT; 382c1df5a1aSDavid Xu else if (error == ERESTART) { 383c1df5a1aSDavid Xu if (hz != 0) 384c1df5a1aSDavid Xu error = EINTR; 385c1df5a1aSDavid Xu } 386c1df5a1aSDavid Xu return (error); 3871713a516SMike Makonnen } 3881713a516SMike Makonnen 3891713a516SMike Makonnen int 3901713a516SMike Makonnen thr_wake(struct thread *td, struct thr_wake_args *uap) 391cd28f17dSMarcel Moolenaar /* long id */ 3921713a516SMike Makonnen { 39344355392SDavid Xu struct proc *p; 394cd28f17dSMarcel Moolenaar struct thread *ttd; 3951713a516SMike Makonnen 39644355392SDavid Xu p = td->td_proc; 39744355392SDavid Xu PROC_LOCK(p); 39844355392SDavid Xu ttd = thread_find(p, uap->id); 3991713a516SMike Makonnen if (ttd == NULL) { 40044355392SDavid Xu PROC_UNLOCK(p); 4011713a516SMike Makonnen return (ESRCH); 4021713a516SMike Makonnen } 4031713a516SMike Makonnen mtx_lock_spin(&sched_lock); 404cd28f17dSMarcel Moolenaar ttd->td_flags |= TDF_THRWAKEUP; 4051713a516SMike Makonnen mtx_unlock_spin(&sched_lock); 406c1df5a1aSDavid Xu wakeup((void *)ttd); 40744355392SDavid Xu PROC_UNLOCK(p); 4081713a516SMike Makonnen return (0); 4091713a516SMike Makonnen } 4109e7d7224SDavid Xu 4119e7d7224SDavid Xu int 4129e7d7224SDavid Xu thr_set_name(struct thread *td, struct thr_set_name_args *uap) 4139e7d7224SDavid Xu { 4149e7d7224SDavid Xu struct proc *p = td->td_proc; 4159e7d7224SDavid Xu char name[MAXCOMLEN + 1]; 4169e7d7224SDavid Xu struct thread *ttd; 4179e7d7224SDavid Xu int error; 4189e7d7224SDavid Xu 4199e7d7224SDavid Xu error = 0; 4209e7d7224SDavid Xu name[0] = '\0'; 4219e7d7224SDavid Xu if (uap->name != NULL) { 4229e7d7224SDavid Xu error = copyinstr(uap->name, name, sizeof(name), 4239e7d7224SDavid Xu NULL); 4249e7d7224SDavid Xu if (error) 4259e7d7224SDavid Xu return (error); 4269e7d7224SDavid Xu } 4279e7d7224SDavid Xu PROC_LOCK(p); 4289e7d7224SDavid Xu if (uap->id == td->td_tid) 4299e7d7224SDavid Xu ttd = td; 4309e7d7224SDavid Xu else 4319e7d7224SDavid Xu ttd = thread_find(p, uap->id); 4329e7d7224SDavid Xu if (ttd != NULL) 4339e7d7224SDavid Xu strcpy(ttd->td_name, name); 4349e7d7224SDavid Xu else 4359e7d7224SDavid Xu error = ESRCH; 4369e7d7224SDavid Xu PROC_UNLOCK(p); 4379e7d7224SDavid Xu return (error); 4389e7d7224SDavid Xu } 43960088160SDavid Xu 44060088160SDavid Xu int 44160088160SDavid Xu thr_setscheduler(struct thread *td, struct thr_setscheduler_args *uap) 44260088160SDavid Xu { 44360088160SDavid Xu struct proc *p; 44460088160SDavid Xu struct thread *ttd; 44560088160SDavid Xu struct rtprio rtp; 44660088160SDavid Xu struct sched_param param; 44760088160SDavid Xu int ret; 44860088160SDavid Xu 44960088160SDavid Xu if (uap->param_size != sizeof(struct sched_param)) 45060088160SDavid Xu return (EINVAL); 45160088160SDavid Xu 45260088160SDavid Xu ret = copyin(uap->param, ¶m, sizeof(struct sched_param)); 45360088160SDavid Xu if (ret) 45460088160SDavid Xu return (ret); 45560088160SDavid Xu 45660088160SDavid Xu switch(uap->policy) { 45760088160SDavid Xu case SCHED_FIFO: 45860088160SDavid Xu if (suser(td) != 0) 45960088160SDavid Xu return (EPERM); 46060088160SDavid Xu rtp.type = PRI_FIFO; 46160088160SDavid Xu break; 46260088160SDavid Xu case SCHED_RR: 46360088160SDavid Xu if (suser(td) != 0) 46460088160SDavid Xu return (EPERM); 46560088160SDavid Xu rtp.type = PRI_REALTIME; 46660088160SDavid Xu break; 46760088160SDavid Xu case SCHED_OTHER: 46860088160SDavid Xu rtp.type = PRI_TIMESHARE; 46960088160SDavid Xu break; 47060088160SDavid Xu default: 47160088160SDavid Xu return (EINVAL); 47260088160SDavid Xu } 47360088160SDavid Xu rtp.prio = param.sched_priority; 47460088160SDavid Xu 47560088160SDavid Xu p = td->td_proc; 47660088160SDavid Xu PROC_LOCK(p); 47760088160SDavid Xu ret = p_cansched(td, p); 47860088160SDavid Xu if (ret != 0) { 47960088160SDavid Xu PROC_UNLOCK(p); 48060088160SDavid Xu return (ret); 48160088160SDavid Xu } 48260088160SDavid Xu 48360088160SDavid Xu ttd = thread_find(p, uap->id); 48460088160SDavid Xu if (ttd == NULL) { 48560088160SDavid Xu PROC_UNLOCK(p); 48660088160SDavid Xu return (ESRCH); 48760088160SDavid Xu } 48860088160SDavid Xu mtx_lock_spin(&sched_lock); 48960088160SDavid Xu ret = rtp_to_pri(&rtp, ttd->td_ksegrp); 49060088160SDavid Xu if (ret == 0) { 49160088160SDavid Xu if (TD_IS_RUNNING(ttd)) 49260088160SDavid Xu ttd->td_flags |= TDF_NEEDRESCHED; 49360088160SDavid Xu else if (ttd->td_priority > ttd->td_ksegrp->kg_user_pri) 49460088160SDavid Xu sched_prio(ttd, ttd->td_ksegrp->kg_user_pri); 49560088160SDavid Xu } 49660088160SDavid Xu mtx_unlock_spin(&sched_lock); 49760088160SDavid Xu PROC_UNLOCK(p); 49860088160SDavid Xu return (ret); 49960088160SDavid Xu } 50060088160SDavid Xu 50160088160SDavid Xu int 50260088160SDavid Xu thr_getscheduler(struct thread *td, struct thr_getscheduler_args *uap) 50360088160SDavid Xu { 50460088160SDavid Xu struct proc *p; 50560088160SDavid Xu struct thread *ttd; 50660088160SDavid Xu struct rtprio rtp; 50760088160SDavid Xu struct sched_param param; 50860088160SDavid Xu int policy; 50960088160SDavid Xu int ret; 51060088160SDavid Xu 51160088160SDavid Xu if (uap->param_size != sizeof(struct sched_param)) 51260088160SDavid Xu return (EINVAL); 51360088160SDavid Xu 51460088160SDavid Xu p = td->td_proc; 51560088160SDavid Xu PROC_LOCK(p); 51660088160SDavid Xu ttd = thread_find(p, uap->id); 51760088160SDavid Xu if (ttd == NULL) { 51860088160SDavid Xu PROC_UNLOCK(p); 51960088160SDavid Xu return (ESRCH); 52060088160SDavid Xu } 52160088160SDavid Xu mtx_lock_spin(&sched_lock); 52260088160SDavid Xu switch(ttd->td_ksegrp->kg_pri_class) { 52360088160SDavid Xu case PRI_TIMESHARE: 52460088160SDavid Xu policy = SCHED_OTHER; 52560088160SDavid Xu break; 52660088160SDavid Xu case PRI_FIFO: 52760088160SDavid Xu policy = SCHED_FIFO; 52860088160SDavid Xu break; 52960088160SDavid Xu case PRI_REALTIME: 53060088160SDavid Xu policy = SCHED_RR; 53160088160SDavid Xu break; 53260088160SDavid Xu default: 53360088160SDavid Xu policy = SCHED_OTHER; /* XXX SCHED_IDLE */ 53460088160SDavid Xu } 53560088160SDavid Xu pri_to_rtp(ttd->td_ksegrp, &rtp); 53660088160SDavid Xu mtx_unlock_spin(&sched_lock); 53760088160SDavid Xu PROC_UNLOCK(p); 53860088160SDavid Xu 53960088160SDavid Xu param.sched_priority = rtp.prio; 54060088160SDavid Xu ret = copyout(&policy, uap->policy, sizeof(policy)); 54160088160SDavid Xu if (ret == 0) 54260088160SDavid Xu ret = copyout(¶m, uap->param, sizeof(param)); 54360088160SDavid Xu return (ret); 54460088160SDavid Xu } 54560088160SDavid Xu 54660088160SDavid Xu int 54760088160SDavid Xu thr_setschedparam(struct thread *td, struct thr_setschedparam_args *uap) 54860088160SDavid Xu { 54960088160SDavid Xu struct proc *p; 55060088160SDavid Xu struct thread *ttd; 55160088160SDavid Xu struct rtprio rtp; 55260088160SDavid Xu struct sched_param param; 55360088160SDavid Xu int ret; 55460088160SDavid Xu 55560088160SDavid Xu if (uap->param_size != sizeof(struct sched_param)) 55660088160SDavid Xu return (EINVAL); 55760088160SDavid Xu 55860088160SDavid Xu ret = copyin(uap->param, ¶m, sizeof(struct sched_param)); 55960088160SDavid Xu if (ret) 56060088160SDavid Xu return (ret); 56160088160SDavid Xu 56260088160SDavid Xu p = td->td_proc; 56360088160SDavid Xu PROC_LOCK(p); 56460088160SDavid Xu ret = p_cansched(td, p); 56560088160SDavid Xu if (ret != 0) { 56660088160SDavid Xu PROC_UNLOCK(p); 56760088160SDavid Xu return (ret); 56860088160SDavid Xu } 56960088160SDavid Xu 57060088160SDavid Xu ttd = thread_find(p, uap->id); 57160088160SDavid Xu if (ttd == NULL) { 57260088160SDavid Xu PROC_UNLOCK(p); 57360088160SDavid Xu return (ESRCH); 57460088160SDavid Xu } 57560088160SDavid Xu 57660088160SDavid Xu mtx_lock_spin(&sched_lock); 57760088160SDavid Xu pri_to_rtp(ttd->td_ksegrp, &rtp); 57860088160SDavid Xu rtp.prio = param.sched_priority; 57960088160SDavid Xu ret = rtp_to_pri(&rtp, ttd->td_ksegrp); 58060088160SDavid Xu if (ret == 0) { 58160088160SDavid Xu if (TD_IS_RUNNING(ttd)) 58260088160SDavid Xu ttd->td_flags |= TDF_NEEDRESCHED; 58360088160SDavid Xu else if (ttd->td_priority > ttd->td_ksegrp->kg_user_pri) 58460088160SDavid Xu sched_prio(ttd, ttd->td_ksegrp->kg_user_pri); 58560088160SDavid Xu } 58660088160SDavid Xu mtx_unlock_spin(&sched_lock); 58760088160SDavid Xu PROC_UNLOCK(p); 58860088160SDavid Xu return (ret); 58960088160SDavid Xu } 590