Skip to content

Commit

Permalink
vmspace: add interfaces stop/resume all procs
Browse files Browse the repository at this point in the history
stop_vmspace_proc() and resume_vmspace_proc() respectively stop and
resume all processes but curproc associated with the vmspace of a
given process.  Functionally this the same a (stop|resume)_all_proc()
except that it walks the vmspace process list rather than allproc.

For each process use a new thread_single(SINGLE_VMSPACE) which acts like
SINGLE_BOUNDRY except that like SINGLE_ALLPROC it suspends all threads
in the process and does not expect proc to be curproc.
  • Loading branch information
brooksdavis committed Jul 25, 2024
1 parent 0340fc6 commit fdb9c4b
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 5 deletions.
121 changes: 121 additions & 0 deletions sys/kern/kern_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3953,6 +3953,127 @@ resume_all_proc(void)
stop_all_proc_unblock();
}

/*
* stop_vmspace_proc() stops all proceses which share a vmspace with
* curproc. It should be run after curproc has entered thread_single.
*/
void
stop_vmspace_proc(struct proc* cp)
{
struct proc *p;
struct vmspace *vm;
int r, gen;
bool restart, seen_stopped, seen_exiting, stopped_some;

/*
* XXX-BD: Prevent multiple callers on a vmspace.
* Maybe atomic CAS on a field in vmspace?
*/

vm = cp->p_vmspace;
vmspace_loop:
VMSPACE_LOCK(vm);
/*
* XXX: allproc_gen should work, but should vmspaces have a generation?
*/
gen = allproc_gen;
seen_exiting = seen_stopped = stopped_some = restart = false;
LIST_REMOVE(cp, p_vm_proclist);
LIST_INSERT_HEAD(&vm->vm_proclist, cp, p_vm_proclist);
for (;;) {
p = LIST_NEXT(cp, p_vm_proclist);
if (p == NULL)
break;
LIST_REMOVE(cp, p_vm_proclist);
LIST_INSERT_AFTER(p, cp, p_vm_proclist);
PROC_LOCK(p);
if ((p->p_flag & (P_KPROC | P_SYSTEM | P_TOTAL_STOP)) != 0) {
PROC_UNLOCK(p);
continue;
}
if ((p->p_flag2 & P2_WEXIT) != 0) {
seen_exiting = true;
PROC_UNLOCK(p);
continue;
}
if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) {
/*
* Stopped processes are tolerated when there
* are no other processes which might continue
* them. P_STOPPED_SINGLE but not
* P_TOTAL_STOP process still has at least one
* thread running.
*/
seen_stopped = true;
PROC_UNLOCK(p);
continue;
}
VMSPACE_UNLOCK(vm);
_PHOLD(p);
r = thread_single(p, SINGLE_VMSPACE);
if (r != 0)
restart = true;
else
stopped_some = true;
_PRELE(p);
PROC_UNLOCK(p);
VMSPACE_LOCK(vm);
}
/* Catch forked children we did not see in iteration. */
if (gen != allproc_gen)
restart = true;
VMSPACE_UNLOCK(vm);
if (restart || stopped_some || seen_exiting || seen_stopped) {
kern_yield(PRI_USER);
goto vmspace_loop;
}
}

void
resume_vmspace_proc(struct proc *cp)
{
struct proc *p;
struct vmspace *vm;

vm = cp->p_vmspace;

VMSPACE_LOCK(vm);
again:
LIST_REMOVE(cp, p_vm_proclist);
LIST_INSERT_HEAD(&vm->vm_proclist, cp, p_vm_proclist);
for (;;) {
p = LIST_NEXT(cp, p_vm_proclist);
if (p == NULL)
break;
LIST_REMOVE(cp, p_vm_proclist);
LIST_INSERT_AFTER(p, cp, p_vm_proclist);
PROC_LOCK(p);
if (p->p_vmspace != cp->p_vmspace) {
PROC_UNLOCK(p);
continue;
}
if ((p->p_flag & P_TOTAL_STOP) != 0) {
VMSPACE_UNLOCK(vm);
_PHOLD(p);
thread_single_end(p, SINGLE_VMSPACE);
_PRELE(p);
PROC_UNLOCK(p);
VMSPACE_LOCK(vm);
} else {
PROC_UNLOCK(p);
}
}
/* Did the loop above missed any stopped process ? */
FOREACH_PROC_IN_SYSTEM(p) {
/* No need for proc lock. */
if ((p->p_flag & P_TOTAL_STOP) != 0)
goto again;
}
VMSPACE_UNLOCK(vm);

/* See "XXX-BD: Prevent multiple callers on a vmspace" above */
}

/* #define TOTAL_STOP_DEBUG 1 */
#ifdef TOTAL_STOP_DEBUG
volatile static int ap_resume;
Expand Down
13 changes: 8 additions & 5 deletions sys/kern/kern_thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -1117,7 +1117,7 @@ calc_remaining(struct proc *p, int mode)
PROC_SLOCK_ASSERT(p, MA_OWNED);
if (mode == SINGLE_EXIT)
remaining = p->p_numthreads;
else if (mode == SINGLE_BOUNDARY)
else if (mode == SINGLE_BOUNDARY || mode == SINGLE_VMSPACE)
remaining = p->p_numthreads - p->p_boundary_count;
else if (mode == SINGLE_NO_EXIT || mode == SINGLE_ALLPROC)
remaining = p->p_numthreads - p->p_suspcount;
Expand Down Expand Up @@ -1163,6 +1163,7 @@ weed_inhib(int mode, struct thread *td2, struct proc *p)
break;
case SINGLE_BOUNDARY:
case SINGLE_NO_EXIT:
case SINGLE_VMSPACE:
if (TD_IS_SUSPENDED(td2) &&
(td2->td_flags & TDF_BOUNDARY) == 0) {
wakeup_swapper |= thread_unsuspend_one(td2, p, false);
Expand Down Expand Up @@ -1224,7 +1225,8 @@ thread_single(struct proc *p, int mode)

td = curthread;
KASSERT(mode == SINGLE_EXIT || mode == SINGLE_BOUNDARY ||
mode == SINGLE_ALLPROC || mode == SINGLE_NO_EXIT,
mode == SINGLE_ALLPROC || mode == SINGLE_NO_EXIT ||
mode == SINGLE_VMSPACE,
("invalid mode %d", mode));
/*
* If allowing non-ALLPROC singlethreading for non-curproc
Expand All @@ -1233,7 +1235,8 @@ thread_single(struct proc *p, int mode)
* this is not implemented because it is not used.
*/
KASSERT((mode == SINGLE_ALLPROC && td->td_proc != p) ||
(mode != SINGLE_ALLPROC && td->td_proc == p),
((mode != SINGLE_ALLPROC || mode != SINGLE_VMSPACE) &&
td->td_proc == p),
("mode %d proc %p curproc %p", mode, p, td->td_proc));
mtx_assert(&Giant, MA_NOTOWNED);
PROC_LOCK_ASSERT(p, MA_OWNED);
Expand All @@ -1258,7 +1261,7 @@ thread_single(struct proc *p, int mode)
p->p_flag &= ~P_SINGLE_BOUNDARY;
} else {
p->p_flag &= ~P_SINGLE_EXIT;
if (mode == SINGLE_BOUNDARY)
if (mode == SINGLE_BOUNDARY || mode == SINGLE_VMSPACE)
p->p_flag |= P_SINGLE_BOUNDARY;
else
p->p_flag &= ~P_SINGLE_BOUNDARY;
Expand Down Expand Up @@ -1326,7 +1329,7 @@ thread_single(struct proc *p, int mode)
PROC_LOCK(p);
PROC_SLOCK(p);
}
} else if (mode == SINGLE_BOUNDARY) {
} else if (mode == SINGLE_BOUNDARY || mode == SINGLE_VMSPACE) {
/*
* Wait until all suspended threads are removed from
* the processors. The thread_suspend_check()
Expand Down
3 changes: 3 additions & 0 deletions sys/sys/proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,7 @@ struct proc {
#define SINGLE_EXIT 1
#define SINGLE_BOUNDARY 2
#define SINGLE_ALLPROC 3
#define SINGLE_VMSPACE 4

#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_PARGS);
Expand Down Expand Up @@ -1330,6 +1331,8 @@ bool stop_all_proc_block(void);
void stop_all_proc_unblock(void);
void stop_all_proc(void);
void resume_all_proc(void);
void stop_vmspace_proc(struct proc *cp);
void resume_vmspace_proc(struct proc *cp);

static __inline int
curthread_pflags_set(int flags)
Expand Down

0 comments on commit fdb9c4b

Please sign in to comment.