Move UPCALL related data structure out of kse, introduce a new

data structure called kse_upcall to manage UPCALL. All KSE binding
and loaning code are gone.

A thread owns an upcall can collect all completed syscall contexts in
its ksegrp, turn itself into UPCALL mode, and takes those contexts back
to userland. Any thread without upcall structure has to export their
contexts and exit at user boundary.

Any thread running in user mode owns an upcall structure, when it enters
kernel, if the kse mailbox's current thread pointer is not NULL, then
when the thread is blocked in kernel, a new UPCALL thread is created and
the upcall structure is transfered to the new UPCALL thread. if the kse
mailbox's current thread pointer is NULL, then when a thread is blocked
in kernel, no UPCALL thread will be created.

Each upcall always has an owner thread. Userland can remove an upcall by
calling kse_exit, when all upcalls in ksegrp are removed, the group is
atomatically shutdown. An upcall owner thread also exits when process is
in exiting state. when an owner thread exits, the upcall it owns is also
removed.

KSE is a pure scheduler entity. it represents a virtual cpu. when a thread
is running, it always has a KSE associated with it. scheduler is free to
assign a KSE to thread according thread priority, if thread priority is changed,
KSE can be moved from one thread to another.

When a ksegrp is created, there is always N KSEs created in the group. the
N is the number of physical cpu in the current system. This makes it is
possible that even an userland UTS is single CPU safe, threads in kernel still
can execute on different cpu in parallel. Userland calls kse_create to add more
upcall structures into ksegrp to increase concurrent in userland itself, kernel
is not restricted by number of upcalls userland provides.

The code hasn't been tested under SMP by author due to lack of hardware.

Reviewed by: julian
This commit is contained in:
David Xu 2003-01-26 11:41:35 +00:00
parent e70e846243
commit 0dbb100b9b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=109877
39 changed files with 1676 additions and 1523 deletions

View File

@ -296,7 +296,7 @@ trap(a0, a1, a2, entry, framep)
CTR5(KTR_TRAP, "%s trap: pid %d, (%lx, %lx, %lx)",
user ? "user" : "kernel", p->p_pid, a0, a1, a2);
if (user) {
sticks = td->td_kse->ke_sticks;
sticks = td->td_sticks;
td->td_frame = framep;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
@ -666,7 +666,7 @@ syscall(code, framep)
cnt.v_syscall++;
td->td_frame = framep;
opc = framep->tf_regs[FRAME_PC] - 4;
sticks = td->td_kse->ke_sticks;
sticks = td->td_sticks;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
if (p->p_flag & P_KSES)

View File

@ -309,7 +309,7 @@ cpu_set_upcall(struct thread *td, void *pcb)
}
void
cpu_set_upcall_kse(struct thread *td, struct kse *ke)
cpu_set_upcall_kse(struct thread *td, struct kse_upcall *ku)
{
/* XXX */

View File

@ -137,7 +137,7 @@ i386_unpend(void)
break;
case 1: /* bit 1 - statclock */
mtx_lock_spin(&sched_lock);
statclock_process(curthread->td_kse,
statclock_process(curthread,
(register_t)i386_unpend, 0);
mtx_unlock_spin(&sched_lock);
break;

View File

@ -298,9 +298,12 @@ doreti_ast:
*/
cli
movl PCPU(CURTHREAD),%eax
testl $TDF_ASTPENDING, TD_FLAGS(%eax)
jnz call_ast
movl TD_KSE(%eax), %eax
testl $KEF_ASTPENDING | KEF_NEEDRESCHED,KE_FLAGS(%eax)
je doreti_exit
call_ast:
sti
pushl %esp /* pass a pointer to the trapframe */
call ast

View File

@ -298,9 +298,12 @@ doreti_ast:
*/
cli
movl PCPU(CURTHREAD),%eax
testl $TDF_ASTPENDING, TD_FLAGS(%eax)
jnz call_ast
movl TD_KSE(%eax), %eax
testl $KEF_ASTPENDING | KEF_NEEDRESCHED,KE_FLAGS(%eax)
je doreti_exit
call_ast:
sti
pushl %esp /* pass a pointer to the trapframe */
call ast

View File

@ -92,6 +92,7 @@ ASSYM(TD_INTR_NESTING_LEVEL, offsetof(struct thread, td_intr_nesting_level));
ASSYM(TD_CRITNEST, offsetof(struct thread, td_critnest));
ASSYM(TD_SWITCHIN, offsetof(struct thread, td_switchin));
ASSYM(TD_MD, offsetof(struct thread, td_md));
ASSYM(TDF_ASTPENDING, TDF_ASTPENDING);
ASSYM(P_MD, offsetof(struct proc, p_md));
ASSYM(MD_LDT, offsetof(struct mdproc, md_ldt));

View File

@ -264,7 +264,7 @@ trap(frame)
!(PCPU_GET(curpcb)->pcb_flags & PCB_VM86CALL))) {
/* user trap */
sticks = td->td_kse->ke_sticks;
sticks = td->td_sticks;
td->td_frame = &frame;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
@ -957,7 +957,7 @@ syscall(frame)
KASSERT((td->td_kse != NULL), ("syscall: kse/thread UNLINKED"));
KASSERT((td->td_kse->ke_thread == td), ("syscall:kse/thread mismatch"));
sticks = td->td_kse->ke_sticks;
sticks = td->td_sticks;
td->td_frame = &frame;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);

View File

@ -312,8 +312,6 @@ cpu_set_upcall(struct thread *td, void *pcb)
{
struct pcb *pcb2;
td->td_flags |= TDF_UPCALLING;
/* Point the pcb to the top of the stack. */
pcb2 = td->td_pcb;
@ -370,7 +368,7 @@ cpu_set_upcall(struct thread *td, void *pcb)
* in thread_userret() itself can be done as well.
*/
void
cpu_set_upcall_kse(struct thread *td, struct kse *ke)
cpu_set_upcall_kse(struct thread *td, struct kse_upcall *ku)
{
/*
@ -387,15 +385,15 @@ cpu_set_upcall_kse(struct thread *td, struct kse *ke)
* function.
*/
td->td_frame->tf_esp =
(int)ke->ke_stack.ss_sp + ke->ke_stack.ss_size - 16;
td->td_frame->tf_eip = (int)ke->ke_upcall;
(int)ku->ku_stack.ss_sp + ku->ku_stack.ss_size - 16;
td->td_frame->tf_eip = (int)ku->ku_func;
/*
* Pass the address of the mailbox for this kse to the uts
* function as a parameter on the stack.
*/
suword((void *)(td->td_frame->tf_esp + sizeof(void *)),
(int)ke->ke_mailbox);
(int)ku->ku_mailbox);
}
void

View File

@ -170,15 +170,6 @@ dumpthread(volatile struct proc *p, volatile struct thread *td)
if (TD_AWAITING_INTR(td)) {
db_printf("[IWAIT]");
}
if (TD_LENDER(td)) {
db_printf("[LOAN]");
}
if (TD_IS_IDLE(td)) {
db_printf("[IDLE]");
}
if (TD_IS_EXITING(td)) {
db_printf("[EXIT]");
}
break;
case TDS_CAN_RUN:
db_printf("[Can run]");

View File

@ -137,7 +137,7 @@ i386_unpend(void)
break;
case 1: /* bit 1 - statclock */
mtx_lock_spin(&sched_lock);
statclock_process(curthread->td_kse,
statclock_process(curthread,
(register_t)i386_unpend, 0);
mtx_unlock_spin(&sched_lock);
break;

View File

@ -298,9 +298,12 @@ doreti_ast:
*/
cli
movl PCPU(CURTHREAD),%eax
testl $TDF_ASTPENDING, TD_FLAGS(%eax)
jnz call_ast
movl TD_KSE(%eax), %eax
testl $KEF_ASTPENDING | KEF_NEEDRESCHED,KE_FLAGS(%eax)
je doreti_exit
call_ast:
sti
pushl %esp /* pass a pointer to the trapframe */
call ast

View File

@ -92,6 +92,7 @@ ASSYM(TD_INTR_NESTING_LEVEL, offsetof(struct thread, td_intr_nesting_level));
ASSYM(TD_CRITNEST, offsetof(struct thread, td_critnest));
ASSYM(TD_SWITCHIN, offsetof(struct thread, td_switchin));
ASSYM(TD_MD, offsetof(struct thread, td_md));
ASSYM(TDF_ASTPENDING, TDF_ASTPENDING);
ASSYM(P_MD, offsetof(struct proc, p_md));
ASSYM(MD_LDT, offsetof(struct mdproc, md_ldt));

View File

@ -264,7 +264,7 @@ trap(frame)
!(PCPU_GET(curpcb)->pcb_flags & PCB_VM86CALL))) {
/* user trap */
sticks = td->td_kse->ke_sticks;
sticks = td->td_sticks;
td->td_frame = &frame;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
@ -957,7 +957,7 @@ syscall(frame)
KASSERT((td->td_kse != NULL), ("syscall: kse/thread UNLINKED"));
KASSERT((td->td_kse->ke_thread == td), ("syscall:kse/thread mismatch"));
sticks = td->td_kse->ke_sticks;
sticks = td->td_sticks;
td->td_frame = &frame;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);

View File

@ -312,8 +312,6 @@ cpu_set_upcall(struct thread *td, void *pcb)
{
struct pcb *pcb2;
td->td_flags |= TDF_UPCALLING;
/* Point the pcb to the top of the stack. */
pcb2 = td->td_pcb;
@ -370,7 +368,7 @@ cpu_set_upcall(struct thread *td, void *pcb)
* in thread_userret() itself can be done as well.
*/
void
cpu_set_upcall_kse(struct thread *td, struct kse *ke)
cpu_set_upcall_kse(struct thread *td, struct kse_upcall *ku)
{
/*
@ -387,15 +385,15 @@ cpu_set_upcall_kse(struct thread *td, struct kse *ke)
* function.
*/
td->td_frame->tf_esp =
(int)ke->ke_stack.ss_sp + ke->ke_stack.ss_size - 16;
td->td_frame->tf_eip = (int)ke->ke_upcall;
(int)ku->ku_stack.ss_sp + ku->ku_stack.ss_size - 16;
td->td_frame->tf_eip = (int)ku->ku_func;
/*
* Pass the address of the mailbox for this kse to the uts
* function as a parameter on the stack.
*/
suword((void *)(td->td_frame->tf_esp + sizeof(void *)),
(int)ke->ke_mailbox);
(int)ku->ku_mailbox);
}
void

View File

@ -331,7 +331,7 @@ trap(int vector, int imm, struct trapframe *framep)
user = ((framep->tf_cr_ipsr & IA64_PSR_CPL) == IA64_PSR_CPL_USER);
if (user) {
sticks = td->td_kse->ke_sticks;
sticks = td->td_sticks;
td->td_frame = framep;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
@ -792,7 +792,7 @@ syscall(int code, u_int64_t *args, struct trapframe *framep)
p = td->td_proc;
td->td_frame = framep;
sticks = td->td_kse->ke_sticks;
sticks = td->td_sticks;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
@ -939,7 +939,7 @@ ia32_syscall(struct trapframe *framep)
*/
cnt.v_syscall++;
sticks = td->td_kse->ke_sticks;
sticks = td->td_sticks;
td->td_frame = framep;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);

View File

@ -117,7 +117,7 @@ cpu_set_upcall(struct thread *td, void *pcb)
}
void
cpu_set_upcall_kse(struct thread *td, struct kse *ke)
cpu_set_upcall_kse(struct thread *td, struct kse_upcall *ku)
{
}

View File

@ -379,7 +379,6 @@ proc0_init(void *dummy __unused)
ke->ke_oncpu = 0;
ke->ke_state = KES_THREAD;
ke->ke_thread = td;
ke->ke_owner = td;
p->p_peers = 0;
p->p_leader = p;

View File

@ -320,6 +320,10 @@ startprofclock(p)
* cover psdiv, etc. as well.
*/
mtx_lock_spin(&sched_lock);
if (p->p_sflag & PS_STOPPROF) {
mtx_unlock_spin(&sched_lock);
return;
}
if ((p->p_sflag & PS_PROFIL) == 0) {
p->p_sflag |= PS_PROFIL;
if (++profprocs == 1 && stathz != 0) {
@ -341,9 +345,19 @@ stopprofclock(p)
{
int s;
PROC_LOCK_ASSERT(p, MA_OWNED);
retry:
mtx_lock_spin(&sched_lock);
if (p->p_sflag & PS_PROFIL) {
p->p_sflag &= ~PS_PROFIL;
if (p->p_profthreads) {
p->p_sflag |= PS_STOPPROF;
mtx_unlock_spin(&sched_lock);
msleep(&p->p_profthreads, &p->p_mtx, PPAUSE,
"stopprof", NULL);
goto retry;
}
p->p_sflag &= ~(PS_PROFIL|PS_STOPPROF);
if (--profprocs == 0 && stathz != 0) {
s = splstatclock();
psdiv = pscnt = 1;
@ -363,10 +377,7 @@ stopprofclock(p)
* this function's relationship to statclock.
*/
void
statclock_process(ke, pc, user)
struct kse *ke;
register_t pc;
int user;
statclock_process(struct thread *td, register_t pc, int user)
{
#ifdef GPROF
struct gmonparam *g;
@ -376,27 +387,31 @@ statclock_process(ke, pc, user)
long rss;
struct rusage *ru;
struct vmspace *vm;
struct proc *p = ke->ke_proc;
struct thread *td = ke->ke_thread; /* current thread */
struct proc *p = td->td_proc;
KASSERT(ke == curthread->td_kse, ("statclock_process: td != curthread"));
mtx_assert(&sched_lock, MA_OWNED);
if (user) {
/*
* Came from user mode; CPU was in user state.
* If this process is being profiled, record the tick.
*/
if (p->p_sflag & PS_PROFIL)
addupc_intr(ke, pc, 1);
if (p->p_sflag & PS_PROFIL) {
/* Only when thread is not in transition */
if (!(td->td_flags & TDF_UPCALLING))
addupc_intr(td, pc, 1);
}
if (pscnt < psdiv)
return;
/*
* Charge the time as appropriate.
*/
if (p->p_flag & P_KSES)
thread_add_ticks_intr(1, 1);
ke->ke_uticks++;
if (ke->ke_ksegrp->kg_nice > NZERO)
thread_statclock(1);
/*
td->td_uticks++;
*/
p->p_uticks++;
if (td->td_ksegrp->kg_nice > NZERO)
cp_time[CP_NICE]++;
else
cp_time[CP_USER]++;
@ -429,12 +444,16 @@ statclock_process(ke, pc, user)
* in ``non-process'' (i.e., interrupt) work.
*/
if ((td->td_ithd != NULL) || td->td_intr_nesting_level >= 2) {
ke->ke_iticks++;
p->p_iticks++;
/*
td->td_iticks++;
*/
cp_time[CP_INTR]++;
} else {
if (p->p_flag & P_KSES)
thread_add_ticks_intr(0, 1);
ke->ke_sticks++;
thread_statclock(0);
td->td_sticks++;
p->p_sticks++;
if (p != PCPU_GET(idlethread)->td_proc)
cp_time[CP_SYS]++;
else
@ -442,7 +461,7 @@ statclock_process(ke, pc, user)
}
}
sched_clock(ke->ke_thread);
sched_clock(td);
/* Update resource usage integrals and maximums. */
if ((pstats = p->p_stats) != NULL &&
@ -472,7 +491,7 @@ statclock(frame)
mtx_lock_spin_flags(&sched_lock, MTX_QUIET);
if (--pscnt == 0)
pscnt = psdiv;
statclock_process(curthread->td_kse, CLKF_PC(frame), CLKF_USERMODE(frame));
statclock_process(curthread, CLKF_PC(frame), CLKF_USERMODE(frame));
mtx_unlock_spin_flags(&sched_lock, MTX_QUIET);
}

View File

@ -210,10 +210,7 @@ kern_execve(td, fname, argv, envv, mac_p)
* so unset the associated flags and lose KSE mode.
*/
p->p_flag &= ~P_KSES;
td->td_flags &= ~TDF_UNBOUND;
td->td_mailbox = NULL;
td->td_kse->ke_mailbox = NULL;
td->td_kse->ke_flags &= ~KEF_DOUPCALL;
thread_single_end();
}
p->p_flag |= P_INEXEC;

View File

@ -147,7 +147,7 @@ exit1(td, rv)
}
/*
* XXXXKSE: MUST abort all other threads before proceeding past here.
* XXXKSE: MUST abort all other threads before proceeding past here.
*/
PROC_LOCK(p);
if (p->p_flag & P_KSES) {
@ -156,17 +156,6 @@ exit1(td, rv)
* if so, act apropriatly, (exit or suspend);
*/
thread_suspend_check(0);
/*
* Here is a trick..
* We need to free up our KSE to process other threads
* so that we can safely set the UNBOUND flag
* (whether or not we have a mailbox) as we are NEVER
* going to return to the user.
* The flag will not be set yet if we are exiting
* because of a signal, pagefault, or similar
* (or even an exit(2) from the UTS).
*/
td->td_flags |= TDF_UNBOUND;
/*
* Kill off the other threads. This requires
@ -192,7 +181,6 @@ exit1(td, rv)
* Turn off threading support.
*/
p->p_flag &= ~P_KSES;
td->td_flags &= ~TDF_UNBOUND;
thread_single_end(); /* Don't need this any more. */
}
/*
@ -237,8 +225,10 @@ exit1(td, rv)
*/
TAILQ_FOREACH(ep, &exit_list, next)
(*ep->function)(p);
PROC_LOCK(p);
stopprofclock(p);
PROC_UNLOCK(p);
MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage),
M_ZOMBIE, 0);

View File

@ -492,9 +492,7 @@ fork1(td, flags, pages, procp)
/* Set up the thread as an active thread (as if runnable). */
ke2->ke_state = KES_THREAD;
ke2->ke_thread = td2;
ke2->ke_owner = td2;
td2->td_kse = ke2;
td2->td_flags &= ~TDF_UNBOUND; /* For the rest of this syscall. */
/*
* Duplicate sub-structures as needed.

File diff suppressed because it is too large Load Diff

View File

@ -219,7 +219,7 @@ debuglockmgr(lkp, flags, interlkp, td, name, file, line)
#endif
{
int error;
pid_t pid;
struct thread *thr;
int extflags, lockflags;
CTR5(KTR_LOCKMGR,
@ -228,9 +228,9 @@ debuglockmgr(lkp, flags, interlkp, td, name, file, line)
error = 0;
if (td == NULL)
pid = LK_KERNPROC;
thr = LK_KERNPROC;
else
pid = td->td_proc->p_pid;
thr = td;
mtx_lock(lkp->lk_interlock);
if (flags & LK_INTERLOCK) {
@ -257,7 +257,7 @@ debuglockmgr(lkp, flags, interlkp, td, name, file, line)
* lock requests or upgrade requests ( but not the exclusive
* lock itself ).
*/
if (lkp->lk_lockholder != pid) {
if (lkp->lk_lockholder != thr) {
lockflags = LK_HAVE_EXCL;
mtx_lock_spin(&sched_lock);
if (td != NULL && !(td->td_flags & TDF_DEADLKTREAT))
@ -268,7 +268,7 @@ debuglockmgr(lkp, flags, interlkp, td, name, file, line)
break;
sharelock(lkp, 1);
#if defined(DEBUG_LOCKS)
lkp->lk_slockholder = pid;
lkp->lk_slockholder = thr;
lkp->lk_sfilename = file;
lkp->lk_slineno = line;
lkp->lk_slockername = name;
@ -283,14 +283,14 @@ debuglockmgr(lkp, flags, interlkp, td, name, file, line)
/* FALLTHROUGH downgrade */
case LK_DOWNGRADE:
KASSERT(lkp->lk_lockholder == pid && lkp->lk_exclusivecount != 0,
KASSERT(lkp->lk_lockholder == thr && lkp->lk_exclusivecount != 0,
("lockmgr: not holding exclusive lock "
"(owner pid (%d) != pid (%d), exlcnt (%d) != 0",
lkp->lk_lockholder, pid, lkp->lk_exclusivecount));
"(owner thread (%p) != thread (%p), exlcnt (%d) != 0",
lkp->lk_lockholder, thr, lkp->lk_exclusivecount));
sharelock(lkp, lkp->lk_exclusivecount);
lkp->lk_exclusivecount = 0;
lkp->lk_flags &= ~LK_HAVE_EXCL;
lkp->lk_lockholder = LK_NOPROC;
lkp->lk_lockholder = (struct thread *)LK_NOPROC;
if (lkp->lk_waitcount)
wakeup((void *)lkp);
break;
@ -317,7 +317,7 @@ debuglockmgr(lkp, flags, interlkp, td, name, file, line)
* after the upgrade). If we return an error, the file
* will always be unlocked.
*/
if ((lkp->lk_lockholder == pid) || (lkp->lk_sharecount <= 0))
if ((lkp->lk_lockholder == thr) || (lkp->lk_sharecount <= 0))
panic("lockmgr: upgrade exclusive lock");
shareunlock(lkp, 1);
/*
@ -342,7 +342,7 @@ debuglockmgr(lkp, flags, interlkp, td, name, file, line)
if (error)
break;
lkp->lk_flags |= LK_HAVE_EXCL;
lkp->lk_lockholder = pid;
lkp->lk_lockholder = thr;
if (lkp->lk_exclusivecount != 0)
panic("lockmgr: non-zero exclusive count");
lkp->lk_exclusivecount = 1;
@ -364,7 +364,7 @@ debuglockmgr(lkp, flags, interlkp, td, name, file, line)
/* FALLTHROUGH exclusive request */
case LK_EXCLUSIVE:
if (lkp->lk_lockholder == pid && pid != LK_KERNPROC) {
if (lkp->lk_lockholder == thr && thr != LK_KERNPROC) {
/*
* Recursive lock.
*/
@ -398,7 +398,7 @@ debuglockmgr(lkp, flags, interlkp, td, name, file, line)
if (error)
break;
lkp->lk_flags |= LK_HAVE_EXCL;
lkp->lk_lockholder = pid;
lkp->lk_lockholder = thr;
if (lkp->lk_exclusivecount != 0)
panic("lockmgr: non-zero exclusive count");
lkp->lk_exclusivecount = 1;
@ -411,10 +411,10 @@ debuglockmgr(lkp, flags, interlkp, td, name, file, line)
case LK_RELEASE:
if (lkp->lk_exclusivecount != 0) {
if (lkp->lk_lockholder != pid &&
if (lkp->lk_lockholder != thr &&
lkp->lk_lockholder != LK_KERNPROC) {
panic("lockmgr: pid %d, not %s %d unlocking",
pid, "exclusive lock holder",
panic("lockmgr: thread %p, not %s %p unlocking",
thr, "exclusive lock holder",
lkp->lk_lockholder);
}
if (lkp->lk_exclusivecount == 1) {
@ -437,14 +437,14 @@ debuglockmgr(lkp, flags, interlkp, td, name, file, line)
* check for holding a shared lock, but at least we can
* check for an exclusive one.
*/
if (lkp->lk_lockholder == pid)
if (lkp->lk_lockholder == thr)
panic("lockmgr: draining against myself");
error = acquiredrain(lkp, extflags);
if (error)
break;
lkp->lk_flags |= LK_DRAINING | LK_HAVE_EXCL;
lkp->lk_lockholder = pid;
lkp->lk_lockholder = thr;
lkp->lk_exclusivecount = 1;
#if defined(DEBUG_LOCKS)
lkp->lk_filename = file;
@ -589,7 +589,7 @@ lockstatus(lkp, td)
mtx_lock(lkp->lk_interlock);
if (lkp->lk_exclusivecount != 0) {
if (td == NULL || lkp->lk_lockholder == td->td_proc->p_pid)
if (td == NULL || lkp->lk_lockholder == td)
lock_type = LK_EXCLUSIVE;
else
lock_type = LK_EXCLOTHER;
@ -627,7 +627,7 @@ lockmgr_printinfo(lkp)
printf(" lock type %s: SHARED (count %d)", lkp->lk_wmesg,
lkp->lk_sharecount);
else if (lkp->lk_flags & LK_HAVE_EXCL)
printf(" lock type %s: EXCL (count %d) by pid %d",
printf(" lock type %s: EXCL (count %d) by thread %p",
lkp->lk_wmesg, lkp->lk_exclusivecount, lkp->lk_lockholder);
if (lkp->lk_waitcount > 0)
printf(" with %d pending", lkp->lk_waitcount);

View File

@ -671,32 +671,23 @@ calcru(p, up, sp, ip)
{
/* {user, system, interrupt, total} {ticks, usec}; previous tu: */
u_int64_t ut, uu, st, su, it, iu, tt, tu, ptu;
u_int64_t uut = 0, sut = 0, iut = 0;
int s;
struct timeval tv;
struct bintime bt;
struct kse *ke;
struct ksegrp *kg;
mtx_assert(&sched_lock, MA_OWNED);
/* XXX: why spl-protect ? worst case is an off-by-one report */
FOREACH_KSEGRP_IN_PROC(p, kg) {
/* we could accumulate per ksegrp and per process here*/
FOREACH_KSE_IN_GROUP(kg, ke) {
s = splstatclock();
ut = ke->ke_uticks;
st = ke->ke_sticks;
it = ke->ke_iticks;
splx(s);
ut = p->p_uticks;
st = p->p_sticks;
it = p->p_iticks;
tt = ut + st + it;
if (tt == 0) {
st = 1;
tt = 1;
}
tt = ut + st + it;
if (tt == 0) {
st = 1;
tt = 1;
}
if (ke == curthread->td_kse) {
if (curthread->td_proc == p) {
/*
* Adjust for the current time slice. This is actually fairly
* important since the error here is on the order of a time
@ -705,64 +696,59 @@ calcru(p, up, sp, ip)
* processors also being 'current'.
*/
binuptime(&bt);
bintime_sub(&bt, PCPU_PTR(switchtime));
bintime_add(&bt, &p->p_runtime);
} else {
bt = p->p_runtime;
}
bintime2timeval(&bt, &tv);
tu = (u_int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
ptu = ke->ke_uu + ke->ke_su + ke->ke_iu;
if (tu < ptu || (int64_t)tu < 0) {
/* XXX no %qd in kernel. Truncate. */
printf("calcru: negative time of %ld usec for pid %d (%s)\n",
(long)tu, p->p_pid, p->p_comm);
tu = ptu;
}
binuptime(&bt);
bintime_sub(&bt, PCPU_PTR(switchtime));
bintime_add(&bt, &p->p_runtime);
} else {
bt = p->p_runtime;
}
bintime2timeval(&bt, &tv);
tu = (u_int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
ptu = p->p_uu + p->p_su + p->p_iu;
if (tu < ptu || (int64_t)tu < 0) {
/* XXX no %qd in kernel. Truncate. */
printf("calcru: negative time of %ld usec for pid %d (%s)\n",
(long)tu, p->p_pid, p->p_comm);
tu = ptu;
}
/* Subdivide tu. */
uu = (tu * ut) / tt;
su = (tu * st) / tt;
iu = tu - uu - su;
/* Subdivide tu. */
uu = (tu * ut) / tt;
su = (tu * st) / tt;
iu = tu - uu - su;
/* Enforce monotonicity. */
if (uu < ke->ke_uu || su < ke->ke_su || iu < ke->ke_iu) {
if (uu < ke->ke_uu)
uu = ke->ke_uu;
else if (uu + ke->ke_su + ke->ke_iu > tu)
uu = tu - ke->ke_su - ke->ke_iu;
if (st == 0)
su = ke->ke_su;
else {
su = ((tu - uu) * st) / (st + it);
if (su < ke->ke_su)
su = ke->ke_su;
else if (uu + su + ke->ke_iu > tu)
su = tu - uu - ke->ke_iu;
}
KASSERT(uu + su + ke->ke_iu <= tu,
("calcru: monotonisation botch 1"));
iu = tu - uu - su;
KASSERT(iu >= ke->ke_iu,
("calcru: monotonisation botch 2"));
}
ke->ke_uu = uu;
ke->ke_su = su;
ke->ke_iu = iu;
uut += uu;
sut += su;
iut += iu;
} /* end kse loop */
} /* end kseg loop */
up->tv_sec = uut / 1000000;
up->tv_usec = uut % 1000000;
sp->tv_sec = sut / 1000000;
sp->tv_usec = sut % 1000000;
/* Enforce monotonicity. */
if (uu < p->p_uu || su < p->p_su || iu < p->p_iu) {
if (uu < p->p_uu)
uu = p->p_uu;
else if (uu + p->p_su + p->p_iu > tu)
uu = tu - p->p_su - p->p_iu;
if (st == 0)
su = p->p_su;
else {
su = ((tu - uu) * st) / (st + it);
if (su < p->p_su)
su = p->p_su;
else if (uu + su + p->p_iu > tu)
su = tu - uu - p->p_iu;
}
KASSERT(uu + su + p->p_iu <= tu,
("calcru: monotonisation botch 1"));
iu = tu - uu - su;
KASSERT(iu >= p->p_iu,
("calcru: monotonisation botch 2"));
}
p->p_uu = uu;
p->p_su = su;
p->p_iu = iu;
up->tv_sec = uu / 1000000;
up->tv_usec = uu % 1000000;
sp->tv_sec = su / 1000000;
sp->tv_usec = su % 1000000;
if (ip != NULL) {
ip->tv_sec = iut / 1000000;
ip->tv_usec = iut % 1000000;
ip->tv_sec = iu / 1000000;
ip->tv_usec = iu % 1000000;
}
}

View File

@ -1525,9 +1525,6 @@ psignal(p, sig)
if (TD_IS_SLEEPING(td) &&
(td->td_flags & TDF_SINTR))
thread_suspend_one(td);
else if (TD_IS_IDLE(td)) {
thread_suspend_one(td);
}
}
if (p->p_suspcount == p->p_numthreads) {
mtx_unlock_spin(&sched_lock);
@ -1640,9 +1637,6 @@ tdsignal(struct thread *td, int sig, sig_t action)
cv_abort(td);
else
abortsleep(td);
} else if (TD_IS_IDLE(td)) {
TD_CLR_IDLE(td);
setrunnable(td);
}
#ifdef SMP
else {

View File

@ -111,7 +111,7 @@ static void runq_readjust(struct runq *rq, struct kse *ke);
* Functions that manipulate runnability from a thread perspective. *
************************************************************************/
/*
* Select the KSE that will be run next. From that find the thread, and x
* Select the KSE that will be run next. From that find the thread, and
* remove it from the KSEGRP's run queue. If there is thread clustering,
* this will be what does it.
*/
@ -127,7 +127,7 @@ choosethread(void)
td = ke->ke_thread;
KASSERT((td->td_kse == ke), ("kse/thread mismatch"));
kg = ke->ke_ksegrp;
if (TD_IS_UNBOUND(td)) {
if (td->td_proc->p_flag & P_KSES) {
TAILQ_REMOVE(&kg->kg_runq, td, td_runq);
if (kg->kg_last_assigned == td) {
kg->kg_last_assigned = TAILQ_PREV(td,
@ -158,9 +158,8 @@ choosethread(void)
}
/*
* Given a KSE (now surplus or at least loanable), either assign a new
* runable thread to it (and put it in the run queue) or put it in
* the ksegrp's idle KSE list.
* Given a surplus KSE, either assign a new runable thread to it
* (and put it in the run queue) or put it in the ksegrp's idle KSE list.
* Or maybe give it back to its owner if it's been loaned.
* Assumes that the original thread is either not runnable or
* already on the run queue
@ -170,108 +169,54 @@ kse_reassign(struct kse *ke)
{
struct ksegrp *kg;
struct thread *td;
struct thread *owner;
struct thread *original;
int loaned;
struct kse_upcall *ku;
KASSERT((ke->ke_owner), ("reassigning KSE with no owner"));
KASSERT((ke->ke_thread && TD_IS_INHIBITED(ke->ke_thread)),
("reassigning KSE with no or runnable thread"));
mtx_assert(&sched_lock, MA_OWNED);
kg = ke->ke_ksegrp;
owner = ke->ke_owner;
loaned = TD_LENDER(owner);
original = ke->ke_thread;
if (TD_CAN_UNBIND(original) && (original->td_standin)) {
KASSERT((owner == original),
("Early thread borrowing?"));
KASSERT(original == NULL || TD_IS_INHIBITED(original),
("reassigning KSE with runnable thread"));
kg = ke->ke_ksegrp;
if (original) {
/*
* The outgoing thread is "threaded" and has never
* scheduled an upcall.
* decide whether this is a short or long term event
* and thus whether or not to schedule an upcall.
* if it is a short term event, just suspend it in
* If the outgoing thread is in threaded group and has never
* scheduled an upcall, decide whether this is a short
* or long term event and thus whether or not to schedule
* an upcall.
* If it is a short term event, just suspend it in
* a way that takes its KSE with it.
* Select the events for which we want to schedule upcalls.
* For now it's just sleep.
* Other threads that still have not fired an upcall
* are held to their KSE using the temorary Binding.
* XXXKSE eventually almost any inhibition could do.
*/
if (TD_ON_SLEEPQ(original)) {
/*
* An bound thread that can still unbind itself
* has been scheduled out.
* If it is sleeping, then we need to schedule an
* upcall.
* XXXKSE eventually almost any inhibition could do.
if (TD_CAN_UNBIND(original) && (original->td_standin) &&
TD_ON_SLEEPQ(original)) {
/*
* Release ownership of upcall, and schedule an upcall
* thread, this new upcall thread becomes the owner of
* the upcall structure.
*/
ku = original->td_upcall;
ku->ku_owner = NULL;
original->td_upcall = NULL;
original->td_flags &= ~TDF_CAN_UNBIND;
original->td_flags |= TDF_UNBOUND;
thread_schedule_upcall(original, ke);
owner = ke->ke_owner;
loaned = 1;
thread_schedule_upcall(original, ku);
}
original->td_kse = NULL;
}
/*
* If the current thread was borrowing, then make things consistent
* by giving it back to the owner for the moment. The original thread
* must be unbound and have already used its chance for
* firing off an upcall. Threads that have not yet made an upcall
* can not borrow KSEs.
*/
if (loaned) {
TD_CLR_LOAN(owner);
ke->ke_thread = owner;
original->td_kse = NULL; /* give it amnesia */
/*
* Upcalling threads have lower priority than all
* in-kernel threads, However threads that have loaned out
* their KSE and are NOT upcalling have the priority that
* they have. In other words, only look for other work if
* the owner is not runnable, OR is upcalling.
*/
if (TD_CAN_RUN(owner) &&
((owner->td_flags & TDF_UPCALLING) == 0)) {
setrunnable(owner);
CTR2(KTR_RUNQ, "kse_reassign: ke%p -> td%p (give back)",
ke, owner);
return;
}
}
/*
* Either the owner is not runnable, or is an upcall.
* Find the first unassigned thread
* If there is a 'last assigned' then see what's next.
* otherwise look at what is first.
*/
if ((td = kg->kg_last_assigned)) {
if ((td = kg->kg_last_assigned) != NULL)
td = TAILQ_NEXT(td, td_runq);
} else {
else
td = TAILQ_FIRST(&kg->kg_runq);
}
/*
* If we found one assign it the kse, otherwise idle the kse.
* If we found one, assign it the kse, otherwise idle the kse.
*/
if (td) {
/*
* Assign the new thread to the KSE.
* and make the KSE runnable again,
*/
if (TD_IS_BOUND(owner)) {
/*
* If there is a reason to keep the previous
* owner, do so.
*/
TD_SET_LOAN(owner);
} else {
/* otherwise, cut it free */
ke->ke_owner = td;
owner->td_kse = NULL;
}
kg->kg_last_assigned = td;
td->td_kse = ke;
ke->ke_thread = td;
@ -280,43 +225,11 @@ kse_reassign(struct kse *ke)
return;
}
/*
* Now handle any waiting upcall.
* Since we didn't make them runnable before.
*/
if (TD_CAN_RUN(owner)) {
setrunnable(owner);
CTR2(KTR_RUNQ, "kse_reassign: ke%p -> td%p (give back)",
ke, owner);
return;
}
/*
* It is possible that this is the last thread in the group
* because the KSE is being shut down or the process
* is exiting.
*/
if (TD_IS_EXITING(owner) || (ke->ke_flags & KEF_EXIT)) {
ke->ke_thread = NULL;
owner->td_kse = NULL;
kse_unlink(ke);
return;
}
/*
* At this stage all we know is that the owner
* is the same as the 'active' thread in the KSE
* and that it is
* Presently NOT loaned out.
* Put it on the loanable queue. Make it fifo
* so that long term sleepers donate their KSE's first.
*/
KASSERT((TD_IS_BOUND(owner)), ("kse_reassign: UNBOUND lender"));
ke->ke_state = KES_THREAD;
ke->ke_flags |= KEF_ONLOANQ;
TAILQ_INSERT_TAIL(&kg->kg_lq, ke, ke_kgrlist);
kg->kg_loan_kses++;
CTR1(KTR_RUNQ, "kse_reassign: ke%p on loan queue", ke);
ke->ke_state = KES_IDLE;
ke->ke_thread = NULL;
TAILQ_INSERT_TAIL(&kg->kg_iq, ke, ke_kgrlist);
kg->kg_idle_kses++;
CTR1(KTR_RUNQ, "kse_reassign: ke%p on idle queue", ke);
return;
}
@ -325,7 +238,7 @@ kse_reassign(struct kse *ke)
* Remove a thread from its KSEGRP's run queue.
* This in turn may remove it from a KSE if it was already assigned
* to one, possibly causing a new thread to be assigned to the KSE
* and the KSE getting a new priority (unless it's a BOUND thread/KSE pair).
* and the KSE getting a new priority.
*/
static void
remrunqueue(struct thread *td)
@ -335,17 +248,16 @@ remrunqueue(struct thread *td)
struct kse *ke;
mtx_assert(&sched_lock, MA_OWNED);
KASSERT ((TD_ON_RUNQ(td)), ("remrunqueue: Bad state on run queue"));
KASSERT((TD_ON_RUNQ(td)), ("remrunqueue: Bad state on run queue"));
kg = td->td_ksegrp;
ke = td->td_kse;
/*
* If it's a bound thread/KSE pair, take the shortcut. All non-KSE
* threads are BOUND.
*/
CTR1(KTR_RUNQ, "remrunqueue: td%p", td);
kg->kg_runnable--;
TD_SET_CAN_RUN(td);
if (TD_IS_BOUND(td)) {
/*
* If it is not a threaded process, take the shortcut.
*/
if ((td->td_proc->p_flag & P_KSES) == 0) {
/* Bring its kse with it, leave the thread attached */
sched_rem(ke);
ke->ke_state = KES_THREAD;
@ -363,7 +275,7 @@ remrunqueue(struct thread *td)
sched_rem(ke);
ke->ke_state = KES_THREAD;
td2 = kg->kg_last_assigned;
KASSERT((td2 != NULL), ("last assigned has wrong value "));
KASSERT((td2 != NULL), ("last assigned has wrong value"));
if (td2 == td)
kg->kg_last_assigned = td3;
kse_reassign(ke);
@ -381,14 +293,14 @@ adjustrunqueue( struct thread *td, int newpri)
struct kse *ke;
mtx_assert(&sched_lock, MA_OWNED);
KASSERT ((TD_ON_RUNQ(td)), ("adjustrunqueue: Bad state on run queue"));
/*
* If it's a bound thread/KSE pair, take the shortcut. All non-KSE
* threads are BOUND.
*/
KASSERT((TD_ON_RUNQ(td)), ("adjustrunqueue: Bad state on run queue"));
ke = td->td_kse;
CTR1(KTR_RUNQ, "adjustrunqueue: td%p", td);
if (TD_IS_BOUND(td)) {
/*
* If it is not a threaded process, take the shortcut.
*/
if ((td->td_proc->p_flag & P_KSES) == 0) {
/* We only care about the kse in the run queue. */
td->td_priority = newpri;
if (ke->ke_rqindex != (newpri / RQ_PPQ)) {
@ -397,9 +309,8 @@ adjustrunqueue( struct thread *td, int newpri)
}
return;
}
/*
* An unbound thread. This is not optimised yet.
*/
/* It is a threaded process */
kg = td->td_ksegrp;
kg->kg_runnable--;
TD_SET_CAN_RUN(td);
@ -439,48 +350,17 @@ setrunqueue(struct thread *td)
sched_add(td->td_kse);
return;
}
/*
* If the process is threaded but the thread is bound then
* there is still a little extra to do re. KSE loaning.
*/
if (TD_IS_BOUND(td)) {
KASSERT((td->td_kse != NULL),
("queueing BAD thread to run queue"));
ke = td->td_kse;
KASSERT((ke->ke_owner == ke->ke_thread),
("setrunqueue: Hey KSE loaned out"));
if (ke->ke_flags & KEF_ONLOANQ) {
ke->ke_flags &= ~KEF_ONLOANQ;
TAILQ_REMOVE(&kg->kg_lq, ke, ke_kgrlist);
kg->kg_loan_kses--;
}
sched_add(td->td_kse);
return;
}
/*
* Ok, so we are threading with this thread.
* We don't have a KSE, see if we can get one..
*/
tda = kg->kg_last_assigned;
if ((ke = td->td_kse) == NULL) {
/*
* We will need a KSE, see if there is one..
* First look for a free one, before getting desperate.
* If we can't get one, our priority is not high enough..
* that's ok..
*/
if (kg->kg_loan_kses) {
if (kg->kg_idle_kses) {
/*
* Failing that see if we can borrow one.
* There is a free one so it's ours for the asking..
*/
ke = TAILQ_FIRST(&kg->kg_lq);
TAILQ_REMOVE(&kg->kg_lq, ke, ke_kgrlist);
ke->ke_flags &= ~KEF_ONLOANQ;
ke = TAILQ_FIRST(&kg->kg_iq);
TAILQ_REMOVE(&kg->kg_iq, ke, ke_kgrlist);
ke->ke_state = KES_THREAD;
TD_SET_LOAN(ke->ke_owner);
ke->ke_thread = NULL;
kg->kg_loan_kses--;
kg->kg_idle_kses--;
} else if (tda && (tda->td_priority > td->td_priority)) {
/*
* None free, but there is one we can commandeer.
@ -495,11 +375,7 @@ setrunqueue(struct thread *td)
} else {
/*
* Temporarily disassociate so it looks like the other cases.
* If the owner wasn't lending before, then it is now..
*/
if (!TD_LENDER(ke->ke_owner)) {
TD_SET_LOAN(ke->ke_owner);
}
ke->ke_thread = NULL;
td->td_kse = NULL;
}
@ -831,6 +707,7 @@ thread_sanity_check(struct thread *td, char *string)
if (kg->kg_last_assigned && (saw_lastassigned == 0)) {
panc(string, "where on earth does lastassigned point?");
}
#if 0
FOREACH_THREAD_IN_GROUP(kg, td2) {
if (((td2->td_flags & TDF_UNBOUND) == 0) &&
(TD_ON_RUNQ(td2))) {
@ -840,6 +717,7 @@ thread_sanity_check(struct thread *td, char *string)
}
}
}
#endif
#if 0
if ((unassigned + assigned) != kg->kg_runnable) {
panc(string, "wrong number in runnable");

File diff suppressed because it is too large Load Diff

View File

@ -358,7 +358,9 @@ sysctl_kern_prof(SYSCTL_HANDLER_ARGS)
return (0);
if (state == GMON_PROF_OFF) {
gp->state = state;
PROC_LOCK(&proc0);
stopprofclock(&proc0);
PROC_UNLOCK(&proc0);
stopguprof(gp);
} else if (state == GMON_PROF_ON) {
gp->state = GMON_PROF_OFF;
@ -369,7 +371,9 @@ sysctl_kern_prof(SYSCTL_HANDLER_ARGS)
#ifdef GUPROF
} else if (state == GMON_PROF_HIRES) {
gp->state = GMON_PROF_OFF;
PROC_LOCK(&proc0);
stopprofclock(&proc0);
PROC_UNLOCK(&proc0);
startguprof(gp);
gp->state = state;
#endif
@ -419,7 +423,7 @@ profil(td, uap)
struct thread *td;
register struct profil_args *uap;
{
register struct uprof *upp;
struct uprof *upp;
int s;
int error = 0;
@ -430,7 +434,9 @@ profil(td, uap)
goto done2;
}
if (uap->scale == 0) {
PROC_LOCK(td->td_proc);
stopprofclock(td->td_proc);
PROC_UNLOCK(td->td_proc);
goto done2;
}
upp = &td->td_proc->p_stats->p_prof;
@ -472,19 +478,16 @@ profil(td, uap)
* inaccurate.
*/
void
addupc_intr(ke, pc, ticks)
register struct kse *ke;
register uintptr_t pc;
u_int ticks;
addupc_intr(struct thread *td, uintptr_t pc, u_int ticks)
{
register struct uprof *prof;
register caddr_t addr;
register u_int i;
register int v;
struct uprof *prof;
caddr_t addr;
u_int i;
int v;
if (ticks == 0)
return;
prof = &ke->ke_proc->p_stats->p_prof;
prof = &td->td_proc->p_stats->p_prof;
if (pc < prof->pr_off ||
(i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
return; /* out of range; ignore */
@ -492,9 +495,9 @@ addupc_intr(ke, pc, ticks)
addr = prof->pr_base + i;
if ((v = fuswintr(addr)) == -1 || suswintr(addr, v + ticks) == -1) {
mtx_lock_spin(&sched_lock);
prof->pr_addr = pc;
prof->pr_ticks = ticks;
ke->ke_flags |= KEF_OWEUPC | KEF_ASTPENDING ;
td->td_praddr = pc;
td->td_prticks = ticks;
td->td_flags |= (TDF_OWEUPC | TDF_ASTPENDING);
mtx_unlock_spin(&sched_lock);
}
}
@ -502,34 +505,56 @@ addupc_intr(ke, pc, ticks)
/*
* Much like before, but we can afford to take faults here. If the
* update fails, we simply turn off profiling.
* XXXKSE, don't use kse unless we got sched lock.
*/
void
addupc_task(ke, pc, ticks)
register struct kse *ke;
register uintptr_t pc;
u_int ticks;
addupc_task(struct thread *td, uintptr_t pc, u_int ticks)
{
struct proc *p = ke->ke_proc;
struct proc *p = td->td_proc;
register struct uprof *prof;
register caddr_t addr;
register u_int i;
u_short v;
int stop = 0;
if (ticks == 0)
return;
PROC_LOCK(p);
mtx_lock_spin(&sched_lock);
if (!(p->p_sflag & PS_PROFIL)) {
mtx_unlock_spin(&sched_lock);
PROC_UNLOCK(p);
return;
}
p->p_profthreads++;
mtx_unlock_spin(&sched_lock);
PROC_UNLOCK(p);
prof = &p->p_stats->p_prof;
if (pc < prof->pr_off ||
(i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
return;
(i = PC_TO_INDEX(pc, prof)) >= prof->pr_size) {
goto out;
}
addr = prof->pr_base + i;
if (copyin(addr, &v, sizeof(v)) == 0) {
v += ticks;
if (copyout(&v, addr, sizeof(v)) == 0)
return;
goto out;
}
stopprofclock(p);
stop = 1;
out:
PROC_LOCK(p);
if (--p->p_profthreads == 0) {
if (p->p_sflag & PS_STOPPROF) {
wakeup(&p->p_profthreads);
stop = 0;
}
}
if (stop)
stopprofclock(p);
PROC_UNLOCK(p);
}
#if defined(__i386__) && __GNUC__ >= 2

View File

@ -73,15 +73,21 @@ userret(td, frame, oticks)
u_int oticks;
{
struct proc *p = td->td_proc;
struct kse *ke = td->td_kse;
#ifdef INVARIANTS
struct kse *ke;
#endif
CTR3(KTR_SYSC, "userret: thread %p (pid %d, %s)", td, p->p_pid,
p->p_comm);
#ifdef INVARIANTS
/* Check that we called signotify() enough. */
/*
* Check that we called signotify() enough.
* XXXKSE this checking is bogus for threaded program,
*/
mtx_lock(&Giant);
PROC_LOCK(p);
mtx_lock_spin(&sched_lock);
ke = td->td_kse;
if (SIGPENDING(p) && ((p->p_sflag & PS_NEEDSIGCHK) == 0 ||
(td->td_kse->ke_flags & KEF_ASTPENDING) == 0))
printf("failed to set signal flags properly for ast()\n");
@ -95,6 +101,18 @@ userret(td, frame, oticks)
*/
sched_userret(td);
/*
* Charge system time if profiling.
*
* XXX should move PS_PROFIL to a place that can obviously be
* accessed safely without sched_lock.
*/
if (p->p_sflag & PS_PROFIL) {
ticks = td->td_sticks - oticks;
addupc_task(td, TRAPF_PC(frame), (u_int)ticks * psratio);
}
/*
* We need to check to see if we have to exit or wait due to a
* single threading requirement or some other STOP condition.
@ -113,21 +131,6 @@ userret(td, frame, oticks)
if (p->p_flag & P_KSES) {
thread_userret(td, frame);
}
/*
* Charge system time if profiling.
*
* XXX should move PS_PROFIL to a place that can obviously be
* accessed safely without sched_lock.
*/
if (p->p_sflag & PS_PROFIL) {
quad_t ticks;
mtx_lock_spin(&sched_lock);
ticks = ke->ke_sticks - oticks;
mtx_unlock_spin(&sched_lock);
addupc_task(ke, TRAPF_PC(frame), (u_int)ticks * psratio);
}
}
/*
@ -146,6 +149,7 @@ ast(struct trapframe *framep)
u_int prticks, sticks;
int sflag;
int flags;
int tflags;
int sig;
#if defined(DEV_NPX) && !defined(SMP)
int ucode;
@ -175,19 +179,21 @@ ast(struct trapframe *framep)
*/
mtx_lock_spin(&sched_lock);
ke = td->td_kse;
sticks = ke->ke_sticks;
sticks = td->td_sticks;
tflags = td->td_flags;
flags = ke->ke_flags;
sflag = p->p_sflag;
p->p_sflag &= ~(PS_ALRMPEND | PS_NEEDSIGCHK | PS_PROFPEND | PS_XCPU);
#ifdef MAC
p->p_sflag &= ~PS_MACPEND;
#endif
ke->ke_flags &= ~(KEF_ASTPENDING | KEF_NEEDRESCHED | KEF_OWEUPC);
ke->ke_flags &= ~(KEF_ASTPENDING | KEF_NEEDRESCHED);
td->td_flags &= ~(TDF_ASTPENDING | TDF_OWEUPC);
cnt.v_soft++;
prticks = 0;
if (flags & KEF_OWEUPC && sflag & PS_PROFIL) {
prticks = p->p_stats->p_prof.pr_ticks;
p->p_stats->p_prof.pr_ticks = 0;
if (tflags & TDF_OWEUPC && sflag & PS_PROFIL) {
prticks = td->td_prticks;
td->td_prticks = 0;
}
mtx_unlock_spin(&sched_lock);
/*
@ -200,8 +206,9 @@ ast(struct trapframe *framep)
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
if (flags & KEF_OWEUPC && sflag & PS_PROFIL)
addupc_task(ke, p->p_stats->p_prof.pr_addr, prticks);
if (tflags & TDF_OWEUPC && sflag & PS_PROFIL) {
addupc_task(td, td->td_praddr, prticks);
}
if (sflag & PS_ALRMPEND) {
PROC_LOCK(p);
psignal(p, SIGVTALRM);

View File

@ -244,7 +244,7 @@ static struct witness_order_list_entry order_lists[] = {
#endif
{ "clk", &lock_class_mtx_spin },
{ "mutex profiling lock", &lock_class_mtx_spin },
{ "zombie_thread_lock", &lock_class_mtx_spin },
{ "kse zombie lock", &lock_class_mtx_spin },
{ "ALD Queue", &lock_class_mtx_spin },
#ifdef __ia64__
{ "MCA spin lock", &lock_class_mtx_spin },

View File

@ -285,7 +285,7 @@ cpu_set_upcall(struct thread *td, void *pcb)
}
void
cpu_set_upcall_kse(struct thread *td, struct kse *ke)
cpu_set_upcall_kse(struct thread *td, struct kse_upcall *ku)
{
return;

View File

@ -285,7 +285,7 @@ cpu_set_upcall(struct thread *td, void *pcb)
}
void
cpu_set_upcall_kse(struct thread *td, struct kse *ke)
cpu_set_upcall_kse(struct thread *td, struct kse_upcall *ku)
{
return;

View File

@ -243,7 +243,7 @@ trap(struct trapframe *tf)
KASSERT(td->td_proc != NULL, ("trap: curproc NULL"));
p = td->td_proc;
sticks = td->td_kse->ke_sticks;
sticks = td->td_sticks;
td->td_frame = tf;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
@ -495,7 +495,7 @@ syscall(struct trapframe *tf)
reg = 0;
regcnt = REG_MAXARGS;
sticks = td->td_kse->ke_sticks;
sticks = td->td_sticks;
td->td_frame = tf;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);

View File

@ -141,7 +141,7 @@ cpu_set_upcall(struct thread *td, void *pcb)
}
void
cpu_set_upcall_kse(struct thread *td, struct kse *ke)
cpu_set_upcall_kse(struct thread *td, struct kse_upcall *ku)
{
}

View File

@ -353,7 +353,7 @@ BUF_KERNPROC(struct buf *bp)
struct thread *td = curthread;
if ((td != PCPU_GET(idlethread))
&& bp->b_lock.lk_lockholder == td->td_proc->p_pid)
&& bp->b_lock.lk_lockholder == td)
td->td_locks--;
bp->b_lock.lk_lockholder = LK_KERNPROC;
}

View File

@ -57,14 +57,14 @@ struct lock {
short lk_prio; /* priority at which to sleep */
const char *lk_wmesg; /* resource sleeping (for tsleep) */
int lk_timo; /* maximum sleep time (for tsleep) */
pid_t lk_lockholder; /* pid of exclusive lock holder */
struct thread *lk_lockholder; /* thread of exclusive lock holder */
struct lock *lk_newlock; /* lock taking over this lock */
#ifdef DEBUG_LOCKS
const char *lk_filename;
const char *lk_lockername;
int lk_lineno;
pid_t lk_slockholder;
struct thread *lk_slockholder;
const char *lk_sfilename;
const char *lk_slockername;
int lk_slineno;
@ -176,8 +176,8 @@ struct lock {
/*
* Indicator that no process holds exclusive lock
*/
#define LK_KERNPROC ((pid_t) -2)
#define LK_NOPROC ((pid_t) -1)
#define LK_KERNPROC ((struct thread *)-2)
#define LK_NOPROC ((struct thread *)-1)
#ifdef INVARIANTS
#define LOCKMGR_ASSERT(lkp, what, p) do { \

View File

@ -185,7 +185,7 @@ struct trapframe;
*
* It is important to remember that a particular thread structure only
* exists as long as the system call or kernel entrance (e.g. by pagefault)
* which it is currently executing. It should threfore NEVER be referenced
* which it is currently executing. It should therefore NEVER be referenced
* by pointers in long lived structures that live longer than a single
* request. If several threads complete their work at the same time,
* they will all rewind their stacks to the user boundary, report their
@ -216,7 +216,7 @@ struct kse;
/*
* The KSEGRP is allocated resources across a number of CPUs.
* (Including a number of CPUxQUANTA. It parcels these QUANTA up among
* Its KSEs, each of which should be running in a different CPU.
* its KSEs, each of which should be running in a different CPU.
* BASE priority and total available quanta are properties of a KSEGRP.
* Multiple KSEGRPs in a single process compete against each other
* for total quanta in the same way that a forked child competes against
@ -258,7 +258,7 @@ They would be given priorities calculated from the KSEG.
* This is what is put to sleep and reactivated.
* The first KSE available in the correct group will run this thread.
* If several are available, use the one on the same CPU as last time.
* When waing to be run, threads are hung off the KSEGRP in priority order.
* When waiting to be run, threads are hung off the KSEGRP in priority order.
* with N runnable and queued KSEs in the KSEGRP, the first N threads
* are linked to them. Other threads are not yet assigned.
*/
@ -298,7 +298,16 @@ struct thread {
struct ucred *td_ucred; /* (k) Reference to credentials. */
void (*td_switchin)(void); /* (k) Switchin special func. */
struct thread *td_standin; /* (?) Use this for an upcall */
u_int td_usticks; /* (?) Statclock kernel hits, for UTS */
struct kse_upcall *td_upcall; /* owned upcall structure. */
u_int64_t td_sticks; /* (j) Statclock hits in system mode. */
#if 0
u_int64_t td_uticks; /* (j) Statclock hits in user mode. */
u_int64_t td_iticks; /* (j) Statclock hits in intr. */
#endif
u_long td_praddr; /* temp storage for addr util AST */
u_int td_prticks; /* temp storage for ticks until AST */
u_int td_usticks; /* Stateclock kern mode hits, UTS */
u_int td_uuticks; /* Stateclock user mode hits, UTS */
u_int td_critnest; /* (k) Critical section nest level. */
#define td_endzero td_base_pri
@ -333,7 +342,6 @@ struct thread {
struct td_sched *td_sched; /* Scheduler specific data */
};
/* flags kept in td_flags */
#define TDF_UNBOUND 0x000001 /* May give away the kse, uses the kg runq. */
#define TDF_INPANIC 0x000002 /* Caused a panic, let it drive crashdump. */
#define TDF_CAN_UNBIND 0x000004 /* Only temporarily bound. */
#define TDF_SINTR 0x000008 /* Sleep is interruptible. */
@ -343,8 +351,11 @@ struct thread {
#define TDF_UPCALLING 0x000100 /* This thread is doing an upcall. */
#define TDF_ONSLEEPQ 0x000200 /* On the sleep queue. */
#define TDF_INMSLEEP 0x000400 /* Don't recurse in msleep(). */
#define TDF_ASTPENDING 0x000800 /* Thread has some asynchronous events. */
#define TDF_TIMOFAIL 0x001000 /* Timeout from sleep after we were awake. */
#define TDF_INTERRUPT 0x002000 /* Thread is marked as interrupted. */
#define TDF_USTATCLOCK 0x004000 /* State clock hits in userland. */
#define TDF_OWEUPC 0x008000 /* Owe thread an addupc() call at next ast. */
#define TDF_DEADLKTREAT 0x800000 /* Lock aquisition - deadlock treatment. */
#define TDI_SUSPENDED 0x0001 /* On suspension queue. */
@ -352,25 +363,17 @@ struct thread {
#define TDI_SWAPPED 0x0004 /* Stack not in mem.. bad juju if run. */
#define TDI_LOCK 0x0008 /* Stopped on a lock. */
#define TDI_IWAIT 0x0010 /* Awaiting interrupt. */
#define TDI_LOAN 0x0020 /* bound thread's KSE is lent */
#define TDI_IDLE 0x0040 /* kse_release() made us surplus */
#define TDI_EXITING 0x0080 /* Thread is in exit processing */
#define TD_IS_UNBOUND(td) ((td)->td_flags & TDF_UNBOUND)
#define TD_IS_BOUND(td) (!TD_IS_UNBOUND(td))
#define TD_CAN_UNBIND(td) \
(((td)->td_flags & (TDF_UNBOUND|TDF_CAN_UNBIND)) == TDF_CAN_UNBIND)
#define TD_CAN_UNBIND(td) \
(((td)->td_flags & TDF_CAN_UNBIND) == TDF_CAN_UNBIND && \
((td)->td_upcall != NULL))
#define TD_IS_SLEEPING(td) ((td)->td_inhibitors & TDI_SLEEPING)
#define TD_ON_SLEEPQ(td) ((td)->td_wchan != NULL)
#define TD_IS_SUSPENDED(td) ((td)->td_inhibitors & TDI_SUSPENDED)
#define TD_IS_SWAPPED(td) ((td)->td_inhibitors & TDI_SWAPPED)
#define TD_ON_LOCK(td) ((td)->td_inhibitors & TDI_LOCK)
#define TD_LENDER(td) ((td)->td_inhibitors & TDI_LOAN)
#define TD_AWAITING_INTR(td) ((td)->td_inhibitors & TDI_IWAIT)
#define TD_IS_IDLE(td) ((td)->td_inhibitors & TDI_IDLE)
#define TD_IS_EXITING(td) ((td)->td_inhibitors & TDI_EXITING)
#define TD_IS_RUNNING(td) ((td)->td_state == TDS_RUNNING)
#define TD_ON_RUNQ(td) ((td)->td_state == TDS_RUNQ)
#define TD_CAN_RUN(td) ((td)->td_state == TDS_CAN_RUN)
@ -378,12 +381,12 @@ struct thread {
#define TD_SET_INHIB(td, inhib) do { \
(td)->td_state = TDS_INHIBITED; \
(td)->td_inhibitors |= inhib; \
(td)->td_inhibitors |= (inhib); \
} while (0)
#define TD_CLR_INHIB(td, inhib) do { \
if (((td)->td_inhibitors & inhib) && \
(((td)->td_inhibitors &= ~inhib) == 0)) \
if (((td)->td_inhibitors & (inhib)) && \
(((td)->td_inhibitors &= ~(inhib)) == 0)) \
(td)->td_state = TDS_CAN_RUN; \
} while (0)
@ -392,8 +395,6 @@ struct thread {
#define TD_SET_LOCK(td) TD_SET_INHIB((td), TDI_LOCK)
#define TD_SET_SUSPENDED(td) TD_SET_INHIB((td), TDI_SUSPENDED)
#define TD_SET_IWAIT(td) TD_SET_INHIB((td), TDI_IWAIT)
#define TD_SET_LOAN(td) TD_SET_INHIB((td), TDI_LOAN)
#define TD_SET_IDLE(td) TD_SET_INHIB((td), TDI_IDLE)
#define TD_SET_EXITING(td) TD_SET_INHIB((td), TDI_EXITING)
#define TD_CLR_SLEEPING(td) TD_CLR_INHIB((td), TDI_SLEEPING)
@ -401,8 +402,6 @@ struct thread {
#define TD_CLR_LOCK(td) TD_CLR_INHIB((td), TDI_LOCK)
#define TD_CLR_SUSPENDED(td) TD_CLR_INHIB((td), TDI_SUSPENDED)
#define TD_CLR_IWAIT(td) TD_CLR_INHIB((td), TDI_IWAIT)
#define TD_CLR_LOAN(td) TD_CLR_INHIB((td), TDI_LOAN)
#define TD_CLR_IDLE(td) TD_CLR_INHIB((td), TDI_IDLE)
#define TD_SET_RUNNING(td) do {(td)->td_state = TDS_RUNNING; } while (0)
#define TD_SET_RUNQ(td) do {(td)->td_state = TDS_RUNQ; } while (0)
@ -413,16 +412,6 @@ struct thread {
(td)->td_wchan = NULL; \
} while (0)
/*
* Traps for young players:
* The main thread variable that controls whether a thread acts as a threaded
* or unthreaded thread is the TDF_UNBOUND flag.
* i.e. they bind themselves to whatever thread thay are first scheduled with.
* You may see BOUND threads in KSE processes but you should never see
* UNBOUND threads in non KSE processes.
*/
/*
* The schedulable entity that can be given a context to run.
* A process may have several of these. Probably one per processor
@ -440,54 +429,47 @@ struct kse {
#define ke_startzero ke_flags
int ke_flags; /* (j) KEF_* flags. */
struct thread *ke_thread; /* Active associated thread. */
struct thread *ke_owner; /* Always points to the owner */
fixpt_t ke_pctcpu; /* (j) %cpu during p_swtime. */
u_int64_t ke_uu; /* (j) Previous user time in usec. */
u_int64_t ke_su; /* (j) Previous system time in usec. */
u_int64_t ke_iu; /* (j) Previous intr time in usec. */
u_int64_t ke_uticks; /* (j) Statclock hits in user mode. */
u_int64_t ke_sticks; /* (j) Statclock hits in system mode. */
u_int64_t ke_iticks; /* (j) Statclock hits in intr. */
u_int ke_uuticks; /* Statclock hits in user, for UTS */
u_int ke_usticks; /* Statclock hits in kernel, for UTS */
fixpt_t ke_pctcpu; /* (j) %cpu during p_swtime. */
u_char ke_oncpu; /* (j) Which cpu we are on. */
char ke_rqindex; /* (j) Run queue index. */
enum {
KES_UNUSED = 0x0,
KES_IDLE,
KES_ONRUNQ,
KES_UNQUEUED, /* in transit */
KES_THREAD /* slaved to thread state */
} ke_state; /* (j) S* process status. */
struct kse_mailbox *ke_mailbox; /* the userland mailbox address */
stack_t ke_stack;
void *ke_upcall;
struct thread *ke_tdspare; /* spare thread for upcalls */
#define ke_endzero ke_dummy
u_char ke_dummy;
struct ke_sched *ke_sched; /* Scheduler specific data */
};
/* flags kept in ke_flags */
#define KEF_OWEUPC 0x00002 /* Owe process an addupc() call at next ast. */
#define KEF_IDLEKSE 0x00004 /* A 'Per CPU idle process'.. has one thread */
#define KEF_LOANED 0x00008 /* On loan from the bound thread to another */
#define KEF_USER 0x00200 /* Process is not officially in the kernel */
#define KEF_ASTPENDING 0x00400 /* KSE has a pending ast. */
#define KEF_NEEDRESCHED 0x00800 /* Process needs to yield. */
#define KEF_ONLOANQ 0x01000 /* KSE is on loan queue. */
#define KEF_DIDRUN 0x02000 /* KSE actually ran. */
#define KEF_EXIT 0x04000 /* KSE is being killed. */
#define KEF_DOUPCALL 0x08000 /* KSE should do upcall now. */
/*
* (*) A bound KSE with a bound thread in a KSE process may be lent to
* Other threads, as long as those threads do not leave the kernel.
* The other threads must be either exiting, or be unbound with a valid
* mailbox so that they can save their state there rather than going
* to user space. While this happens the real bound thread is still linked
* to the kse via the ke_bound field, and the KSE has its "KEF_LOANED
* flag set.
* The upcall management structure. Any thread owns an upcall structure
* can goto userland, it is various whether it uses the upcall or not.
* Any thread does not own an upcall should export its context and
* suicide at user boundary, they do not directly return to userland,
* an upcall thread takes them back to userland.
*/
struct kse_upcall {
TAILQ_ENTRY(kse_upcall) ku_link;/* List of upcall in KSEG. */
struct ksegrp *ku_ksegrp; /* Associated KSEG. */
struct thread *ku_owner; /* Thread owns the upcall. */
int ku_flags; /* KUF_* flags. */
struct kse_mailbox *ku_mailbox; /* The userland mailbox address. */
stack_t ku_stack; /* The userland upcall stack. */
void *ku_func; /* The userland upcall function. */
};
#define KUF_DOUPCALL 0x00001 /* Do upcall now, don't wait */
/*
* Kernel-scheduled entity group (KSEG). The scheduler considers each KSEG to
@ -498,18 +480,20 @@ struct ksegrp {
struct proc *kg_proc; /* Process that contains this KSEG. */
TAILQ_ENTRY(ksegrp) kg_ksegrp; /* Queue of KSEGs in kg_proc. */
TAILQ_HEAD(, kse) kg_kseq; /* (ke_kglist) All KSEs. */
TAILQ_HEAD(, kse) kg_lq; /* (ke_kgrlist) Loan KSEs. */
TAILQ_HEAD(, kse) kg_iq; /* (ke_kgrlist) All idle KSEs. */
TAILQ_HEAD(, thread) kg_threads;/* (td_kglist) All threads. */
TAILQ_HEAD(, thread) kg_runq; /* (td_runq) waiting RUNNABLE threads */
TAILQ_HEAD(, thread) kg_slpq; /* (td_runq) NONRUNNABLE threads. */
TAILQ_HEAD(, kse_upcall) kg_upcalls; /* All upcalls in the group */
#define kg_startzero kg_estcpu
u_int kg_estcpu; /* Sum of the same field in KSEs. */
u_int kg_slptime; /* (j) How long completely blocked. */
struct thread *kg_last_assigned; /* Last thread assigned to a KSE */
int kg_runnable; /* Num runnable threads on queue. */
int kg_runq_kses; /* Num KSEs on runq. */
int kg_loan_kses; /* Num KSEs on loan queue. */
struct thread *kg_last_assigned; /* (j) Last thread assigned to a KSE */
int kg_runnable; /* (j) Num runnable threads on queue. */
int kg_runq_kses; /* (j) Num KSEs on runq. */
int kg_idle_kses; /* (j) Num KSEs on iq */
int kg_numupcalls; /* (j) Num upcalls */
int kg_upsleeps; /* (c) Num threads in kse_release() */
struct kse_thr_mailbox *kg_completed; /* (c) completed thread mboxes */
#define kg_endzero kg_pri_class
@ -518,8 +502,8 @@ struct ksegrp {
u_char kg_user_pri; /* (j) User pri from estcpu and nice. */
char kg_nice; /* (j?/k?) Process "nice" value. */
#define kg_endcopy kg_numthreads
int kg_numthreads; /* Num threads in total */
int kg_kses; /* Num KSEs in group. */
int kg_numthreads; /* (j) Num threads in total */
int kg_kses; /* (j) Num KSEs in group. */
struct kg_sched *kg_sched; /* Scheduler specific data */
};
@ -569,12 +553,19 @@ struct proc {
u_int p_swtime; /* (j) Time swapped in or out. */
struct itimerval p_realtimer; /* (h?/k?) Alarm timer. */
struct bintime p_runtime; /* (j) Real time. */
u_int64_t p_uu; /* (j) Previous user time in usec. */
u_int64_t p_su; /* (j) Previous system time in usec. */
u_int64_t p_iu; /* (j) Previous intr time in usec. */
u_int64_t p_uticks; /* (j) Statclock hits in user mode. */
u_int64_t p_sticks; /* (j) Statclock hits in system mode. */
u_int64_t p_iticks; /* (j) Statclock hits in intr. */
int p_profthreads; /* (c) Num threads in addupc_task */
int p_traceflag; /* (o) Kernel trace points. */
struct vnode *p_tracep; /* (c + o) Trace to vnode. */
sigset_t p_siglist; /* (c) Sigs arrived, not delivered. */
struct vnode *p_textvp; /* (b) Vnode of executable. */
char p_lock; /* (c) Proclock (prevent swap) count. */
struct klist p_klist; /* (c) Knotes attached to this proc. */
struct klist p_klist; /* (c) Knotes attached to this proc. */
struct sigiolst p_sigiolst; /* (c) List of sigio sources. */
int p_sigparent; /* (c) Signal to parent on exit. */
sigset_t p_oldsigmask; /* (c) Saved mask from pre sigpause. */
@ -669,6 +660,7 @@ struct proc {
#define PS_INMEM 0x00001 /* Loaded into memory. */
#define PS_XCPU 0x00002 /* Exceeded CPU limit. */
#define PS_PROFIL 0x00004 /* Has started profiling. */
#define PS_STOPPROF 0x00008 /* Has thread in requesting to stop prof */
#define PS_ALRMPEND 0x00020 /* Pending SIGVTALRM needs to be posted. */
#define PS_PROFPEND 0x00040 /* Pending SIGPROF needs to be posted. */
#define PS_SWAPINREQ 0x00100 /* Swapin request due to wakeup. */
@ -706,6 +698,8 @@ MALLOC_DECLARE(M_ZOMBIE);
TAILQ_FOREACH((td), &(kg)->kg_threads, td_kglist)
#define FOREACH_KSE_IN_GROUP(kg, ke) \
TAILQ_FOREACH((ke), &(kg)->kg_kseq, ke_kglist)
#define FOREACH_UPCALL_IN_GROUP(kg, ku) \
TAILQ_FOREACH((ku), &(kg)->kg_upcalls, ku_link)
#define FOREACH_THREAD_IN_PROC(p, td) \
TAILQ_FOREACH((td), &(p)->p_threads, td_plist)
@ -920,7 +914,7 @@ struct kse *kse_alloc(void);
void kse_free(struct kse *ke);
void kse_stash(struct kse *ke);
void cpu_set_upcall(struct thread *td, void *pcb);
void cpu_set_upcall_kse(struct thread *td, struct kse *ke);
void cpu_set_upcall_kse(struct thread *td, struct kse_upcall *ku);
void cpu_thread_clean(struct thread *);
void cpu_thread_exit(struct thread *);
void cpu_thread_setup(struct thread *td);
@ -929,7 +923,6 @@ void kse_link(struct kse *ke, struct ksegrp *kg);
void kse_unlink(struct kse *ke);
void ksegrp_link(struct ksegrp *kg, struct proc *p);
void ksegrp_unlink(struct ksegrp *kg);
void make_kse_runnable(struct kse *ke);
struct thread *signal_upcall(struct proc *p, int sig);
struct thread *thread_alloc(void);
void thread_exit(void) __dead2;
@ -938,7 +931,7 @@ void thread_free(struct thread *td);
void thread_getcontext(struct thread *td, ucontext_t *uc);
void thread_link(struct thread *td, struct ksegrp *kg);
void thread_reap(void);
struct thread *thread_schedule_upcall(struct thread *td, struct kse *ke);
struct thread *thread_schedule_upcall(struct thread *td, struct kse_upcall *ku);
int thread_setcontext(struct thread *td, ucontext_t *uc);
int thread_single(int how);
#define SINGLE_NO_EXIT 0 /* values for 'how' */
@ -952,8 +945,13 @@ void thread_unsuspend_one(struct thread *td);
int thread_userret(struct thread *td, struct trapframe *frame);
void thread_user_enter(struct proc *p, struct thread *td);
void thread_wait(struct proc *p);
int thread_add_ticks_intr(int user, uint ticks);
int thread_statclock(int user);
struct kse_upcall *upcall_alloc(void);
void upcall_free(struct kse_upcall *ku);
void upcall_link(struct kse_upcall *ku, struct ksegrp *kg);
void upcall_unlink(struct kse_upcall *ku);
void upcall_remove(struct thread *td);
void upcall_stash(struct kse_upcall *ke);
void thread_sanity_check(struct thread *td, char *);
#endif /* _KERNEL */

View File

@ -62,8 +62,6 @@ struct pstats {
u_long pr_size; /* buffer size */
u_long pr_off; /* pc offset */
u_long pr_scale; /* pc scaling */
u_long pr_addr; /* temp storage for addr until AST */
u_int pr_ticks; /* temp storage for ticks until AST */
} p_prof;
#define pstat_endcopy p_start
struct timeval p_start; /* starting time */
@ -105,8 +103,8 @@ struct thread;
struct kse;
struct proc;
void addupc_intr(struct kse *ke, uintptr_t pc, u_int ticks);
void addupc_task(struct kse *ke, uintptr_t pc, u_int ticks);
void addupc_intr(struct thread *td, uintptr_t pc, u_int ticks);
void addupc_task(struct thread *td, uintptr_t pc, u_int ticks);
void calcru(struct proc *p, struct timeval *up, struct timeval *sp,
struct timeval *ip);
int chgproccnt(struct uidinfo *uip, int diff, int max);

View File

@ -202,7 +202,7 @@ void hardclock(struct clockframe *frame);
void hardclock_process(struct thread *td, int user);
void softclock(void *);
void statclock(struct clockframe *frame);
void statclock_process(struct kse *ke, register_t pc, int user);
void statclock_process(struct thread *td, register_t pc, int user);
void startprofclock(struct proc *);
void stopprofclock(struct proc *);