On Mon, 3 Mar 2025 14:01:08 +0100
Corinna Vinschen wrote:
> On Mar  3 21:24, Takashi Yano wrote:
> > On Mon, 3 Mar 2025 10:51:30 +0100
> > Corinna Vinschen wrote:
> > > On Mar  1 08:33, Takashi Yano wrote:
> > > > The PID_STOPPED flag in _ponfo::process_state is sometimes accidentally
> > > > cleared due to a race condition when modifying it with the "|=" or "&="
> > > > operators. This patch uses InterlockedOr/And() instead to avoid the
> > > > race condition.
> > > 
> > > Is this really sufficent?  I'm asking because of...
> > > 
> > > > @@ -678,8 +678,9 @@ dofork (void **proc, bool *with_forkables)
> > > >  
> > > >    if (ischild)
> > > >      {
> > > > -      myself->process_state |= PID_ACTIVE;
> > > > -      myself->process_state &= ~(PID_INITIALIZING | PID_EXITED | 
> > > > PID_REAPED);
> > > > +      InterlockedOr ((LONG *) &myself->process_state, PID_ACTIVE);
> > > > +      InterlockedAnd ((LONG *) &myself->process_state,
> > > > +                     ~(PID_INITIALIZING | PID_EXITED | PID_REAPED));
> > > >      }
> > > >    else if (res < 0)
> > > >      {
> > > 
> > > ...places like these.  Every single Interlocked call is safe in itself,
> > > but what if somebody else changes something between the two interlocked
> > > calls?  Maybe this should be done with InterlockedCompareExchange.
> > 
> > Thanks for reviewing.
> > 
> > How can we guard that situation by using InterlockedCompareExchange()?
> > Could you please give me some more instruction?
> 
> The InterlockedCompareExchange can be used to check for a parallel
> change, kind of like this:
> 
>   DWORD old_state, new_state;
>   do
>     {
>       old_state = myself->process_state;
>       new_state = old_state | PID_ACTIVE;
>       new_state &= ~(PID_INITIALIZING | PID_EXITED | PID_REAPED);
>     }
>   while (InterlockedCompareExchange (&myself->process_state,
>                                      new_state,
>                                      old_state) != old_state);

Thanks!

> but now that I'm writing it I'm even more unsure this is necessary.
> The only two places doing an And and an Or are doing it with the
> exact same flags.  And the combination of PID_ACTIVE and the other
> three flags is never tested together.
> 
> What do you think?

No other code touches these flags except for:

diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
index 1ffe00a94..8739f18f5 100644
--- a/winsup/cygwin/sigproc.cc
+++ b/winsup/cygwin/sigproc.cc
@@ -252,7 +252,7 @@ proc_subproc (DWORD what, uintptr_t val)
          vchild->sid = myself->sid;
          vchild->ctty = myself->ctty;
          vchild->cygstarted = true;
-         vchild->process_state |= PID_INITIALIZING;
+         InterlockedOr ((LONG *)&vchild->process_state, PID_INITIALIZING);
          vchild->ppid = myself->pid;   /* always set last */
        }
       break;

Moreover, using InterlockedOr()/InterlockedAnd() can ensure that
the other flags than the current code is modifying will be kept
during modification. So using InterlockedCompareExchange() might
be over the top.

> Either way, I would add a volatile to _pinfo::process_state.

Thanks. I will.

-- 
Takashi Yano <takashi.y...@nifty.ne.jp>

Reply via email to