summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_thread.c
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2002-09-03 12:56:01 +0000
committerdavidxu <davidxu@FreeBSD.org>2002-09-03 12:56:01 +0000
commitde678b0952b815e5f9fbd2960bc2f410a7c36dad (patch)
tree1ce482e3c0180b8dcabc22f76c3684380ea90f32 /sys/kern/kern_thread.c
parentb88e0c1555e8f2f9f2dc75b59374dcd60b1576a2 (diff)
downloadFreeBSD-src-de678b0952b815e5f9fbd2960bc2f410a7c36dad.zip
FreeBSD-src-de678b0952b815e5f9fbd2960bc2f410a7c36dad.tar.gz
In the kernel code, we have the tsleep() call with the PCATCH argument.
PCATCH means 'if we get a signal, interrupt me!" and tsleep returns either EINTR or ERESTART depending on the circumstances. ERESTART is "special" because it causes the system call to fail, but right as it returns back to userland it tells the trap handler to move %eip back a bit so that userland will immediately re-run the syscall. This is a syscall restart. It only works for things like read() etc where nothing has changed yet. Note that *userland* is tricked into restarting the syscall by the kernel. The kernel doesn't actually do the restart. It is deadly for things like select, poll, nanosleep etc where it might cause the elapsed time to be reset and start again from scratch. So those syscalls do this to prevent userland rerunning the syscall: if (error == ERESTART) error = EINTR; Fake "signals" like SIGTSTP from ^Z etc do not normally invoke userland signal handlers. But, in -current, the PCATCH *is* being triggered and tsleep is returning ERESTART, and the syscall is aborted even though no userland signal handler was run. That is the fault here. We're triggering the PCATCH in cases that we shouldn't. ie: it is being triggered on *any* signal processing, rather than the case where the signal is posted to userland. --- Peter The work of psignal() is a patchwork of special case required by the process debugging and job-control facilities... --- Kirk McKusick "The design and impelementation of the 4.4BSD Operating system" Page 105 in STABLE source, when psignal is posting a STOP signal to sleeping process and the signal action of the process is SIG_DFL, system will directly change the process state from SSLEEP to SSTOP, and when SIGCONT is posted to the stopped process, if it finds that the process is still on sleep queue, the process state will be restored to SSLEEP, and won't wakeup the process. this commit mimics the behaviour in STABLE source tree. Reviewed by: Jon Mini, Tim Robbins, Peter Wemm Approved by: julian@freebsd.org (mentor)
Diffstat (limited to 'sys/kern/kern_thread.c')
-rw-r--r--sys/kern/kern_thread.c38
1 files changed, 32 insertions, 6 deletions
diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c
index fd4f0b3..ce2b125 100644
--- a/sys/kern/kern_thread.c
+++ b/sys/kern/kern_thread.c
@@ -761,6 +761,36 @@ thread_suspend_check(int return_instead)
return (0);
}
+void
+thread_suspend_one(struct thread *td)
+{
+ struct proc *p = td->td_proc;
+
+ mtx_assert(&sched_lock, MA_OWNED);
+ p->p_suspcount++;
+ td->td_state = TDS_SUSPENDED;
+ TAILQ_INSERT_TAIL(&p->p_suspended, td, td_runq);
+}
+
+void
+thread_unsuspend_one(struct thread *td)
+{
+ struct proc *p = td->td_proc;
+
+ mtx_assert(&sched_lock, MA_OWNED);
+ TAILQ_REMOVE(&p->p_suspended, td, td_runq);
+ p->p_suspcount--;
+ if (td->td_wchan != NULL) {
+ td->td_state = TDS_SLP;
+ } else {
+ if (td->td_ksegrp->kg_slptime > 1) {
+ updatepri(td->td_ksegrp);
+ td->td_ksegrp->kg_slptime = 0;
+ }
+ setrunqueue(td);
+ }
+}
+
/*
* Allow all threads blocked by single threading to continue running.
*/
@@ -773,9 +803,7 @@ thread_unsuspend(struct proc *p)
PROC_LOCK_ASSERT(p, MA_OWNED);
if (!P_SHOULDSTOP(p)) {
while (( td = TAILQ_FIRST(&p->p_suspended))) {
- TAILQ_REMOVE(&p->p_suspended, td, td_runq);
- p->p_suspcount--;
- setrunqueue(td);
+ thread_unsuspend_one(td);
}
} else if ((P_SHOULDSTOP(p) == P_STOPPED_SNGL) &&
(p->p_numthreads == p->p_suspcount)) {
@@ -784,9 +812,7 @@ thread_unsuspend(struct proc *p)
* threading request. Now we've downgraded to single-threaded,
* let it continue.
*/
- TAILQ_REMOVE(&p->p_suspended, p->p_singlethread, td_runq);
- p->p_suspcount--;
- setrunqueue(p->p_singlethread);
+ thread_unsuspend_one(p->p_singlethread);
}
}
OpenPOWER on IntegriCloud