This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: catch(...) and forced unwind
- From: Christopher Eltschka <celtschk at web dot de>
- To: gcc at gcc dot gnu dot org
- Date: Thu, 18 Dec 2003 23:35:08 +0100
- Subject: Re: catch(...) and forced unwind
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