On 04/03/21(Thu) 11:45, Mark Kettenis wrote:
> > Date: Thu, 4 Mar 2021 11:19:23 +0100
> > From: Martin Pieuchot <[email protected]>
> >
> > On 04/03/21(Thu) 11:01, Mark Kettenis wrote:
> > > > Date: Thu, 4 Mar 2021 10:54:48 +0100
> > > > From: Patrick Wildt <[email protected]>
> > > >
> > > > Am Thu, Mar 04, 2021 at 10:42:24AM +0100 schrieb Mark Kettenis:
> > > > > > Date: Thu, 4 Mar 2021 10:34:24 +0100
> > > > > > From: Martin Pieuchot <[email protected]>
> > > > > >
> > > > > > Running t/rw/msleep(9) w/o KERNEL_LOCK() implies that a thread can
> > > > > > change the value of `ps_single' while one of its siblings might be
> > > > > > dereferencing it.
> > > > > >
> > > > > > To prevent inconsistencies in the code executed by sibling thread,
> > > > > > the
> > > > > > diff below makes sure `ps_single' is dereferenced only once in
> > > > > > various
> > > > > > parts of the kernel.
> > > > > >
> > > > > > ok?
> > > > >
> > > > > I think that means that ps_single has to be declared "volatile".
> > > >
> > > > Isn't there the READ_ONCE(x) macro, that does exactly that?
> > >
> > > Not a big fan of READ_ONCE() and WRITE_ONCE(), but apparently those
> > > are needed to comply with the alpha memory model. At least in some
> > > cases...
> >
> > Updated diff using READ_ONCE(), ok?
>
> If you use READ_ONCE() you shoul also use WRITE_ONCE() everywhere
> where you modify ps_single isn't it?
I don't know, I'm learning how to do it. I'd appreciate if somebody could
come with a READ_ONCE(9) manual explaining how this API should be used.
Updated diff including the WRITE_ONCE().
Index: kern/kern_exit.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_exit.c,v
retrieving revision 1.196
diff -u -p -r1.196 kern_exit.c
--- kern/kern_exit.c 15 Feb 2021 09:35:59 -0000 1.196
+++ kern/kern_exit.c 5 Mar 2021 10:28:05 -0000
@@ -274,6 +274,8 @@ exit1(struct proc *p, int xexit, int xsi
*/
if (qr->ps_flags & PS_TRACED &&
!(qr->ps_flags & PS_EXITING)) {
+ struct proc *st;
+
process_untrace(qr);
/*
@@ -281,9 +283,9 @@ exit1(struct proc *p, int xexit, int xsi
* direct the signal to the active
* thread to avoid deadlock.
*/
- if (qr->ps_single)
- ptsignal(qr->ps_single, SIGKILL,
- STHREAD);
+ st = READ_ONCE(qr->ps_single);
+ if (st != NULL)
+ ptsignal(st, SIGKILL, STHREAD);
else
prsignal(qr, SIGKILL);
} else {
@@ -510,7 +512,7 @@ dowait4(struct proc *q, pid_t pid, int *
{
int nfound;
struct process *pr;
- struct proc *p;
+ struct proc *p, *st;
int error;
if (pid == 0)
@@ -541,10 +543,11 @@ loop:
proc_finish_wait(q, p);
return (0);
}
+
+ st = READ_ONCE(pr->ps_single);
if (pr->ps_flags & PS_TRACED &&
- (pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
- pr->ps_single->p_stat == SSTOP &&
- (pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
+ (pr->ps_flags & PS_WAITED) == 0 && st != NULL &&
+ st->p_stat == SSTOP && (st->p_flag & P_SUSPSINGLE) == 0) {
if (single_thread_wait(pr, 0))
goto loop;
Index: kern/kern_sig.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sig.c,v
retrieving revision 1.274
diff -u -p -r1.274 kern_sig.c
--- kern/kern_sig.c 4 Mar 2021 09:02:37 -0000 1.274
+++ kern/kern_sig.c 5 Mar 2021 10:28:05 -0000
@@ -2040,7 +2040,7 @@ single_thread_set(struct proc *p, enum s
}
pr->ps_singlecount = 0;
membar_producer();
- pr->ps_single = p;
+ WRITE_ONCE(pr->ps_single, p);
TAILQ_FOREACH(q, &pr->ps_threads, p_thr_link) {
if (q == p)
continue;
@@ -2131,7 +2131,7 @@ single_thread_clear(struct proc *p, int
KERNEL_ASSERT_LOCKED();
SCHED_LOCK(s);
- pr->ps_single = NULL;
+ WRITE_ONCE(pr->ps_single, NULL);
atomic_clearbits_int(&pr->ps_flags, PS_SINGLEUNWIND | PS_SINGLEEXIT);
TAILQ_FOREACH(q, &pr->ps_threads, p_thr_link) {
if (q == p || (q->p_flag & P_SUSPSINGLE) == 0)
Index: kern/sys_process.c
===================================================================
RCS file: /cvs/src/sys/kern/sys_process.c,v
retrieving revision 1.86
diff -u -p -r1.86 sys_process.c
--- kern/sys_process.c 8 Feb 2021 10:51:02 -0000 1.86
+++ kern/sys_process.c 5 Mar 2021 10:28:06 -0000
@@ -273,7 +273,7 @@ sys_ptrace(struct proc *p, void *v, regi
int
ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t addr, int data)
{
- struct proc *t; /* target thread */
+ struct proc *st, *t; /* target thread */
struct process *tr; /* target process */
int error = 0;
int s;
@@ -433,8 +433,9 @@ ptrace_ctrl(struct proc *p, int req, pid
* from where it stopped."
*/
- if (pid < THREAD_PID_OFFSET && tr->ps_single)
- t = tr->ps_single;
+ st = READ_ONCE(tr->ps_single);
+ if (pid < THREAD_PID_OFFSET && st != NULL)
+ t = st;
/* If the address parameter is not (int *)1, set the pc. */
if ((int *)addr != (int *)1)
@@ -464,8 +465,9 @@ ptrace_ctrl(struct proc *p, int req, pid
* from where it stopped."
*/
- if (pid < THREAD_PID_OFFSET && tr->ps_single)
- t = tr->ps_single;
+ st = READ_ONCE(tr->ps_single);
+ if (pid < THREAD_PID_OFFSET && st != NULL)
+ t = st;
#ifdef PT_STEP
/*
@@ -495,8 +497,9 @@ ptrace_ctrl(struct proc *p, int req, pid
break;
case PT_KILL:
- if (pid < THREAD_PID_OFFSET && tr->ps_single)
- t = tr->ps_single;
+ st = READ_ONCE(tr->ps_single);
+ if (pid < THREAD_PID_OFFSET && st != NULL)
+ t = st;
/* just send the process a KILL signal. */
data = SIGKILL;
@@ -536,6 +539,7 @@ int
ptrace_kstate(struct proc *p, int req, pid_t pid, void *addr)
{
struct process *tr; /* target process */
+ struct proc *st;
struct ptrace_event *pe = addr;
int error;
@@ -582,9 +586,9 @@ ptrace_kstate(struct proc *p, int req, p
tr->ps_ptmask = pe->pe_set_event;
break;
case PT_GET_PROCESS_STATE:
- if (tr->ps_single)
- tr->ps_ptstat->pe_tid =
- tr->ps_single->p_tid + THREAD_PID_OFFSET;
+ st = READ_ONCE(tr->ps_single);
+ if (st != NULL)
+ tr->ps_ptstat->pe_tid = st->p_tid + THREAD_PID_OFFSET;
memcpy(addr, tr->ps_ptstat, sizeof *tr->ps_ptstat);
break;
default: