public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* catch(...) and forced unwind
@ 2003-12-12 22:54 Jason Merrill
  2003-12-13  0:09 ` David Abrahams
                   ` (2 more replies)
  0 siblings, 3 replies; 74+ messages in thread
From: Jason Merrill @ 2003-12-12 22:54 UTC (permalink / raw)
  To: gcc
  Cc: Richard Henderson, Mark Mitchell, Ulrich Drepper,
	Benjamin Kosnik, Jakub Jelinek, ncm,
	Gabriel Dos Reis <gdr@codesourcery.com>David Abrahams,
	wekempf, fjh, Jason Merrill

Yes, it's that topic again.  The previous discussion can be found here:

  http://gcc.gnu.org/ml/gcc-patches/2003-04/threads.html#02246
  http://gcc.gnu.org/ml/gcc-patches/2003-05/threads.html#00000

I've tried to CC everyone who contributed to the earlier discussion.  

It's coming up again because it turns out that the obvious implementation
of the iostream inserters and extractors involves a catch(...) which does
not rethrow, so the question of what to do with such a catch block has
significant practical consequences.

To recap, some folks thought that such a catch block should rethrow
automatically, and some thought that it should work just like it does for
any other exception, effectively deferring the cancellation until the next
call to a cancel point.

The argument for rethrow is that it's probably the right behavior.
The argument for continue is that it's what the user wrote and we shouldn't
  be changing the semantics of their code behind their back.
The current compromise behavior is to call terminate so that the user is
  aware of the problem.

The relevant verbiage from the C++ standard:

  27.6.1.1  Class template basic_istream                   [lib.istream]

4 If one of these called functions  throws  an  exception,  then  unless
  explicitly  noted  otherwise,  the input function sets badbit in error
  state.  If badbit is on in exceptions(), the  input  function rethrows
  the exception without completing its actions, otherwise  it  does  not
  throw anything and proceeds as  if  the called function had returned a
  failure indication.

As a result, the following testcase will abort under the compromise
behavior:

  #include <pthread.h>
  #include <iostream>

  void *
  tf (void *)
  {
    while (true)
      std::cout << "." << std::flush;
    return NULL;
  }

  int
  main (void)
  {
    pthread_t t;
    while (true)
      {
        if (pthread_create (&t, NULL, tf, NULL))
          break;
        if (pthread_cancel (t))
          break;
        if (pthread_join (t, NULL))
          break;
      }
    return 1;
  }

Clearly, this high-level behavior is wrong.  iostream code should be
cancelable.  

Either of the proposed behaviors would make this particular testcase work;
the rethrow option would cause cancellation to finish sooner, but the
continue option would only defer cancellation until the next flush.  If we
left out the flush, however, the continue option would never actually
cancel because the only cancel point in the loop is guarded by the
catch(...) in the string inserter.

I believe this is a bug in the library: it thinks it knows what sorts of
exceptions it will see and wants to swallow all of them, but it is wrong.

I see three ways to fix this:

1) automatically rethrow cancellation.
2) explicitly rethrow cancellation--this would require some way to catch it
   specifically, but we really ought to have that anyway.
3) don't catch and swallow all exceptions; changing the catch(...) to
   catch(std::exception) would catch all exceptions thrown by other parts
   of the library, which AFAIK is what we're trying to accomplish.

Thoughts?

Jason

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-12 22:54 catch(...) and forced unwind Jason Merrill
@ 2003-12-13  0:09 ` David Abrahams
  2003-12-13  2:22 ` Benjamin Kosnik
       [not found] ` <ud6at1wvg.fsf@boost-consulting.com>
  2 siblings, 0 replies; 74+ messages in thread
From: David Abrahams @ 2003-12-13  0:09 UTC (permalink / raw)
  To: gcc


> Yes, it's that topic again.  The previous discussion can be found here:
>
>   http://gcc.gnu.org/ml/gcc-patches/2003-04/threads.html#02246
>   http://gcc.gnu.org/ml/gcc-patches/2003-05/threads.html#00000
>
> I've tried to CC everyone who contributed to the earlier discussion.  
>
> It's coming up again because it turns out that the obvious implementation
> of the iostream inserters and extractors involves a catch(...) which does
> not rethrow, so the question of what to do with such a catch block has
> significant practical consequences.
>
> To recap, some folks thought that such a catch block should rethrow
> automatically, and some thought that it should work just like it does for
> any other exception, effectively deferring the cancellation until the next
> call to a cancel point.
>
> The argument for rethrow is that it's probably the right behavior.

Except when it isn't.  Think of the boundary between C++ and other
code which can't propagate exceptions.

> The argument for continue is that it's what the user wrote and we shouldn't
>   be changing the semantics of their code behind their back.

Sounds reasonable to me.

> The current compromise behavior is to call terminate so that the user is
>   aware of the problem.

How is that a compromise?  Because nobody gets what they want?  The
user's behavior is changed, and you don't rethrow.

> The relevant verbiage from the C++ standard:
>
>   27.6.1.1  Class template basic_istream                   [lib.istream]
>
> 4 If one of these called functions  throws  an  exception,  then  unless
>   explicitly  noted  otherwise,  the input function sets badbit in error
>   state.  If badbit is on in exceptions(), the  input  function rethrows
>   the exception without completing its actions, otherwise  it  does  not
>   throw anything and proceeds as  if  the called function had returned a
>   failure indication.
>
> As a result, the following testcase will abort under the compromise
> behavior:
>
>   #include <pthread.h>
>   #include <iostream>
>
>   void *
>   tf (void *)
>   {
>     while (true)
>       std::cout << "." << std::flush;
>     return NULL;
>   }
>
>   int
>   main (void)
>   {
>     pthread_t t;
>     while (true)
>       {
>         if (pthread_create (&t, NULL, tf, NULL))
>           break;
>         if (pthread_cancel (t))
>           break;
>         if (pthread_join (t, NULL))
>           break;
>       }
>     return 1;
>   }
>
> Clearly, this high-level behavior is wrong.  iostream code should be
> cancelable.  

I'm going to assume some things of which I have no knowledge:

1. Thread cancellation doesn't induce an asynchronous C++ exception in
   the thread.

2. There is some documentation somewhere which indicates that one of
   the functions called by tf is a "cancellation point" (i.e. may
   throw thread cancellation exceptions).  Otherwise, it seems to me,
   "this high-level behavior" would not be wrong.

> Either of the proposed behaviors would make this particular testcase work;
> the rethrow option would cause cancellation to finish sooner, but the
> continue option would only defer cancellation until the next
> flush.  

As I understand cancellation, it is only a request, so that's
entirely reasonable.

> If we left out the flush, however, the continue option would never
> actually cancel because the only cancel point in the loop is guarded
> by the catch(...) in the string inserter.
>
> I believe this is a bug in the library: it thinks it knows what sorts of
> exceptions it will see and wants to swallow all of them, but it is wrong.

It's definitely not a bug if you're just considering the specification
you quoted above.  You must have some other criteria for saying it
is.  Care to share them?

> I see three ways to fix this:
>
> 1) automatically rethrow cancellation.

That's a bad idea.  At language boundaries you might need to
translate a cancellation exception into something else, then
re-generate a cancellation exception when you get back to C++.

> 2) explicitly rethrow cancellation--

That seems to violate the specification you quoted.

>    this would require some way to catch it
>    specifically, but we really ought to have that anyway.

Probably.

> 3) don't catch and swallow all exceptions; changing the catch(...) to
>    catch(std::exception) would catch all exceptions thrown by other parts
>    of the library, which AFAIK is what we're trying to accomplish.

That also seems to violate the specification you quoted.

> Thoughts?

Either you have to lobby to get the standard changed, live with the
fact that you're going to break it, or live with the fact that not
having badbit set will suppress cancellation in some circumstances.  I
don't think it's honest to "fix" the problem by calling the latter
behavior a bug if that's what the specifications say to do.

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


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-12 22:54 catch(...) and forced unwind Jason Merrill
  2003-12-13  0:09 ` David Abrahams
@ 2003-12-13  2:22 ` Benjamin Kosnik
  2003-12-13  8:28   ` Jason Merrill
  2003-12-15 22:24   ` Richard Henderson
       [not found] ` <ud6at1wvg.fsf@boost-consulting.com>
  2 siblings, 2 replies; 74+ messages in thread
From: Benjamin Kosnik @ 2003-12-13  2:22 UTC (permalink / raw)
  To: Jason Merrill
  Cc: gcc, rth, mark, drepper, jakub, ncm, dave, wekempf, fjh, jason


>I see three ways to fix this:
>
>1) automatically rethrow cancellation.
>2) explicitly rethrow cancellation--this would require some way to catch it
>   specifically, but we really ought to have that anyway.

What about 

  typedef void (*__cancellation_handler)();
  __cancellation_handler __set_cancellation(__cancellation_handler  f ) throw();
  void __cancellation();

Ie, not overloading terminate and just calling a spade a spade, and
inventing new bits to take care of this without overloading the meaning
of terminate or confusing the issue, in the same familiar way that
terminate is handled?

Then people could use __set_cancellation above with these new functions:

void __abort_cancellation() { std::abort }

void __rethrow_cancellation() { __throw_exception_again; }
 
void __continue_cancellation() { }

Ie, a __cancellation_handler that could be set to either rethrow,
continue, or abort? I think a user-configurable solution is really the
only solution that is going to get any traction.

>3) don't catch and swallow all exceptions; changing the catch(...) to
>   catch(std::exception) would catch all exceptions thrown by other parts
>   of the library, which AFAIK is what we're trying to accomplish.

I would dearly love to do this, and this is the way v3 originally
implemented these catch clauses. I think this is really the correct
behavior for iostreams. However, this violates both exisiting code and
the current text of the standard, so I think it's a non-starter.

-benjamin 

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
       [not found] ` <ud6at1wvg.fsf@boost-consulting.com>
@ 2003-12-13  6:55   ` Jason Merrill
       [not found]     ` <u65gkyhv4.fsf@boost-consulting.com>
  0 siblings, 1 reply; 74+ messages in thread
From: Jason Merrill @ 2003-12-13  6:55 UTC (permalink / raw)
  To: David Abrahams
  Cc: gcc, Richard Henderson, Mark Mitchell, Ulrich Drepper,
	Benjamin Kosnik, Jakub Jelinek, ncm, wekempf, fjh

On Fri, 12 Dec 2003 17:42:27 -0500, David Abrahams <dave@boost-consulting.com> wrote:

> Jason Merrill <jason@redhat.com> writes:

>> As a result, the following testcase will abort under the compromise
>> behavior:
>>
>>   #include <pthread.h>
>>   #include <iostream>
>>
>>   void *
>>   tf (void *)
>>   {
>>     while (true)
>>       std::cout << "." << std::flush;
>>     return NULL;
>>   }
>>
>>   int
>>   main (void)
>>   {
>>     pthread_t t;
>>     while (true)
>>       {
>>         if (pthread_create (&t, NULL, tf, NULL))
>>           break;
>>         if (pthread_cancel (t))
>>           break;
>>         if (pthread_join (t, NULL))
>>           break;
>>       }
>>     return 1;
>>   }
>>
>> Clearly, this high-level behavior is wrong.  iostream code should be
>> cancelable.  
>
> I'm going to assume some things of which I have no knowledge:
>
> 1. Thread cancellation doesn't induce an asynchronous C++ exception in
>    the thread.

Correct.

> 2. There is some documentation somewhere which indicates that one of
>    the functions called by tf is a "cancellation point" (i.e. may
>    throw thread cancellation exceptions).  Otherwise, it seems to me,
>    "this high-level behavior" would not be wrong.

Basically, all of the C library I/O functions are cancellation points.

>> If we left out the flush, however, the continue option would never
>> actually cancel because the only cancel point in the loop is guarded
>> by the catch(...) in the string inserter.
>>
>> I believe this is a bug in the library: it thinks it knows what sorts of
>> exceptions it will see and wants to swallow all of them, but it is wrong.
>
> It's definitely not a bug if you're just considering the specification
> you quoted above.  You must have some other criteria for saying it
> is.  Care to share them?

I don't expect writing 'cout << "."' to suppress thread cancellation.
Do you disagree that this is an extremely surprising side-effect?

>> 2) explicitly rethrow cancellation--
>
> That seems to violate the specification you quoted.

I don't think the specification is relevant in this case.  Cancellation
uses the exception handling runtime but is not a normal exception; this is
outside the scope of the current standard.

>> 3) don't catch and swallow all exceptions; changing the catch(...) to
>>    catch(std::exception) would catch all exceptions thrown by other parts
>>    of the library, which AFAIK is what we're trying to accomplish.
>
> That also seems to violate the specification you quoted.

Yes, this would require a change in the standard.

> Either you have to lobby to get the standard changed, live with the
> fact that you're going to break it, or live with the fact that not
> having badbit set will suppress cancellation in some circumstances.  I
> don't think it's honest to "fix" the problem by calling the latter
> behavior a bug if that's what the specifications say to do.

The specifications don't say anything about cancellation.  We're in
extensions-land here, so we get to decide what it means.  We can decide
that cancellation acts just like an exception, or we can decide that it
acts like an exception except when it doesn't.  The standard may provide
guidance about what the best solution might be, but no more than that.

Jason

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-13  2:22 ` Benjamin Kosnik
@ 2003-12-13  8:28   ` Jason Merrill
       [not found]     ` <20031213082241.GB2416@tofu.dreamhost.com>
  2003-12-15 22:24   ` Richard Henderson
  1 sibling, 1 reply; 74+ messages in thread
From: Jason Merrill @ 2003-12-13  8:28 UTC (permalink / raw)
  To: Benjamin Kosnik; +Cc: gcc, rth, mark, drepper, jakub, ncm, dave, wekempf, fjh

On Fri, 12 Dec 2003 18:37:54 -0600, Benjamin Kosnik <bkoz@redhat.com> wrote:

>>I see three ways to fix this:
>>
>>1) automatically rethrow cancellation.
>>2) explicitly rethrow cancellation--this would require some way to catch it
>>   specifically, but we really ought to have that anyway.
>
> What about 
>[...]
> Ie, a __cancellation_handler that could be set to either rethrow,
> continue, or abort?

That seems plausible to me.  I think that #2 would still be appropriate.

Jason

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
       [not found]     ` <20031213082241.GB2416@tofu.dreamhost.com>
@ 2003-12-13  9:26       ` Nathan Myers
  0 siblings, 0 replies; 74+ messages in thread
From: Nathan Myers @ 2003-12-13  9:26 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Benjamin Kosnik, gcc, rth, mark, drepper, jakub, dave, wekempf, fjh

[apologies to those seeing this twice -- mailing list trouble.]
On Sat, Dec 13, 2003 at 01:54:55AM -0500, Jason Merrill wrote:
> On Fri, 12 Dec 2003 18:37:54 -0600, Benjamin Kosnik <bkoz@redhat.com> wrote:
> 
> >>I see three ways to fix this:
> >>
> >>1) automatically rethrow cancellation.
> >>2) explicitly rethrow cancellation--this would require some way to catch it
> >>   specifically, but we really ought to have that anyway.
> >
> > What about 
> >[...]
> > Ie, a __cancellation_handler that could be set to either rethrow,
> > continue, or abort?
> 
> That seems plausible to me.  I think that #2 would still be appropriate.

I suggested the distinct handler the last time this was discussed, and 
the only comments on it were in agreement.

The point is that a program would be equipped to enforce 
standard-conforming behavior.  Just as now every C++ program that 
uses cin and/or cout where performance matters starts with a call 
"std::ios::sync_with_stdio(false);", every threaded program where 
correctness matters would need to start with a call to fix the 
cancellation handler, to behave in the way that well-written
libraries expect (and, therefore, require):

  int main()
  {
    std::ios:sync_with_stdio(false);
#   ifdef __GLIBC__  /* or some damn thing */
      __gnu::set_cancellation(__gnu::__continue_cancellation);
#   endif
  ...

It would stink, but would beat being unable to ship a program that has 
documentable behavior.  I would prefer to put that call in the static
init code for libstdc++.  Of course the best approach would be to 
leave exception semantics the hell alone; a patchable handler amounts
to damage control.

For an iostream exception handler, it would be fine for it to set 
badbit and return, when a cancellation exception occurred.  The next 
cancellation exception wouldn't be in iostream code any more, because 
the stream active when the cancellation occurred would be no longer 
usable, and good code already handles finding badbit set.

Nathan Myers
ncm-nospam@cantrip.org

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
       [not found]     ` <u65gkyhv4.fsf@boost-consulting.com>
@ 2003-12-14  4:23       ` Nathan Myers
  2003-12-15 20:29         ` Jason Merrill
  2003-12-15 10:16       ` Richard Henderson
  1 sibling, 1 reply; 74+ messages in thread
From: Nathan Myers @ 2003-12-14  4:23 UTC (permalink / raw)
  To: David Abrahams
  Cc: Jason Merrill, gcc, Richard Henderson, Mark Mitchell,
	Ulrich Drepper, Benjamin Kosnik, Jakub Jelinek, wekempf, fjh

On Sat, Dec 13, 2003 at 08:20:15AM -0500, David Abrahams wrote:
> Jason Merrill <jason@redhat.com> writes:
> 
> > On Fri, 12 Dec 2003 17:42:27 -0500, David Abrahams 
> >
> >> 2. There is some documentation somewhere which indicates that one of
> >>    the functions called by tf is a "cancellation point" (i.e. may
> >>    throw thread cancellation exceptions).  Otherwise, it seems to me,
> >>    "this high-level behavior" would not be wrong.
> >
> > Basically, all of the C library I/O functions are cancellation points.
> 
> Well, I constider that very surprising. It harms the ability to write
> portable code, for reasons explained below.

Indeed, it's commmon to declare external C functions "throw()", meaning
no exceptions can ever come out of them, and expect the compiler to 
optimize accordingly.

> >>> I believe this is a bug in the library: it thinks it knows what sorts of
> >>> exceptions it will see and wants to swallow all of them, but it is wrong.
> >>
> >> It's definitely not a bug if you're just considering the specification
> >> you quoted above.  You must have some other criteria for saying it
> >> is.  Care to share them?
> >
> > I don't expect writing 'cout << "."' to suppress thread cancellation.
> > Do you disagree that this is an extremely surprising side-effect?
> 
> Yes, I disagree that it's surprising.  I know that iostream operations
> won't throw unless you set badbit, and I therefore expect them not to
> throw.  
>
> Knowing which operations can throw and which can't is crucial to
> writing exception-safe code (see
> http://www.boost.org/more/generic_exception_safety.html), regardless
> of the reasons for the exception.  If you violate the guarantee that
> certain non-throwing operations won't throw, you fundamentally
> undermine people's ability to correctly deal with exceptions
> (e.g. clean up resources).

Not throwing is part of iostream's contract.  For the runtime system
to arbitrarily change that contract makes any code written to the old 
contract indeterminate and likely wrong.
 
> Furthermore, throwing against the standard's guarantees undermines
> portability.  All code which can run in a cancellable thread now has
> to have special knowledge of the behavior of the system it's running
> on.  That could mean, for example, that people can't pick up the Boost
> libraries and use them inside of a thread.  This effect is bad with
> functions people don't *expect* to throw (the C I/O) but the standard
> does allow those to throw implementation-defined exceptions.  It's
> *really really* bad with functions the standard guarantees won't
> throw.

Changing the semantics of C++ exceptions demands special versions of 
every library, just for use in threaded programs on this one platform.
It will make most threaded programs not portable to this platform.

> >>> 2) explicitly rethrow cancellation--
> >>
> >> That seems to violate the specification you quoted.
> >
> > I don't think the specification is relevant in this case.  Cancellation
> > uses the exception handling runtime but is not a normal exception; 
> 
> In what sense?
> 
> > this is outside the scope of the current standard.
> 
> I think it's not the nature of the exception, but the fact that you're
> running in a thread which makes it "outside the scope", since the
> standard doesn't cover threading.  Still, the ability to use code in
> threads which was written without knowledge of your threading system,
> I would think, is crucial.

The population of coders willing to write code just for this one threading
system is necessarily small.

> >>> 3) don't catch and swallow all exceptions; changing the catch(...) to
> >>>    catch(std::exception) would catch all exceptions thrown by other parts
> >>>    of the library, which AFAIK is what we're trying to accomplish.
> >>
> >> That also seems to violate the specification you quoted.
> >
> > Yes, this would require a change in the standard.
> >
> >> Either you have to lobby to get the standard changed, live with the
> >> fact that you're going to break it, or live with the fact that not
> >> having badbit set will suppress cancellation in some circumstances.  I
> >> don't think it's honest to "fix" the problem by calling the latter
> >> behavior a bug if that's what the specifications say to do.
> >
> > The specifications don't say anything about cancellation.  We're in
> > extensions-land here, so we get to decide what it means.  We can decide
> > that cancellation acts just like an exception, or we can decide that it
> > acts like an exception except when it doesn't.  The standard may provide
> > guidance about what the best solution might be, but no more than that.
> 
> I'm not sure I agree with you on the fine points, but regardless, I
> think the code interoperability arguments I made above indicate that
> you'd better not let exceptions propagate when the standard says they
> won't.  It's a bad idea to let a non-standard extension completely
> change the assumptions code can make about its execution environment.

This is a difference from the C world.  With C, no one expects a library 
to work right in a threaded program if it wasn't written with that target 
in mind.  Contrarily, C++ users routinely expect portable C++ libraries 
to be exception- and thread-safe, and an enormous amount of such code
has already been written that is.  Changing the semantics of exception 
handlers breaks it all.

The largest probable effect of this change in semantics would be for 
library writers to warn against ever allowing thread cancellation in 
any program that uses the library.  In practice, it would mean that 
thread cancellation is not available on this platform.  It would be
odd to do all this work just to eliminate any possibility of usable
thread cancellation.

In the meantime, the ISO committee is discussing a standard threads
library for C++, including a cancellation model incompatible with what
is being proposed here.  It would be better for everybody involved for 
Gcc to match it.

For an operation as dubious as thread cancellation to demand a 
fundamental change in language semantics, and a rewrite of so many
libraries, is a very small tail wagging a very big dog.  

Nathan Myers
ncm@cantrip.org

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
       [not found]     ` <u65gkyhv4.fsf@boost-consulting.com>
  2003-12-14  4:23       ` Nathan Myers
@ 2003-12-15 10:16       ` Richard Henderson
  2003-12-15 15:44         ` David Abrahams
       [not found]         ` <u8yler71p.fsf@boost-consulting.com>
  1 sibling, 2 replies; 74+ messages in thread
From: Richard Henderson @ 2003-12-15 10:16 UTC (permalink / raw)
  To: David Abrahams
  Cc: Jason Merrill, gcc, Mark Mitchell, Ulrich Drepper,
	Benjamin Kosnik, Jakub Jelinek, ncm, wekempf, fjh

On Sat, Dec 13, 2003 at 08:20:15AM -0500, David Abrahams wrote:
> > Basically, all of the C library I/O functions are cancellation points.
> 
> Well, I constider that very surprising. It harms the ability to write
> portable code, for reasons explained below.

No.  If you're writing a threaded program that cancels code, then
I expect that you've *read* POSIX, and thus realize that if you 
want to output bits via write, and you don't want to be canceled,
then you should call pthread_setcancelstate(PTHREAD_CANCEL_DISABLE).

If you havn't done this, then you aren't using the thread API correctly,
and thus are *not* writing portable code.

If you don't want to know about pthread_setcancelstate, then you should
not use pthread_cancel either.  If you never use pthread_cancel, then
none of this thread is even relevant.


r~

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-15 10:16       ` Richard Henderson
@ 2003-12-15 15:44         ` David Abrahams
       [not found]         ` <u8yler71p.fsf@boost-consulting.com>
  1 sibling, 0 replies; 74+ messages in thread
From: David Abrahams @ 2003-12-15 15:44 UTC (permalink / raw)
  To: gcc


Richard Henderson <rth@redhat.com> writes:

> On Sat, Dec 13, 2003 at 08:20:15AM -0500, David Abrahams wrote:
>> > Basically, all of the C library I/O functions are cancellation points.
>> 
>> Well, I constider that very surprising. It harms the ability to write
>> portable code, for reasons explained below.
>
> No.  If you're writing a threaded program that cancels code, then
> I expect that you've *read* POSIX, and thus realize that if you 
> want to output bits via write, and you don't want to be canceled,
> then you should call pthread_setcancelstate(PTHREAD_CANCEL_DISABLE).

Yes.  I would hope that people writing threaded programs could use
libraries written to be generally threadsafe but which don't
specifically prevent posix thread cancellation.

> If you havn't done this, then you aren't using the thread API correctly,
> and thus are *not* writing portable code.

It's not a matter of using the thread API at all; threadsafe libraries
may never touch a thread API function.

> If you don't want to know about pthread_setcancelstate, then you should
> not use pthread_cancel either.  If you never use pthread_cancel, then
> none of this thread is even relevant.

I'm a library provider ;-)

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-14  4:23       ` Nathan Myers
@ 2003-12-15 20:29         ` Jason Merrill
  2003-12-15 23:34           ` David Abrahams
  0 siblings, 1 reply; 74+ messages in thread
From: Jason Merrill @ 2003-12-15 20:29 UTC (permalink / raw)
  To: Nathan Myers
  Cc: David Abrahams, gcc, Richard Henderson, Mark Mitchell,
	Ulrich Drepper, Benjamin Kosnik, Jakub Jelinek, wekempf, fjh

On Sat, 13 Dec 2003 19:59:09 -0800, Nathan Myers <ncm@cantrip.org> wrote:

> On Sat, Dec 13, 2003 at 08:20:15AM -0500, David Abrahams wrote:
>> Jason Merrill <jason@redhat.com> writes:
>> 
>> > On Fri, 12 Dec 2003 17:42:27 -0500, David Abrahams 
>> >
>> >> 2. There is some documentation somewhere which indicates that one of
>> >>    the functions called by tf is a "cancellation point" (i.e. may
>> >>    throw thread cancellation exceptions).  Otherwise, it seems to me,
>> >>    "this high-level behavior" would not be wrong.
>> >
>> > Basically, all of the C library I/O functions are cancellation points.
>> 
>> Well, I constider that very surprising. It harms the ability to write
>> portable code, for reasons explained below.
>
> Indeed, it's commmon to declare external C functions "throw()", meaning
> no exceptions can ever come out of them, and expect the compiler to 
> optimize accordingly.

And g++ does.  I'm not sure at the moment what we do when a forced unwind
tries to unwind through a throw(); things don't seem to be working
properly on my laptop at the moment.  I suspect that we fall back on the
old semantics, i.e. run explicitly pushed cleanups and kill the thread.

>> > I don't expect writing 'cout << "."' to suppress thread cancellation.
>> > Do you disagree that this is an extremely surprising side-effect?
>> 
>> Yes, I disagree that it's surprising.  I know that iostream operations
>> won't throw unless you set badbit, and I therefore expect them not to
>> throw.  

Aha.  I didn't realize that the disagreement was so basic.

> Not throwing is part of iostream's contract.  For the runtime system
> to arbitrarily change that contract makes any code written to the old 
> contract indeterminate and likely wrong.

I don't see any such contract.

  17.4.4.8  Restrictions on              [lib.res.on.exception.handling]
       exception handling

2 None of the functions from the Standard  C  library  shall  report  an
  error by throwing an exception,176) unless it calls a program-supplied
  function that throws an exception.177)

3 No destructor operation defined in the C++ Standard Library will throw
  an exception.  Any other functions defined in the C++ Standard Library
  that  do not have an exception-specification may throw implementation-
  defined  exceptions  unless otherwise specified.178)

This passage seems to give the implementation the latitude to throw an
implementation-defined exception from any of the iostream functions, since
none of them are specified throw().

>> Furthermore, throwing against the standard's guarantees undermines
>> portability.  All code which can run in a cancellable thread now has
>> to have special knowledge of the behavior of the system it's running
>> on.  That could mean, for example, that people can't pick up the Boost
>> libraries and use them inside of a thread.  This effect is bad with
>> functions people don't *expect* to throw (the C I/O) but the standard
>> does allow those to throw implementation-defined exceptions.  It's
>> *really really* bad with functions the standard guarantees won't
>> throw.

Actually, this is backwards -- the standard doesn't allow the C I/O
functions to throw any exceptions; see the passage above.  This obviously
needs to change if we're going to do anything useful with POSIX thread
cancellation.

>> I think it's not the nature of the exception, but the fact that you're
>> running in a thread which makes it "outside the scope", since the
>> standard doesn't cover threading.  Still, the ability to use code in
>> threads which was written without knowledge of your threading system,
>> I would think, is crucial.

Oh, I agree.  I'm just skeptical that iostream code throwing a cancellation
exception would interfere with this ability.

> The population of coders willing to write code just for this one
> threading system is necessarily small.

Which one?  POSIX threads?  I hear they're pretty widespread.  But
seriously, we have a number of customers writing code for that threading
system, and asking for this functionality.

> This is a difference from the C world.  With C, no one expects a library 
> to work right in a threaded program if it wasn't written with that target 
> in mind.  Contrarily, C++ users routinely expect portable C++ libraries 
> to be exception- and thread-safe, and an enormous amount of such code
> has already been written that is.  Changing the semantics of exception 
> handlers breaks it all.

Nathan, you seem to assume that I'm advocating implicit rethrow.  I'm not.
I'm only suggesting that cancellation should propagate out of iostream
code, and suggested several ways that might happen.

Both your and David's replies seem to have amounted to saying that any
change to current behavior is unacceptable.  That isn't very useful.  Just
to step back a moment, can we all agree that we want pthread cancellation
to run C++ cleanups?  And that we might have to adjust a few things to make
that work?

> In the meantime, the ISO committee is discussing a standard threads
> library for C++, including a cancellation model incompatible with what
> is being proposed here.  It would be better for everybody involved for 
> Gcc to match it.

Please elaborate.  I don't see a relevant paper in any of the recent
mailings.

Jason

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
       [not found]         ` <u8yler71p.fsf@boost-consulting.com>
@ 2003-12-15 22:19           ` Richard Henderson
  2003-12-15 23:36             ` David Abrahams
  0 siblings, 1 reply; 74+ messages in thread
From: Richard Henderson @ 2003-12-15 22:19 UTC (permalink / raw)
  To: David Abrahams
  Cc: Jason Merrill, gcc, Mark Mitchell, Ulrich Drepper,
	Benjamin Kosnik, Jakub Jelinek, ncm, wekempf, fjh

On Mon, Dec 15, 2003 at 12:20:18AM -0500, David Abrahams wrote:
> > If you don't want to know about pthread_setcancelstate, then you should
> > not use pthread_cancel either.  If you never use pthread_cancel, then
> > none of this thread is even relevant.
> 
> I'm a library provider ;-)

Then you have to either have to document that the library is
not cancelation safe and point users at TFM when they don't
read it, or expect pthread_cancel to be used and thus call
pthread_setcancelstate appropriately.


r~

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-13  2:22 ` Benjamin Kosnik
  2003-12-13  8:28   ` Jason Merrill
@ 2003-12-15 22:24   ` Richard Henderson
  2003-12-15 22:45     ` Benjamin Kosnik
  1 sibling, 1 reply; 74+ messages in thread
From: Richard Henderson @ 2003-12-15 22:24 UTC (permalink / raw)
  To: Benjamin Kosnik
  Cc: Jason Merrill, gcc, mark, drepper, jakub, ncm, dave, wekempf, fjh

On Fri, Dec 12, 2003 at 06:37:54PM -0600, Benjamin Kosnik wrote:
> Then people could use __set_cancellation above with these new functions:
[...]
> void __rethrow_cancellation() { __throw_exception_again; }

This one doesn't work, for the reason that Jason gave earlier:
we've already committed to deleting the exception.  If we want
to rethrow, then we have to hook into __cxa_end_catch.


r~

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-15 22:24   ` Richard Henderson
@ 2003-12-15 22:45     ` Benjamin Kosnik
  2003-12-15 22:52       ` Richard Henderson
  0 siblings, 1 reply; 74+ messages in thread
From: Benjamin Kosnik @ 2003-12-15 22:45 UTC (permalink / raw)
  To: Richard Henderson
  Cc: jason, gcc, mark, drepper, jakub, ncm, dave, wekempf, fjh


>This one doesn't work, for the reason that Jason gave earlier:
>we've already committed to deleting the exception.  If we want
>to rethrow, then we have to hook into __cxa_end_catch.

Ok. So, just to clarify: 

void __rethrow_cancellation() 
{ 
    // something else
}

might be valid (given sufficient smarts, not given at the moment), or
the whole idea is shot? Keep in mind that the __cancellation_handler is
set once, so it could be used to set the __cxa_end_catch personality to
something that rethrows.

-benjamin

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-15 22:45     ` Benjamin Kosnik
@ 2003-12-15 22:52       ` Richard Henderson
  2003-12-15 22:54         ` Richard Henderson
  2003-12-15 23:05         ` Benjamin Kosnik
  0 siblings, 2 replies; 74+ messages in thread
From: Richard Henderson @ 2003-12-15 22:52 UTC (permalink / raw)
  To: Benjamin Kosnik; +Cc: jason, gcc, mark, drepper, jakub, ncm, dave, wekempf, fjh

On Mon, Dec 15, 2003 at 04:39:06PM -0600, Benjamin Kosnik wrote:
> Ok. So, just to clarify: 
> 
> void __rethrow_cancellation() 
> { 
>     // something else
> }
> 
> might be valid (given sufficient smarts, not given at the moment), or
> the whole idea is shot?

The only thing that would work is

  void __rethrow_cancellation() { }

and then do something like

  if (get_cancelation_handler() == __rethrow_cancellation)
    _Unwind_Resume (current_exception);

in __cxa_end_catch.  Which seems kinda gross to me.

Keep in mind that __cancel_cancellation WILL NOT WORK without help from
and buy-in from the pthread library.  Which does not currently exist.


r~

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-15 22:52       ` Richard Henderson
@ 2003-12-15 22:54         ` Richard Henderson
  2003-12-15 23:05         ` Benjamin Kosnik
  1 sibling, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2003-12-15 22:54 UTC (permalink / raw)
  To: Benjamin Kosnik, jason, gcc, mark, drepper, jakub, ncm, dave,
	wekempf, fjh

I'd just like to add that yet another reason to go with 
explicit rethrows instead of implicit rethrows is that
the compiler expects that

	catch (...) { }

consumes all exceptions, and so will DCE EH cleanups for
objects in outer scopes of the same function.  Disabling
this optimization is almost certainly a bad idea.


r~

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-15 22:52       ` Richard Henderson
  2003-12-15 22:54         ` Richard Henderson
@ 2003-12-15 23:05         ` Benjamin Kosnik
  2003-12-16  0:04           ` Richard Henderson
  1 sibling, 1 reply; 74+ messages in thread
From: Benjamin Kosnik @ 2003-12-15 23:05 UTC (permalink / raw)
  To: Richard Henderson
  Cc: jason, gcc, mark, drepper, jakub, ncm, dave, wekempf, fjh


>The only thing that would work is
>
>  void __rethrow_cancellation() { }
>
>and then do something like
>
>  if (get_cancelation_handler() == __rethrow_cancellation)
>    _Unwind_Resume (current_exception);
>
>in __cxa_end_catch.  Which seems kinda gross to me.

Huh! So, it is possible.

Maybe this is gross to you, but this is pretty much the way the
terminate handler works.

FWIW, I don't think this is too bad, and at least it gives people options.

>Keep in mind that __cancel_cancellation WILL NOT WORK without help from
>and buy-in from the pthread library.  Which does not currently exist.

Perhaps you mean __continue_cancellation? What's needed from the
pthreads library to make this work?

-benjamin

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-15 20:29         ` Jason Merrill
@ 2003-12-15 23:34           ` David Abrahams
  2003-12-16  0:29             ` Mark Mitchell
  2003-12-16  0:52             ` Jason Merrill
  0 siblings, 2 replies; 74+ messages in thread
From: David Abrahams @ 2003-12-15 23:34 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Nathan Myers, gcc, Richard Henderson, Mark Mitchell,
	Ulrich Drepper, Benjamin Kosnik, Jakub Jelinek, wekempf, fjh

Jason Merrill <jason@redhat.com> writes:

> On Sat, 13 Dec 2003 19:59:09 -0800, Nathan Myers <ncm@cantrip.org> wrote:
>
>> On Sat, Dec 13, 2003 at 08:20:15AM -0500, David Abrahams wrote:
>>> Jason Merrill <jason@redhat.com> writes:
>>> 
>>> > On Fri, 12 Dec 2003 17:42:27 -0500, David Abrahams 
>>> >
>>> >> 2. There is some documentation somewhere which indicates that one of
>>> >>    the functions called by tf is a "cancellation point" (i.e. may
>>> >>    throw thread cancellation exceptions).  Otherwise, it seems to me,
>>> >>    "this high-level behavior" would not be wrong.
>>> >
>>> > Basically, all of the C library I/O functions are cancellation points.
>>> 
>>> Well, I constider that very surprising. It harms the ability to write
>>> portable code, for reasons explained below.
>>
>> Indeed, it's commmon to declare external C functions "throw()", meaning
>> no exceptions can ever come out of them, and expect the compiler to 
>> optimize accordingly.
>
> And g++ does.  I'm not sure at the moment what we do when a forced unwind
> tries to unwind through a throw(); things don't seem to be working
> properly on my laptop at the moment.  I suspect that we fall back on the
> old semantics, i.e. run explicitly pushed cleanups and kill the thread.
>
>>> > I don't expect writing 'cout << "."' to suppress thread cancellation.
>>> > Do you disagree that this is an extremely surprising side-effect?
>>> 
>>> Yes, I disagree that it's surprising.  I know that iostream operations
>>> won't throw unless you set badbit, and I therefore expect them not to
>>> throw.  
>
> Aha.  I didn't realize that the disagreement was so basic.
>
>> Not throwing is part of iostream's contract.  For the runtime system
>> to arbitrarily change that contract makes any code written to the old 
>> contract indeterminate and likely wrong.
>
> I don't see any such contract.
>
>   17.4.4.8  Restrictions on              [lib.res.on.exception.handling]
>        exception handling
>
> 2 None of the functions from the Standard  C  library  shall  report  an
>   error by throwing an exception,176) unless it calls a program-supplied
>   function that throws an exception.177)
>
> 3 No destructor operation defined in the C++ Standard Library will throw
>   an exception.  Any other functions defined in the C++ Standard Library
>   that  do not have an exception-specification may throw implementation-
>   defined  exceptions  unless otherwise specified.178)
>
> This passage seems to give the implementation the latitude to throw an
> implementation-defined exception from any of the iostream functions, since
> none of them are specified throw().

Of course they couldn't be specified that way, since they are
specified to have throwing behavior which can be turned on and off at
runtime.

I have to admit I am not familiar with the specification of iostreams
- in fact, I try to avoid getting familiar with that part of the
standard. I have been going on the assumption that the specification
of badbit handling counts as "otherwise specified".  If I am wrong
(and I may be) then I take it all back.  Am I?  

>>> Furthermore, throwing against the standard's guarantees undermines
>>> portability.  All code which can run in a cancellable thread now has
>>> to have special knowledge of the behavior of the system it's running
>>> on.  That could mean, for example, that people can't pick up the Boost
>>> libraries and use them inside of a thread.  This effect is bad with
>>> functions people don't *expect* to throw (the C I/O) but the standard
>>> does allow those to throw implementation-defined exceptions.  It's
>>> *really really* bad with functions the standard guarantees won't
>>> throw.
>
> Actually, this is backwards -- the standard doesn't allow the C I/O
> functions to throw any exceptions; see the passage above.  This obviously
> needs to change if we're going to do anything useful with POSIX thread
> cancellation.

Not sure what "anything useful" means.

>>> I think it's not the nature of the exception, but the fact that you're
>>> running in a thread which makes it "outside the scope", since the
>>> standard doesn't cover threading.  Still, the ability to use code in
>>> threads which was written without knowledge of your threading system,
>>> I would think, is crucial.
>
> Oh, I agree.  I'm just skeptical that iostream code throwing a cancellation
> exception would interfere with this ability.

That's reasonable.

>> The population of coders willing to write code just for this one
>> threading system is necessarily small.

Whoa; that was Nathan, not me.

> Which one?  POSIX threads?  I hear they're pretty widespread.  But
> seriously, we have a number of customers writing code for that threading
> system, and asking for this functionality.
>
>> This is a difference from the C world.  With C, no one expects a library 
>> to work right in a threaded program if it wasn't written with that target 
>> in mind.  Contrarily, C++ users routinely expect portable C++ libraries 
>> to be exception- and thread-safe, and an enormous amount of such code
>> has already been written that is.  Changing the semantics of exception 
>> handlers breaks it all.
>
> Nathan, you seem to assume that I'm advocating implicit rethrow.  I'm not.
> I'm only suggesting that cancellation should propagate out of iostream
> code, and suggested several ways that might happen.
>
> Both your and David's replies seem to have amounted to saying that any
> change to current behavior is unacceptable.

Not the way I understand the status quo.  As far as I can tell, what
was described as the current compromise (termination) is unacceptable
to me.  If I've misunderstood what you said I would be willing to
revise my position.

> That isn't very useful.  Just to step back a moment, can we all
> agree that we want pthread cancellation to run C++ cleanups?  

I think so.

> And that we might have to adjust a few things to make that work?

Yes.  The only things I think are crucial here is that functions which
are specified not to throw (or conditions which are specified not to
throw) continue to not throw anything, including cancellation, and
that whatever guarantees functions give about program state in case
they throw an exception also apply if the exception is a thread
cancellation.  Almost without exception (NPI), code that works in the
presence of exceptions does not depend on the meaning of said
exceptions, so giving cancellation exceptions any kind of special
license to violate assumptions made about other exceptions would be
wrong.

>> In the meantime, the ISO committee is discussing a standard threads
>> library for C++, including a cancellation model incompatible with what
>> is being proposed here.  It would be better for everybody involved for 
>> Gcc to match it.
>
> Please elaborate.  I don't see a relevant paper in any of the recent
> mailings.

There ain't nothin'.  The effort to standardize Boost.Threads has been
languishing :(

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-15 22:19           ` Richard Henderson
@ 2003-12-15 23:36             ` David Abrahams
  2003-12-16  0:08               ` Richard Henderson
  0 siblings, 1 reply; 74+ messages in thread
From: David Abrahams @ 2003-12-15 23:36 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Jason Merrill, gcc, Mark Mitchell, Ulrich Drepper,
	Benjamin Kosnik, Jakub Jelinek, ncm, wekempf, fjh

Richard Henderson <rth@redhat.com> writes:

> On Mon, Dec 15, 2003 at 12:20:18AM -0500, David Abrahams wrote:
>> > If you don't want to know about pthread_setcancelstate, then you should
>> > not use pthread_cancel either.  If you never use pthread_cancel, then
>> > none of this thread is even relevant.
>> 
>> I'm a library provider ;-)
>
> Then you have to either have to document that the library is
> not cancelation safe and point users at TFM when they don't
> read it, or expect pthread_cancel to be used and thus call
> pthread_setcancelstate appropriately.

Meaning that I have to know specifically about pthreads.  While I
agree that it's a widespread threading standard, I don't think that's
a good precedent to set.

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-15 23:05         ` Benjamin Kosnik
@ 2003-12-16  0:04           ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2003-12-16  0:04 UTC (permalink / raw)
  To: Benjamin Kosnik; +Cc: jason, gcc, mark, drepper, jakub, ncm, dave, wekempf, fjh

On Mon, Dec 15, 2003 at 04:55:57PM -0600, Benjamin Kosnik wrote:
> >Keep in mind that __cancel_cancellation WILL NOT WORK without help from
> >and buy-in from the pthread library.  Which does not currently exist.
> 
> Perhaps you mean __continue_cancellation?

Whatever.

> What's needed from the pthreads library to make this work?

You have to be able to say that the thread is no longer in pending
cancellation state.  Otherwise you'll never get re-cancelled.

POSIX allows a cancellation handler to call functions that are
cancellation points.  Which means that the library cannot just
re-raise the cancellation exception on the next call to write.


r~

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-15 23:36             ` David Abrahams
@ 2003-12-16  0:08               ` Richard Henderson
  0 siblings, 0 replies; 74+ messages in thread
From: Richard Henderson @ 2003-12-16  0:08 UTC (permalink / raw)
  To: David Abrahams
  Cc: Jason Merrill, gcc, Mark Mitchell, Ulrich Drepper,
	Benjamin Kosnik, Jakub Jelinek, ncm, wekempf, fjh

On Mon, Dec 15, 2003 at 06:34:00PM -0500, David Abrahams wrote:
> Meaning that I have to know specifically about pthreads.

Yes.

> While I agree that it's a widespread threading standard, I don't
> think that's a good precedent to set.

It's made unavoidable by the way pthreads has been defined.
You'll either have to ifdef or come up with some wrappers.
That's the nature of real-life portability...


r~

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-15 23:34           ` David Abrahams
@ 2003-12-16  0:29             ` Mark Mitchell
  2003-12-16  0:37               ` Ulrich Drepper
  2003-12-16  0:52             ` Jason Merrill
  1 sibling, 1 reply; 74+ messages in thread
From: Mark Mitchell @ 2003-12-16  0:29 UTC (permalink / raw)
  To: David Abrahams
  Cc: Jason Merrill, Nathan Myers, gcc, Richard Henderson,
	Ulrich Drepper, Benjamin Kosnik, Jakub Jelinek, wekempf, fjh


> > That isn't very useful.  Just to step back a moment, can we all
> > agree that we want pthread cancellation to run C++ cleanups?  
> 
> I think so.

Having cancellation result in throwing an exception seems reasonable.  

The only other plausible alternative is not unwinding the stack.

That does seem inferior, but I'm not sure it's as bad a choice as people
seem to think.  After all, you could always get SIGKILL, which might
leave resources lying around.  If pthread_cancel just killed the thread,
the remaining threads have the same problem that remaining process have
after one of their brethren is SIGKILL'd.

> > And that we might have to adjust a few things to make that work?
> 
> Yes.  The only things I think are crucial here is that functions which
> are specified not to throw (or conditions which are specified not to
> throw) continue to not throw anything, including cancellation, and
> that whatever guarantees functions give about program state in case
> they throw an exception also apply if the exception is a thread
> cancellation.  Almost without exception (NPI), code that works in the
> presence of exceptions does not depend on the meaning of said
> exceptions, so giving cancellation exceptions any kind of special
> license to violate assumptions made about other exceptions would be
> wrong.

I agree.

That is essentially what I argued the last time: we should just treat
cancellation like throwing an exception of a special type, and have an
implicit handler for it outside the first function called when the
thread was started.  This implicit handler would just terminate the
thread.

If the exception is caught, fine, the thread is not cancelled.  If the
exception causes the program to violate a throw spec, fine, the program
calls unexpected().

-- 
Mark Mitchell <mark@codesourcery.com>
CodeSourcery, LLC

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16  0:29             ` Mark Mitchell
@ 2003-12-16  0:37               ` Ulrich Drepper
  2003-12-16  1:42                 ` Zack Weinberg
                                   ` (2 more replies)
  0 siblings, 3 replies; 74+ messages in thread
From: Ulrich Drepper @ 2003-12-16  0:37 UTC (permalink / raw)
  To: mark
  Cc: David Abrahams, Jason Merrill, Nathan Myers, gcc,
	Richard Henderson, Benjamin Kosnik, Jakub Jelinek, wekempf, fjh

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


> If the exception is caught, fine, the thread is not cancelled.

No.  A canceled thread cannot continue.  Period.  There is no room for
discussion.

- -- 
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)

iD8DBQE/3lAJ2ijCOnn/RHQRAp/zAKCrx99JySjgzK/V5iYn6N3zhM7KSACfcCeD
YZ0fGeshiGwuusrZLNeT5s0=
=rBLZ
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-15 23:34           ` David Abrahams
  2003-12-16  0:29             ` Mark Mitchell
@ 2003-12-16  0:52             ` Jason Merrill
  2003-12-16 14:31               ` David Abrahams
  1 sibling, 1 reply; 74+ messages in thread
From: Jason Merrill @ 2003-12-16  0:52 UTC (permalink / raw)
  To: David Abrahams
  Cc: Nathan Myers, gcc, Richard Henderson, Mark Mitchell,
	Ulrich Drepper, Benjamin Kosnik, Jakub Jelinek, wekempf, fjh,
	Jason Merrill

On Mon, 15 Dec 2003 18:32:10 -0500, David Abrahams <dave@boost-consulting.com> wrote:

> Jason Merrill <jason@redhat.com> writes:
>
> I have to admit I am not familiar with the specification of iostreams
> - in fact, I try to avoid getting familiar with that part of the
> standard. I have been going on the assumption that the specification
> of badbit handling counts as "otherwise specified".  If I am wrong
> (and I may be) then I take it all back.  Am I?  

  27.6.1  Input streams                              [lib.input.streams]

2 Two  groups of member function signatures share common properties: the
  formatted input functions (or extractors) and  the  unformatted  input
  functions.  Both  groups  of input functions are described as if they
  obtain (or extract) input characters by calling  rdbuf()->sbumpc()  or
  rdbuf()->sgetc().  They may use other public members of istream.

3 If  rdbuf()->sbumpc()  or rdbuf()->sgetc() returns traits::eof(), then
  the input function, except as explicitly  noted  otherwise,  completes
  its    actions    and   does   setstate(eofbit),   which   may   throw
  ios_base::failure (_lib.iostate.flags_), before returning.

4 If one of these called functions  throws  an  exception,  then  unless
  explicitly  noted  otherwise,  the input function sets badbit in error
  state.  If badbit is on in exceptions(), the input  function  rethrows 
  the exception without  completing its  actions, otherwise  it does not
  throw anything and proceeds as if the called function had  returned  a
  failure indication.

The text for output streams is similar.  I note, though I concede that this
is something of a perverse reading of the standard, that although this says
that the functions don't rethrow, nothing precludes them from throwing
implementation-defined exceptions of their own.

Also, this restriction only applies to the {un,}formatted i/o functions,
not to any other operations.

I would like to loosen the passage quoted above to allow rethrowing some
exceptions as defined by the implementation.  I don't think this change
would break anyone's code, since the existing guarantee is so weak.

>> Actually, this is backwards -- the standard doesn't allow the C I/O
>> functions to throw any exceptions; see the passage above.  This obviously
>> needs to change if we're going to do anything useful with POSIX thread
>> cancellation.

> Not sure what "anything useful" means.

If all of the cancellation points are throw(), the cancellation exception
can't propagate, so we can't run any cleanups.  Which isn't very useful.

>> Both your and David's replies seem to have amounted to saying that any
>> change to current behavior is unacceptable.
>
> Not the way I understand the status quo.  As far as I can tell, what
> was described as the current compromise (termination) is unacceptable
> to me.  If I've misunderstood what you said I would be willing to
> revise my position.

To clarify, by "current behavior" I meant the C++ standard.

I certainly don't see the termination compromise as The Right Thing.  It's
just that in the previous discussion, we failed to reach agreement as to
what ought to happen when a catch(...) block doesn't rethrow a cancellation
exception.  Termination makes nobody happy, but it means that any eventual
resolution is a pure extension; nobody has written code that will break
when the semantics change.

>> And that we might have to adjust a few things to make that work?
>
> Yes.  The only things I think are crucial here is that functions which
> are specified not to throw (or conditions which are specified not to
> throw) continue to not throw anything, including cancellation, and
> that whatever guarantees functions give about program state in case
> they throw an exception also apply if the exception is a thread
> cancellation.  Almost without exception (NPI), code that works in the
> presence of exceptions does not depend on the meaning of said
> exceptions, so giving cancellation exceptions any kind of special
> license to violate assumptions made about other exceptions would be
> wrong.

I am sympathetic to this position.

>>> In the meantime, the ISO committee is discussing a standard threads
>>> library for C++, including a cancellation model incompatible with what
>>> is being proposed here.  It would be better for everybody involved for 
>>> Gcc to match it.
>>
>> Please elaborate.  I don't see a relevant paper in any of the recent
>> mailings.
>
> There ain't nothin'.  The effort to standardize Boost.Threads has been
> languishing :(

Well, can either of you give a brief sketch of the Boost.Threads
cancellation model?  Has David Butenhof been involved at all?  He seems to
have been thinking about the interaction of threads and exceptions longer
than anyone else.

Jason

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16  0:37               ` Ulrich Drepper
@ 2003-12-16  1:42                 ` Zack Weinberg
  2003-12-16  1:52                   ` Zack Weinberg
  2003-12-16  2:18                   ` Ulrich Drepper
  2003-12-16 10:16                 ` Nathan Myers
  2003-12-16 14:07                 ` David Abrahams
  2 siblings, 2 replies; 74+ messages in thread
From: Zack Weinberg @ 2003-12-16  1:42 UTC (permalink / raw)
  To: Ulrich Drepper
  Cc: mark, David Abrahams, Jason Merrill, Nathan Myers, gcc,
	Richard Henderson, Benjamin Kosnik, Jakub Jelinek, wekempf, fjh

Ulrich Drepper <drepper@redhat.com> writes:

>> If the exception is caught, fine, the thread is not cancelled.
>
> No.  A canceled thread cannot continue.  Period.  There is no room for
> discussion.

You have said this repeatedly and you have never explained why.

zw

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16  1:42                 ` Zack Weinberg
@ 2003-12-16  1:52                   ` Zack Weinberg
  2003-12-16  2:18                   ` Ulrich Drepper
  1 sibling, 0 replies; 74+ messages in thread
From: Zack Weinberg @ 2003-12-16  1:52 UTC (permalink / raw)
  To: Ulrich Drepper
  Cc: mark, David Abrahams, Jason Merrill, Nathan Myers, gcc,
	Richard Henderson, Benjamin Kosnik, Jakub Jelinek, wekempf, fjh

Ulrich Drepper <drepper@redhat.com> writes:

>> If the exception is caught, fine, the thread is not cancelled.
>
> No.  A canceled thread cannot continue.  Period.  There is no room for
> discussion.

You have said this repeatedly and you have never explained why.

zw

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16  2:18                   ` Ulrich Drepper
@ 2003-12-16  2:04                     ` Zack Weinberg
  2003-12-16  5:53                       ` Jim Wilson
  0 siblings, 1 reply; 74+ messages in thread
From: Zack Weinberg @ 2003-12-16  2:04 UTC (permalink / raw)
  To: Ulrich Drepper
  Cc: mark, David Abrahams, Jason Merrill, Nathan Myers, gcc,
	Richard Henderson, Benjamin Kosnik, Jakub Jelinek, wekempf, fjh

Ulrich Drepper <drepper@redhat.com> writes:

> Zack Weinberg wrote:
>
>> You have said this repeatedly and you have never explained why.
>
> Then you haven't really read what I wrote.

Please either explain it again or provide a pointer to your previous
explanation, because I never saw it.

zw

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16  1:42                 ` Zack Weinberg
  2003-12-16  1:52                   ` Zack Weinberg
@ 2003-12-16  2:18                   ` Ulrich Drepper
  2003-12-16  2:04                     ` Zack Weinberg
  1 sibling, 1 reply; 74+ messages in thread
From: Ulrich Drepper @ 2003-12-16  2:18 UTC (permalink / raw)
  To: Zack Weinberg
  Cc: mark, David Abrahams, Jason Merrill, Nathan Myers, gcc,
	Richard Henderson, Benjamin Kosnik, Jakub Jelinek, wekempf, fjh

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Zack Weinberg wrote:

> You have said this repeatedly and you have never explained why.

Then you haven't really read what I wrote.

- -- 
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)

iD8DBQE/3l5S2ijCOnn/RHQRArYpAKCw58CTEH5o8GZ4Ty5Q+n2HHeWcoQCcDuX+
gRKdFguexvyxkudT7pl0Zyc=
=RVmG
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16  2:04                     ` Zack Weinberg
@ 2003-12-16  5:53                       ` Jim Wilson
  2003-12-16  7:46                         ` Zack Weinberg
  0 siblings, 1 reply; 74+ messages in thread
From: Jim Wilson @ 2003-12-16  5:53 UTC (permalink / raw)
  To: gcc

Zack Weinberg wrote:
> Please either explain it again or provide a pointer to your previous
> explanation, because I never saw it.

The earlier thread was in gcc-patches April 30-May 1.  See for instance
   http://gcc.gnu.org/ml/gcc-patches/2003-04/msg02284.html
   http://gcc.gnu.org/ml/gcc-patches/2003-05/msg00016.html
   http://gcc.gnu.org/ml/gcc-patches/2003-05/msg00055.html
There are also other relevant messages in this thread.
-- 
Jim Wilson, GNU Tools Support, http://www.SpecifixInc.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16  5:53                       ` Jim Wilson
@ 2003-12-16  7:46                         ` Zack Weinberg
  0 siblings, 0 replies; 74+ messages in thread
From: Zack Weinberg @ 2003-12-16  7:46 UTC (permalink / raw)
  To: gcc

Jim Wilson <wilson@specifixinc.com> writes:

> Zack Weinberg wrote:
>> Please either explain it again or provide a pointer to your previous
>> explanation, because I never saw it.
>
> The earlier thread was in gcc-patches April 30-May 1.  See for instance
>    http://gcc.gnu.org/ml/gcc-patches/2003-04/msg02284.html
>    http://gcc.gnu.org/ml/gcc-patches/2003-05/msg00016.html
>    http://gcc.gnu.org/ml/gcc-patches/2003-05/msg00055.html
> There are also other relevant messages in this thread.

Thanks.  My summary:

1) Everyone - absolutely everyone - who knows anything about C++
   agrees that the sane semantic is for a catch(...) that does not
   rethrow to intercept and discard a pthread_cancel() operation.

1a) These same people also suspect it would be a good idea for
    pthread_cancel to throw a real live C++ exception, with a name,
    that can be caught explicitly.  But they want to think about that
    a bit more before implementing it.

2) William Kempf (who is one of the people mentioned in (1)) pointed
   to Tru64 UNIX as an example of an operating system that implements
   this semantic, and also gave an argument that this is also the
   correct semantic per POSIX.1-2001.
     [http://gcc.gnu.org/ml/gcc-patches/2003-05/msg00211.html]

3) Ulrich Drepper insists that libpthread cannot implement this
   semantic and still operate correctly in all circumstances.  His
   statement is, I emphasize, one of possibility: he says it can't be
   done, not that he won't do it.

I do not think re-hashing the previous argument is useful.  Instead, I
suggest we call for volunteers to design patches to libgcc and glibc's
libpthread which will implement the desired semantic, and therefore
disprove (3).  If it does turn out to be impossible, fine.  If it
is possible, then we can have an argument about whether the patches
get into glibc, which is at least progress.

zw

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16  0:37               ` Ulrich Drepper
  2003-12-16  1:42                 ` Zack Weinberg
@ 2003-12-16 10:16                 ` Nathan Myers
  2003-12-16 11:55                   ` Ulrich Drepper
  2003-12-16 14:07                 ` David Abrahams
  2 siblings, 1 reply; 74+ messages in thread
From: Nathan Myers @ 2003-12-16 10:16 UTC (permalink / raw)
  To: Ulrich Drepper
  Cc: mark, David Abrahams, Jason Merrill, gcc, Richard Henderson,
	Benjamin Kosnik, Jakub Jelinek, wekempf, fjh

On Mon, Dec 15, 2003 at 04:21:29PM -0800, Ulrich Drepper wrote:
> No.  A canceled thread cannot continue.  Period.  There is no room for
> discussion.

Ulrich, what you are describing is SIGKILL.  If _any_ cleanup code
is to run, the thread really is continuing, at least for a while.  
That means that the details of what happens as the code runs matter.  
We need for those details to be consistent with language semantics 
that existing code (at least some existing code, as we'll see) 
depends upon.  

Main programs can be assumed to know they're running under special
circumstances.  They can be required to have set up any environment
details that matter, and to be coded peculiarly to accommodate 
oddities in runtime behavior.  For a library, it's different.  A 
third-party library cannot set environment details.  In any case, 
it doesn't know enough about the threading regime it's running in
to set them properly.

If threading makes language semantics too different, then threaded
programs that might include cancellation can't use libraries.  The
universe of programs that can practically be written without using
libraries is very small indeed.

Our task is to discover an accommodation so that libraries can 
do the Right Thing without knowing whether they are in a thread
that has been, or might be, cancelled.  We can demand almost 
anything of the main program to make that possible.  This is 
familiar territory; thread-safety and exception-safety discipline
are well-known to competent library coders.  

As an example of an accommodation, most C++ libraries don't call C 
code directly.  However, they often call back into user-supplied code 
that itself might call C functions, which might be cancellation points.
It might be OK for a cancellation-safe library not to be allowed to
call external C code directly, and require instead that the main
program provide wrappers for any code that might hit a cancellation
point.

The alternative to discovering an accommodation for libraries is to
announce that you have made a thread cancellation apparatus that is 
incompatible with C++, or with C++ libraries.  If that's where we end 
up, that's also where we started.  If thread cancellation is useful 
at all, we need to figure out under what limitations it can safely 
be used, and design the semantics we control to ensure that those 
limitations are minimal, or at least reasonable.

Nathan Myers
ncm@cantrip.org

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16 10:16                 ` Nathan Myers
@ 2003-12-16 11:55                   ` Ulrich Drepper
  0 siblings, 0 replies; 74+ messages in thread
From: Ulrich Drepper @ 2003-12-16 11:55 UTC (permalink / raw)
  To: Nathan Myers
  Cc: mark, David Abrahams, Jason Merrill, gcc, Richard Henderson,
	Benjamin Kosnik, Jakub Jelinek, wekempf, fjh

Nathan Myers wrote:

> Ulrich, what you are describing is SIGKILL. 

Come back when you know something about this topic.

-- 
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16  0:37               ` Ulrich Drepper
  2003-12-16  1:42                 ` Zack Weinberg
  2003-12-16 10:16                 ` Nathan Myers
@ 2003-12-16 14:07                 ` David Abrahams
  2 siblings, 0 replies; 74+ messages in thread
From: David Abrahams @ 2003-12-16 14:07 UTC (permalink / raw)
  To: Ulrich Drepper
  Cc: mark, Jason Merrill, Nathan Myers, gcc, Richard Henderson,
	Benjamin Kosnik, Jakub Jelinek, wekempf, fjh

Ulrich Drepper <drepper@redhat.com> writes:

>> If the exception is caught, fine, the thread is not cancelled.
>
> No.  A canceled thread cannot continue.  Period.  

I suppose you realize that Mr. Butenhof takes a different position on
this?

> There is no room for discussion.

Then what are you doing here?

Of course I mean that (somewhat) facetiously, but saying "there's no
room for discussion" is unproductive and bordering on the ridiculous.
Discussion is what we're here to do.  If you can't or won't explain
yourself so that the rest of us can understand you, what's the point
in posting at all?

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16  0:52             ` Jason Merrill
@ 2003-12-16 14:31               ` David Abrahams
  2003-12-16 20:07                 ` Matt Austern
  2003-12-16 20:57                 ` Jason Merrill
  0 siblings, 2 replies; 74+ messages in thread
From: David Abrahams @ 2003-12-16 14:31 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Nathan Myers, gcc, Richard Henderson, Mark Mitchell,
	Ulrich Drepper, Benjamin Kosnik, Jakub Jelinek, wekempf, fjh,
	William Kempf

Jason Merrill <jason@redhat.com> writes:

> On Mon, 15 Dec 2003 18:32:10 -0500, David Abrahams <dave@boost-consulting.com> wrote:
>
>> Jason Merrill <jason@redhat.com> writes:
>>
>> I have to admit I am not familiar with the specification of iostreams
>> - in fact, I try to avoid getting familiar with that part of the
>> standard. I have been going on the assumption that the specification
>> of badbit handling counts as "otherwise specified".  If I am wrong
>> (and I may be) then I take it all back.  Am I?  
>
>   27.6.1  Input streams                              [lib.input.streams]
>
> 2 Two  groups of member function signatures share common properties: the
>   formatted input functions (or extractors) and  the  unformatted  input
>   functions.  Both  groups  of input functions are described as if they
>   obtain (or extract) input characters by calling  rdbuf()->sbumpc()  or
>   rdbuf()->sgetc().  They may use other public members of istream.
>
> 3 If  rdbuf()->sbumpc()  or rdbuf()->sgetc() returns traits::eof(), then
>   the input function, except as explicitly  noted  otherwise,  completes
>   its    actions    and   does   setstate(eofbit),   which   may   throw
>   ios_base::failure (_lib.iostate.flags_), before returning.
>
> 4 If one of these called functions  throws  an  exception,  then  unless
>   explicitly  noted  otherwise,  the input function sets badbit in error
>   state.  If badbit is on in exceptions(), the input  function  rethrows 
>   the exception without  completing its  actions, otherwise  it does not
>   throw anything and proceeds as if the called function had  returned  a
>   failure indication.
>
> The text for output streams is similar.  I note, though I concede that this
> is something of a perverse reading of the standard, that although this says
> that the functions don't rethrow, nothing precludes them from throwing
> implementation-defined exceptions of their own.

I think that's beyond perverse.  The language is clear: "otherwise it
does not throw anything".  That precludes any throwing whatsoever,
unless of course I've misread that text and paragraph 4 is only
describing one corner of the behavior while exceptions are allowed to
escape under other conditions.

> Also, this restriction only applies to the {un,}formatted i/o functions,
> not to any other operations.
>
> I would like to loosen the passage quoted above to allow rethrowing some
> exceptions as defined by the implementation.  I don't think this change
> would break anyone's code, since the existing guarantee is so weak.

I don't think that's a safe conclusion.  There's plenty of legacy code
which acts as though there is no such thing as an exception.  You can
pretty much do all the iostream-ing you want under that assumption,
since they are handed to you out of the box in that state.  One
obvious place output streaming might be done is in an object's
destructor, for logging purposes.  It seems entirely plausible that
people might scatter local objects throughout throughout functions in
order to do tracing.  If thread cancellation is picked up by an output
streaming call in a destructor during unwinding, we'll go directly to
terminate (boom).

>>> Actually, this is backwards -- the standard doesn't allow the C I/O
>>> functions to throw any exceptions; see the passage above.  This obviously
>>> needs to change if we're going to do anything useful with POSIX thread
>>> cancellation.
>
>> Not sure what "anything useful" means.
>
> If all of the cancellation points are throw(), 

well, then they're not cancellation points anymore, are they?

> the cancellation exception can't propagate, so we can't run any
> cleanups.  Which isn't very useful.

It's obvious that unwinding due to cancellation has to be possible.
[I presume there's a function people can call to explicitly induce
unwinding when the thread is cancelled?]  The question is whether it's
appropriate to force unwinding in this one particular case where users
have been given license to assume there will be none.

> I certainly don't see the termination compromise as The Right Thing.  It's
> just that in the previous discussion, we failed to reach agreement as to
> what ought to happen when a catch(...) block doesn't rethrow a cancellation
> exception.  Termination makes nobody happy, but it means that any eventual
> resolution is a pure extension; nobody has written code that will break
> when the semantics change.

Makes sense now that you explain it.

>>> And that we might have to adjust a few things to make that work?
>>
>> Yes.  The only things I think are crucial here is that functions which
>> are specified not to throw (or conditions which are specified not to
>> throw) continue to not throw anything, including cancellation, and
>> that whatever guarantees functions give about program state in case
>> they throw an exception also apply if the exception is a thread
>> cancellation.  Almost without exception (NPI), code that works in the
>> presence of exceptions does not depend on the meaning of said
>> exceptions, so giving cancellation exceptions any kind of special
>> license to violate assumptions made about other exceptions would be
>> wrong.
>
> I am sympathetic to this position.
>
>>>> In the meantime, the ISO committee is discussing a standard threads
>>>> library for C++, including a cancellation model incompatible with what
>>>> is being proposed here.  It would be better for everybody involved for 
>>>> Gcc to match it.
>>>
>>> Please elaborate.  I don't see a relevant paper in any of the recent
>>> mailings.
>>
>> There ain't nothin'.  The effort to standardize Boost.Threads has been
>> languishing :(
>
> Well, can either of you give a brief sketch of the Boost.Threads
> cancellation model?  

I'm afraid http://www.boost.org/libs/thread/doc/faq.html#question8 is
all I can offer, which isn't much help.  The reason it's been
languishing is that the author/maintainer seems to have evaporated,
so I don't know if we'll be able to find out much more, but I've
cc:'d him.

> Has David Butenhof been involved at all?  He seems to have been
> thinking about the interaction of threads and exceptions longer than
> anyone else.

Yes, though not directly.  Bill Kempf (the Boost.Threads guy)
communicated with him and extensively read his writings on the subject
before he vaporized.  My understanding, from everything I've read, is
that David Butenhof believes that *any* asynchronous (forced, not
under user control) cancellation model is wrong.  IIRC there's
something like that in pthreads and he regrets it.  But rather than
speaking for him, I should let him speak for himself.

  http://tinyurl.com/zg5d

Plus, we can ask him questions.  He's quite approachable, I've found.

The one place I have to pre-emptively disagree with him is (from the
first link):

   "NOBODY has any business "finalizing" (catching and not 
    releasing) an exception they don't know by name. If you can't identify the 
    exception, you can't know why it was raised or what it means. And if you 
    don't understand what it means, you cannot possibly know that it doesn't 
    need to be handled further down the stack."

Not all code is exception-safe, and not all languages can handle C++
exceptions.  At the boundaries between exception-safe code and
everything else, catch(...) is appropriate.

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16 14:31               ` David Abrahams
@ 2003-12-16 20:07                 ` Matt Austern
  2003-12-16 20:31                   ` David Abrahams
  2003-12-18 16:48                   ` Jamie Lokier
  2003-12-16 20:57                 ` Jason Merrill
  1 sibling, 2 replies; 74+ messages in thread
From: Matt Austern @ 2003-12-16 20:07 UTC (permalink / raw)
  To: David Abrahams
  Cc: Jason Merrill, Ulrich Drepper, gcc, Richard Henderson,
	Nathan Myers, Jakub Jelinek, wekempf, Mark Mitchell, fjh,
	Benjamin Kosnik, William Kempf

On Dec 16, 2003, at 4:23 AM, David Abrahams wrote:

> Yes, though not directly.  Bill Kempf (the Boost.Threads guy)
> communicated with him and extensively read his writings on the subject
> before he vaporized.  My understanding, from everything I've read, is
> that David Butenhof believes that *any* asynchronous (forced, not
> under user control) cancellation model is wrong.

It's quite true that he thinks asynchronous cancellation is 
hard/impossible
to use reliably.  You can see that in sectiom 5.3.2 of his very clearly
written book.

But we aren't talking about asynchronous cancellation.  We're talking
about deferred cancellation, which means that the thread may be
cancelled at any cancellation point.  POSIX requires a number of
functions (such as read, write, open, and close) to be cancellation
points, and allows but does not require a number of others (such as
fread, fwrite, and putc).

Deferred cancallation is scary enough, because it means that
most interesting C library functions or system calls may be cancellation
points.  Asynchronous cancellation is *really* scary: it means that
literally anything may be a cancellation point, that you can get thread
cancellation even in a tight loop that does nothing but arithmetic.  
That's
why David Butenhof thinks that using asynchronous cancellation is
nearly always a mistake, and why I'm inclined to agree with him.

Note that it's possible to temporarily disable thread cancellation in
critical regions of code.  It might be appropriate for glibc and/or
libstdc++ to do that.  On the other hand, we'll have to think carefully
about standard conformance if we do something like that.

			--Matt

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16 20:07                 ` Matt Austern
@ 2003-12-16 20:31                   ` David Abrahams
  2003-12-16 21:50                     ` Matt Austern
  2003-12-18 16:48                   ` Jamie Lokier
  1 sibling, 1 reply; 74+ messages in thread
From: David Abrahams @ 2003-12-16 20:31 UTC (permalink / raw)
  To: Matt Austern
  Cc: Jason Merrill, Ulrich Drepper, gcc, Richard Henderson,
	Nathan Myers, Jakub Jelinek, wekempf, Mark Mitchell, fjh,
	Benjamin Kosnik, William Kempf

Matt Austern <austern@apple.com> writes:

> On Dec 16, 2003, at 4:23 AM, David Abrahams wrote:
>
>> Yes, though not directly.  Bill Kempf (the Boost.Threads guy)
>> communicated with him and extensively read his writings on the subject
>> before he vaporized.  My understanding, from everything I've read, is
>> that David Butenhof believes that *any* asynchronous (forced, not
>> under user control) cancellation model is wrong.
>
> It's quite true that he thinks asynchronous cancellation is
> hard/impossible to use reliably.  You can see that in sectiom 5.3.2
> of his very clearly written book.
>
> But we aren't talking about asynchronous cancellation.  We're talking
> about deferred cancellation, which means that the thread may be
> cancelled at any cancellation point.  

I'm sorry, I was using a shorthand.  Let me be clear: a cancellation
exception which propagates from a function which is specified not to
throw is the "moral equivalent" of an async exception.  The reason
async exceptions are hard/impossible to use reliably is that
exceptions crop up in regions of code that would normally be nothrow.

> Note that it's possible to temporarily disable thread cancellation in
> critical regions of code.  It might be appropriate for glibc and/or
> libstdc++ to do that.  On the other hand, we'll have to think carefully
> about standard conformance if we do something like that.

Yeah, that idiom is, again, a library-killer.  It requires portable
library authors to be aware of pthreads and insert disablers.

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16 14:31               ` David Abrahams
  2003-12-16 20:07                 ` Matt Austern
@ 2003-12-16 20:57                 ` Jason Merrill
  2003-12-16 21:55                   ` David Abrahams
  2003-12-17  0:32                   ` Jason Merrill
  1 sibling, 2 replies; 74+ messages in thread
From: Jason Merrill @ 2003-12-16 20:57 UTC (permalink / raw)
  To: David Abrahams
  Cc: Nathan Myers, gcc, Richard Henderson, Mark Mitchell,
	Ulrich Drepper, Benjamin Kosnik, Jakub Jelinek, wekempf, fjh,
	William Kempf, Jason Merrill

On Tue, 16 Dec 2003 07:23:05 -0500, David Abrahams <dave@boost-consulting.com> wrote:

> Jason Merrill <jason@redhat.com> writes:

>> The text for output streams is similar.  I note, though I concede that this
>> is something of a perverse reading of the standard, that although this says
>> that the functions don't rethrow, nothing precludes them from throwing
>> implementation-defined exceptions of their own.
>
> I think that's beyond perverse.  The language is clear: "otherwise it
> does not throw anything".  That precludes any throwing whatsoever,
> unless of course I've misread that text and paragraph 4 is only
> describing one corner of the behavior while exceptions are allowed to
> escape under other conditions.

That is my interpretation; I think that it only describes what happens when
one of the called functions throws.

>> Also, this restriction only applies to the {un,}formatted i/o functions,
>> not to any other operations.

Any response to this point?

>> I would like to loosen the passage quoted above to allow rethrowing some
>> exceptions as defined by the implementation.  I don't think this change
>> would break anyone's code, since the existing guarantee is so weak.
>
> I don't think that's a safe conclusion.  There's plenty of legacy code
> which acts as though there is no such thing as an exception.  You can
> pretty much do all the iostream-ing you want under that assumption,
> since they are handed to you out of the box in that state.  One
> obvious place output streaming might be done is in an object's
> destructor, for logging purposes.  It seems entirely plausible that
> people might scatter local objects throughout throughout functions in
> order to do tracing.  If thread cancellation is picked up by an output
> streaming call in a destructor during unwinding, we'll go directly to
> terminate (boom).

Yes, that's a significant issue; this would mean people need to be even
more careful about what they do in a destructor, perhaps to the point of
disabling cancellation while the destructor is running.

>>>> Actually, this is backwards -- the standard doesn't allow the C I/O
>>>> functions to throw any exceptions; see the passage above.  This obviously
>>>> needs to change if we're going to do anything useful with POSIX thread
>>>> cancellation.
>>
>>> Not sure what "anything useful" means.
>>
>> If all of the cancellation points are throw(), 
>
> well, then they're not cancellation points anymore, are they?

Yes, the set of cancellation points is defined by POSIX.  Cancellation will
happen regardless of whether or not C++ cleanups are run.  And I believe
that sometimes silently ignoring cleanups is worse than sometimes calling
terminate.

>> the cancellation exception can't propagate, so we can't run any
>> cleanups.  Which isn't very useful.
>
> It's obvious that unwinding due to cancellation has to be possible.
> [I presume there's a function people can call to explicitly induce
> unwinding when the thread is cancelled?]

Yes, pthread_testcancel.  A C++ program that wants (or needs) explicit
control over where cancellation will happen can

  pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);

in the thread startup function and

  pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
  pthread_testcancel ();
  pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);

to allow cancellation.  But as you say, this requires explicit handling and
most exception-safe code should also be thread-safe, so we want to find the
default behavior which will be most useful.

> The question is whether it's appropriate to force unwinding in this one
> particular case where users have been given license to assume there will
> be none.

I believe that is the least bad solution.

>> Has David Butenhof been involved at all?  He seems to have been
>> thinking about the interaction of threads and exceptions longer than
>> anyone else.
>
> Yes, though not directly.  Bill Kempf (the Boost.Threads guy)
> communicated with him and extensively read his writings on the subject
> before he vaporized.  My understanding, from everything I've read, is
> that David Butenhof believes that *any* asynchronous (forced, not
> under user control) cancellation model is wrong.  IIRC there's
> something like that in pthreads and he regrets it.

I think everyone agrees that asynchronous cancellation is bad and wrong.
We're only talking about synchronous (PTHREAD_CANCEL_DEFERRED) cancellation
here, whereby cancellation occurs only at certain defined cancellation
points.

> But rather than speaking for him, I should let him speak for himself.
>
>   http://tinyurl.com/zg5d
>
> Plus, we can ask him questions.  He's quite approachable, I've found.
>
> The one place I have to pre-emptively disagree with him is (from the
> first link):
>
>    "NOBODY has any business "finalizing" (catching and not 
>     releasing) an exception they don't know by name. If you can't identify the 
>     exception, you can't know why it was raised or what it means. And if you 
>     don't understand what it means, you cannot possibly know that it doesn't 
>     need to be handled further down the stack."
>
> Not all code is exception-safe, and not all languages can handle C++
> exceptions.  At the boundaries between exception-safe code and
> everything else, catch(...) is appropriate.

Perhaps, but it's not clear to me that this is a justification for the use
in iostreams.

I think it's important to understand that, contrary to Bill's post

  http://gcc.gnu.org/ml/gcc-patches/2003-05/msg00211.html

the POSIX standard does not allow cancellation to be deferred again once
the request is acted upon; it states that each of the handlers are run, and
then the thread exits.  Allowing a catch block to finalize a cancellation
exception would be an extension to the POSIX semantics.

That said, Butenhof's postings certainly suggest that he thinks that this
is an appropriate extension:

  http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=3B03B13A.D4796297%40compaq.com

  You cannot "catch" a cancel and continue. That would require a full
  exception model, which was beyond the scope of POSIX. However,
  POSIX cancellation was loosely based on an implementation that did use
  exceptions, and an ideal/complete/"philosophically correct"
  implementation of POSIX cancellation will be based on exceptions. On
  such a system, you can use non-standard mechanisms to "finalize" a
  cancellation exception and continue. For example, you should be able to
  enclose your do_something_with_pthread_testcancel() in a C++
  try/catch(...) block, and "return 1" from the catch.

  That's almost always a bad idea, though, since cancellation is designed
  to cleanly terminate a thread; you shouldn't be using it this way.
  That's especially true where your function may be called in a thread
  someone else created. Only the CREATOR should ever cancel a thread; and
  then your code will be foiling the legitimate intent of the thread's
  creator to terminate it. You should cleanup on a cancel and then allow
  it to propagate.

I agree completely with this, both that catch(...) should finalize a
cancellation and that it should almost never be used that way--in
particular, that it should not be used that way in iostreams.

The other cases of forced unwind are less clear.  It's pretty obvious that
finalizing a cancellation exception would simply cause the cancellation to
be deferred until the next cancellation point.  But what would it mean to
finalize a pthread_exit exception?  And though we could argue that a
cancellation request isn't urgent, since it is already deferred until the
next cancellation point, that's hard to justify for pthread_exit.  Harder
yet for longjmp_unwind.

Does anyone have a Tru64 system with the Compaq C++ compiler installed?

Benjamin: Pending a resolution of these issues, I suggest that we work
around the problem by disabling cancellation in the iostream try blocks.
I'm playing with this now.

Jason

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16 20:31                   ` David Abrahams
@ 2003-12-16 21:50                     ` Matt Austern
  2003-12-16 22:49                       ` David Abrahams
  0 siblings, 1 reply; 74+ messages in thread
From: Matt Austern @ 2003-12-16 21:50 UTC (permalink / raw)
  To: David Abrahams
  Cc: Jason Merrill, Ulrich Drepper, gcc, Richard Henderson,
	Nathan Myers, Jakub Jelinek, wekempf, Mark Mitchell, fjh,
	Benjamin Kosnik, William Kempf

On Dec 16, 2003, at 12:05 PM, David Abrahams wrote:

> Matt Austern <austern@apple.com> writes:
>
>> On Dec 16, 2003, at 4:23 AM, David Abrahams wrote:
>>
>>> Yes, though not directly.  Bill Kempf (the Boost.Threads guy)
>>> communicated with him and extensively read his writings on the 
>>> subject
>>> before he vaporized.  My understanding, from everything I've read, is
>>> that David Butenhof believes that *any* asynchronous (forced, not
>>> under user control) cancellation model is wrong.
>>
>> It's quite true that he thinks asynchronous cancellation is
>> hard/impossible to use reliably.  You can see that in sectiom 5.3.2
>> of his very clearly written book.
>>
>> But we aren't talking about asynchronous cancellation.  We're talking
>> about deferred cancellation, which means that the thread may be
>> cancelled at any cancellation point.
>
> I'm sorry, I was using a shorthand.  Let me be clear: a cancellation
> exception which propagates from a function which is specified not to
> throw is the "moral equivalent" of an async exception.  The reason
> async exceptions are hard/impossible to use reliably is that
> exceptions crop up in regions of code that would normally be nothrow.

Yep, I appreciate your point.  I just wanted to make the distinction 
clear
for those who weren't familiar with pthreads, especially since we were
talking about David Butenhof's opinion.  He's very clear that he thinks
asynchronous cancelation (in the technical POSIX sense) is an evil
feature, but I haven't seen anything to suggest that he feels that way
about deferred cancellation.

I recommend his book, by the way, _Programming with POSIX
Threads_.

			--Matt

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16 20:57                 ` Jason Merrill
@ 2003-12-16 21:55                   ` David Abrahams
  2003-12-17  0:32                   ` Jason Merrill
  1 sibling, 0 replies; 74+ messages in thread
From: David Abrahams @ 2003-12-16 21:55 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Nathan Myers, gcc, Richard Henderson, Mark Mitchell,
	Ulrich Drepper, Benjamin Kosnik, Jakub Jelinek, wekempf, fjh,
	William Kempf

Jason Merrill <jason@redhat.com> writes:

> Does anyone have a Tru64 system with the Compaq C++ compiler installed?

I have access to one; I can run a test program there if it helps.

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16 21:50                     ` Matt Austern
@ 2003-12-16 22:49                       ` David Abrahams
  2003-12-16 23:44                         ` Matt Austern
  0 siblings, 1 reply; 74+ messages in thread
From: David Abrahams @ 2003-12-16 22:49 UTC (permalink / raw)
  To: Matt Austern
  Cc: Jason Merrill, Ulrich Drepper, gcc, Richard Henderson,
	Nathan Myers, Jakub Jelinek, wekempf, Mark Mitchell, fjh,
	Benjamin Kosnik, William Kempf

Matt Austern <austern@apple.com> writes:

> On Dec 16, 2003, at 12:05 PM, David Abrahams wrote:
>
>> Matt Austern <austern@apple.com> writes:
>>
>>> On Dec 16, 2003, at 4:23 AM, David Abrahams wrote:
>>>
>>>> Yes, though not directly.  Bill Kempf (the Boost.Threads guy)
>>>> communicated with him and extensively read his writings on the
>>>> subject
>>>> before he vaporized.  My understanding, from everything I've read, is
>>>> that David Butenhof believes that *any* asynchronous (forced, not
>>>> under user control) cancellation model is wrong.
>>>
>>> It's quite true that he thinks asynchronous cancellation is
>>> hard/impossible to use reliably.  You can see that in sectiom 5.3.2
>>> of his very clearly written book.
>>>
>>> But we aren't talking about asynchronous cancellation.  We're talking
>>> about deferred cancellation, which means that the thread may be
>>> cancelled at any cancellation point.
>>
>> I'm sorry, I was using a shorthand.  Let me be clear: a cancellation
>> exception which propagates from a function which is specified not to
>> throw is the "moral equivalent" of an async exception.  The reason
>> async exceptions are hard/impossible to use reliably is that
>> exceptions crop up in regions of code that would normally be nothrow.
>
> Yep, I appreciate your point.  I just wanted to make the distinction
> clear
> for those who weren't familiar with pthreads, especially since we were
> talking about David Butenhof's opinion.  He's very clear that he thinks
> asynchronous cancelation (in the technical POSIX sense) is an evil
> feature, but I haven't seen anything to suggest that he feels that way
> about deferred cancellation.

Right.  Nothing at all wrong with deferred cancellation per say.
Deferred cancellation good; violating contracts bad.

> I recommend his book, by the way, _Programming with POSIX
> Threads_.

Got it.

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16 22:49                       ` David Abrahams
@ 2003-12-16 23:44                         ` Matt Austern
  2003-12-17  0:43                           ` David Abrahams
  0 siblings, 1 reply; 74+ messages in thread
From: Matt Austern @ 2003-12-16 23:44 UTC (permalink / raw)
  To: David Abrahams
  Cc: Jason Merrill, Ulrich Drepper, gcc, Richard Henderson,
	Nathan Myers, Jakub Jelinek, wekempf, Mark Mitchell, fjh,
	Benjamin Kosnik, William Kempf

On Dec 16, 2003, at 1:49 PM, David Abrahams wrote:

>> Yep, I appreciate your point.  I just wanted to make the distinction
>> clear
>> for those who weren't familiar with pthreads, especially since we were
>> talking about David Butenhof's opinion.  He's very clear that he 
>> thinks
>> asynchronous cancelation (in the technical POSIX sense) is an evil
>> feature, but I haven't seen anything to suggest that he feels that way
>> about deferred cancellation.
>
> Right.  Nothing at all wrong with deferred cancellation per say.
> Deferred cancellation good; violating contracts bad.

The real issue, of course is the old one: that the people defining the
POSIX standard and the people defining the C++ standard didn't
spend enough time talking to each other.  POSIX doesn't know
anything about C++ contracts.

			--Matt

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16 20:57                 ` Jason Merrill
  2003-12-16 21:55                   ` David Abrahams
@ 2003-12-17  0:32                   ` Jason Merrill
  2003-12-17  5:28                     ` Jason Merrill
  1 sibling, 1 reply; 74+ messages in thread
From: Jason Merrill @ 2003-12-17  0:32 UTC (permalink / raw)
  To: Benjamin Kosnik; +Cc: gcc, Ulrich Drepper, Jason Merrill

[-- Attachment #1: Type: text/plain, Size: 448 bytes --]

On Tue, 16 Dec 2003 15:30:24 -0500, Jason Merrill <jason@redhat.com> wrote:

> Benjamin: Pending a resolution of these issues, I suggest that we work
> around the problem by disabling cancellation in the iostream try blocks.
> I'm playing with this now.

Thus.  Unfortunately, pthread_setcancelstate doesn't seem to actually
disable cancellation on my Fedora Core 1 laptop, so this doesn't actually
help.  I'll try to test it on an RHEL box soon.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-patch, Size: 19697 bytes --]

Index: libstdc++-v3/include/bits/ios_base.h
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/include/bits/ios_base.h,v
retrieving revision 1.36
diff -c -p -r1.36 ios_base.h
*** libstdc++-v3/include/bits/ios_base.h	16 Dec 2003 00:15:24 -0000	1.36
--- libstdc++-v3/include/bits/ios_base.h	16 Dec 2003 23:40:24 -0000
***************
*** 45,50 ****
--- 45,51 ----
  #include <bits/atomicity.h>
  #include <bits/localefwd.h>
  #include <bits/locale_classes.h>
+ #include <bits/gthr.h>
  
  namespace std
  {
*************** namespace std
*** 478,483 ****
--- 479,512 ----
  
      void 
      _M_init();
+ 
+     // The C++ I/O functions catch all exceptions and only rethrow them if
+     // badbit is set in exceptions().  This causes problems for pthread
+     // cancellation, which (currently) calls terminate if a catch block
+     // tries to finalize the cancellation exception.  So we use this struct
+     // to disable cancellation within the try block.
+     struct _Cancel_guard
+     {
+ #ifdef PTHREAD_CANCEL_DISABLE
+       int _M_oldstate;
+       _Cancel_guard (const ios_base &__i, iostate __bit)
+       {
+ 	if (__i._M_exception & __bit)
+ 	  // Don't suppress cancellation if it will be rethrown.
+ 	  _M_oldstate = -1;
+ 	else
+ 	  pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &_M_oldstate);
+       }
+ 
+       ~_Cancel_guard ()
+       {
+ 	if (_M_oldstate != -1)
+ 	  pthread_setcancelstate (_M_oldstate, NULL);
+       }
+ #else
+       _Cancel_guard (const ios_base &) {}
+ #endif
+     };
  
    public:
  
Index: libstdc++-v3/include/bits/istream.tcc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/include/bits/istream.tcc,v
retrieving revision 1.60
diff -c -p -r1.60 istream.tcc
*** libstdc++-v3/include/bits/istream.tcc	2 Dec 2003 02:48:49 -0000	1.60
--- libstdc++-v3/include/bits/istream.tcc	16 Dec 2003 23:40:25 -0000
*************** namespace std 
*** 116,121 ****
--- 116,122 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_get_type& __ng = __check_facet(this->_M_num_get);
  	      __ng.get(*this, 0, *this, __err, __n);
  	    }
*************** namespace std 
*** 138,143 ****
--- 139,145 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      long __l;
  	      const __num_get_type& __ng = __check_facet(this->_M_num_get);
  	      __ng.get(*this, 0, *this, __err, __l);
*************** namespace std 
*** 169,174 ****
--- 171,177 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_get_type& __ng = __check_facet(this->_M_num_get);
  	      __ng.get(*this, 0, *this, __err, __n);
  	    }
*************** namespace std 
*** 191,196 ****
--- 194,200 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      long __l;
  	      const __num_get_type& __ng = __check_facet(this->_M_num_get);
  	      __ng.get(*this, 0, *this, __err, __l);
*************** namespace std 
*** 222,227 ****
--- 226,232 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_get_type& __ng = __check_facet(this->_M_num_get);
  	      __ng.get(*this, 0, *this, __err, __n);
  	    }
*************** namespace std 
*** 244,249 ****
--- 249,255 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_get_type& __ng = __check_facet(this->_M_num_get);
  	      __ng.get(*this, 0, *this, __err, __n);
  	    }
*************** namespace std 
*** 266,271 ****
--- 272,278 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_get_type& __ng = __check_facet(this->_M_num_get);
  	      __ng.get(*this, 0, *this, __err, __n);
  	    }
*************** namespace std 
*** 289,294 ****
--- 296,302 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_get_type& __ng = __check_facet(this->_M_num_get);
  	      __ng.get(*this, 0, *this, __err, __n);
  	    }
*************** namespace std 
*** 311,316 ****
--- 319,325 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_get_type& __ng = __check_facet(this->_M_num_get);
  	      __ng.get(*this, 0, *this, __err, __n);
  	    }
*************** namespace std 
*** 334,339 ****
--- 343,349 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_get_type& __ng = __check_facet(this->_M_num_get);
  	      __ng.get(*this, 0, *this, __err, __n);
  	    }
*************** namespace std 
*** 356,361 ****
--- 366,372 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_get_type& __ng = __check_facet(this->_M_num_get);
  	      __ng.get(*this, 0, *this, __err, __n);
  	    }
*************** namespace std 
*** 378,383 ****
--- 389,395 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_get_type& __ng = __check_facet(this->_M_num_get);
  	      __ng.get(*this, 0, *this, __err, __n);
  	    }
*************** namespace std 
*** 400,405 ****
--- 412,418 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_get_type& __ng = __check_facet(this->_M_num_get);
  	      __ng.get(*this, 0, *this, __err, __n);
  	    }
*************** namespace std 
*** 422,427 ****
--- 435,441 ----
  	{
  	  try
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::failbit);
  	      if (!__copy_streambufs(this->rdbuf(), __sbout))
  		__err |= ios_base::failbit;
  	    }
*************** namespace std 
*** 449,454 ****
--- 463,469 ----
  	{
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      __c = this->rdbuf()->sbumpc();
  	      // 27.6.1.1 paragraph 3
  	      if (!traits_type::eq_int_type(__c, __eof))
*************** namespace std 
*** 478,483 ****
--- 493,499 ----
  	{
   	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      int_type __cb = this->rdbuf()->sbumpc();
  	      // 27.6.1.1 paragraph 3
  	      if (!traits_type::eq_int_type(__cb, traits_type::eof()))
*************** namespace std 
*** 510,515 ****
--- 526,532 ----
  	{
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const int_type __idelim = traits_type::to_int_type(__delim);
  	      const int_type __eof = traits_type::eof();
  	      __streambuf_type* __sb = this->rdbuf();
*************** namespace std 
*** 549,554 ****
--- 566,572 ----
  	{
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const int_type __idelim = traits_type::to_int_type(__delim);
  	      const int_type __eof = traits_type::eof();	      
  	      __streambuf_type* __this_sb = this->rdbuf();
*************** namespace std 
*** 588,593 ****
--- 606,612 ----
  	{
            try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const int_type __idelim = traits_type::to_int_type(__delim);
  	      const int_type __eof = traits_type::eof();
  	      __streambuf_type* __sb = this->rdbuf();
*************** namespace std 
*** 637,642 ****
--- 656,662 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const int_type __eof = traits_type::eof();
  	      __streambuf_type* __sb = this->rdbuf();
  	      int_type __c;
*************** namespace std 
*** 673,678 ****
--- 693,699 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      __c = this->rdbuf()->sgetc();
  	      if (traits_type::eq_int_type(__c, traits_type::eof()))
  		__err |= ios_base::eofbit;
*************** namespace std 
*** 697,702 ****
--- 718,724 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      _M_gcount = this->rdbuf()->sgetn(__s, __n);
  	      if (_M_gcount != __n)
  		__err |= (ios_base::eofbit | ios_base::failbit);
*************** namespace std 
*** 721,726 ****
--- 743,749 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      // Cannot compare int_type with streamsize generically.
  	      streamsize __num = this->rdbuf()->in_avail();
  	      if (__num >= 0)
*************** namespace std 
*** 754,759 ****
--- 777,783 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const int_type __eof = traits_type::eof();
  	      __streambuf_type* __sb = this->rdbuf();
  	      if (!__sb 
*************** namespace std 
*** 782,787 ****
--- 806,812 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const int_type __eof = traits_type::eof();
  	      __streambuf_type* __sb = this->rdbuf();
  	      if (!__sb 
*************** namespace std 
*** 810,815 ****
--- 835,841 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      __streambuf_type* __sb = this->rdbuf();
  	      if (__sb)
  		{
*************** namespace std 
*** 837,842 ****
--- 863,869 ----
        pos_type __ret = pos_type(-1);
        try
  	{
+ 	  ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	  if (!this->fail())
  	    __ret = this->rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in);
  	}
*************** namespace std 
*** 855,860 ****
--- 882,888 ----
        ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
        try
  	{
+ 	  ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	  if (!this->fail())
  	    {
  	      // 136.  seekp, seekg setting wrong streams?
*************** namespace std 
*** 882,887 ****
--- 910,916 ----
        ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
        try
  	{
+ 	  ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	  if (!this->fail())
  	    {
  	      // 136.  seekp, seekg setting wrong streams?
*************** namespace std 
*** 912,917 ****
--- 941,947 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(__in, ios_base::badbit);
  	      typename __istream_type::int_type __cb = __in.rdbuf()->sbumpc();
  	      if (!_Traits::eq_int_type(__cb, _Traits::eof()))
  		__c = _Traits::to_char_type(__cb);
*************** namespace std 
*** 943,948 ****
--- 973,979 ----
  	{
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(__in, ios_base::badbit);
  	      // Figure out how many characters to extract.
  	      streamsize __num = __in.width();
  	      if (__num <= 0)
*************** namespace std 
*** 1025,1030 ****
--- 1056,1062 ----
  	{
  	  try
  	    {
+ 	      ios_base::_Cancel_guard __g(__in, ios_base::badbit);
  	      __str.erase();
  	      streamsize __w = __in.width();
  	      __size_type __n;
*************** namespace std 
*** 1084,1089 ****
--- 1116,1122 ----
  	{
  	  try
  	    {
+ 	      ios_base::_Cancel_guard __g(__in, ios_base::badbit);
  	      __str.erase();
  	      __int_type __idelim = _Traits::to_int_type(__delim);
  	      __streambuf_type* __sb = __in.rdbuf();
Index: libstdc++-v3/include/bits/ostream.tcc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/include/bits/ostream.tcc,v
retrieving revision 1.50
diff -c -p -r1.50 ostream.tcc
*** libstdc++-v3/include/bits/ostream.tcc	2 Dec 2003 02:48:49 -0000	1.50
--- libstdc++-v3/include/bits/ostream.tcc	16 Dec 2003 23:40:25 -0000
*************** namespace std 
*** 105,110 ****
--- 105,111 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_put_type& __np = __check_facet(this->_M_num_put);
  	      if (__np.put(*this, *this, this->fill(), __n).failed())
  		__err |= ios_base::badbit;
*************** namespace std 
*** 128,133 ****
--- 129,135 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      bool __b = false;
  	      char_type __c = this->fill();
  	      ios_base::fmtflags __fmt = this->flags() & ios_base::basefield;
*************** namespace std 
*** 161,166 ****
--- 163,169 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_put_type& __np = __check_facet(this->_M_num_put);
  	      if (__np.put(*this, *this, this->fill(), __n).failed())
  		__err |= ios_base::badbit;
*************** namespace std 
*** 185,190 ****
--- 188,194 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      bool __b = false;
  	      char_type __c = this->fill();
  	      ios_base::fmtflags __fmt = this->flags() & ios_base::basefield;
*************** namespace std 
*** 219,224 ****
--- 223,229 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_put_type& __np = __check_facet(this->_M_num_put);
  	      if (__np.put(*this, *this, this->fill(), __n).failed())
  		__err |= ios_base::badbit;
*************** namespace std 
*** 243,248 ****
--- 248,254 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_put_type& __np = __check_facet(this->_M_num_put);
  	      if (__np.put(*this, *this, this->fill(), __n).failed())
  		__err |= ios_base::badbit;
*************** namespace std 
*** 266,271 ****
--- 272,278 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_put_type& __np = __check_facet(this->_M_num_put);
  	      if (__np.put(*this, *this, this->fill(), __n).failed())
  		__err |= ios_base::badbit;
*************** namespace std 
*** 289,294 ****
--- 296,302 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      const __num_put_type& __np = __check_facet(this->_M_num_put);
  	      if (__np.put(*this, *this, this->fill(), __n).failed())
  		__err |= ios_base::badbit;
*************** namespace std 
*** 312,317 ****
--- 320,326 ----
  	{
  	  try
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::failbit);
  	      if (!__copy_streambufs(__sbin, this->rdbuf()))
  		__err |= ios_base::failbit;
  	    }
*************** namespace std 
*** 342,347 ****
--- 351,357 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try
  	    {
+ 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	      int_type __put = this->rdbuf()->sputc(__c); 
  	      if (traits_type::eq_int_type(__put, traits_type::eof()))
  		__err |= ios_base::badbit;
*************** namespace std 
*** 370,376 ****
        if (__cerb)
  	{
  	  try
! 	    { _M_write(__s, __n); }
  	  catch (...)
  	    { this->_M_setstate(ios_base::badbit); }
  	}
--- 380,389 ----
        if (__cerb)
  	{
  	  try
! 	    {
! 	      ios_base::_Cancel_guard __g(*this, ios_base::badbit);
! 	      _M_write(__s, __n);
! 	    }
  	  catch (...)
  	    { this->_M_setstate(ios_base::badbit); }
  	}
*************** namespace std 
*** 388,393 ****
--- 401,407 ----
        ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
        try
  	{
+ 	  ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	  if (this->rdbuf() && this->rdbuf()->pubsync() == -1)
  	    __err |= ios_base::badbit;
  	}
*************** namespace std 
*** 406,411 ****
--- 420,426 ----
        pos_type __ret = pos_type(-1);
        try
  	{
+ 	  ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	  if (!this->fail())
  	    __ret = this->rdbuf()->pubseekoff(0, ios_base::cur, ios_base::out);
  	}
*************** namespace std 
*** 422,427 ****
--- 437,443 ----
        ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
        try
  	{
+ 	  ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	  if (!this->fail())
  	    {
  	      // _GLIBCXX_RESOLVE_LIB_DEFECTS
*************** namespace std 
*** 448,453 ****
--- 464,470 ----
        ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
        try
  	{
+ 	  ios_base::_Cancel_guard __g(*this, ios_base::badbit);
  	  if (!this->fail())
  	    {
  	      // _GLIBCXX_RESOLVE_LIB_DEFECTS
*************** namespace std 
*** 478,483 ****
--- 495,501 ----
  	{
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(__out, ios_base::badbit);
  	      const streamsize __w = __out.width();
  	      streamsize __len = 1;
  	      _CharT* __cs = &__c;
*************** namespace std 
*** 509,514 ****
--- 527,533 ----
  	{
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(__out, ios_base::badbit);
  	      const streamsize __w = __out.width();
  	      streamsize __len = 1;
  	      char* __cs = &__c;
*************** namespace std 
*** 538,543 ****
--- 557,563 ----
  	{
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(__out, ios_base::badbit);
  	      const streamsize __w = __out.width();
  	      streamsize __len = static_cast<streamsize>(_Traits::length(__s));
  	      if (__w > __len)
*************** namespace std 
*** 581,586 ****
--- 601,607 ----
  	  
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(__out, ios_base::badbit);
  	      const streamsize __w = __out.width();
  	      streamsize __len = static_cast<streamsize>(__clen);
  	      if (__w > __len)
*************** namespace std 
*** 614,619 ****
--- 635,641 ----
  	{
  	  try 
  	    {
+ 	      ios_base::_Cancel_guard __g(__out, ios_base::badbit);
  	      const streamsize __w = __out.width();
  	      streamsize __len = static_cast<streamsize>(_Traits::length(__s));
  	      if (__w > __len)

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16 23:44                         ` Matt Austern
@ 2003-12-17  0:43                           ` David Abrahams
  2003-12-17  3:55                             ` Jason Merrill
  0 siblings, 1 reply; 74+ messages in thread
From: David Abrahams @ 2003-12-17  0:43 UTC (permalink / raw)
  To: Matt Austern
  Cc: Jason Merrill, Ulrich Drepper, gcc, Richard Henderson,
	Nathan Myers, Jakub Jelinek, wekempf, Mark Mitchell, fjh,
	Benjamin Kosnik, William Kempf

Matt Austern <austern@apple.com> writes:

> On Dec 16, 2003, at 1:49 PM, David Abrahams wrote:
>
>>> Yep, I appreciate your point.  I just wanted to make the distinction
>>> clear
>>> for those who weren't familiar with pthreads, especially since we were
>>> talking about David Butenhof's opinion.  He's very clear that he
>>> thinks
>>> asynchronous cancelation (in the technical POSIX sense) is an evil
>>> feature, but I haven't seen anything to suggest that he feels that way
>>> about deferred cancellation.
>>
>> Right.  Nothing at all wrong with deferred cancellation per say.
>> Deferred cancellation good; violating contracts bad.
>
> The real issue, of course is the old one: that the people defining the
> POSIX standard and the people defining the C++ standard didn't
> spend enough time talking to each other.  POSIX doesn't know
> anything about C++ contracts.

Nor about standard C++ library functions, I presume?  Why should it
have any impact on the behavior of the C++ lib from a standards POV?

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17  0:43                           ` David Abrahams
@ 2003-12-17  3:55                             ` Jason Merrill
  2003-12-17  7:04                               ` David Abrahams
                                                 ` (2 more replies)
  0 siblings, 3 replies; 74+ messages in thread
From: Jason Merrill @ 2003-12-17  3:55 UTC (permalink / raw)
  To: David Abrahams
  Cc: Matt Austern, Ulrich Drepper, gcc, Richard Henderson,
	Nathan Myers, Jakub Jelinek, wekempf, Mark Mitchell, fjh,
	Benjamin Kosnik, William Kempf

On Tue, 16 Dec 2003 18:55:13 -0500, David Abrahams <dave@boost-consulting.com> wrote:

> Matt Austern <austern@apple.com> writes:
>
>> The real issue, of course is the old one: that the people defining the
>> POSIX standard and the people defining the C++ standard didn't
>> spend enough time talking to each other.  POSIX doesn't know
>> anything about C++ contracts.

> Nor about standard C++ library functions, I presume?  Why should it
> have any impact on the behavior of the C++ lib from a standards POV?

The two standards are incompatible as written.  To make pthreads and C++
play nice together, one or both need some adjustment.

Jason

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17  0:32                   ` Jason Merrill
@ 2003-12-17  5:28                     ` Jason Merrill
  0 siblings, 0 replies; 74+ messages in thread
From: Jason Merrill @ 2003-12-17  5:28 UTC (permalink / raw)
  To: Benjamin Kosnik; +Cc: gcc, Ulrich Drepper

On Tue, 16 Dec 2003 18:44:17 -0500, Jason Merrill <jason@redhat.com> wrote:

> On Tue, 16 Dec 2003 15:30:24 -0500, Jason Merrill <jason@redhat.com> wrote:
>
>> Benjamin: Pending a resolution of these issues, I suggest that we work
>> around the problem by disabling cancellation in the iostream try blocks.
>> I'm playing with this now.
>
> Thus.  Unfortunately, pthread_setcancelstate doesn't seem to actually
> disable cancellation on my Fedora Core 1 laptop, so this doesn't actually
> help.  I'll try to test it on an RHEL box soon.

Well, it doesn't seem to work on an RHEL3 box either--nor does the
catch(...) block the cancellation exception.  Seems that there's some more
fundamental work still to be done.

Jason

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17  3:55                             ` Jason Merrill
@ 2003-12-17  7:04                               ` David Abrahams
  2003-12-17  9:47                               ` Mark Mitchell
  2003-12-17 23:35                               ` Geoff Keating
  2 siblings, 0 replies; 74+ messages in thread
From: David Abrahams @ 2003-12-17  7:04 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Matt Austern, Ulrich Drepper, gcc, Richard Henderson,
	Nathan Myers, Jakub Jelinek, wekempf, Mark Mitchell, fjh,
	Benjamin Kosnik, William Kempf

Jason Merrill <jason@redhat.com> writes:

> On Tue, 16 Dec 2003 18:55:13 -0500, David Abrahams <dave@boost-consulting.com> wrote:
>
>> Matt Austern <austern@apple.com> writes:
>>
>>> The real issue, of course is the old one: that the people defining the
>>> POSIX standard and the people defining the C++ standard didn't
>>> spend enough time talking to each other.  POSIX doesn't know
>>> anything about C++ contracts.
>
>> Nor about standard C++ library functions, I presume?  Why should it
>> have any impact on the behavior of the C++ lib from a standards POV?
>
> The two standards are incompatible as written.  To make pthreads and C++
> play nice together, one or both need some adjustment.

Thanks, I gathered someone is saying that.  I'm asking someone to
connect the dots for me so I can see what, specifically, makes them
incompatible.

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17  3:55                             ` Jason Merrill
  2003-12-17  7:04                               ` David Abrahams
@ 2003-12-17  9:47                               ` Mark Mitchell
  2003-12-17  9:54                                 ` Jason Merrill
                                                   ` (2 more replies)
  2003-12-17 23:35                               ` Geoff Keating
  2 siblings, 3 replies; 74+ messages in thread
From: Mark Mitchell @ 2003-12-17  9:47 UTC (permalink / raw)
  To: Jason Merrill
  Cc: David Abrahams, Matt Austern, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf, fjh,
	Benjamin Kosnik, William Kempf

On Tue, 2003-12-16 at 19:20, Jason Merrill wrote:
> On Tue, 16 Dec 2003 18:55:13 -0500, David Abrahams <dave@boost-consulting.com> wrote:
> 
> > Matt Austern <austern@apple.com> writes:
> >
> >> The real issue, of course is the old one: that the people defining the
> >> POSIX standard and the people defining the C++ standard didn't
> >> spend enough time talking to each other.  POSIX doesn't know
> >> anything about C++ contracts.
> 
> > Nor about standard C++ library functions, I presume?  Why should it
> > have any impact on the behavior of the C++ lib from a standards POV?
> 
> The two standards are incompatible as written.  To make pthreads and C++
> play nice together, one or both need some adjustment.

I agree.

In my opinion, the most logical way to do this is to make the following
changes:

(1) In C++, the various POSIX thread cancellation points (e.g., "read")
should have the exception-specification "throw
(posix::thread_cancellation) rather than "throw ()".  They would throw
an exception of this type if the thread is cancelled.

(2) The POSIX thread specification should allow a cancelled thread to
uncancel itself.  After that point, the thread continues as if it had
never been cancelled.  (It can be cancelled again, of course, after it
is uncancelled.)  

(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.

With these changes, library designers can still say "catch all
exceptions", but they can also say "catch all exceptions except thread
cancellation".  It may be that catching all exceptions is a bad idea,
but that is up to the library designer.

These changes are a pure extension to POSIX threads; they do not break
any existing POSIX threads code.  

These changes are not quite a pure extension to standard C++; the C++
standard prohibits C library functions from throwing exceptions, so, for
example, "printf" cannot throw an exception.  

Therefore, I would make one other change:

(4) The POSIX thread specification should provide an interface (perhaps
an additional field in pthread_attr_t) that indicates whether or not
cancellation should result in throwing an exception.   The default will
be to throw an exception.  However, if cancellation does not result in
throwing an exception, the thread exits without even running cleanup
handlers registered with pthread_cleanup_push.

That way a library which depends on the strictly conforming C++ behavior
can still be used in a thread.  There really are situations where the
best behavior is going to be *not* to do stack unwinding at all. 
There's no reason to expect that all C++ threads will need to have their
stack unwound.

-- 
Mark Mitchell <mark@codesourcery.com>
CodeSourcery, LLC

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17  9:47                               ` Mark Mitchell
@ 2003-12-17  9:54                                 ` Jason Merrill
  2003-12-17 10:28                                   ` Mark Mitchell
  2003-12-17 13:26                                 ` David Abrahams
  2003-12-17 22:48                                 ` Matt Austern
  2 siblings, 1 reply; 74+ messages in thread
From: Jason Merrill @ 2003-12-17  9:54 UTC (permalink / raw)
  To: Mark Mitchell
  Cc: David Abrahams, Matt Austern, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf, fjh,
	Benjamin Kosnik, William Kempf

On 16 Dec 2003 21:28:10 -0800, Mark Mitchell <mark@codesourcery.com> wrote:

> On Tue, 2003-12-16 at 19:20, Jason Merrill wrote:

>> The two standards are incompatible as written.  To make pthreads and C++
>> play nice together, one or both need some adjustment.
>
> I agree.
>
> In my opinion, the most logical way to do this is to make the following
> changes:
>
> (1) In C++, the various POSIX thread cancellation points (e.g., "read")
> should have the exception-specification "throw
> (posix::thread_cancellation) rather than "throw ()".  They would throw
> an exception of this type if the thread is cancelled.

Yep.

> (2) The POSIX thread specification should allow a cancelled thread to
> uncancel itself.  After that point, the thread continues as if it had
> never been cancelled.  (It can be cancelled again, of course, after it
> is uncancelled.)  

It's not so much uncancelling as re-deferring cancellation--I assume that's
what you meant, but it sounds like you're suggesting that the cancellation
request be discarded entirely, which I don't think is appropriate.

There's still the question of what to do with pthread_exit.

> (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.

This seems unnecessary.  Why would we need to copy the exception?  AFAICT
we would only need to change the cancellation destructor, which currently
calls terminate, to do #2 instead.

> (4) The POSIX thread specification should provide an interface (perhaps
> an additional field in pthread_attr_t) that indicates whether or not
> cancellation should result in throwing an exception.   The default will
> be to throw an exception.  However, if cancellation does not result in
> throwing an exception, the thread exits without even running cleanup
> handlers registered with pthread_cleanup_push.
>
> That way a library which depends on the strictly conforming C++ behavior
> can still be used in a thread.  There really are situations where the
> best behavior is going to be *not* to do stack unwinding at all. 
> There's no reason to expect that all C++ threads will need to have their
> stack unwound.

If you want to kill a thread without running any cleanups, there's always
pthread_kill.  If the C++ code can't cope with a cancel exception, it can
suppress cancellation with pthread_setcancelstate until it's ready.  I
don't think that your suggestion adds much.

Jason

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17  9:54                                 ` Jason Merrill
@ 2003-12-17 10:28                                   ` Mark Mitchell
  2003-12-17 18:25                                     ` Gabriel Dos Reis
  0 siblings, 1 reply; 74+ messages in thread
From: Mark Mitchell @ 2003-12-17 10:28 UTC (permalink / raw)
  To: Jason Merrill
  Cc: David Abrahams, Matt Austern, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf, fjh,
	Benjamin Kosnik, William Kempf

> > (2) The POSIX thread specification should allow a cancelled thread to
> > uncancel itself.  After that point, the thread continues as if it had
> > never been cancelled.  (It can be cancelled again, of course, after it
> > is uncancelled.)  
> 
> It's not so much uncancelling as re-deferring cancellation--I assume that's
> what you meant, but it sounds like you're suggesting that the cancellation
> request be discarded entirely, which I don't think is appropriate.

Actually, I really meant uncancelling.  

I think that "catch (posix::thread_cancellation)" should just work
exactly as with catching any other exception.  I don't see any need for
special rules here.

You should be able to go on from there as if you were never cancelled,
just as you can call "longjmp" from a handler for "SIGTERM" and go along
from there.

> There's still the question of what to do with pthread_exit.

The consistent thing would seem to be to have it throw
"posix::thread_exit".  (This, by the way, is analagous to the Python
idea that "return" statements are equivalent to throwing a special kind
of exception.)

> > (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.
> 
> This seems unnecessary.  Why would we need to copy the exception?  AFAICT
> we would only need to change the cancellation destructor, which currently
> calls terminate, to do #2 instead.

If we do not allow uncancelling, then what you suggest is probably OK. 
This is a detail, in either case.

> > (4) The POSIX thread specification should provide an interface (perhaps
> > an additional field in pthread_attr_t) that indicates whether or not
> > cancellation should result in throwing an exception.   The default will
> > be to throw an exception.  However, if cancellation does not result in
> > throwing an exception, the thread exits without even running cleanup
> > handlers registered with pthread_cleanup_push.
> >
> > That way a library which depends on the strictly conforming C++ behavior
> > can still be used in a thread.  There really are situations where the
> > best behavior is going to be *not* to do stack unwinding at all. 
> > There's no reason to expect that all C++ threads will need to have their
> > stack unwound.
> 
> If you want to kill a thread without running any cleanups, there's always
> pthread_kill.  If the C++ code can't cope with a cancel exception, it can
> suppress cancellation with pthread_setcancelstate until it's ready.  I
> don't think that your suggestion adds much.

The point is to be able to use a strictly-conforming thread-unaware C++
library in a thread.  You can't have "printf" throw an exception because
that might break critical assumptions in the library.  With your
suggestion, the cancelling thread has to know that it should use
pthread_kill; I'd rather than the cancelled thread be able to say "I'm
not the kind of thread that can handle exceptions."

-- 
Mark Mitchell <mark@codesourcery.com>
CodeSourcery, LLC

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17  9:47                               ` Mark Mitchell
  2003-12-17  9:54                                 ` Jason Merrill
@ 2003-12-17 13:26                                 ` David Abrahams
  2003-12-17 17:19                                   ` Mark Mitchell
  2003-12-17 22:48                                 ` Matt Austern
  2 siblings, 1 reply; 74+ messages in thread
From: David Abrahams @ 2003-12-17 13:26 UTC (permalink / raw)
  To: Mark Mitchell
  Cc: Jason Merrill, Matt Austern, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf, fjh,
	Benjamin Kosnik, William Kempf

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));
  }

?

> With these changes, library designers can still say "catch all
> exceptions", but they can also say "catch all exceptions except thread
> cancellation".  

How?  You must mean something like:

  try { ... }
  catch (posix::thread_cancellation&) { throw; }
  catch (...) {
        ... // here
  }

That's still catching thread cancellation, so I would choose a
different description if that's what you meant.

> It may be that catching all exceptions is a bad idea,
> but that is up to the library designer.
>
> These changes are a pure extension to POSIX threads; they do not break
> any existing POSIX threads code.  
>
> These changes are not quite a pure extension to standard C++; the C++
> standard prohibits C library functions from throwing exceptions, so, for
> example, "printf" cannot throw an exception.  

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.

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.

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17 13:26                                 ` David Abrahams
@ 2003-12-17 17:19                                   ` Mark Mitchell
  2003-12-17 17:48                                     ` David Abrahams
  0 siblings, 1 reply; 74+ messages in thread
From: Mark Mitchell @ 2003-12-17 17:19 UTC (permalink / raw)
  To: David Abrahams
  Cc: Jason Merrill, Matt Austern, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf, fjh,
	Benjamin Kosnik, William Kempf

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.

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.  (Think of that case like using longjmp to escape from
SIGTERM.)  In other words, if you do not copy "x" above, then you have
exited the cancellation handler mode; you are back to normal thread
operation as if you had never been cancelled.  (This is an extension to
POSIX thread semantics and is the bit that Ulrich objects to so
vehemently.)

> > With these changes, library designers can still say "catch all
> > exceptions", but they can also say "catch all exceptions except thread
> > cancellation".  
> 
> How?  You must mean something like:
> 
>   try { ... }
>   catch (posix::thread_cancellation&) { throw; }
>   catch (...) {
>         ... // here
>   }

Yes, that is what I mean.

> > It may be that catching all exceptions is a bad idea,
> > but that is up to the library designer.
> >
> > These changes are a pure extension to POSIX threads; they do not break
> > any existing POSIX threads code.  
> >
> > These changes are not quite a pure extension to standard C++; the C++
> > standard prohibits C library functions from throwing exceptions, so, for
> > example, "printf" cannot throw an exception.  
> 
> 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: 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.

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.  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.

-- 
Mark Mitchell <mark@codesourcery.com>
CodeSourcery, LLC

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17 17:19                                   ` Mark Mitchell
@ 2003-12-17 17:48                                     ` David Abrahams
  2003-12-17 18:36                                       ` Mark Mitchell
  0 siblings, 1 reply; 74+ messages in thread
From: David Abrahams @ 2003-12-17 17:48 UTC (permalink / raw)
  To: Mark Mitchell
  Cc: Jason Merrill, Matt Austern, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf, fjh,
	Benjamin Kosnik

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17 10:28                                   ` Mark Mitchell
@ 2003-12-17 18:25                                     ` Gabriel Dos Reis
  0 siblings, 0 replies; 74+ messages in thread
From: Gabriel Dos Reis @ 2003-12-17 18:25 UTC (permalink / raw)
  To: Mark Mitchell
  Cc: Jason Merrill, David Abrahams, Matt Austern, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf, fjh,
	Benjamin Kosnik, William Kempf

Mark Mitchell <mark@codesourcery.com> writes:

| > There's still the question of what to do with pthread_exit.
| 
| The consistent thing would seem to be to have it throw
| "posix::thread_exit".  (This, by the way, is analagous to the Python
| idea that "return" statements are equivalent to throwing a special kind
| of exception.)

Yeah, that might be fine for Python and other languages like ML that
use exceptions to return value.  But, I would strongly recommend
against introducing that slippery slope in C++, C++ libraries.

-- Gaby

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17 17:48                                     ` David Abrahams
@ 2003-12-17 18:36                                       ` Mark Mitchell
  2003-12-17 19:48                                         ` David Abrahams
  0 siblings, 1 reply; 74+ messages in thread
From: Mark Mitchell @ 2003-12-17 18:36 UTC (permalink / raw)
  To: David Abrahams
  Cc: Jason Merrill, Matt Austern, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf, fjh,
	Benjamin Kosnik

> >
> > 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?

Yes, that re-enables cancellation points.  I don't know if that's an odd
paradox. :-)

> > 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.

The point is that both SIGTERM and thread-cancellation are ways that
some external influence can try to make your thread of control
terminate.  In both cases, you have to figure out what resources you
need to deallocate when that happens.  Alternatively, in both cases, you
can block the external interrupt.

> > 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.

So, then, you would want to use the other mode. :)

-- 
Mark Mitchell <mark@codesourcery.com>
CodeSourcery, LLC

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17 18:36                                       ` Mark Mitchell
@ 2003-12-17 19:48                                         ` David Abrahams
  2003-12-17 20:18                                           ` Mark Mitchell
  0 siblings, 1 reply; 74+ messages in thread
From: David Abrahams @ 2003-12-17 19:48 UTC (permalink / raw)
  To: Mark Mitchell
  Cc: Jason Merrill, Matt Austern, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf, fjh,
	Benjamin Kosnik

Mark Mitchell <mark@codesourcery.com> writes:

>> >
>> > 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?
>
> Yes, that re-enables cancellation points.  I don't know if that's an odd
> paradox. :-)
>
>> > 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.
>
> The point is that both SIGTERM and thread-cancellation are ways that
> some external influence can try to make your thread of control
> terminate.  In both cases, you have to figure out what resources you
> need to deallocate when that happens.  Alternatively, in both cases, you
> can block the external interrupt.
>
>> > 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.
>
> So, then, you would want to use the other mode. :)

Huh?  No, not IIUC.  The other mode will throw exceptions from 'C'
lib functions, right?

I want to be *able* to say, "don't throw any cancellation exceptions
at me except where I explicitly call pthread_whatever_its_called (the
one which just throws if there's a cancellation pending and does
nothing otherwise)".  There's nothing wrong with your other modes,
but IMO the mode I'm describing would provide the safest route to
integrate library source code into a threaded app.

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17 19:48                                         ` David Abrahams
@ 2003-12-17 20:18                                           ` Mark Mitchell
  2003-12-17 22:10                                             ` Richard Henderson
  0 siblings, 1 reply; 74+ messages in thread
From: Mark Mitchell @ 2003-12-17 20:18 UTC (permalink / raw)
  To: David Abrahams
  Cc: Jason Merrill, Matt Austern, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf, fjh,
	Benjamin Kosnik


> I want to be *able* to say, "don't throw any cancellation exceptions
> at me except where I explicitly call pthread_whatever_its_called (the
> one which just throws if there's a cancellation pending and does
> nothing otherwise)".  There's nothing wrong with your other modes,
> but IMO the mode I'm describing would provide the safest route to
> integrate library source code into a threaded app.

Yes, that is a 3rd mode: a fully synchronous model.

That would also be a POSIX threads extension; essentially, this would be
the deferred cancellation model, except that pthread_testcancel would be
the only cancellation point.

I think that, too, is a reasonable mode.

-- 
Mark Mitchell <mark@codesourcery.com>
CodeSourcery, LLC

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17 20:18                                           ` Mark Mitchell
@ 2003-12-17 22:10                                             ` Richard Henderson
  2003-12-17 22:43                                               ` Mark Mitchell
  0 siblings, 1 reply; 74+ messages in thread
From: Richard Henderson @ 2003-12-17 22:10 UTC (permalink / raw)
  To: Mark Mitchell
  Cc: David Abrahams, Jason Merrill, Matt Austern, Ulrich Drepper, gcc,
	Nathan Myers, Jakub Jelinek, wekempf, fjh, Benjamin Kosnik

On Wed, Dec 17, 2003 at 10:36:15AM -0800, Mark Mitchell wrote:
> That would also be a POSIX threads extension; essentially, this would be
> the deferred cancellation model, except that pthread_testcancel would be
> the only cancellation point.

I would think that disabling cancellation and then using testcancel
would be equivalent.


r~

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17 22:10                                             ` Richard Henderson
@ 2003-12-17 22:43                                               ` Mark Mitchell
  2003-12-17 22:44                                                 ` David Abrahams
       [not found]                                                 ` <20031217192555.GY12344@sunsite.ms.mff.cuni.cz>
  0 siblings, 2 replies; 74+ messages in thread
From: Mark Mitchell @ 2003-12-17 22:43 UTC (permalink / raw)
  To: Richard Henderson
  Cc: David Abrahams, Jason Merrill, Matt Austern, Ulrich Drepper, gcc,
	Nathan Myers, Jakub Jelinek, wekempf, fjh, Benjamin Kosnik

On Wed, 2003-12-17 at 12:30, Richard Henderson wrote:
> On Wed, Dec 17, 2003 at 10:36:15AM -0800, Mark Mitchell wrote:
> > That would also be a POSIX threads extension; essentially, this would be
> > the deferred cancellation model, except that pthread_testcancel would be
> > the only cancellation point.
> 
> I would think that disabling cancellation and then using testcancel
> would be equivalent.

I don't think so; pthread_setcancelstate (PTHREAD_CANCEL_DISABLE) means
that the thread will not receive cancellation requests at all.

What David was proposing was that the cancellation request would be
received, but queued until pthread_testcancel was called.  In
particular, "write" and such would not be cancellation points.

-- 
Mark Mitchell <mark@codesourcery.com>
CodeSourcery, LLC

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17 22:43                                               ` Mark Mitchell
@ 2003-12-17 22:44                                                 ` David Abrahams
       [not found]                                                 ` <20031217192555.GY12344@sunsite.ms.mff.cuni.cz>
  1 sibling, 0 replies; 74+ messages in thread
From: David Abrahams @ 2003-12-17 22:44 UTC (permalink / raw)
  To: mark
  Cc: Richard Henderson, Jason Merrill, Matt Austern, Ulrich Drepper,
	gcc, Nathan Myers, Jakub Jelinek, wekempf, fjh, Benjamin Kosnik

Mark Mitchell <mark@codesourcery.com> writes:

> What David was proposing was that the cancellation request would be
> received, but queued until pthread_testcancel was called.  In
> particular, "write" and such would not be cancellation points.

C'est exact.

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17  9:47                               ` Mark Mitchell
  2003-12-17  9:54                                 ` Jason Merrill
  2003-12-17 13:26                                 ` David Abrahams
@ 2003-12-17 22:48                                 ` Matt Austern
  2003-12-17 22:58                                   ` Mark Mitchell
  2 siblings, 1 reply; 74+ messages in thread
From: Matt Austern @ 2003-12-17 22:48 UTC (permalink / raw)
  To: Mark Mitchell
  Cc: Jason Merrill, Ulrich Drepper, gcc, Richard Henderson,
	Nathan Myers, Jakub Jelinek, wekempf, fjh, Benjamin Kosnik,
	David Abrahams, William Kempf

On Dec 16, 2003, at 9:28 PM, Mark Mitchell wrote:

> On Tue, 2003-12-16 at 19:20, Jason Merrill wrote:
>> On Tue, 16 Dec 2003 18:55:13 -0500, David Abrahams 
>> <dave@boost-consulting.com> wrote:
>>
>>> Matt Austern <austern@apple.com> writes:
>>>
>>>> The real issue, of course is the old one: that the people defining 
>>>> the
>>>> POSIX standard and the people defining the C++ standard didn't
>>>> spend enough time talking to each other.  POSIX doesn't know
>>>> anything about C++ contracts.
>>
>>> Nor about standard C++ library functions, I presume?  Why should it
>>> have any impact on the behavior of the C++ lib from a standards POV?
>>
>> The two standards are incompatible as written.  To make pthreads and 
>> C++
>> play nice together, one or both need some adjustment.
>
> I agree.
>
> In my opinion, the most logical way to do this is to make the following
> changes:

I wonder if this is the right forum for this discussion?

I agree with you and Jason that the C++ and POSIX standards are
incompatible.  I also agree that it's very important to reconcile
them, and that it's an embarrassment that it's taken so long to
do it.  Essentially, you're proposing a C++ binding to (a part of)
POSIX.

The reason I wonder whether this is the right forum: this is the
gcc mailing list.  But we don't want a gcc C++ POSIX binding, we
want to have the same C++ POSIX binding for all relevant compilers
and operating systems.

			--Matt

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17 22:48                                 ` Matt Austern
@ 2003-12-17 22:58                                   ` Mark Mitchell
  2003-12-18 18:51                                     ` Matt Austern
  0 siblings, 1 reply; 74+ messages in thread
From: Mark Mitchell @ 2003-12-17 22:58 UTC (permalink / raw)
  To: Matt Austern
  Cc: Jason Merrill, Ulrich Drepper, gcc, Richard Henderson,
	Nathan Myers, Jakub Jelinek, wekempf, fjh, Benjamin Kosnik,
	David Abrahams, William Kempf

On Wed, 2003-12-17 at 13:54, Matt Austern wrote:
> On Dec 16, 2003, at 9:28 PM, Mark Mitchell wrote:
> 
> > On Tue, 2003-12-16 at 19:20, Jason Merrill wrote:
> >> On Tue, 16 Dec 2003 18:55:13 -0500, David Abrahams 
> >> <dave@boost-consulting.com> wrote:
> >>
> >>> Matt Austern <austern@apple.com> writes:
> >>>
> >>>> The real issue, of course is the old one: that the people defining 
> >>>> the
> >>>> POSIX standard and the people defining the C++ standard didn't
> >>>> spend enough time talking to each other.  POSIX doesn't know
> >>>> anything about C++ contracts.
> >>
> >>> Nor about standard C++ library functions, I presume?  Why should it
> >>> have any impact on the behavior of the C++ lib from a standards POV?
> >>
> >> The two standards are incompatible as written.  To make pthreads and 
> >> C++
> >> play nice together, one or both need some adjustment.
> >
> > I agree.
> >
> > In my opinion, the most logical way to do this is to make the following
> > changes:
> 
> I wonder if this is the right forum for this discussion?

I agree that it is not.

Some people want to make changes to GCC/G++/GLIBC and so the discussion
is taking place here.  

I think it would be a mistake to make those changes and check them in to
the FSF version of things without getting at least an informal buy-in
from both the POSIX threads and ISO C++ communities, but I seem to be
more conservative than most about these sorts of things.

-- 
Mark Mitchell <mark@codesourcery.com>
CodeSourcery, LLC

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
       [not found]                                                 ` <20031217192555.GY12344@sunsite.ms.mff.cuni.cz>
@ 2003-12-17 22:59                                                   ` Mark Mitchell
  0 siblings, 0 replies; 74+ messages in thread
From: Mark Mitchell @ 2003-12-17 22:59 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Richard Henderson, David Abrahams, Jason Merrill, Matt Austern,
	Ulrich Drepper, gcc, Nathan Myers, wekempf, fjh, Benjamin Kosnik

On Wed, 2003-12-17 at 11:25, Jakub Jelinek wrote:
> On Wed, Dec 17, 2003 at 01:20:33PM -0800, Mark Mitchell wrote:
> > On Wed, 2003-12-17 at 12:30, Richard Henderson wrote:
> > > On Wed, Dec 17, 2003 at 10:36:15AM -0800, Mark Mitchell wrote:
> > > > That would also be a POSIX threads extension; essentially, this would be
> > > > the deferred cancellation model, except that pthread_testcancel would be
> > > > the only cancellation point.
> > > 
> > > I would think that disabling cancellation and then using testcancel
> > > would be equivalent.
> > 
> > I don't think so; pthread_setcancelstate (PTHREAD_CANCEL_DISABLE) means
> > that the thread will not receive cancellation requests at all.
> 
> No.  PTHREAD_CANCEL_DISABLE means that cancellation requests are queued.
> See http://www.opengroup.org/onlinepubs/007904975/functions/xsh_chap02_09.html#tag_02_09_05_01

Ah.  

That was not clear to me from the GNU/Linux info files, but I should
have gone to the source.

Given that, I agree with you and Richard: David's alternative is
equivalent to just disabling cancellation, and then using
pthread_testcancel at appropriate points.  No additional
compiler/library support is required to implement that model.

Thanks,

-- 
Mark Mitchell <mark@codesourcery.com>
CodeSourcery, LLC

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17  3:55                             ` Jason Merrill
  2003-12-17  7:04                               ` David Abrahams
  2003-12-17  9:47                               ` Mark Mitchell
@ 2003-12-17 23:35                               ` Geoff Keating
  2 siblings, 0 replies; 74+ messages in thread
From: Geoff Keating @ 2003-12-17 23:35 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Matt Austern, Ulrich Drepper, gcc, Richard Henderson,
	Nathan Myers, Jakub Jelinek, wekempf, Mark Mitchell, fjh,
	Benjamin Kosnik, William Kempf

Jason Merrill <jason@redhat.com> writes:

> On Tue, 16 Dec 2003 18:55:13 -0500, David Abrahams <dave@boost-consulting.com> wrote:
> 
> > Matt Austern <austern@apple.com> writes:
> >
> >> The real issue, of course is the old one: that the people defining the
> >> POSIX standard and the people defining the C++ standard didn't
> >> spend enough time talking to each other.  POSIX doesn't know
> >> anything about C++ contracts.
> 
> > Nor about standard C++ library functions, I presume?  Why should it
> > have any impact on the behavior of the C++ lib from a standards POV?
> 
> The two standards are incompatible as written.  To make pthreads and C++
> play nice together, one or both need some adjustment.

That's not really correct, though, is it?  You can't write a strictly
conforming C++ program that uses threads.  Pthreads doesn't impose any
requirements on C++ code when pthreads is not used.  Thus, the
standards do not conflict.

-- 
- Geoffrey Keating <geoffk@geoffk.org>

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-16 20:07                 ` Matt Austern
  2003-12-16 20:31                   ` David Abrahams
@ 2003-12-18 16:48                   ` Jamie Lokier
  2003-12-18 16:56                     ` David Abrahams
  2003-12-18 17:31                     ` Mark Mitchell
  1 sibling, 2 replies; 74+ messages in thread
From: Jamie Lokier @ 2003-12-18 16:48 UTC (permalink / raw)
  To: Matt Austern
  Cc: David Abrahams, Jason Merrill, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf,
	Mark Mitchell, fjh, Benjamin Kosnik, William Kempf

Matt Austern wrote:
> Note that it's possible to temporarily disable thread cancellation in
> critical regions of code.  It might be appropriate for glibc and/or
> libstdc++ to do that.  On the other hand, we'll have to think carefully
> about standard conformance if we do something like that.

Why not make C++ "throw()" functions automatically disable thread
cancellation when they are entered and restore the state when they exit?

The code to do this could be optimised away with glibc support, but
conceptually it's a pair of pthread_setcancelstate() calls.

That doesn't violate pthreads - it's a change to C++, not pthreads.
I'm not sure if it violates C++.

-- Jamie

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-18 16:48                   ` Jamie Lokier
@ 2003-12-18 16:56                     ` David Abrahams
  2003-12-18 19:06                       ` Jamie Lokier
  2003-12-18 17:31                     ` Mark Mitchell
  1 sibling, 1 reply; 74+ messages in thread
From: David Abrahams @ 2003-12-18 16:56 UTC (permalink / raw)
  To: Jamie Lokier
  Cc: Matt Austern, Jason Merrill, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf,
	Mark Mitchell, fjh, Benjamin Kosnik, William Kempf

Jamie Lokier <jamie@shareable.org> writes:

> Matt Austern wrote:
>> Note that it's possible to temporarily disable thread cancellation in
>> critical regions of code.  It might be appropriate for glibc and/or
>> libstdc++ to do that.  On the other hand, we'll have to think carefully
>> about standard conformance if we do something like that.
>
> Why not make C++ "throw()" functions automatically disable thread
> cancellation when they are entered and restore the state when they exit?
>
> The code to do this could be optimised away with glibc support, but
> conceptually it's a pair of pthread_setcancelstate() calls.
>
> That doesn't violate pthreads - it's a change to C++, not pthreads.
> I'm not sure if it violates C++.

IIUC The 'C' lib functions are "throw()" when invoked from C++, so if
pthreads mandates that C I/O functions throw in C++, I think your idea
does violate pthreads.

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-18 16:48                   ` Jamie Lokier
  2003-12-18 16:56                     ` David Abrahams
@ 2003-12-18 17:31                     ` Mark Mitchell
  2003-12-18 18:56                       ` Jamie Lokier
  1 sibling, 1 reply; 74+ messages in thread
From: Mark Mitchell @ 2003-12-18 17:31 UTC (permalink / raw)
  To: Jamie Lokier
  Cc: Matt Austern, David Abrahams, Jason Merrill, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf, fjh,
	Benjamin Kosnik, William Kempf

On Thu, 2003-12-18 at 05:38, Jamie Lokier wrote:
> Matt Austern wrote:
> > Note that it's possible to temporarily disable thread cancellation in
> > critical regions of code.  It might be appropriate for glibc and/or
> > libstdc++ to do that.  On the other hand, we'll have to think carefully
> > about standard conformance if we do something like that.
> 
> Why not make C++ "throw()" functions automatically disable thread
> cancellation when they are entered and restore the state when they exit?

That's a special case.

You'd also want to do the disabling inside "throw (int)" functions for
example.  And, then, you'd want to reenable if a "throw (int)" function
called a "throw (...)" function (perhaps inside a try-block).

I think that if you did all that, your idea would not violate either
standard.  However, it still wouldn't really solve the problem.  For
example:

  // This function has no exception-specification but I know
  // it only throws ints!
  inline void f() { printf ("Throwing now!"); throw 3; }

  // This function will never throw anything.
  void g() throw () { try { f(); } catch (int) { } }

is the sort of C++ code that could be validated in a non-threaded
environment, but would call "std::terminate" if "printf" were
cancelled.  (Unless other changes were made to C++ to special-case the
thread cancellation exception, which is the idea that I oppose.)

-- 
Mark Mitchell <mark@codesourcery.com>
CodeSourcery, LLC

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-17 22:58                                   ` Mark Mitchell
@ 2003-12-18 18:51                                     ` Matt Austern
  2003-12-18 20:42                                       ` Mark Mitchell
  2003-12-18 21:20                                       ` David Abrahams
  0 siblings, 2 replies; 74+ messages in thread
From: Matt Austern @ 2003-12-18 18:51 UTC (permalink / raw)
  To: mark
  Cc: Jason Merrill, Ulrich Drepper, gcc, Richard Henderson,
	Nathan Myers, Jakub Jelinek, wekempf, fjh, Benjamin Kosnik,
	David Abrahams, William Kempf

My guess is that we aren't going to make progress on this issue on this 
list, mainly because it's a C++/POSIX issue and not a gcc issue.

I suggest that we set up a mailing list to discuss what a C++ binding 
to pthreads should look like (or perhaps, more generally, a C++ binding 
to POSIX).  My guess is that most of the people in the CC list would be 
interested in that question, and probably a few other people as well.  
I'd certainly want to include David Butenhof in the discussion, and my 
experience is the same as Dave Abrahams's: he's very willing to discuss 
the implication of pthread design issues for C++.

The goal of this discussion should be to get POSIX/C++ issues into one 
or both of the relevant standards.  Gcc and glibc and libstdc++ don't 
have to wait until the standardization effort is officially complete, 
of course, but it would be nice to get an idea of the direction before 
we go off implementing things.

			--Matt

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-18 17:31                     ` Mark Mitchell
@ 2003-12-18 18:56                       ` Jamie Lokier
  0 siblings, 0 replies; 74+ messages in thread
From: Jamie Lokier @ 2003-12-18 18:56 UTC (permalink / raw)
  To: Mark Mitchell
  Cc: Matt Austern, David Abrahams, Jason Merrill, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf, fjh,
	Benjamin Kosnik, William Kempf

Mark Mitchell wrote:
> You'd also want to do the disabling inside "throw (int)" functions for
> example.  And, then, you'd want to reenable if a "throw (int)" function
> called a "throw (...)" function (perhaps inside a try-block).
> 
> I think that if you did all that, your idea would not violate either
> standard.  However, it still wouldn't really solve the problem.  For
> example:
> 
>   // This function has no exception-specification but I know
>   // it only throws ints!
>   inline void f() { printf ("Throwing now!"); throw 3; }
> 
>   // This function will never throw anything.
>   void g() throw () { try { f(); } catch (int) { } }
> 
> is the sort of C++ code that could be validated in a non-threaded
> environment, but would call "std::terminate" if "printf" were
> cancelled.

No, it wouldn't call std::terminate.

g() would disable cancellations for its duration due to "throw()", and
the "try {} catch (int) {}" block doesn't change that.  ("catch (...)"
would change it as you said).  g() calls f() which makes no change to
the cancellation state.  Therefore the printf cannot be cancelled -
the cancellation will be deferred to the next cancellation point after
g() returns, assuming g()'s caller didn't disable cancellations too.

-- Jamie

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-18 16:56                     ` David Abrahams
@ 2003-12-18 19:06                       ` Jamie Lokier
  0 siblings, 0 replies; 74+ messages in thread
From: Jamie Lokier @ 2003-12-18 19:06 UTC (permalink / raw)
  To: David Abrahams
  Cc: Matt Austern, Jason Merrill, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf,
	Mark Mitchell, fjh, Benjamin Kosnik, William Kempf

David Abrahams wrote:
> IIUC The 'C' lib functions are "throw()" when invoked from C++, so if
> pthreads mandates that C I/O functions throw in C++, I think your idea
> does violate pthreads.

If it's true that C library functions are throw(), even functions
which are cancellation points, then the rule needs to be that
_calling_ a throw() function disables cancellations for the duration
of the call.

This does seem to prevent deferred cancellations from ever being
delivered, alas.

-- Jamie

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-18 18:51                                     ` Matt Austern
@ 2003-12-18 20:42                                       ` Mark Mitchell
  2003-12-18 22:32                                         ` Gabriel Dos Reis
  2003-12-18 22:58                                         ` Jonathan Lennox
  2003-12-18 21:20                                       ` David Abrahams
  1 sibling, 2 replies; 74+ messages in thread
From: Mark Mitchell @ 2003-12-18 20:42 UTC (permalink / raw)
  To: Matt Austern
  Cc: Jason Merrill, Ulrich Drepper, gcc, Richard Henderson,
	Nathan Myers, Jakub Jelinek, wekempf, fjh, Benjamin Kosnik,
	David Abrahams, William Kempf

On Thu, 2003-12-18 at 10:04, Matt Austern wrote:
> My guess is that we aren't going to make progress on this issue on this 
> list, mainly because it's a C++/POSIX issue and not a gcc issue.
> 
> I suggest that we set up a mailing list to discuss what a C++ binding 
> to pthreads should look like (or perhaps, more generally, a C++ binding 
> to POSIX).

Yes, I agree.

CodeSourcery would be happy to host the mailing list.

Does anyone in the CC list not want to be on the mailing list?

-- 
Mark Mitchell <mark@codesourcery.com>
CodeSourcery, LLC

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-18 18:51                                     ` Matt Austern
  2003-12-18 20:42                                       ` Mark Mitchell
@ 2003-12-18 21:20                                       ` David Abrahams
  1 sibling, 0 replies; 74+ messages in thread
From: David Abrahams @ 2003-12-18 21:20 UTC (permalink / raw)
  To: Matt Austern
  Cc: mark, Jason Merrill, Ulrich Drepper, gcc, Richard Henderson,
	Nathan Myers, Jakub Jelinek, wekempf, fjh, Benjamin Kosnik,
	William Kempf

Matt Austern <austern@apple.com> writes:

> My guess is that we aren't going to make progress on this issue on
> this list, mainly because it's a C++/POSIX issue and not a gcc issue.
>
> I suggest that we set up a mailing list to discuss what a C++ binding
> to pthreads should look like (or perhaps, more generally, a C++
> binding to POSIX).  My guess is that most of the people in the CC list
> would be interested in that question, and probably a few other people
> as well.  I'd certainly want to include David Butenhof in the
> discussion, and my experience is the same as Dave Abrahams's: he's
> very willing to discuss the implication of pthread design issues for
> C++.
>
> The goal of this discussion should be to get POSIX/C++ issues into one
> or both of the relevant standards.  Gcc and glibc and libstdc++ don't
> have to wait until the standardization effort is officially complete,
> of course, but it would be nice to get an idea of the direction before
> we go off implementing things.

There has been a resurgence of interest in the Boost.Threads library
on the Boost list as well; I think you'll find some people there who
are interested in this discussion.

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

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-18 20:42                                       ` Mark Mitchell
@ 2003-12-18 22:32                                         ` Gabriel Dos Reis
  2003-12-18 22:58                                         ` Jonathan Lennox
  1 sibling, 0 replies; 74+ messages in thread
From: Gabriel Dos Reis @ 2003-12-18 22:32 UTC (permalink / raw)
  To: mark
  Cc: Matt Austern, Jason Merrill, Ulrich Drepper, gcc,
	Richard Henderson, Nathan Myers, Jakub Jelinek, wekempf, fjh,
	Benjamin Kosnik, David Abrahams, William Kempf

Mark Mitchell <mark@codesourcery.com> writes:

| Does anyone in the CC list not want to be on the mailing list?

I'm not in the CC list but I definitely want to be on the mailing
list.

-- Gaby

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-18 20:42                                       ` Mark Mitchell
  2003-12-18 22:32                                         ` Gabriel Dos Reis
@ 2003-12-18 22:58                                         ` Jonathan Lennox
  2003-12-19  0:44                                           ` Mark Mitchell
  1 sibling, 1 reply; 74+ messages in thread
From: Jonathan Lennox @ 2003-12-18 22:58 UTC (permalink / raw)
  To: Mark Mitchell; +Cc: gcc

Mark Mitchell writes:
> On Thu, 2003-12-18 at 10:04, Matt Austern wrote:
> > I suggest that we set up a mailing list to discuss what a C++ binding 
> > to pthreads should look like (or perhaps, more generally, a C++ binding 
> > to POSIX).
> 
> Yes, I agree.
> 
> CodeSourcery would be happy to host the mailing list.
> 
> Does anyone in the CC list not want to be on the mailing list?

I'd also suggest advertising this new list to austin-group-l@opengroup.org
and to news:comp.std.c++ -- I believe those are the current forums for POSIX
and C++ standardization work respectively.

-- 
Jonathan Lennox
lennox at cs dot columbia dot edu

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
  2003-12-18 22:58                                         ` Jonathan Lennox
@ 2003-12-19  0:44                                           ` Mark Mitchell
  0 siblings, 0 replies; 74+ messages in thread
From: Mark Mitchell @ 2003-12-19  0:44 UTC (permalink / raw)
  To: Jonathan Lennox; +Cc: gcc

On Thu, 2003-12-18 at 13:40, Jonathan Lennox wrote:
> Mark Mitchell writes:
> > On Thu, 2003-12-18 at 10:04, Matt Austern wrote:
> > > I suggest that we set up a mailing list to discuss what a C++ binding 
> > > to pthreads should look like (or perhaps, more generally, a C++ binding 
> > > to POSIX).
> > 
> > Yes, I agree.
> > 
> > CodeSourcery would be happy to host the mailing list.
> > 
> > Does anyone in the CC list not want to be on the mailing list?
> 
> I'd also suggest advertising this new list to austin-group-l@opengroup.org
> and to news:comp.std.c++ -- I believe those are the current forums for POSIX
> and C++ standardization work respectively.

Done.

-- 
Mark Mitchell <mark@codesourcery.com>
CodeSourcery, LLC

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: catch(...) and forced unwind
@ 2003-12-18 23:03 Christopher Eltschka
  0 siblings, 0 replies; 74+ messages in thread
From: Christopher Eltschka @ 2003-12-18 23:03 UTC (permalink / raw)
  To: gcc

Hi all,

sorry for entering this discussion as "outsider", but I've seen your
ML Thread about translation of pthread_cancel into exceptions, and I
think your argumentations bases on wrong assumtions (namely, that a
C++ implementation translating synchronous cancels into C++ exceptions
cannot be both conforming to POSIX and C++).

Now I must admit I'm not a threading expert, so my argumentation may
be flawed. However, I believe my analysis to be correct, and therefore
I wrote this mail.

Let me first sum up the conclusions of the analysis (if you consider
them wrong, please go on to the argumentation anyway and tell me
*where* it is wrong).

* It is possible to translate cancels into C++ exceptions and at
  the same time conform both to C++ and POSIX standards.
* For such an implementation, the C standard I/O functions (like
  fread) and C++ standard functions (linke operator>> on streams)
  are *no* cancellation points, while POSIX-only I/O functions
  (like read) *are* cancellation points.

Now to my argumentation:

First, let's start with POSIX threads (this is the area where errors
are most likely). According to
http://www.opengroup.org/onlinepubs/007904975/functions/xsh_chap02_09.html
there are some functions which *shall* be cancellation points (i.e.
any implementations where those functions are not cancellation points
are non-conforming), and others which *may* be cancellation points
(i.e. if those are cancellation points in a given implementation
doesn't affect if that implementation is conforming).

Now AFAICS all functions from the C standard library are in the "maybe
class". This means that f.ex. an implementation where fread is no
cancellation point is still POSIX conforming (unless there are other
reasons why it isn't, of course). Note that this also means that any
program relying on e.g. fread being a cancellation point is relying on
implementation defined behaviour, and therefore by definition
unportable.

Since the POSIX standard doesn't speak about C++, it doesn't directly
impose any conditions on which C++ functions are cancellation points.

As has been said in the ML thread, "un-cancelling" (by catching
without rethrowing) is a pure extension to POSIX threads and therefore
conforming.


Next, to the C++ standard (in this area, I'm quite confident that my
arguments are correct):

First, the C++ standard clearly doesn't pose any conditions on POSIX
functions which are not part of the standard C library, since those
functions are non-standard as far as C++ is concerned. Especially it
does not impose the condition that they don't throw. Therefore they
may be cancellation points even if cancellation results in an
exception to be thrown.

The C++ standard defines the C++ I/O functions in term of the standard
C I/O functions. Therefore, the C++ I/O functions are forced to be
cancellation points iff the C functions are forced to be. Therefore if
my above analysis of POSIX requirements is correct, the C++ I/O
functions are not forced to be cancellations.

Now in C++, the standard C I/O functions are not allowed to throw,
therefore if cancellation is translated into an exception, those
functions are not to be allowed to be cancellation points. If my above
POSIX analysis is correct, this is allowed by the POSIX standard.

The same applies for C++ I/O on streams where badbit is not set in the
exception mask, for the same reason: Exceptions are not allowed to
escape. Now for streams where badbit is set, there are strictly
speaking no requirements about C++ I/O functions being cancellation
points (since neither standard has any clause disallowing), but it
would be perverse if C++ I/O being a cancellation point would depend
on badbit being set, while C I/O never is.


Note that if no part of the C or C++ standard library is a
cancellation point (and if my analysis is correct, this is conpletely
conforming to POSIX), then with one exception noted below, every code
which is purely standard C++ is by definition synchronous cancel safe,
since synchronous cancels simply cannot occur (except maybe in user
code called by the library if that code may throw exceptions; but then
the library just has to be exception safe to be synchronous cancel
safe, which it should be anyway). OTOH, libraries calling POSIX
functions not in the C++ standard have to be prepared to handle cancel
exceptions.

The one exception is if streams using user-defined streambufs don't
have badbit set in the exception mask, and the user-defined streambuf
contains calls to POSIX functions not part of standard C++. In that
case, the stream may silently eat cancel requests. However I consider
that a minor problem, since the writer of that non-standard stream
buffer can just document that it may only be used on streambufs with
badbit set in the exception mask if cancellation shall be possible.

Best regards,
Christopher Eltschka


^ permalink raw reply	[flat|nested] 74+ messages in thread

end of thread, other threads:[~2003-12-18 22:38 UTC | newest]

Thread overview: 74+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-12-12 22:54 catch(...) and forced unwind Jason Merrill
2003-12-13  0:09 ` David Abrahams
2003-12-13  2:22 ` Benjamin Kosnik
2003-12-13  8:28   ` Jason Merrill
     [not found]     ` <20031213082241.GB2416@tofu.dreamhost.com>
2003-12-13  9:26       ` Nathan Myers
2003-12-15 22:24   ` Richard Henderson
2003-12-15 22:45     ` Benjamin Kosnik
2003-12-15 22:52       ` Richard Henderson
2003-12-15 22:54         ` Richard Henderson
2003-12-15 23:05         ` Benjamin Kosnik
2003-12-16  0:04           ` Richard Henderson
     [not found] ` <ud6at1wvg.fsf@boost-consulting.com>
2003-12-13  6:55   ` Jason Merrill
     [not found]     ` <u65gkyhv4.fsf@boost-consulting.com>
2003-12-14  4:23       ` Nathan Myers
2003-12-15 20:29         ` Jason Merrill
2003-12-15 23:34           ` David Abrahams
2003-12-16  0:29             ` Mark Mitchell
2003-12-16  0:37               ` Ulrich Drepper
2003-12-16  1:42                 ` Zack Weinberg
2003-12-16  1:52                   ` Zack Weinberg
2003-12-16  2:18                   ` Ulrich Drepper
2003-12-16  2:04                     ` Zack Weinberg
2003-12-16  5:53                       ` Jim Wilson
2003-12-16  7:46                         ` Zack Weinberg
2003-12-16 10:16                 ` Nathan Myers
2003-12-16 11:55                   ` Ulrich Drepper
2003-12-16 14:07                 ` David Abrahams
2003-12-16  0:52             ` Jason Merrill
2003-12-16 14:31               ` David Abrahams
2003-12-16 20:07                 ` Matt Austern
2003-12-16 20:31                   ` David Abrahams
2003-12-16 21:50                     ` Matt Austern
2003-12-16 22:49                       ` David Abrahams
2003-12-16 23:44                         ` Matt Austern
2003-12-17  0:43                           ` David Abrahams
2003-12-17  3:55                             ` Jason Merrill
2003-12-17  7:04                               ` David Abrahams
2003-12-17  9:47                               ` Mark Mitchell
2003-12-17  9:54                                 ` Jason Merrill
2003-12-17 10:28                                   ` Mark Mitchell
2003-12-17 18:25                                     ` Gabriel Dos Reis
2003-12-17 13:26                                 ` David Abrahams
2003-12-17 17:19                                   ` Mark Mitchell
2003-12-17 17:48                                     ` David Abrahams
2003-12-17 18:36                                       ` Mark Mitchell
2003-12-17 19:48                                         ` David Abrahams
2003-12-17 20:18                                           ` Mark Mitchell
2003-12-17 22:10                                             ` Richard Henderson
2003-12-17 22:43                                               ` Mark Mitchell
2003-12-17 22:44                                                 ` David Abrahams
     [not found]                                                 ` <20031217192555.GY12344@sunsite.ms.mff.cuni.cz>
2003-12-17 22:59                                                   ` Mark Mitchell
2003-12-17 22:48                                 ` Matt Austern
2003-12-17 22:58                                   ` Mark Mitchell
2003-12-18 18:51                                     ` Matt Austern
2003-12-18 20:42                                       ` Mark Mitchell
2003-12-18 22:32                                         ` Gabriel Dos Reis
2003-12-18 22:58                                         ` Jonathan Lennox
2003-12-19  0:44                                           ` Mark Mitchell
2003-12-18 21:20                                       ` David Abrahams
2003-12-17 23:35                               ` Geoff Keating
2003-12-18 16:48                   ` Jamie Lokier
2003-12-18 16:56                     ` David Abrahams
2003-12-18 19:06                       ` Jamie Lokier
2003-12-18 17:31                     ` Mark Mitchell
2003-12-18 18:56                       ` Jamie Lokier
2003-12-16 20:57                 ` Jason Merrill
2003-12-16 21:55                   ` David Abrahams
2003-12-17  0:32                   ` Jason Merrill
2003-12-17  5:28                     ` Jason Merrill
2003-12-15 10:16       ` Richard Henderson
2003-12-15 15:44         ` David Abrahams
     [not found]         ` <u8yler71p.fsf@boost-consulting.com>
2003-12-15 22:19           ` Richard Henderson
2003-12-15 23:36             ` David Abrahams
2003-12-16  0:08               ` Richard Henderson
2003-12-18 23:03 Christopher Eltschka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).