This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: catch(...) and forced unwind


Mark Mitchell <mark@codesourcery.com> writes:

> On Wed, 2003-12-17 at 03:22, David Abrahams wrote:
>> Mark Mitchell <mark@codesourcery.com> writes:
>> 
>> > (3) The thread_cancellation objects contain a reference count; copying
>> > the object increments the reference count and destroying the object
>> > decrements the reference count.  If the reference count goes to zero (as
>> > would happen when the exception is caught and not rethrown) the thread
>> > is uncancelled.
>> 
>> If "uncancelled" doesn't mean "re-deferred", I don't see the point of
>> the reference count.  How is the "uncancelled" case different from
>> the one where a copy of the thread_cancellation object is kept alive
>> indefinitely, i.e.
>> 
>>   catch (posix::thread_cancellation& x)
>>   { 
>>      some_stack.push(new (nothrow) thread_cancellation(x));
>>   }
>
> I'm not sure exactly what you're getting at here.  
>
> I was looking for semantics like auto_ptr.  
>
> In particular, as long as you hold on to the thread_cancellation object
> things are as if you are in a POSIX thread cancellation handler --
> nothing is a cancellation point.

I get it.

> Consider this code:
>
>   posix::thread_cancellation* p = NULL;
>   try { } 
>   catch (posix::thread_cancellation& x) {
>     // Continue with the code outside this catch block, but 
>     // as if we are in a thread cancellation handler.
>     p = new (nothrow) posix::thread_cancellation (x);
>     // x is destroyed as we leave this scope.
>   }
>   // Do some more stuff.
>   ...
>   // Now rethrow the cancellation exception.
>   if (p)
>     throw *p;
>
> If, on the other hand, you let go of all references to the
> thread_cancellation object, then you decided you do not want to be
> cancelled at all.  

*This time*.  Because by letting go of the cancellation object, you
 re-enable cancellation points.  That's kind of an odd paradox isn't
 it?

>> I'm not convinced there's a better solution, but it seems to me that
>> this could be a disaster for the ability to freely use C++ libraries
>> in threads without knowing something about their implementations.
>
> I don't think there is any way to combine C++ and POSIX threads such
> that all existing thread-safe, exception-safe C++ libraries will work in
> the presence of cancellation.  Fundamentally, the idea of cancellation
> means that you have to audit your entire library before using it in a
> thread.  That's not news: 

It's news to me, but then I haven't been paying too enough attention
to threading issues ;-)

> the same problems come up with cooperating processes in the presence
> of signals. A correct program, written for an environment without
> SIGTERM, must be audited before being deployed in an environment
> with SIGTERM.

Yeah, but signals were fundamentally different from exceptions until
the posix/c++ standard conflict about which functions can throw arose.

> My proposal gives two operating modes for the combination of POSIX
> threads and C++. 
>
> In one mode, the C++ thread sees a conforming C++ environment (i.e., one
> in which "printf" never throws exceptions).  Stack unwinding will not be
> done in that environment, so if such a thread is cancelled, it will not
> get a chance to clean up after itself.  

Y'know, I don't like that.  It doesn't give people the choice to add
explicit cancellation checks to a codebase while preserving the C++
standard behavior of functions that don't throw.  If I was trying to
import some generally-threadsafe code to a threaded environment,
looking for a few places where it's safe to throw cancellations would
be my first strategy.

> For many threads, that will be OK, just as it is OK for many
> processes not to have a SIGTERM handler.  In this situation, you
> have to audit your C++ code to make sure that it is safe for it to
> go away without running cleanups.
>
> In the other mode, the C++ thread sees a non-conforming environment, in
> that some C library functions can throw exceptions.  In some cases,
> simply writing exception-safe code around such calls may be good
> enough.  In the general case, the library will have to be modified to
> know about the idea of cancellation exceptions and take appropriate
> action.  No surprise, that; lots of programs need modification to deal
> with SIGTERM.  In this situation, you have to audit your C++ code to
> make sure you've handled all the cancellation points correctly.
>
> There's no way to avoid having to do an audit, but you can pick which
> audit you have to do.
>
>> Is it worth considering adding a mechanism which turns off
>> cancellation exceptions during unwinding?  I realize it's a
>> half-measure, but at least it would prevent some printf logging code
>> from sending us to terminate.
>
> I think this is a good suggestion.  It is orthogonal to my proposal,
> though.

Yes, I recognize that.  Well, not completely orthogonal.  If we were
just going to override Posix with C++ against your advice, my
suggestion would be pointless.

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]