On 08/16, Roland McGrath wrote: > > > - It is possible that both ->death and ->reap are true. In this > > case it is OK to clear UTRACE_EVENT(REAP), but set_events fails. > > No, it's not OK to clear it. Once ->reap is set, then the engine's > ops->report_reap might or might not have been called already.
Afaics - no. If utrace->death is set (and we check it under utrace->lock) we can ignore utrace->reap. In short, if ops->report_reap can be called before ->death is cleared, then 2 possible callers of utrace_maybe_reap() can race with each other, but this can't happen. utrace->death == T means: - (utrace_flags & _UTRACE_DEATH_EVENTS) == T - utrace->death was set by utrace_report_death() which will take utrace->lock later and clear ->death, only then it may call ops->report_reap(). - until utrace_report_death() clears ->death, _UTRACE_DEATH_EVENTS must be set in ->utrace_flags, otherwise utrace_maybe_reap(true) is buggy. Note that both utrace->death and _UTRACE_DEATH_EVENTS are cleared "atomically" from utrace->lock pov. IOW. utrace->death is true, then IF (utrace->reap) tracehook_prepare_releas()->utrace_maybe_reap(true) was already called, this is how utrace->reap was set. But utrace_maybe_reap() did nothing and returned. We rely on the subsequent utrace_maybe_reap(false) from utrace_report_death() - but this can't happen until we drop utrace->lock ELSE utrace->reap can't be set until we drop utrace->lock. Now that you merged c93fecc925ea7567168f0c94414b9021de2708c5 "get_utrace_lock() must not succeed if utrace->reap == T", this becomes a bit off-topic. However, I thought about relaxing the "dead" check in get_utrace_lock(), instead of utrace->reap we could check "utrace->reap && !utrace->death". In fact, initially I was going to do this, but then decided to make the simpler patch for now. Oleg.