Create a global thread hash table to speed up thread lookup, use
rwlock to protect the table. In old code, thread lookup is done with process lock held, to find a thread, kernel has to iterate through process and thread list, this is quite inefficient. With this change, test shows in extreme case performance is dramatically improved. Earlier patch was reviewed by: jhb, julian
This commit is contained in:
parent
a362d75576
commit
cf7d9a8ca8
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=213642
@ -443,6 +443,7 @@ proc0_init(void *dummy __unused)
|
|||||||
*/
|
*/
|
||||||
LIST_INSERT_HEAD(&allproc, p, p_list);
|
LIST_INSERT_HEAD(&allproc, p, p_list);
|
||||||
LIST_INSERT_HEAD(PIDHASH(0), p, p_hash);
|
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);
|
mtx_init(&pgrp0.pg_mtx, "process group", NULL, MTX_DEF | MTX_DUPOK);
|
||||||
p->p_pgrp = &pgrp0;
|
p->p_pgrp = &pgrp0;
|
||||||
LIST_INSERT_HEAD(PGRPHASH(0), &pgrp0, pg_hash);
|
LIST_INSERT_HEAD(PGRPHASH(0), &pgrp0, pg_hash);
|
||||||
|
@ -403,6 +403,8 @@ exit1(struct thread *td, int rv)
|
|||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
lim_free(plim);
|
lim_free(plim);
|
||||||
|
|
||||||
|
tidhash_remove(td);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove proc from allproc queue and pidhash chain.
|
* Remove proc from allproc queue and pidhash chain.
|
||||||
* Place onto zombproc. Unlink from parent's child list.
|
* Place onto zombproc. Unlink from parent's child list.
|
||||||
|
@ -456,7 +456,7 @@ fork1(td, flags, pages, procp)
|
|||||||
AUDIT_ARG_PID(p2->p_pid);
|
AUDIT_ARG_PID(p2->p_pid);
|
||||||
LIST_INSERT_HEAD(&allproc, p2, p_list);
|
LIST_INSERT_HEAD(&allproc, p2, p_list);
|
||||||
LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash);
|
LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash);
|
||||||
|
tidhash_add(td2);
|
||||||
PROC_LOCK(p2);
|
PROC_LOCK(p2);
|
||||||
PROC_LOCK(p1);
|
PROC_LOCK(p1);
|
||||||
|
|
||||||
|
@ -295,6 +295,7 @@ kthread_add(void (*func)(void *), void *arg, struct proc *p,
|
|||||||
thread_unlock(oldtd);
|
thread_unlock(oldtd);
|
||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
|
|
||||||
|
tidhash_add(newtd);
|
||||||
|
|
||||||
/* Delay putting it on the run queue until now. */
|
/* Delay putting it on the run queue until now. */
|
||||||
if (!(flags & RFSTOPPED)) {
|
if (!(flags & RFSTOPPED)) {
|
||||||
@ -314,6 +315,8 @@ kthread_exit(void)
|
|||||||
|
|
||||||
p = curthread->td_proc;
|
p = curthread->td_proc;
|
||||||
|
|
||||||
|
tidhash_remove(curthread);
|
||||||
|
|
||||||
/* A module may be waiting for us to exit. */
|
/* A module may be waiting for us to exit. */
|
||||||
wakeup(curthread);
|
wakeup(curthread);
|
||||||
PROC_LOCK(p);
|
PROC_LOCK(p);
|
||||||
|
@ -295,25 +295,23 @@ rtprio_thread(struct thread *td, struct rtprio_thread_args *uap)
|
|||||||
else
|
else
|
||||||
cierror = 0;
|
cierror = 0;
|
||||||
|
|
||||||
/*
|
if (uap->lwpid == 0 || uap->lwpid == td->td_tid) {
|
||||||
* Though lwpid is unique, only current process is supported
|
p = td->td_proc;
|
||||||
* since there is no efficient way to look up a LWP yet.
|
td1 = td;
|
||||||
*/
|
PROC_LOCK(p);
|
||||||
p = td->td_proc;
|
} else {
|
||||||
PROC_LOCK(p);
|
/* 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) {
|
switch (uap->function) {
|
||||||
case RTP_LOOKUP:
|
case RTP_LOOKUP:
|
||||||
if ((error = p_cansee(td, p)))
|
if ((error = p_cansee(td, p)))
|
||||||
break;
|
break;
|
||||||
if (uap->lwpid == 0 || uap->lwpid == td->td_tid)
|
pri_to_rtp(td1, &rtp);
|
||||||
td1 = td;
|
|
||||||
else
|
|
||||||
td1 = thread_find(p, uap->lwpid);
|
|
||||||
if (td1 != NULL)
|
|
||||||
pri_to_rtp(td1, &rtp);
|
|
||||||
else
|
|
||||||
error = ESRCH;
|
|
||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
return (copyout(&rtp, uap->rtp, sizeof(struct rtprio)));
|
return (copyout(&rtp, uap->rtp, sizeof(struct rtprio)));
|
||||||
case RTP_SET:
|
case RTP_SET:
|
||||||
@ -337,15 +335,7 @@ rtprio_thread(struct thread *td, struct rtprio_thread_args *uap)
|
|||||||
if (error)
|
if (error)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
error = rtp_to_pri(&rtp, td1);
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
|
@ -107,8 +107,6 @@ static int killpg1(struct thread *td, int sig, int pgid, int all,
|
|||||||
ksiginfo_t *ksi);
|
ksiginfo_t *ksi);
|
||||||
static int issignal(struct thread *td, int stop_allowed);
|
static int issignal(struct thread *td, int stop_allowed);
|
||||||
static int sigprop(int sig);
|
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 tdsigwakeup(struct thread *, int, sig_t, int);
|
||||||
static void sig_suspend_threads(struct thread *, struct proc *, int);
|
static void sig_suspend_threads(struct thread *, struct proc *, int);
|
||||||
static int filt_sigattach(struct knote *kn);
|
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));
|
return (tdsendsignal(p, NULL, sig, ksi));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Utility function for finding a thread to send signal event to. */
|
||||||
int
|
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;
|
struct thread *td;
|
||||||
|
|
||||||
PROC_LOCK_ASSERT(p, MA_OWNED);
|
|
||||||
|
|
||||||
KASSERT(!KSI_ONQ(ksi), ("psignal_event: ksi on queue"));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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) {
|
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)
|
if (td == NULL)
|
||||||
return (ESRCH);
|
return (ESRCH);
|
||||||
|
*ttd = td;
|
||||||
|
} else {
|
||||||
|
*ttd = NULL;
|
||||||
|
PROC_LOCK(p);
|
||||||
}
|
}
|
||||||
return (tdsendsignal(p, td, ksi->ksi_signo, ksi));
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2015,7 +2008,7 @@ tdksignal(struct thread *td, int sig, ksiginfo_t *ksi)
|
|||||||
(void) tdsendsignal(td->td_proc, td, sig, ksi);
|
(void) tdsendsignal(td->td_proc, td, sig, ksi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
int
|
||||||
tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
|
tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
|
||||||
{
|
{
|
||||||
sig_t action;
|
sig_t action;
|
||||||
@ -2026,6 +2019,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
int wakeup_swapper;
|
int wakeup_swapper;
|
||||||
|
|
||||||
|
MPASS(td == NULL || p == td->td_proc);
|
||||||
PROC_LOCK_ASSERT(p, MA_OWNED);
|
PROC_LOCK_ASSERT(p, MA_OWNED);
|
||||||
|
|
||||||
if (!_SIG_VALID(sig))
|
if (!_SIG_VALID(sig))
|
||||||
|
@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
#include <sys/sysproto.h>
|
#include <sys/sysproto.h>
|
||||||
#include <sys/signalvar.h>
|
#include <sys/signalvar.h>
|
||||||
|
#include <sys/sx.h>
|
||||||
#include <sys/ucontext.h>
|
#include <sys/ucontext.h>
|
||||||
#include <sys/thr.h>
|
#include <sys/thr.h>
|
||||||
#include <sys/rtprio.h>
|
#include <sys/rtprio.h>
|
||||||
@ -240,6 +241,9 @@ create_thread(struct thread *td, mcontext_t *ctx,
|
|||||||
if (P_SHOULDSTOP(p))
|
if (P_SHOULDSTOP(p))
|
||||||
newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
|
newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
|
||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
|
|
||||||
|
tidhash_add(newtd);
|
||||||
|
|
||||||
thread_lock(newtd);
|
thread_lock(newtd);
|
||||||
if (rtp != NULL) {
|
if (rtp != NULL) {
|
||||||
if (!(td->td_pri_class == PRI_TIMESHARE &&
|
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);
|
kern_umtx_wake(td, uap->state, INT_MAX, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tidhash_remove(td);
|
||||||
|
|
||||||
PROC_LOCK(p);
|
PROC_LOCK(p);
|
||||||
tdsigcleanup(td);
|
tdsigcleanup(td);
|
||||||
PROC_SLOCK(p);
|
PROC_SLOCK(p);
|
||||||
@ -309,18 +315,17 @@ thr_kill(struct thread *td, struct thr_kill_args *uap)
|
|||||||
int error;
|
int error;
|
||||||
|
|
||||||
p = td->td_proc;
|
p = td->td_proc;
|
||||||
error = 0;
|
|
||||||
ksiginfo_init(&ksi);
|
ksiginfo_init(&ksi);
|
||||||
ksi.ksi_signo = uap->sig;
|
ksi.ksi_signo = uap->sig;
|
||||||
ksi.ksi_code = SI_LWP;
|
ksi.ksi_code = SI_LWP;
|
||||||
ksi.ksi_pid = p->p_pid;
|
ksi.ksi_pid = p->p_pid;
|
||||||
ksi.ksi_uid = td->td_ucred->cr_ruid;
|
ksi.ksi_uid = td->td_ucred->cr_ruid;
|
||||||
PROC_LOCK(p);
|
|
||||||
if (uap->id == -1) {
|
if (uap->id == -1) {
|
||||||
if (uap->sig != 0 && !_SIG_VALID(uap->sig)) {
|
if (uap->sig != 0 && !_SIG_VALID(uap->sig)) {
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
} else {
|
} else {
|
||||||
error = ESRCH;
|
error = ESRCH;
|
||||||
|
PROC_LOCK(p);
|
||||||
FOREACH_THREAD_IN_PROC(p, ttd) {
|
FOREACH_THREAD_IN_PROC(p, ttd) {
|
||||||
if (ttd != td) {
|
if (ttd != td) {
|
||||||
error = 0;
|
error = 0;
|
||||||
@ -329,22 +334,21 @@ thr_kill(struct thread *td, struct thr_kill_args *uap)
|
|||||||
tdksignal(ttd, uap->sig, &ksi);
|
tdksignal(ttd, uap->sig, &ksi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PROC_UNLOCK(p);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (uap->id != td->td_tid)
|
error = 0;
|
||||||
ttd = thread_find(p, uap->id);
|
ttd = tdfind((lwpid_t)uap->id, p->p_pid);
|
||||||
else
|
|
||||||
ttd = td;
|
|
||||||
if (ttd == NULL)
|
if (ttd == NULL)
|
||||||
error = ESRCH;
|
return (ESRCH);
|
||||||
else if (uap->sig == 0)
|
if (uap->sig == 0)
|
||||||
;
|
;
|
||||||
else if (!_SIG_VALID(uap->sig))
|
else if (!_SIG_VALID(uap->sig))
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
else
|
else
|
||||||
tdksignal(ttd, uap->sig, &ksi);
|
tdksignal(ttd, uap->sig, &ksi);
|
||||||
|
PROC_UNLOCK(ttd->td_proc);
|
||||||
}
|
}
|
||||||
PROC_UNLOCK(p);
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,51 +363,49 @@ thr_kill2(struct thread *td, struct thr_kill2_args *uap)
|
|||||||
|
|
||||||
AUDIT_ARG_SIGNUM(uap->sig);
|
AUDIT_ARG_SIGNUM(uap->sig);
|
||||||
|
|
||||||
if (uap->pid == td->td_proc->p_pid) {
|
ksiginfo_init(&ksi);
|
||||||
p = td->td_proc;
|
ksi.ksi_signo = uap->sig;
|
||||||
PROC_LOCK(p);
|
ksi.ksi_code = SI_LWP;
|
||||||
} else if ((p = pfind(uap->pid)) == NULL) {
|
ksi.ksi_pid = td->td_proc->p_pid;
|
||||||
return (ESRCH);
|
ksi.ksi_uid = td->td_ucred->cr_ruid;
|
||||||
}
|
if (uap->id == -1) {
|
||||||
AUDIT_ARG_PROCESS(p);
|
if ((p = pfind(uap->pid)) == NULL)
|
||||||
|
return (ESRCH);
|
||||||
error = p_cansignal(td, p, uap->sig);
|
AUDIT_ARG_PROCESS(p);
|
||||||
if (error == 0) {
|
error = p_cansignal(td, p, uap->sig);
|
||||||
ksiginfo_init(&ksi);
|
if (error) {
|
||||||
ksi.ksi_signo = uap->sig;
|
PROC_UNLOCK(p);
|
||||||
ksi.ksi_code = SI_LWP;
|
return (error);
|
||||||
ksi.ksi_pid = td->td_proc->p_pid;
|
}
|
||||||
ksi.ksi_uid = td->td_ucred->cr_ruid;
|
if (uap->sig != 0 && !_SIG_VALID(uap->sig)) {
|
||||||
if (uap->id == -1) {
|
error = EINVAL;
|
||||||
if (uap->sig != 0 && !_SIG_VALID(uap->sig)) {
|
} else {
|
||||||
error = EINVAL;
|
error = ESRCH;
|
||||||
} else {
|
FOREACH_THREAD_IN_PROC(p, ttd) {
|
||||||
error = ESRCH;
|
if (ttd != td) {
|
||||||
FOREACH_THREAD_IN_PROC(p, ttd) {
|
error = 0;
|
||||||
if (ttd != td) {
|
if (uap->sig == 0)
|
||||||
error = 0;
|
break;
|
||||||
if (uap->sig == 0)
|
tdksignal(ttd, uap->sig, &ksi);
|
||||||
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);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,12 +487,9 @@ thr_wake(struct thread *td, struct thr_wake_args *uap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
p = td->td_proc;
|
p = td->td_proc;
|
||||||
PROC_LOCK(p);
|
ttd = tdfind((lwpid_t)uap->id, p->p_pid);
|
||||||
ttd = thread_find(p, uap->id);
|
if (ttd == NULL)
|
||||||
if (ttd == NULL) {
|
|
||||||
PROC_UNLOCK(p);
|
|
||||||
return (ESRCH);
|
return (ESRCH);
|
||||||
}
|
|
||||||
thread_lock(ttd);
|
thread_lock(ttd);
|
||||||
ttd->td_flags |= TDF_THRWAKEUP;
|
ttd->td_flags |= TDF_THRWAKEUP;
|
||||||
thread_unlock(ttd);
|
thread_unlock(ttd);
|
||||||
@ -502,7 +501,7 @@ thr_wake(struct thread *td, struct thr_wake_args *uap)
|
|||||||
int
|
int
|
||||||
thr_set_name(struct thread *td, struct thr_set_name_args *uap)
|
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];
|
char name[MAXCOMLEN + 1];
|
||||||
struct thread *ttd;
|
struct thread *ttd;
|
||||||
int error;
|
int error;
|
||||||
@ -515,15 +514,11 @@ thr_set_name(struct thread *td, struct thr_set_name_args *uap)
|
|||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
PROC_LOCK(p);
|
p = td->td_proc;
|
||||||
if (uap->id == td->td_tid)
|
ttd = tdfind((lwpid_t)uap->id, p->p_pid);
|
||||||
ttd = td;
|
if (ttd == NULL)
|
||||||
else
|
return (ESRCH);
|
||||||
ttd = thread_find(p, uap->id);
|
strcpy(ttd->td_name, name);
|
||||||
if (ttd != NULL)
|
|
||||||
strcpy(ttd->td_name, name);
|
|
||||||
else
|
|
||||||
error = ESRCH;
|
|
||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/selinfo.h>
|
#include <sys/selinfo.h>
|
||||||
#include <sys/turnstile.h>
|
#include <sys/turnstile.h>
|
||||||
#include <sys/ktr.h>
|
#include <sys/ktr.h>
|
||||||
|
#include <sys/rwlock.h>
|
||||||
#include <sys/umtx.h>
|
#include <sys/umtx.h>
|
||||||
#include <sys/cpuset.h>
|
#include <sys/cpuset.h>
|
||||||
#ifdef HWPMC_HOOKS
|
#ifdef HWPMC_HOOKS
|
||||||
@ -83,6 +84,12 @@ static void thread_zombie(struct thread *);
|
|||||||
struct mtx tid_lock;
|
struct mtx tid_lock;
|
||||||
static struct unrhdr *tid_unrhdr;
|
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.
|
* Prepare a thread for use.
|
||||||
*/
|
*/
|
||||||
@ -230,6 +237,8 @@ threadinit(void)
|
|||||||
thread_zone = uma_zcreate("THREAD", sched_sizeof_thread(),
|
thread_zone = uma_zcreate("THREAD", sched_sizeof_thread(),
|
||||||
thread_ctor, thread_dtor, thread_init, thread_fini,
|
thread_ctor, thread_dtor, thread_init, thread_fini,
|
||||||
16 - 1, 0);
|
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.
|
* this thread should just suicide.
|
||||||
* Assumes that P_SINGLE_EXIT implies P_STOPPED_SINGLE.
|
* 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();
|
thread_exit();
|
||||||
|
}
|
||||||
if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) {
|
if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) {
|
||||||
if (p->p_numthreads == p->p_suspcount + 1) {
|
if (p->p_numthreads == p->p_suspcount + 1) {
|
||||||
thread_lock(p->p_singlethread);
|
thread_lock(p->p_singlethread);
|
||||||
@ -923,3 +938,57 @@ thread_find(struct proc *p, lwpid_t tid)
|
|||||||
}
|
}
|
||||||
return (td);
|
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);
|
||||||
|
}
|
||||||
|
@ -1402,28 +1402,22 @@ void
|
|||||||
itimer_fire(struct itimer *it)
|
itimer_fire(struct itimer *it)
|
||||||
{
|
{
|
||||||
struct proc *p = it->it_proc;
|
struct proc *p = it->it_proc;
|
||||||
int ret;
|
struct thread *td;
|
||||||
|
|
||||||
if (it->it_sigev.sigev_notify == SIGEV_SIGNAL ||
|
if (it->it_sigev.sigev_notify == SIGEV_SIGNAL ||
|
||||||
it->it_sigev.sigev_notify == SIGEV_THREAD_ID) {
|
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)) {
|
if (!KSI_ONQ(&it->it_ksi)) {
|
||||||
it->it_ksi.ksi_errno = 0;
|
it->it_ksi.ksi_errno = 0;
|
||||||
ret = psignal_event(p, &it->it_sigev, &it->it_ksi);
|
ksiginfo_set_sigev(&it->it_ksi, &it->it_sigev);
|
||||||
if (__predict_false(ret != 0)) {
|
tdsendsignal(p, td, it->it_ksi.ksi_signo, &it->it_ksi);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (it->it_overrun < INT_MAX)
|
if (it->it_overrun < INT_MAX)
|
||||||
it->it_overrun++;
|
it->it_overrun++;
|
||||||
|
@ -1588,20 +1588,15 @@ umtxq_sleep_pi(struct umtx_q *uq, struct umtx_pi *pi,
|
|||||||
umtxq_insert(uq);
|
umtxq_insert(uq);
|
||||||
mtx_lock_spin(&umtx_lock);
|
mtx_lock_spin(&umtx_lock);
|
||||||
if (pi->pi_owner == NULL) {
|
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);
|
mtx_unlock_spin(&umtx_lock);
|
||||||
PROC_LOCK(curproc);
|
/* XXX Only look up thread in current process. */
|
||||||
td1 = thread_find(curproc, owner);
|
td1 = tdfind(owner, curproc->p_pid);
|
||||||
mtx_lock_spin(&umtx_lock);
|
mtx_lock_spin(&umtx_lock);
|
||||||
if (td1 != NULL && pi->pi_owner == NULL) {
|
if (td1 != NULL && pi->pi_owner == NULL) {
|
||||||
uq1 = td1->td_umtxq;
|
uq1 = td1->td_umtxq;
|
||||||
umtx_pi_setowner(pi, td1);
|
umtx_pi_setowner(pi, td1);
|
||||||
}
|
}
|
||||||
PROC_UNLOCK(curproc);
|
PROC_UNLOCK(td1->td_proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
TAILQ_FOREACH(uq1, &pi->pi_blocked, uq_lockq) {
|
TAILQ_FOREACH(uq1, &pi->pi_blocked, uq_lockq) {
|
||||||
|
@ -721,24 +721,13 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
|
|||||||
return (ESRCH);
|
return (ESRCH);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* this is slow, should be optimized */
|
td2 = tdfind(pid, -1);
|
||||||
sx_slock(&allproc_lock);
|
if (td2 == NULL) {
|
||||||
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) {
|
|
||||||
if (proctree_locked)
|
if (proctree_locked)
|
||||||
sx_xunlock(&proctree_lock);
|
sx_xunlock(&proctree_lock);
|
||||||
return (ESRCH);
|
return (ESRCH);
|
||||||
}
|
}
|
||||||
|
p = td2->td_proc;
|
||||||
tid = pid;
|
tid = pid;
|
||||||
pid = p->p_pid;
|
pid = p->p_pid;
|
||||||
}
|
}
|
||||||
|
@ -1747,15 +1747,23 @@ static void
|
|||||||
mqueue_send_notification(struct mqueue *mq)
|
mqueue_send_notification(struct mqueue *mq)
|
||||||
{
|
{
|
||||||
struct mqueue_notifier *nt;
|
struct mqueue_notifier *nt;
|
||||||
|
struct thread *td;
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
int error;
|
||||||
|
|
||||||
mtx_assert(&mq->mq_mutex, MA_OWNED);
|
mtx_assert(&mq->mq_mutex, MA_OWNED);
|
||||||
nt = mq->mq_notifier;
|
nt = mq->mq_notifier;
|
||||||
if (nt->nt_sigev.sigev_notify != SIGEV_NONE) {
|
if (nt->nt_sigev.sigev_notify != SIGEV_NONE) {
|
||||||
p = nt->nt_proc;
|
p = nt->nt_proc;
|
||||||
PROC_LOCK(p);
|
error = sigev_findtd(p, &nt->nt_sigev, &td);
|
||||||
if (!KSI_ONQ(&nt->nt_ksi))
|
if (error) {
|
||||||
psignal_event(p, &nt->nt_sigev, &nt->nt_ksi);
|
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);
|
PROC_UNLOCK(p);
|
||||||
}
|
}
|
||||||
mq->mq_notifier = NULL;
|
mq->mq_notifier = NULL;
|
||||||
|
@ -609,16 +609,20 @@ aio_init_aioinfo(struct proc *p)
|
|||||||
static int
|
static int
|
||||||
aio_sendsig(struct proc *p, struct sigevent *sigev, ksiginfo_t *ksi)
|
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)) {
|
if (!KSI_ONQ(ksi)) {
|
||||||
|
ksiginfo_set_sigev(ksi, sigev);
|
||||||
ksi->ksi_code = SI_ASYNCIO;
|
ksi->ksi_code = SI_ASYNCIO;
|
||||||
ksi->ksi_flags |= KSI_EXT | KSI_INS;
|
ksi->ksi_flags |= KSI_EXT | KSI_INS;
|
||||||
ret = psignal_event(p, sigev, ksi);
|
tdsendsignal(p, td, ksi->ksi_signo, ksi);
|
||||||
}
|
}
|
||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
return (ret);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -205,6 +205,7 @@ struct thread {
|
|||||||
TAILQ_ENTRY(thread) td_runq; /* (t) Run queue. */
|
TAILQ_ENTRY(thread) td_runq; /* (t) Run queue. */
|
||||||
TAILQ_ENTRY(thread) td_slpq; /* (t) Sleep queue. */
|
TAILQ_ENTRY(thread) td_slpq; /* (t) Sleep queue. */
|
||||||
TAILQ_ENTRY(thread) td_lockq; /* (t) Lock queue. */
|
TAILQ_ENTRY(thread) td_lockq; /* (t) Lock queue. */
|
||||||
|
LIST_ENTRY(thread) td_hash; /* (d) Hash chain. */
|
||||||
struct cpuset *td_cpuset; /* (t) CPU affinity mask. */
|
struct cpuset *td_cpuset; /* (t) CPU affinity mask. */
|
||||||
struct seltd *td_sel; /* Select queue/channel. */
|
struct seltd *td_sel; /* Select queue/channel. */
|
||||||
struct sleepqueue *td_sleepqueue; /* (k) Associated sleep queue. */
|
struct sleepqueue *td_sleepqueue; /* (k) Associated sleep queue. */
|
||||||
@ -766,6 +767,10 @@ MALLOC_DECLARE(M_ZOMBIE);
|
|||||||
#define PIDHASH(pid) (&pidhashtbl[(pid) & pidhash])
|
#define PIDHASH(pid) (&pidhashtbl[(pid) & pidhash])
|
||||||
extern LIST_HEAD(pidhashhead, proc) *pidhashtbl;
|
extern LIST_HEAD(pidhashhead, proc) *pidhashtbl;
|
||||||
extern u_long pidhash;
|
extern u_long pidhash;
|
||||||
|
#define TIDHASH(tid) (&tidhashtbl[(tid) & tidhash])
|
||||||
|
extern LIST_HEAD(tidhashhead, thread) *tidhashtbl;
|
||||||
|
extern u_long tidhash;
|
||||||
|
extern struct rwlock tidhash_lock;
|
||||||
|
|
||||||
#define PGRPHASH(pgid) (&pgrphashtbl[(pgid) & pgrphash])
|
#define PGRPHASH(pgid) (&pgrphashtbl[(pgid) & pgrphash])
|
||||||
extern LIST_HEAD(pgrphashhead, pgrp) *pgrphashtbl;
|
extern LIST_HEAD(pgrphashhead, pgrp) *pgrphashtbl;
|
||||||
@ -837,7 +842,10 @@ void setsugid(struct proc *p);
|
|||||||
int sigonstack(size_t sp);
|
int sigonstack(size_t sp);
|
||||||
void sleepinit(void);
|
void sleepinit(void);
|
||||||
void stopevent(struct proc *, u_int, u_int);
|
void stopevent(struct proc *, u_int, u_int);
|
||||||
|
struct thread *tdfind(lwpid_t, pid_t);
|
||||||
void threadinit(void);
|
void threadinit(void);
|
||||||
|
void tidhash_add(struct thread *);
|
||||||
|
void tidhash_remove(struct thread *);
|
||||||
void cpu_idle(int);
|
void cpu_idle(int);
|
||||||
int cpu_idle_wakeup(int);
|
int cpu_idle_wakeup(int);
|
||||||
extern void (*cpu_idle_hook)(void); /* Hook to machdep CPU idler. */
|
extern void (*cpu_idle_hook)(void); /* Hook to machdep CPU idler. */
|
||||||
|
@ -294,6 +294,13 @@ ksiginfo_copy(ksiginfo_t *src, ksiginfo_t *dst)
|
|||||||
(dst)->ksi_flags = (src->ksi_flags & KSI_COPYMASK);
|
(dst)->ksi_flags = (src->ksi_flags & KSI_COPYMASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __inline void
|
||||||
|
ksiginfo_set_sigev(ksiginfo_t *dst, struct sigevent *sigev)
|
||||||
|
{
|
||||||
|
dst->ksi_signo = sigev->sigev_signo;
|
||||||
|
dst->ksi_value = sigev->sigev_value;
|
||||||
|
}
|
||||||
|
|
||||||
struct pgrp;
|
struct pgrp;
|
||||||
struct proc;
|
struct proc;
|
||||||
struct sigio;
|
struct sigio;
|
||||||
@ -331,7 +338,6 @@ void pgsigio(struct sigio **sigiop, int sig, int checkctty);
|
|||||||
void pgsignal(struct pgrp *pgrp, int sig, int checkctty, ksiginfo_t *ksi);
|
void pgsignal(struct pgrp *pgrp, int sig, int checkctty, ksiginfo_t *ksi);
|
||||||
int postsig(int sig);
|
int postsig(int sig);
|
||||||
void psignal(struct proc *p, int sig);
|
void psignal(struct proc *p, int sig);
|
||||||
int psignal_event(struct proc *p, struct sigevent *sigev, ksiginfo_t *ksi);
|
|
||||||
int ptracestop(struct thread *td, int sig);
|
int ptracestop(struct thread *td, int sig);
|
||||||
void sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *retmask);
|
void sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *retmask);
|
||||||
struct sigacts *sigacts_alloc(void);
|
struct sigacts *sigacts_alloc(void);
|
||||||
@ -340,6 +346,7 @@ void sigacts_free(struct sigacts *ps);
|
|||||||
struct sigacts *sigacts_hold(struct sigacts *ps);
|
struct sigacts *sigacts_hold(struct sigacts *ps);
|
||||||
int sigacts_shared(struct sigacts *ps);
|
int sigacts_shared(struct sigacts *ps);
|
||||||
void sigexit(struct thread *td, int sig) __dead2;
|
void sigexit(struct thread *td, int sig) __dead2;
|
||||||
|
int sigev_findtd(struct proc *p, struct sigevent *sigev, struct thread **);
|
||||||
int sig_ffs(sigset_t *set);
|
int sig_ffs(sigset_t *set);
|
||||||
void siginit(struct proc *p);
|
void siginit(struct proc *p);
|
||||||
void signotify(struct thread *td);
|
void signotify(struct thread *td);
|
||||||
@ -349,6 +356,8 @@ void sigqueue_flush(struct sigqueue *queue);
|
|||||||
void sigqueue_init(struct sigqueue *queue, struct proc *p);
|
void sigqueue_init(struct sigqueue *queue, struct proc *p);
|
||||||
void sigqueue_take(ksiginfo_t *ksi);
|
void sigqueue_take(ksiginfo_t *ksi);
|
||||||
void tdksignal(struct thread *td, int sig, ksiginfo_t *ksi);
|
void tdksignal(struct thread *td, int sig, ksiginfo_t *ksi);
|
||||||
|
int tdsendsignal(struct proc *p, struct thread *td, int sig,
|
||||||
|
ksiginfo_t *ksi);
|
||||||
void tdsigcleanup(struct thread *td);
|
void tdsigcleanup(struct thread *td);
|
||||||
void tdsignal(struct thread *td, int sig);
|
void tdsignal(struct thread *td, int sig);
|
||||||
void trapsignal(struct thread *td, ksiginfo_t *ksi);
|
void trapsignal(struct thread *td, ksiginfo_t *ksi);
|
||||||
|
Loading…
Reference in New Issue
Block a user