From: Paul E. McKenney on
On Thu, Jun 24, 2010 at 02:14:46PM -0700, Roland McGrath wrote:
> > First, what "bad things" can happen to a reader scanning a thread
> > group?
> >
> > 1. The thread-group leader might do exec(), destroying the old
> > list and forming a new one. In this case, we want any readers
> > to stop scanning.
>
> This doesn't do anything different (for these concerns) from just all the
> other threads happening to exit right before the exec. There is no
> "destroying the old" and "forming the new", it's just that all the other
> threads are convinced to die now. There is no problem here.

Understood -- I wasn't saying that each category posed a unique problem,
but rather making sure that I really had enumerated all the possibilities.
The reason for my "destroying the old" and "forming the new" is the
possibility of someone doing proc_task_readdir() when the group leader
does exec(), which causes all to die, and then the new process does
pthread_create(), forming a new thread group. Because proc_task_readdir()
neither holds a lock nor stays in an RCU read-side critical section
for the full /proc scan, the old group might really be destroyed from
the reader's point of view.

That said, I freely admit that I am not very familiar with this code.

> > 2. Some other thread might do exec(), destroying the old list and
> > forming a new one. In this case, we also want any readers to
> > stop scanning.
>
> Again, the list is not really destroyed, just everybody dies. What is
> different here is that ->group_leader changes. This is the only time
> that ever happens. Moreover, it's the only time that a task that was
> previously pointed to by any ->group_leader can be reaped before the
> rest of the group has already been reaped first (and thus the
> thread_group made a singleton).

Yep! Same proc_task_readdir() situation as before. The group leader
cannot go away because proc_task_readdir() takes a reference.

> > 3. The thread-group leader might do pthread_exit(), removing itself
> > from the thread group -- and might do so while the hapless reader
> > is referencing that thread.
>
> This is called the delay_group_leader() case. It doesn't happen in a
> way that has the problems you are concerned with. The group_leader
> remains in EXIT_ZOMBIE state and can't be reaped until all the other
> threads have been reaped. There is no time at which any thread in the
> group is in any hashes or accessible by any means after the (final)
> group_leader is reaped.

OK, good to know -- that does make things simpler.

> > 4. Some other thread might do pthread_exit(), removing itself
> > from the thread group, and again might do so while the hapless
> > reader is referencing that thread. In this case, we want
> > the hapless reader to continue scanning the remainder of the
> > thread group.
>
> This is the most normal case (and #1 is effectively just this repeated
> by every thread in parallel).

Agreed. One possible difference is that in #1, no one is going to
complain about the reader quitting, while in this case someone might
well be annoyed if the list of threads is incomplete.

> > 5. The thread-group leader might do exit(), destroying the old
> > list without forming a new one. In this case, we want any
> > readers to stop scanning.
>
> All this means is everybody is convinced to die, and the group_leader
> dies too. It is not discernibly different from #6.

Seems reasonable.

> > 6. Some other thread might do exit(), destroying the old list
> > without forming a new one. In this case, we also want any
> > readers to stop scanning.
>
> This just means everybody is convinced to die and is not materially
> different from each individual thread all happening to die at the same
> time.

Fair enough. Again, my goal was to ensure that I had covered all the
cases as opposed to ensuring that I had described them minimally.

> You've described all these cases as "we want any readers to stop
> scanning". That is far too strong, and sounds like some kind of
> guaranteed synchronization, which does not and need not exist. Any
> reader that needs a dead thread to be off the list holds siglock
> and/or tasklist_lock. For the casual readers that only use
> rcu_read_lock, we only "want any readers' loops eventually to
> terminate and never to dereference stale pointers". That's why
> normal RCU listiness is generally fine.

OK, so maybe "it is OK for readers to stop scanning" is a better way
of putting it?

> The only problem we have is in #2. This is only a problem because
> readers' loops may be using the old ->group_leader pointer as the
> anchor for their circular-list round-robin loop. Once the former
> leader is removed from the list, that loop termination condition can
> never be met.

Does Oleg's checking for the group leader still being alive look correct
to you?

Thanx, Paul
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Paul E. McKenney on
On Thu, Jun 24, 2010 at 05:08:10PM -0700, Eric W. Biederman wrote:
> Oleg Nesterov <oleg(a)redhat.com> writes:
>
> > On 06/24, Chris Friesen wrote:
> >>
> >> On 06/24/2010 12:07 PM, Paul E. McKenney wrote:
> >>
> >> > 3. The thread-group leader might do pthread_exit(), removing itself
> >> > from the thread group -- and might do so while the hapless reader
> >> > is referencing that thread.
> >> >
> >> > But isn't this prohibited? Or is it really legal to do a
> >> > pthread_create() to create a new thread and then have the
> >> > parent thread call pthread_exit()? Not something I would
> >> > consider trying in my own code! Well, I might, just to
> >> > be perverse, but... ;-)
> >>
> >> I believe SUS allows the main thread to explicitly call pthread_exit(),
> >> leaving the other threads to run. If the main() routine just returns
> >> then it implicitly calls exit().
> >
> > Correct.
> >
> > But, to clarify, if the main thread does pthread_exit() (sys_exit,
> > actually), it won't be removed from the group. It will be zombie
> > until all other threads exit.
>
> That we don't cleanup that zombie leaders is unfortunate really, it
> means we have the entire de_thread special case. But short fixing
> libpthread to not make bad assumptions there is little we can do about
> it really.

Keeping the zombie leaders does make at least one of the lockless
scan cases quite a bit simpler. I think, anyway.

> I'm only half following this conversation.
>
> If what we are looking for is a stable list_head that won't disappear
> on us we should be able to put one in sighand_struct or signal_struct
> (I forget which is which at the moment) and have a list_head that
> lives for the life of the longest living thread, and that won't get
> messed up by things like de_thread, and then next_thread could simply
> return NULL when we hit the end of the list.

Oleg did suggest this possibility, but there were complications that
I do not claim to fully understand.

Thanx, Paul
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Oleg Nesterov on
On 06/24, Paul E. McKenney wrote:
>
> On Thu, Jun 24, 2010 at 11:57:02PM +0200, Oleg Nesterov wrote:
> > On 06/24, Paul E. McKenney wrote:
> > >
> > > 4. Some other thread might do pthread_exit(), removing itself
> > > from the thread group, and again might do so while the hapless
> > > reader is referencing that thread. In this case, we want
> > > the hapless reader to continue scanning the remainder of the
> > > thread group.
> >
> > Yes.
> >
> > But, if that thread was used as a starting point g, then
> >
> > before the patch: loop forever
> > after the patch: break
>
> So it is OK to skip some of the other threads in this case, even
> though they were present throughout the whole procedure?

I think, yes. We can miss them in any case, they can go away before
while_each_thread(g, t) starts the scan.

If g == group_leader (old or new), then we should notice this thread
at least.

Otherwise we can miss them all, with or without next_thread_careful().

Oleg.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Oleg Nesterov on
On 06/24, Eric W. Biederman wrote:
>
> Oleg Nesterov <oleg(a)redhat.com> writes:
>
> If what we are looking for is a stable list_head that won't disappear
> on us we should be able to put one in sighand_struct or signal_struct
> (I forget which is which at the moment) and have a list_head that
> lives for the life of the longest living thread, and that won't get
> messed up by things like de_thread, and then next_thread could simply
> return NULL when we hit the end of the list.

This was already discussed.

Yes, we can add list_head into signal_struct. But this breaks, say,
thread_group_empty() and the similar code. This is fixeable.

But. We need to convert the code which does while_each_thread(g, t) to
use list_for_each(t, head). And, if g != group_leader this can't work.

Not to mention the increase of sizeof(signal_struct).

Oleg.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Paul E. McKenney on
On Fri, Jun 25, 2010 at 11:55:48AM +0200, Oleg Nesterov wrote:
> On 06/24, Paul E. McKenney wrote:
> >
> > On Thu, Jun 24, 2010 at 11:57:02PM +0200, Oleg Nesterov wrote:
> > > On 06/24, Paul E. McKenney wrote:
> > > >
> > > > 4. Some other thread might do pthread_exit(), removing itself
> > > > from the thread group, and again might do so while the hapless
> > > > reader is referencing that thread. In this case, we want
> > > > the hapless reader to continue scanning the remainder of the
> > > > thread group.
> > >
> > > Yes.
> > >
> > > But, if that thread was used as a starting point g, then
> > >
> > > before the patch: loop forever
> > > after the patch: break
> >
> > So it is OK to skip some of the other threads in this case, even
> > though they were present throughout the whole procedure?
>
> I think, yes. We can miss them in any case, they can go away before
> while_each_thread(g, t) starts the scan.
>
> If g == group_leader (old or new), then we should notice this thread
> at least.
>
> Otherwise we can miss them all, with or without next_thread_careful().

Just to be sure that we are actually talking about the same scenario...

Suppose that a task group is lead by 2908 and has member 2909, 2910,
2911, and 2912. Suppose that 2910 does pthread_exit() just as some
other task is "ls"ing the relevant /proc entry. Is it really OK for
"ls" to show 2909 but not 2911 and 2912, even though 2911 and 2912
were alive and kicking the entire time?

Thanx, Paul
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/