1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-15 10:17:20 +00:00

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)
This commit is contained in:
David Xu 2002-09-03 12:56:01 +00:00
parent b4dde36292
commit 35c32a76f9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=102898
4 changed files with 93 additions and 13 deletions

View File

@ -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);
}
}

View File

@ -1434,13 +1434,39 @@ psignal(p, sig)
SIGDELSET(p->p_siglist, sig);
goto out;
}
if (prop & SA_STOP) {
if ((p->p_flag & P_TRACED) || (action != SIG_DFL) ||
!(prop & SA_STOP)) {
mtx_lock_spin(&sched_lock);
FOREACH_THREAD_IN_PROC(p, td)
tdsignal(td, sig, action);
mtx_unlock_spin(&sched_lock);
goto out;
}
if (prop & SA_STOP) {
if (p->p_flag & P_PPWAIT)
goto out;
mtx_lock_spin(&sched_lock);
FOREACH_THREAD_IN_PROC(p, td) {
if (td->td_state == TDS_SLP &&
(td->td_flags & TDF_SINTR))
thread_suspend_one(td);
}
if (p->p_suspcount == p->p_numthreads) {
mtx_unlock_spin(&sched_lock);
stop(p);
p->p_xstat = sig;
SIGDELSET(p->p_siglist, sig);
PROC_LOCK(p->p_pptr);
if ((p->p_pptr->p_procsig->ps_flag &
PS_NOCLDSTOP) == 0) {
psignal(p->p_pptr, SIGCHLD);
}
PROC_UNLOCK(p->p_pptr);
} else {
mtx_unlock_spin(&sched_lock);
}
goto out;
}
else
goto runfast;
/* NOTREACHED */

View File

@ -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);
}
}

View File

@ -868,6 +868,8 @@ void thread_single_end(void);
void thread_stash(struct thread *td);
int thread_suspend_check(int how);
void thread_unsuspend(struct proc *p);
void thread_suspend_one(struct thread *td);
void thread_unsuspend_one(struct thread *td);
int thread_userret(struct proc *p, struct ksegrp *kg, struct kse *ke,
struct thread *td, struct trapframe *frame);