diff options
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/init_main.c | 1 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 2 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 2 | ||||
-rw-r--r-- | sys/kern/kern_kthread.c | 3 | ||||
-rw-r--r-- | sys/kern/kern_resource.c | 36 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 28 | ||||
-rw-r--r-- | sys/kern/kern_thr.c | 127 | ||||
-rw-r--r-- | sys/kern/kern_thread.c | 71 | ||||
-rw-r--r-- | sys/kern/kern_time.c | 28 | ||||
-rw-r--r-- | sys/kern/kern_umtx.c | 11 | ||||
-rw-r--r-- | sys/kern/sys_process.c | 17 | ||||
-rw-r--r-- | sys/kern/uipc_mqueue.c | 14 | ||||
-rw-r--r-- | sys/kern/vfs_aio.c | 12 |
13 files changed, 198 insertions, 154 deletions
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index de35a52..1dd8e73 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -443,6 +443,7 @@ proc0_init(void *dummy __unused) */ LIST_INSERT_HEAD(&allproc, p, p_list); LIST_INSERT_HEAD(PIDHASH(0), p, p_hash); + LIST_INSERT_HEAD(TIDHASH(0), td, td_hash); mtx_init(&pgrp0.pg_mtx, "process group", NULL, MTX_DEF | MTX_DUPOK); p->p_pgrp = &pgrp0; LIST_INSERT_HEAD(PGRPHASH(0), &pgrp0, pg_hash); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 8358f75..029f1c3 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -403,6 +403,8 @@ exit1(struct thread *td, int rv) PROC_UNLOCK(p); lim_free(plim); + tidhash_remove(td); + /* * Remove proc from allproc queue and pidhash chain. * Place onto zombproc. Unlink from parent's child list. diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 81631f6..da2c415 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -456,7 +456,7 @@ again: AUDIT_ARG_PID(p2->p_pid); LIST_INSERT_HEAD(&allproc, p2, p_list); LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash); - + tidhash_add(td2); PROC_LOCK(p2); PROC_LOCK(p1); diff --git a/sys/kern/kern_kthread.c b/sys/kern/kern_kthread.c index 264fc4a..9ab0922 100644 --- a/sys/kern/kern_kthread.c +++ b/sys/kern/kern_kthread.c @@ -295,6 +295,7 @@ kthread_add(void (*func)(void *), void *arg, struct proc *p, thread_unlock(oldtd); PROC_UNLOCK(p); + tidhash_add(newtd); /* Delay putting it on the run queue until now. */ if (!(flags & RFSTOPPED)) { @@ -314,6 +315,8 @@ kthread_exit(void) p = curthread->td_proc; + tidhash_remove(curthread); + /* A module may be waiting for us to exit. */ wakeup(curthread); PROC_LOCK(p); diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index ec2d6b6..09c8603 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -295,25 +295,23 @@ rtprio_thread(struct thread *td, struct rtprio_thread_args *uap) else cierror = 0; - /* - * Though lwpid is unique, only current process is supported - * since there is no efficient way to look up a LWP yet. - */ - p = td->td_proc; - PROC_LOCK(p); + if (uap->lwpid == 0 || uap->lwpid == td->td_tid) { + p = td->td_proc; + td1 = td; + PROC_LOCK(p); + } else { + /* Only look up thread in current process */ + td1 = tdfind(uap->lwpid, curproc->p_pid); + if (td1 == NULL) + return (ESRCH); + p = td1->td_proc; + } switch (uap->function) { case RTP_LOOKUP: if ((error = p_cansee(td, p))) break; - if (uap->lwpid == 0 || uap->lwpid == td->td_tid) - td1 = td; - else - td1 = thread_find(p, uap->lwpid); - if (td1 != NULL) - pri_to_rtp(td1, &rtp); - else - error = ESRCH; + pri_to_rtp(td1, &rtp); PROC_UNLOCK(p); return (copyout(&rtp, uap->rtp, sizeof(struct rtprio))); case RTP_SET: @@ -337,15 +335,7 @@ rtprio_thread(struct thread *td, struct rtprio_thread_args *uap) if (error) break; } - - if (uap->lwpid == 0 || uap->lwpid == td->td_tid) - td1 = td; - else - td1 = thread_find(p, uap->lwpid); - if (td1 != NULL) - error = rtp_to_pri(&rtp, td1); - else - error = ESRCH; + error = rtp_to_pri(&rtp, td1); break; default: error = EINVAL; diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index d315ff1..4ac4d78 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -107,8 +107,6 @@ static int killpg1(struct thread *td, int sig, int pgid, int all, ksiginfo_t *ksi); static int issignal(struct thread *td, int stop_allowed); static int sigprop(int sig); -static int tdsendsignal(struct proc *p, struct thread *td, int sig, - ksiginfo_t *ksi); static void tdsigwakeup(struct thread *, int, sig_t, int); static void sig_suspend_threads(struct thread *, struct proc *, int); static int filt_sigattach(struct knote *kn); @@ -1974,27 +1972,22 @@ pksignal(struct proc *p, int sig, ksiginfo_t *ksi) return (tdsendsignal(p, NULL, sig, ksi)); } +/* Utility function for finding a thread to send signal event to. */ int -psignal_event(struct proc *p, struct sigevent *sigev, ksiginfo_t *ksi) +sigev_findtd(struct proc *p ,struct sigevent *sigev, struct thread **ttd) { - struct thread *td = NULL; - - PROC_LOCK_ASSERT(p, MA_OWNED); - - KASSERT(!KSI_ONQ(ksi), ("psignal_event: ksi on queue")); + struct thread *td; - /* - * ksi_code and other fields should be set before - * calling this function. - */ - ksi->ksi_signo = sigev->sigev_signo; - ksi->ksi_value = sigev->sigev_value; if (sigev->sigev_notify == SIGEV_THREAD_ID) { - td = thread_find(p, sigev->sigev_notify_thread_id); + td = tdfind(sigev->sigev_notify_thread_id, p->p_pid); if (td == NULL) return (ESRCH); + *ttd = td; + } else { + *ttd = NULL; + PROC_LOCK(p); } - return (tdsendsignal(p, td, ksi->ksi_signo, ksi)); + return (0); } void @@ -2015,7 +2008,7 @@ tdksignal(struct thread *td, int sig, ksiginfo_t *ksi) (void) tdsendsignal(td->td_proc, td, sig, ksi); } -static int +int tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi) { sig_t action; @@ -2026,6 +2019,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi) int ret = 0; int wakeup_swapper; + MPASS(td == NULL || p == td->td_proc); PROC_LOCK_ASSERT(p, MA_OWNED); if (!_SIG_VALID(sig)) diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c index 21f0644..7627027 100644 --- a/sys/kern/kern_thr.c +++ b/sys/kern/kern_thr.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/sysproto.h> #include <sys/signalvar.h> +#include <sys/sx.h> #include <sys/ucontext.h> #include <sys/thr.h> #include <sys/rtprio.h> @@ -240,6 +241,9 @@ create_thread(struct thread *td, mcontext_t *ctx, if (P_SHOULDSTOP(p)) newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK; PROC_UNLOCK(p); + + tidhash_add(newtd); + thread_lock(newtd); if (rtp != NULL) { if (!(td->td_pri_class == PRI_TIMESHARE && @@ -281,6 +285,8 @@ thr_exit(struct thread *td, struct thr_exit_args *uap) kern_umtx_wake(td, uap->state, INT_MAX, 0); } + tidhash_remove(td); + PROC_LOCK(p); tdsigcleanup(td); PROC_SLOCK(p); @@ -309,18 +315,17 @@ thr_kill(struct thread *td, struct thr_kill_args *uap) int error; p = td->td_proc; - error = 0; ksiginfo_init(&ksi); ksi.ksi_signo = uap->sig; ksi.ksi_code = SI_LWP; ksi.ksi_pid = p->p_pid; ksi.ksi_uid = td->td_ucred->cr_ruid; - PROC_LOCK(p); if (uap->id == -1) { if (uap->sig != 0 && !_SIG_VALID(uap->sig)) { error = EINVAL; } else { error = ESRCH; + PROC_LOCK(p); FOREACH_THREAD_IN_PROC(p, ttd) { if (ttd != td) { error = 0; @@ -329,22 +334,21 @@ thr_kill(struct thread *td, struct thr_kill_args *uap) tdksignal(ttd, uap->sig, &ksi); } } + PROC_UNLOCK(p); } } else { - if (uap->id != td->td_tid) - ttd = thread_find(p, uap->id); - else - ttd = td; + error = 0; + ttd = tdfind((lwpid_t)uap->id, p->p_pid); if (ttd == NULL) - error = ESRCH; - else if (uap->sig == 0) + return (ESRCH); + if (uap->sig == 0) ; else if (!_SIG_VALID(uap->sig)) error = EINVAL; - else + else tdksignal(ttd, uap->sig, &ksi); + PROC_UNLOCK(ttd->td_proc); } - PROC_UNLOCK(p); return (error); } @@ -359,51 +363,49 @@ thr_kill2(struct thread *td, struct thr_kill2_args *uap) AUDIT_ARG_SIGNUM(uap->sig); - if (uap->pid == td->td_proc->p_pid) { - p = td->td_proc; - PROC_LOCK(p); - } else if ((p = pfind(uap->pid)) == NULL) { - return (ESRCH); - } - AUDIT_ARG_PROCESS(p); - - error = p_cansignal(td, p, uap->sig); - if (error == 0) { - ksiginfo_init(&ksi); - ksi.ksi_signo = uap->sig; - ksi.ksi_code = SI_LWP; - ksi.ksi_pid = td->td_proc->p_pid; - ksi.ksi_uid = td->td_ucred->cr_ruid; - if (uap->id == -1) { - if (uap->sig != 0 && !_SIG_VALID(uap->sig)) { - error = EINVAL; - } else { - error = ESRCH; - FOREACH_THREAD_IN_PROC(p, ttd) { - if (ttd != td) { - error = 0; - if (uap->sig == 0) - break; - tdksignal(ttd, uap->sig, &ksi); - } + ksiginfo_init(&ksi); + ksi.ksi_signo = uap->sig; + ksi.ksi_code = SI_LWP; + ksi.ksi_pid = td->td_proc->p_pid; + ksi.ksi_uid = td->td_ucred->cr_ruid; + if (uap->id == -1) { + if ((p = pfind(uap->pid)) == NULL) + return (ESRCH); + AUDIT_ARG_PROCESS(p); + error = p_cansignal(td, p, uap->sig); + if (error) { + PROC_UNLOCK(p); + return (error); + } + if (uap->sig != 0 && !_SIG_VALID(uap->sig)) { + error = EINVAL; + } else { + error = ESRCH; + FOREACH_THREAD_IN_PROC(p, ttd) { + if (ttd != td) { + error = 0; + if (uap->sig == 0) + break; + tdksignal(ttd, uap->sig, &ksi); } } - } else { - if (uap->id != td->td_tid) - ttd = thread_find(p, uap->id); - else - ttd = td; - if (ttd == NULL) - error = ESRCH; - else if (uap->sig == 0) - ; - else if (!_SIG_VALID(uap->sig)) - error = EINVAL; - else - tdksignal(ttd, uap->sig, &ksi); } + PROC_UNLOCK(p); + } else { + ttd = tdfind((lwpid_t)uap->id, uap->pid); + if (ttd == NULL) + return (ESRCH); + p = ttd->td_proc; + AUDIT_ARG_PROCESS(p); + error = p_cansignal(td, p, uap->sig); + if (uap->sig == 0) + ; + else if (!_SIG_VALID(uap->sig)) + error = EINVAL; + else + tdksignal(ttd, uap->sig, &ksi); + PROC_UNLOCK(p); } - PROC_UNLOCK(p); return (error); } @@ -485,12 +487,9 @@ thr_wake(struct thread *td, struct thr_wake_args *uap) } p = td->td_proc; - PROC_LOCK(p); - ttd = thread_find(p, uap->id); - if (ttd == NULL) { - PROC_UNLOCK(p); + ttd = tdfind((lwpid_t)uap->id, p->p_pid); + if (ttd == NULL) return (ESRCH); - } thread_lock(ttd); ttd->td_flags |= TDF_THRWAKEUP; thread_unlock(ttd); @@ -502,7 +501,7 @@ thr_wake(struct thread *td, struct thr_wake_args *uap) int thr_set_name(struct thread *td, struct thr_set_name_args *uap) { - struct proc *p = td->td_proc; + struct proc *p; char name[MAXCOMLEN + 1]; struct thread *ttd; int error; @@ -515,15 +514,11 @@ thr_set_name(struct thread *td, struct thr_set_name_args *uap) if (error) return (error); } - PROC_LOCK(p); - if (uap->id == td->td_tid) - ttd = td; - else - ttd = thread_find(p, uap->id); - if (ttd != NULL) - strcpy(ttd->td_name, name); - else - error = ESRCH; + p = td->td_proc; + ttd = tdfind((lwpid_t)uap->id, p->p_pid); + if (ttd == NULL) + return (ESRCH); + strcpy(ttd->td_name, name); PROC_UNLOCK(p); return (error); } diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index e500e0a..89f6137 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include <sys/selinfo.h> #include <sys/turnstile.h> #include <sys/ktr.h> +#include <sys/rwlock.h> #include <sys/umtx.h> #include <sys/cpuset.h> #ifdef HWPMC_HOOKS @@ -83,6 +84,12 @@ static void thread_zombie(struct thread *); struct mtx tid_lock; static struct unrhdr *tid_unrhdr; +static MALLOC_DEFINE(M_TIDHASH, "tidhash", "thread hash"); + +struct tidhashhead *tidhashtbl; +u_long tidhash; +struct rwlock tidhash_lock; + /* * Prepare a thread for use. */ @@ -230,6 +237,8 @@ threadinit(void) thread_zone = uma_zcreate("THREAD", sched_sizeof_thread(), thread_ctor, thread_dtor, thread_init, thread_fini, 16 - 1, 0); + tidhashtbl = hashinit(maxproc / 2, M_TIDHASH, &tidhash); + rw_init(&tidhash_lock, "tidhash"); } /* @@ -748,8 +757,14 @@ thread_suspend_check(int return_instead) * this thread should just suicide. * Assumes that P_SINGLE_EXIT implies P_STOPPED_SINGLE. */ - if ((p->p_flag & P_SINGLE_EXIT) && (p->p_singlethread != td)) + if ((p->p_flag & P_SINGLE_EXIT) && (p->p_singlethread != td)) { + PROC_SUNLOCK(p); + PROC_UNLOCK(p); + tidhash_remove(td); + PROC_LOCK(p); + PROC_SLOCK(p); thread_exit(); + } if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) { if (p->p_numthreads == p->p_suspcount + 1) { thread_lock(p->p_singlethread); @@ -923,3 +938,57 @@ thread_find(struct proc *p, lwpid_t tid) } return (td); } + +/* Locate a thread by number; return with proc lock held. */ +struct thread * +tdfind(lwpid_t tid, pid_t pid) +{ +#define RUN_THRESH 16 + struct thread *td; + int run = 0; + + rw_rlock(&tidhash_lock); + LIST_FOREACH(td, TIDHASH(tid), td_hash) { + if (td->td_tid == tid) { + if (pid != -1 && td->td_proc->p_pid != pid) { + td = NULL; + break; + } + if (td->td_proc->p_state == PRS_NEW) { + td = NULL; + break; + } + if (run > RUN_THRESH) { + if (rw_try_upgrade(&tidhash_lock)) { + LIST_REMOVE(td, td_hash); + LIST_INSERT_HEAD(TIDHASH(td->td_tid), + td, td_hash); + PROC_LOCK(td->td_proc); + rw_wunlock(&tidhash_lock); + return (td); + } + } + PROC_LOCK(td->td_proc); + break; + } + run++; + } + rw_runlock(&tidhash_lock); + return (td); +} + +void +tidhash_add(struct thread *td) +{ + rw_wlock(&tidhash_lock); + LIST_INSERT_HEAD(TIDHASH(td->td_tid), td, td_hash); + rw_wunlock(&tidhash_lock); +} + +void +tidhash_remove(struct thread *td) +{ + rw_wlock(&tidhash_lock); + LIST_REMOVE(td, td_hash); + rw_wunlock(&tidhash_lock); +} diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 3aea2bd..a153fbc 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -1402,28 +1402,22 @@ void itimer_fire(struct itimer *it) { struct proc *p = it->it_proc; - int ret; + struct thread *td; if (it->it_sigev.sigev_notify == SIGEV_SIGNAL || it->it_sigev.sigev_notify == SIGEV_THREAD_ID) { - PROC_LOCK(p); + if (sigev_findtd(p, &it->it_sigev, &td) != 0) { + ITIMER_LOCK(it); + timespecclear(&it->it_time.it_value); + timespecclear(&it->it_time.it_interval); + callout_stop(&it->it_callout); + ITIMER_UNLOCK(it); + return; + } if (!KSI_ONQ(&it->it_ksi)) { it->it_ksi.ksi_errno = 0; - ret = psignal_event(p, &it->it_sigev, &it->it_ksi); - if (__predict_false(ret != 0)) { - it->it_overrun++; - /* - * Broken userland code, thread went - * away, disarm the timer. - */ - if (ret == ESRCH) { - ITIMER_LOCK(it); - timespecclear(&it->it_time.it_value); - timespecclear(&it->it_time.it_interval); - callout_stop(&it->it_callout); - ITIMER_UNLOCK(it); - } - } + ksiginfo_set_sigev(&it->it_ksi, &it->it_sigev); + tdsendsignal(p, td, it->it_ksi.ksi_signo, &it->it_ksi); } else { if (it->it_overrun < INT_MAX) it->it_overrun++; diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c index bdae3e8..cf8c534 100644 --- a/sys/kern/kern_umtx.c +++ b/sys/kern/kern_umtx.c @@ -1588,20 +1588,15 @@ umtxq_sleep_pi(struct umtx_q *uq, struct umtx_pi *pi, umtxq_insert(uq); mtx_lock_spin(&umtx_lock); if (pi->pi_owner == NULL) { - /* XXX - * Current, We only support process private PI-mutex, - * we need a faster way to find an owner thread for - * process-shared mutex (not available yet). - */ mtx_unlock_spin(&umtx_lock); - PROC_LOCK(curproc); - td1 = thread_find(curproc, owner); + /* XXX Only look up thread in current process. */ + td1 = tdfind(owner, curproc->p_pid); mtx_lock_spin(&umtx_lock); if (td1 != NULL && pi->pi_owner == NULL) { uq1 = td1->td_umtxq; umtx_pi_setowner(pi, td1); } - PROC_UNLOCK(curproc); + PROC_UNLOCK(td1->td_proc); } TAILQ_FOREACH(uq1, &pi->pi_blocked, uq_lockq) { diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 525c0e2..af6b298 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -721,24 +721,13 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) return (ESRCH); } } else { - /* this is slow, should be optimized */ - sx_slock(&allproc_lock); - FOREACH_PROC_IN_SYSTEM(p) { - PROC_LOCK(p); - FOREACH_THREAD_IN_PROC(p, td2) { - if (td2->td_tid == pid) - break; - } - if (td2 != NULL) - break; /* proc lock held */ - PROC_UNLOCK(p); - } - sx_sunlock(&allproc_lock); - if (p == NULL) { + td2 = tdfind(pid, -1); + if (td2 == NULL) { if (proctree_locked) sx_xunlock(&proctree_lock); return (ESRCH); } + p = td2->td_proc; tid = pid; pid = p->p_pid; } diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c index de65462..30c1aa9 100644 --- a/sys/kern/uipc_mqueue.c +++ b/sys/kern/uipc_mqueue.c @@ -1747,15 +1747,23 @@ static void mqueue_send_notification(struct mqueue *mq) { struct mqueue_notifier *nt; + struct thread *td; struct proc *p; + int error; mtx_assert(&mq->mq_mutex, MA_OWNED); nt = mq->mq_notifier; if (nt->nt_sigev.sigev_notify != SIGEV_NONE) { p = nt->nt_proc; - PROC_LOCK(p); - if (!KSI_ONQ(&nt->nt_ksi)) - psignal_event(p, &nt->nt_sigev, &nt->nt_ksi); + error = sigev_findtd(p, &nt->nt_sigev, &td); + if (error) { + mq->mq_notifier = NULL; + return; + } + if (!KSI_ONQ(&nt->nt_ksi)) { + ksiginfo_set_sigev(&nt->nt_ksi, &nt->nt_sigev); + tdsendsignal(p, td, nt->nt_ksi.ksi_signo, &nt->nt_ksi); + } PROC_UNLOCK(p); } mq->mq_notifier = NULL; diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c index e05106a..69b4e0a 100644 --- a/sys/kern/vfs_aio.c +++ b/sys/kern/vfs_aio.c @@ -609,16 +609,20 @@ aio_init_aioinfo(struct proc *p) static int aio_sendsig(struct proc *p, struct sigevent *sigev, ksiginfo_t *ksi) { - int ret = 0; + struct thread *td; + int error; - PROC_LOCK(p); + error = sigev_findtd(p, sigev, &td); + if (error) + return (error); if (!KSI_ONQ(ksi)) { + ksiginfo_set_sigev(ksi, sigev); ksi->ksi_code = SI_ASYNCIO; ksi->ksi_flags |= KSI_EXT | KSI_INS; - ret = psignal_event(p, sigev, ksi); + tdsendsignal(p, td, ksi->ksi_signo, ksi); } PROC_UNLOCK(p); - return (ret); + return (error); } /* |