189bb1cefSJeff Roberson /* 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); 52a8b491c1SJulian Elischer static int thr_scope_sys = 0; 53a8b491c1SJulian Elischer SYSCTL_INT(_kern_threads, OID_AUTO, thr_scope_sys, CTLFLAG_RW, 54a8b491c1SJulian Elischer &thr_scope_sys, 0, "sys or proc scope scheduling"); 55a8b491c1SJulian Elischer 56a8b491c1SJulian Elischer static int thr_concurency = 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 6089bb1cefSJeff Roberson /* 6189bb1cefSJeff Roberson * Back end support functions. 6289bb1cefSJeff Roberson */ 6389bb1cefSJeff Roberson 6489bb1cefSJeff Roberson #define RANGEOF(type, start, end) (offsetof(type, end) - offsetof(type, start)) 6589bb1cefSJeff Roberson 6689bb1cefSJeff Roberson /* 6789bb1cefSJeff Roberson * System call interface. 6889bb1cefSJeff Roberson */ 6989bb1cefSJeff Roberson int 7089bb1cefSJeff Roberson thr_create(struct thread *td, struct thr_create_args *uap) 71cd28f17dSMarcel Moolenaar /* ucontext_t *ctx, long *id, int flags */ 7289bb1cefSJeff Roberson { 73ed062c8dSJulian Elischer struct thread *newtd; 7489bb1cefSJeff Roberson ucontext_t ctx; 75cd28f17dSMarcel Moolenaar long id; 7689bb1cefSJeff Roberson int error; 77ed062c8dSJulian Elischer struct ksegrp *kg, *newkg; 78ed062c8dSJulian Elischer struct proc *p; 7989bb1cefSJeff Roberson 80ed062c8dSJulian Elischer p = td->td_proc; 81ed062c8dSJulian Elischer kg = td->td_ksegrp; 8289bb1cefSJeff Roberson if ((error = copyin(uap->ctx, &ctx, sizeof(ctx)))) 8389bb1cefSJeff Roberson return (error); 8489bb1cefSJeff Roberson 85ed062c8dSJulian Elischer /* Have race condition but it is cheap */ 86ed062c8dSJulian Elischer if ((p->p_numksegrps >= max_groups_per_proc) || 87ed062c8dSJulian Elischer (p->p_numthreads >= max_threads_per_proc)) { 88ed062c8dSJulian Elischer return (EPROCLIM); 89ed062c8dSJulian Elischer } 90ed062c8dSJulian Elischer /* Initialize our td and new ksegrp.. */ 91ed062c8dSJulian Elischer newtd = thread_alloc(); 92a8b491c1SJulian Elischer if (thr_scope_sys) 93ed062c8dSJulian Elischer newkg = ksegrp_alloc(); 94a8b491c1SJulian Elischer else 95a8b491c1SJulian Elischer newkg = kg; 9689bb1cefSJeff Roberson /* 9789bb1cefSJeff Roberson * Try the copyout as soon as we allocate the td so we don't have to 9889bb1cefSJeff Roberson * tear things down in a failure case below. 9989bb1cefSJeff Roberson */ 100ed062c8dSJulian Elischer id = newtd->td_tid; 101cd28f17dSMarcel Moolenaar if ((error = copyout(&id, uap->id, sizeof(long)))) { 102a8b491c1SJulian Elischer if (thr_scope_sys) 103ed062c8dSJulian Elischer ksegrp_free(newkg); 104ed062c8dSJulian Elischer thread_free(newtd); 10589bb1cefSJeff Roberson return (error); 10689bb1cefSJeff Roberson } 10789bb1cefSJeff Roberson 108ed062c8dSJulian Elischer bzero(&newtd->td_startzero, 10989bb1cefSJeff Roberson (unsigned) RANGEOF(struct thread, td_startzero, td_endzero)); 110ed062c8dSJulian Elischer bcopy(&td->td_startcopy, &newtd->td_startcopy, 11189bb1cefSJeff Roberson (unsigned) RANGEOF(struct thread, td_startcopy, td_endcopy)); 11289bb1cefSJeff Roberson 113a8b491c1SJulian Elischer if (thr_scope_sys) { 114ed062c8dSJulian Elischer bzero(&newkg->kg_startzero, 115ed062c8dSJulian Elischer (unsigned)RANGEOF(struct ksegrp, kg_startzero, kg_endzero)); 116ed062c8dSJulian Elischer bcopy(&kg->kg_startcopy, &newkg->kg_startcopy, 117ed062c8dSJulian Elischer (unsigned)RANGEOF(struct ksegrp, kg_startcopy, kg_endcopy)); 118a8b491c1SJulian Elischer } 11989bb1cefSJeff Roberson 120ed062c8dSJulian Elischer newtd->td_proc = td->td_proc; 121ed062c8dSJulian Elischer newtd->td_ucred = crhold(td->td_ucred); 12289bb1cefSJeff Roberson 12389bb1cefSJeff Roberson /* Set up our machine context. */ 124ed062c8dSJulian Elischer cpu_set_upcall(newtd, td); 125ed062c8dSJulian Elischer error = set_mcontext(newtd, &ctx.uc_mcontext); 12689bb1cefSJeff Roberson if (error != 0) { 127a8b491c1SJulian Elischer if (thr_scope_sys) 128ed062c8dSJulian Elischer ksegrp_free(newkg); 129ed062c8dSJulian Elischer thread_free(newtd); 130ed062c8dSJulian Elischer crfree(td->td_ucred); 13189bb1cefSJeff Roberson goto out; 13289bb1cefSJeff Roberson } 13389bb1cefSJeff Roberson 13489bb1cefSJeff Roberson /* Link the thread and kse into the ksegrp and make it runnable. */ 135ed062c8dSJulian Elischer PROC_LOCK(td->td_proc); 136a8b491c1SJulian Elischer if (thr_scope_sys) { 137a8b491c1SJulian Elischer sched_init_concurrency(newkg); 138a8b491c1SJulian Elischer } else { 139a8b491c1SJulian Elischer if ((td->td_proc->p_flag & P_HADTHREADS) == 0) { 140a8b491c1SJulian Elischer sched_set_concurrency(kg, 141a8b491c1SJulian Elischer thr_concurrency ? thr_concurrency : (2*mp_ncpus)); 142a8b491c1SJulian Elischer } 143a8b491c1SJulian Elischer } 144a8b491c1SJulian Elischer 145ed062c8dSJulian Elischer td->td_proc->p_flag |= P_HADTHREADS; 146ed062c8dSJulian Elischer newtd->td_sigmask = td->td_sigmask; 14789bb1cefSJeff Roberson mtx_lock_spin(&sched_lock); 148a8b491c1SJulian Elischer if (thr_scope_sys) 149ed062c8dSJulian Elischer ksegrp_link(newkg, p); 150ed062c8dSJulian Elischer thread_link(newtd, newkg); 151ed062c8dSJulian Elischer mtx_unlock_spin(&sched_lock); 152ed062c8dSJulian Elischer PROC_UNLOCK(p); 15389bb1cefSJeff Roberson 154ed062c8dSJulian Elischer /* let the scheduler know about these things. */ 155ed062c8dSJulian Elischer mtx_lock_spin(&sched_lock); 156a8b491c1SJulian Elischer if (thr_scope_sys) 157ed062c8dSJulian Elischer sched_fork_ksegrp(td, newkg); 158ed062c8dSJulian Elischer sched_fork_thread(td, newtd); 15989bb1cefSJeff Roberson 160ed062c8dSJulian Elischer TD_SET_CAN_RUN(newtd); 16189bb1cefSJeff Roberson if ((uap->flags & THR_SUSPENDED) == 0) 162ed062c8dSJulian Elischer setrunqueue(newtd, SRQ_BORING); 16389bb1cefSJeff Roberson 16489bb1cefSJeff Roberson mtx_unlock_spin(&sched_lock); 16589bb1cefSJeff Roberson 16689bb1cefSJeff Roberson out: 16789bb1cefSJeff Roberson return (error); 16889bb1cefSJeff Roberson } 16989bb1cefSJeff Roberson 17089bb1cefSJeff Roberson int 17189bb1cefSJeff Roberson thr_self(struct thread *td, struct thr_self_args *uap) 172cd28f17dSMarcel Moolenaar /* long *id */ 17389bb1cefSJeff Roberson { 174cd28f17dSMarcel Moolenaar long id; 17589bb1cefSJeff Roberson int error; 17689bb1cefSJeff Roberson 177cd28f17dSMarcel Moolenaar id = td->td_tid; 178cd28f17dSMarcel Moolenaar if ((error = copyout(&id, uap->id, sizeof(long)))) 17989bb1cefSJeff Roberson return (error); 18089bb1cefSJeff Roberson 18189bb1cefSJeff Roberson return (0); 18289bb1cefSJeff Roberson } 18389bb1cefSJeff Roberson 18489bb1cefSJeff Roberson int 18589bb1cefSJeff Roberson thr_exit(struct thread *td, struct thr_exit_args *uap) 18689bb1cefSJeff Roberson /* NULL */ 18789bb1cefSJeff Roberson { 18889bb1cefSJeff Roberson struct proc *p; 18989bb1cefSJeff Roberson 19089bb1cefSJeff Roberson p = td->td_proc; 19189bb1cefSJeff Roberson 19289bb1cefSJeff Roberson PROC_LOCK(p); 19389bb1cefSJeff Roberson mtx_lock_spin(&sched_lock); 19489bb1cefSJeff Roberson 19589bb1cefSJeff Roberson /* 196ed062c8dSJulian Elischer * Shutting down last thread in the proc. This will actually 197ed062c8dSJulian Elischer * call exit() in the trampoline when it returns. 19889bb1cefSJeff Roberson */ 199ed062c8dSJulian Elischer if (p->p_numthreads != 1) { 200ed062c8dSJulian Elischer thread_exit(); 201ed062c8dSJulian Elischer /* NOTREACHED */ 202ed062c8dSJulian Elischer } 20389bb1cefSJeff Roberson mtx_unlock_spin(&sched_lock); 204ed062c8dSJulian Elischer PROC_UNLOCK(p); 20589bb1cefSJeff Roberson return (0); 20689bb1cefSJeff Roberson } 20789bb1cefSJeff Roberson 20889bb1cefSJeff Roberson int 20989bb1cefSJeff Roberson thr_kill(struct thread *td, struct thr_kill_args *uap) 210cd28f17dSMarcel Moolenaar /* long id, int sig */ 21189bb1cefSJeff Roberson { 21289bb1cefSJeff Roberson struct thread *ttd; 21389bb1cefSJeff Roberson struct proc *p; 21489bb1cefSJeff Roberson int error; 21589bb1cefSJeff Roberson 21689bb1cefSJeff Roberson p = td->td_proc; 21789bb1cefSJeff Roberson error = 0; 21889bb1cefSJeff Roberson PROC_LOCK(p); 21971cfaac0SMike Makonnen FOREACH_THREAD_IN_PROC(p, ttd) { 220cd28f17dSMarcel Moolenaar if (ttd->td_tid == uap->id) 22189bb1cefSJeff Roberson break; 22271cfaac0SMike Makonnen } 22389bb1cefSJeff Roberson if (ttd == NULL) { 22489bb1cefSJeff Roberson error = ESRCH; 22589bb1cefSJeff Roberson goto out; 22689bb1cefSJeff Roberson } 22789bb1cefSJeff Roberson if (uap->sig == 0) 22889bb1cefSJeff Roberson goto out; 22989bb1cefSJeff Roberson if (!_SIG_VALID(uap->sig)) { 23089bb1cefSJeff Roberson error = EINVAL; 23189bb1cefSJeff Roberson goto out; 23289bb1cefSJeff Roberson } 233c197abc4SMike Makonnen tdsignal(ttd, uap->sig, SIGTARGET_TD); 23489bb1cefSJeff Roberson out: 23589bb1cefSJeff Roberson PROC_UNLOCK(p); 23689bb1cefSJeff Roberson return (error); 23789bb1cefSJeff Roberson } 2381713a516SMike Makonnen 2391713a516SMike Makonnen int 2401713a516SMike Makonnen thr_suspend(struct thread *td, struct thr_suspend_args *uap) 2411713a516SMike Makonnen /* const struct timespec *timeout */ 2421713a516SMike Makonnen { 2431713a516SMike Makonnen struct timespec ts; 2441713a516SMike Makonnen struct timeval tv; 2451713a516SMike Makonnen int error; 2461713a516SMike Makonnen int hz; 2471713a516SMike Makonnen 2481713a516SMike Makonnen hz = 0; 2491713a516SMike Makonnen error = 0; 2501713a516SMike Makonnen if (uap->timeout != NULL) { 2511713a516SMike Makonnen error = copyin((const void *)uap->timeout, (void *)&ts, 2521713a516SMike Makonnen sizeof(struct timespec)); 2531713a516SMike Makonnen if (error != 0) 2541713a516SMike Makonnen return (error); 2551713a516SMike Makonnen if (ts.tv_nsec < 0 || ts.tv_nsec > 1000000000) 2561713a516SMike Makonnen return (EINVAL); 2571713a516SMike Makonnen if (ts.tv_sec == 0 && ts.tv_nsec == 0) 2581713a516SMike Makonnen return (ETIMEDOUT); 2591713a516SMike Makonnen TIMESPEC_TO_TIMEVAL(&tv, &ts); 2601713a516SMike Makonnen hz = tvtohz(&tv); 2611713a516SMike Makonnen } 2621713a516SMike Makonnen PROC_LOCK(td->td_proc); 263c21e3b38SMike Makonnen if ((td->td_flags & TDF_THRWAKEUP) == 0) 2641713a516SMike Makonnen error = msleep((void *)td, &td->td_proc->p_mtx, 2651713a516SMike Makonnen td->td_priority | PCATCH, "lthr", hz); 2661713a516SMike Makonnen mtx_lock_spin(&sched_lock); 2671713a516SMike Makonnen td->td_flags &= ~TDF_THRWAKEUP; 2681713a516SMike Makonnen mtx_unlock_spin(&sched_lock); 2691713a516SMike Makonnen PROC_UNLOCK(td->td_proc); 2701713a516SMike Makonnen return (error == EWOULDBLOCK ? ETIMEDOUT : error); 2711713a516SMike Makonnen } 2721713a516SMike Makonnen 2731713a516SMike Makonnen int 2741713a516SMike Makonnen thr_wake(struct thread *td, struct thr_wake_args *uap) 275cd28f17dSMarcel Moolenaar /* long id */ 2761713a516SMike Makonnen { 277cd28f17dSMarcel Moolenaar struct thread *ttd; 2781713a516SMike Makonnen 279b9fb5d42SMike Makonnen PROC_LOCK(td->td_proc); 280b9fb5d42SMike Makonnen FOREACH_THREAD_IN_PROC(td->td_proc, ttd) { 281cd28f17dSMarcel Moolenaar if (ttd->td_tid == uap->id) 2821713a516SMike Makonnen break; 2831713a516SMike Makonnen } 2841713a516SMike Makonnen if (ttd == NULL) { 285b9fb5d42SMike Makonnen PROC_UNLOCK(td->td_proc); 2861713a516SMike Makonnen return (ESRCH); 2871713a516SMike Makonnen } 2881713a516SMike Makonnen mtx_lock_spin(&sched_lock); 289cd28f17dSMarcel Moolenaar ttd->td_flags |= TDF_THRWAKEUP; 2901713a516SMike Makonnen mtx_unlock_spin(&sched_lock); 291cd28f17dSMarcel Moolenaar wakeup_one((void *)ttd); 292b9fb5d42SMike Makonnen PROC_UNLOCK(td->td_proc); 2931713a516SMike Makonnen return (0); 2941713a516SMike Makonnen } 295