[c++-pthreads] Re: pthread_cancel and EH: let's try this again
Nathan (Jasper) Myers
ncm at codesourcery.com
Thu Jul 21 06:25:37 UTC 2005
On Wed, Jul 20, 2005 at 07:00:35PM -0700, Mark Mitchell wrote:
> Nathan (Jasper) Myers wrote:
> >On Wed, Jul 20, 2005 at 05:42:57PM -0700, Mark Mitchell wrote:
> >>Nathan (Jasper) Myers wrote:
> >>
> >>>* During the lifetime of object C, the semantics of destructors and
> >>> catch blocks are undefined if the thread is cancelled and a POSIX C
> >>> cancellation point is encountered. Any cleanup ends at the scope
> >>> of object C, and control leaves this scope via an ordinary exception.
> >>>
> >>>* Outside the scope of a cancellation_context, the effect of
> >>> pthread_cleanup_push etc. is undefined.
> >>
> >>It sounds like you're coming up with entirely new thread semantics that
> >>have nothing much to do with POSIX thread cancellation, in that they
> >>seem to leave the POSIX thread cancellation behavior undefined.
> >
> >Within a cancellation context scope, you have bog-standard POSIX C
> >cancellation semantics. Outside it, you have standard C++ semantics.
>
> That wasn't clear to me.
>
> I'd be OK with that -- but most people seem to want POSIX thread
> cancellation to throw an exception in contrast with:
>
> >There is no interaction between POSIX cancellation cleanup and C++
> >exceptions, so no possibility of surprises, and no hard choices.
>
> and GNU/Linux started implementing pthread_cleanup_push as a destructor
> a while back. So, now, there's no way to run pthread cleanups without
> also doing stack unwinding. To do bog-standard POSIX C cancellation
> semantics (i.e., without running destructors) would require changes to
> GLIBC (to put it back the way it used to be), and, of course,
> recompilation of all pthread_cleanup-using binaries.
POSIX doesn't forbid running destructors; it says nothing about them.
The specification above says that if there are any of the users' to
be run, the effect is undefined. Run them, don't run them, crash,
whatever you like. It's easy to conform, because it demands nothing
beyond what J. Random POSIX C does already.
All I propose requiring is that whatever it does, it stop running
cleanup handlers where the cancellation_context object is, and throw.
Conveniently, it also guarantees that in portable code there are no
more cleanup handlers to be run.
So, maybe the cancellation_context registers a cleanup handler that
throws an exception, short-circuiting a cleanup loop; or maybe it
does nothing, because an exception is what has been running those
cleanup handlers, and will now go on to run the users' destructors
and catch clauses. Either way conforms, and you don't have to know
much about your C library to implement either one.
> >Of course testing doesn't tell you whether it has defined behavior.
>
> True -- but that is in fact the behavior that was defined in the last
> iteration of that debate that the behavior shown was what was wanted.
> That behavior isn't an accident.
Wanted by whom? As I recall, the "zero uptake!" crowd meant for no
library (C or C++) to work right unless it had been written with full
expectation of system calls and C library functions throwing exceptions,
even in destructors, even during ordinary-exception unwinding. Falling
out of the catch clause was just one sticky detail.
> >>I think the only reasonable choices are:
> >>
> >>1) Fall off the end of the catch clause in the usual way, but the
> >>thread is still cancelled. Encountering another cancellation point
> >>will result in re-raising the cancellation exception.
> >>
> >>2) Fall off the end of the catch clause in the usual way, but the
> >>thread is no longer cancelled. It can be re-cancelled, but until it
> >>is, it will operate normally.
> >
> >It doesn't matter much which it does; probably (1) is fine, as far as
> >that goes.
>
> I agree that the choice doesn't matter much. Heck, this whole issue
> doesn't matter much to me; I'm just trying to keep us from going in
> some really bad direction...
They did that a long time ago. Our only hope is to undo the damage
within the context of C++ programs.
> >Making the spec depend on compiler support practically guarantees
> >that most users won't get anything reasonable, because that depends
> >on "uptake" by people implacably hostile to C++. That's whey we're
> >at this impasse in the first place.
>
> Nothing we're talking about requires compiler support per se; it's
> all C library support -- including your proposal, if I understand it
> correctly, since you want to not do unwinding when inside a
> cancellation region, which requires changing pthread_cleanup_push
> not to be a destructor.
OK, not compiler support; compiler-runtime support.
People have been posting about how to keep cancellation from
happening during ordinary-exception unwinding, or while a destructor
is active. (Most who think it's fine to throw from C-library functions
-- specified by the standard never to throw -- pause at exceptions
coming out of random destructors.) All this requires an intimate
relationship between the exception ABI and the cancellation apparatus.
Nothing I wrote says that pthread cleanup mustn't be done with a
destructor, underneath. There's no way for a conforming program to
tell. That makes it easy to implement without knowing any ABI
details of how unwinding is done. That's half the point: it means
third parties probably can implement it independently of what their
C library vendor has done -- or has categorically refused to do --
just by reimplementing a few pthread functions.
The other half is that regular libraries can have well-defined
semantics in real threaded C++ programs, even with POSIX-standard
cancellation bombs exploding left and right, and without depending
on blind luck. If we don't rescue the libraries, whatever we do
end up with won't matter to real-world programmers.
Nathan Myers
ncm at codesourcery.com
More information about the c++-pthreads
mailing list