Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F163260378
D35310.id106748.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D35310.id106748.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D35310: Set of fixes for REAP_KILL_SUBTREE
Attached
Detach File
Event Timeline
Log In to Comment