Page MenuHomeFreeBSD

D35310.id106748.diff
No OneTemporary

D35310.id106748.diff

diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -307,8 +307,17 @@
p = td->td_proc;
if ((p->p_flag & P_HADTHREADS) != 0) {
PROC_LOCK(p);
+ while (p->p_singlethr > 0) {
+ error = msleep(&p->p_singlethr, &p->p_mtx,
+ PWAIT | PCATCH, "exec1t", 0);
+ if (error != 0) {
+ error = ERESTART;
+ goto unlock;
+ }
+ }
if (thread_single(p, SINGLE_BOUNDARY) != 0)
error = ERESTART;
+unlock:
PROC_UNLOCK(p);
}
KASSERT(error != 0 || (td->td_pflags & TDP_EXECVMSPC) == 0,
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -213,6 +213,15 @@
__unreachable();
}
+void
+proc_set_p2_wexit(struct proc *p)
+{
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ p->p_flag2 |= P2_WEXIT;
+ while (p->p_singlethr > 0)
+ msleep(&p->p_singlethr, &p->p_mtx, PWAIT | PCATCH, "exit1t", 0);
+}
+
/*
* Exit: deallocate address space and other resources, change proc state to
* zombie, and unlink proc from allproc and parent's lists. Save exit status
@@ -251,6 +260,8 @@
* MUST abort all other threads before proceeding past here.
*/
PROC_LOCK(p);
+ proc_set_p2_wexit(p);
+
/*
* First check if some other thread or external request got
* here before us. If so, act appropriately: exit or suspend.
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -3399,10 +3399,10 @@
static struct sx stop_all_proc_blocker;
SX_SYSINIT(stop_all_proc_blocker, &stop_all_proc_blocker, "sapblk");
-void
+bool
stop_all_proc_block(void)
{
- sx_xlock(&stop_all_proc_blocker);
+ return (sx_xlock_sig(&stop_all_proc_blocker) == 0);
}
void
@@ -3426,7 +3426,8 @@
int r, gen;
bool restart, seen_stopped, seen_exiting, stopped_some;
- stop_all_proc_block();
+ if (!stop_all_proc_block())
+ return;
cp = curproc;
allproc_loop:
@@ -3446,7 +3447,7 @@
PROC_UNLOCK(p);
continue;
}
- if ((p->p_flag & P_WEXIT) != 0) {
+ if ((p->p_flag2 & P2_WEXIT) != 0) {
seen_exiting = true;
PROC_UNLOCK(p);
continue;
diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c
--- a/sys/kern/kern_procctl.c
+++ b/sys/kern/kern_procctl.c
@@ -254,7 +254,7 @@
PROC_LOCK(p);
}
-static bool
+static void
reap_kill_proc_locked(struct thread *td, struct proc *p2,
ksiginfo_t *ksi, struct procctl_reaper_kill *rk, int *error)
{
@@ -270,7 +270,7 @@
rk->rk_fpid = p2->p_pid;
*error = error1;
}
- return (true);
+ return;
}
/*
@@ -291,47 +291,38 @@
* race.
*/
need_stop = p2 != td->td_proc &&
- (p2->p_flag & (P_KPROC | P_SYSTEM)) == 0 &&
+ (td->td_proc->p_flag2 & P2_WEXIT) == 0 &&
+ (p2->p_flag & (P_KPROC | P_SYSTEM | P_STOPPED)) == 0 &&
(rk->rk_flags & REAPER_KILL_CHILDREN) == 0;
if (need_stop) {
- if (P_SHOULDSTOP(p2) == P_STOPPED_SINGLE)
- return (false); /* retry later */
xlocked = sx_xlocked(&proctree_lock);
sx_unlock(&proctree_lock);
r = thread_single(p2, SINGLE_ALLPROC);
- if (r != 0) {
- reap_kill_proc_relock(p2, xlocked);
- return (false);
- }
+ reap_kill_proc_relock(p2, xlocked);
+ if (r != 0)
+ need_stop = false;
}
pksignal(p2, rk->rk_sig, ksi);
rk->rk_killed++;
*error = error1;
- if (need_stop) {
- reap_kill_proc_relock(p2, xlocked);
+ if (need_stop)
thread_single_end(p2, SINGLE_ALLPROC);
- }
- return (true);
}
-static bool
+static void
reap_kill_proc(struct thread *td, struct proc *p2, ksiginfo_t *ksi,
struct procctl_reaper_kill *rk, int *error)
{
- bool res;
-
- res = true;
PROC_LOCK(p2);
- if ((p2->p_flag & P_WEXIT) == 0) {
+ if ((p2->p_flag2 & P2_WEXIT) == 0) {
_PHOLD_LITE(p2);
- res = reap_kill_proc_locked(td, p2, ksi, rk, error);
+ reap_kill_proc_locked(td, p2, ksi, rk, error);
_PRELE(p2);
}
PROC_UNLOCK(p2);
- return (res);
}
struct reap_kill_tracker {
@@ -346,11 +337,25 @@
{
struct reap_kill_tracker *t;
+ PROC_LOCK(p2);
+ if ((p2->p_flag2 & P2_WEXIT) != 0) {
+ PROC_UNLOCK(p2);
+ return;
+ }
+ _PHOLD_LITE(p2);
+ PROC_UNLOCK(p2);
t = malloc(sizeof(struct reap_kill_tracker), M_TEMP, M_WAITOK);
t->parent = p2;
TAILQ_INSERT_TAIL(tracker, t, link);
}
+static void
+reap_kill_sched_free(struct reap_kill_tracker *t)
+{
+ PRELE(t->parent);
+ free(t, M_TEMP);
+}
+
static void
reap_kill_children(struct thread *td, struct proc *reaper,
struct procctl_reaper_kill *rk, ksiginfo_t *ksi, int *error)
@@ -380,8 +385,20 @@
TAILQ_INIT(&tracker);
reap_kill_sched(&tracker, reaper);
while ((t = TAILQ_FIRST(&tracker)) != NULL) {
- MPASS((t->parent->p_treeflag & P_TREE_REAPER) != 0);
TAILQ_REMOVE(&tracker, t, link);
+
+ /*
+ * Since reap_kill_proc() drops proctree_lock sx, it
+ * is possible that the tracked reaper is no longer.
+ * In this case the subtree is reparented to the new
+ * reaper, which should handle it.
+ */
+ if ((t->parent->p_treeflag & P_TREE_REAPER) == 0) {
+ reap_kill_sched_free(t);
+ res = true;
+ continue;
+ }
+
LIST_FOREACH(p2, &t->parent->p_reaplist, p_reapsibling) {
if (t->parent == reaper &&
(rk->rk_flags & REAPER_KILL_SUBTREE) != 0 &&
@@ -391,11 +408,10 @@
reap_kill_sched(&tracker, p2);
if (alloc_unr_specific(pids, p2->p_pid) != p2->p_pid)
continue;
- if (!reap_kill_proc(td, p2, ksi, rk, error))
- free_unr(pids, p2->p_pid);
+ reap_kill_proc(td, p2, ksi, rk, error);
res = true;
}
- free(t, M_TEMP);
+ reap_kill_sched_free(t);
}
return (res);
}
@@ -412,8 +428,21 @@
* repeated.
*/
init_unrhdr(&pids, 1, PID_MAX, UNR_NO_MTX);
+ PROC_LOCK(td->td_proc);
+ if ((td->td_proc->p_flag2 & P2_WEXIT) != 0) {
+ PROC_UNLOCK(td->td_proc);
+ goto out;
+ }
+ td->td_proc->p_singlethr++;
+ PROC_UNLOCK(td->td_proc);
while (reap_kill_subtree_once(td, p, reaper, rk, ksi, error, &pids))
;
+ PROC_LOCK(td->td_proc);
+ td->td_proc->p_singlethr--;
+ if (td->td_proc->p_singlethr == 0)
+ wakeup(&p->p_singlethr);
+ PROC_UNLOCK(td->td_proc);
+out:
clean_unrhdr(&pids);
clear_unrhdr(&pids);
}
@@ -1050,8 +1079,8 @@
sapblk = false;
if (cmd_info->sapblk != NULL) {
sapblk = cmd_info->sapblk(td, data);
- if (sapblk)
- stop_all_proc_block();
+ if (sapblk && !stop_all_proc_block())
+ return (ERESTART);
}
switch (cmd_info->lock_tree) {
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -2928,7 +2928,7 @@
/*
* We should allow pending but ignored signals below
- * only if there is sigwait() active, or P_TRACED was
+ * if there is sigwait() active, or P_TRACED was
* on when they were posted.
*/
if (SIGISMEMBER(ps->ps_sigignore, sig) &&
@@ -2937,6 +2937,16 @@
return (SIGSTATUS_IGNORE);
}
+ /*
+ * If the process is going to single-thread mode to prepare
+ * for exit, there is no sense in delivering any signal
+ * to usermode. Another important consequence is that
+ * msleep(..., PCATCH, ...) now is only interruptible by a
+ * suspend request.
+ */
+ if ((p->p_flag2 & P2_WEXIT) != 0)
+ return (SIGSTATUS_IGNORE);
+
if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED) {
/*
* If traced, always stop.
@@ -3406,6 +3416,8 @@
struct proc *p = td->td_proc;
PROC_LOCK_ASSERT(p, MA_OWNED);
+ proc_set_p2_wexit(p);
+
p->p_acflag |= AXSIG;
/*
* We must be single-threading to generate a core dump. This
diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c
--- a/sys/kern/kern_thread.c
+++ b/sys/kern/kern_thread.c
@@ -99,7 +99,7 @@
"struct proc KBI p_pid");
_Static_assert(offsetof(struct proc, p_filemon) == 0x3c8,
"struct proc KBI p_filemon");
-_Static_assert(offsetof(struct proc, p_comm) == 0x3e0,
+_Static_assert(offsetof(struct proc, p_comm) == 0x3e4,
"struct proc KBI p_comm");
_Static_assert(offsetof(struct proc, p_emuldata) == 0x4c8,
"struct proc KBI p_emuldata");
@@ -1144,24 +1144,20 @@
* ALLPROC suspend tries to avoid spurious EINTR for
* threads sleeping interruptable, by suspending the
* thread directly, similarly to sig_suspend_threads().
- * Since such sleep is not performed at the user
- * boundary, TDF_BOUNDARY flag is not set, and TDF_ALLPROCSUSP
- * is used to avoid immediate un-suspend.
+ * Since such sleep is not neccessary performed at the user
+ * boundary, TDF_ALLPROCSUSP is used to avoid immediate
+ * un-suspend.
*/
- if (TD_IS_SUSPENDED(td2) && (td2->td_flags & (TDF_BOUNDARY |
- TDF_ALLPROCSUSP)) == 0) {
+ if (TD_IS_SUSPENDED(td2) && (td2->td_flags &
+ TDF_ALLPROCSUSP) == 0) {
wakeup_swapper |= thread_unsuspend_one(td2, p, false);
thread_lock(td2);
goto restart;
}
if (TD_CAN_ABORT(td2)) {
- if ((td2->td_flags & TDF_SBDRY) == 0) {
- thread_suspend_one(td2);
- td2->td_flags |= TDF_ALLPROCSUSP;
- } else {
- wakeup_swapper |= sleepq_abort(td2, ERESTART);
- return (wakeup_swapper);
- }
+ td2->td_flags |= TDF_ALLPROCSUSP;
+ wakeup_swapper |= sleepq_abort(td2, ERESTART);
+ return (wakeup_swapper);
}
break;
default:
@@ -1207,10 +1203,18 @@
mtx_assert(&Giant, MA_NOTOWNED);
PROC_LOCK_ASSERT(p, MA_OWNED);
- if ((p->p_flag & P_HADTHREADS) == 0 && mode != SINGLE_ALLPROC)
+ /*
+ * Is someone already single threading?
+ * Or may be singlethreading is not needed at all.
+ */
+ if (mode == SINGLE_ALLPROC) {
+ while ((p->p_flag & P_STOPPED_SINGLE) != 0) {
+ if ((p->p_flag2 & P2_WEXIT) != 0)
+ return (1);
+ msleep(&p->p_flag, &p->p_mtx, PCATCH, "thrsgl", 0);
+ }
+ } else if ((p->p_flag & P_HADTHREADS) == 0)
return (0);
-
- /* Is someone already single threading? */
if (p->p_singlethread != NULL && p->p_singlethread != td)
return (1);
@@ -1224,8 +1228,12 @@
else
p->p_flag &= ~P_SINGLE_BOUNDARY;
}
- if (mode == SINGLE_ALLPROC)
+ if (mode == SINGLE_ALLPROC) {
p->p_flag |= P_TOTAL_STOP;
+ thread_lock(td);
+ td->td_flags |= TDF_DOING_SA;
+ thread_unlock(td);
+ }
p->p_flag |= P_STOPPED_SINGLE;
PROC_SLOCK(p);
p->p_singlethread = td;
@@ -1242,7 +1250,7 @@
if (TD_IS_INHIBITED(td2)) {
wakeup_swapper |= weed_inhib(mode, td2, p);
#ifdef SMP
- } else if (TD_IS_RUNNING(td2) && td != td2) {
+ } else if (TD_IS_RUNNING(td2)) {
forward_signal(td2);
thread_unlock(td2);
#endif
@@ -1312,6 +1320,11 @@
}
}
PROC_SUNLOCK(p);
+ if (mode == SINGLE_ALLPROC) {
+ thread_lock(td);
+ td->td_flags &= ~TDF_DOING_SA;
+ thread_unlock(td);
+ }
return (0);
}
@@ -1598,7 +1611,8 @@
if (!P_SHOULDSTOP(p)) {
FOREACH_THREAD_IN_PROC(p, td) {
thread_lock(td);
- if (TD_IS_SUSPENDED(td)) {
+ if (TD_IS_SUSPENDED(td) && (td->td_flags &
+ TDF_DOING_SA) == 0) {
wakeup_swapper |= thread_unsuspend_one(td, p,
true);
} else
@@ -1669,6 +1683,7 @@
PROC_SUNLOCK(p);
if (wakeup_swapper)
kick_proc0();
+ wakeup(&p->p_flag);
}
/*
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -468,7 +468,7 @@
#define TDF_THRWAKEUP 0x00100000 /* Libthr thread must not suspend itself. */
#define TDF_SEINTR 0x00200000 /* EINTR on stop attempts. */
#define TDF_SWAPINREQ 0x00400000 /* Swapin request due to wakeup. */
-#define TDF_UNUSED23 0x00800000 /* --available-- */
+#define TDF_DOING_SA 0x00800000 /* Doing SINGLE_ALLPROC, do not unsuspend me */
#define TDF_SCHED0 0x01000000 /* Reserved for scheduler private use */
#define TDF_SCHED1 0x02000000 /* Reserved for scheduler private use */
#define TDF_SCHED2 0x04000000 /* Reserved for scheduler private use */
@@ -691,6 +691,8 @@
int p_pendingexits; /* (c) Count of pending thread exits. */
struct filemon *p_filemon; /* (c) filemon-specific data. */
int p_pdeathsig; /* (c) Signal from parent on exit. */
+ int p_singlethr; /* (c) Count of threads doing
+ external thread_single() */
/* End area that is zeroed on creation. */
#define p_endzero p_magic
@@ -847,6 +849,9 @@
#define P2_NO_NEW_PRIVS 0x00008000 /* Ignore setuid */
#define P2_WXORX_DISABLE 0x00010000 /* WX mappings enabled */
#define P2_WXORX_ENABLE_EXEC 0x00020000 /* WXORX enabled after exec */
+#define P2_WEXIT 0x00040000 /* exit just started, no
+ external thread_single() is
+ permitted */
/* Flags protected by proctree_lock, kept in p_treeflags. */
#define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */
@@ -1155,6 +1160,7 @@
struct proc *proc_realparent(struct proc *child);
void proc_reap(struct thread *td, struct proc *p, int *status, int options);
void proc_reparent(struct proc *child, struct proc *newparent, bool set_oppid);
+void proc_set_p2_wexit(struct proc *p);
void proc_set_traced(struct proc *p, bool stop);
void proc_wkilled(struct proc *p);
struct pstats *pstats_alloc(void);
@@ -1232,7 +1238,7 @@
void thread_unsuspend(struct proc *p);
void thread_wait(struct proc *p);
-void stop_all_proc_block(void);
+bool stop_all_proc_block(void);
void stop_all_proc_unblock(void);
void stop_all_proc(void);
void resume_all_proc(void);

File Metadata

Mime Type
text/plain
Expires
Wed, Jul 22, 12:57 PM (15 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35364810
Default Alt Text
D35310.id106748.diff (12 KB)

Event Timeline