[c++-pthreads] Restating the Jason model
Dave Butenhof
David.Butenhof at hp.com
Tue Jan 13 12:47:17 UTC 2004
Jason Merrill wrote:
>I think this is an appropriate time to restate my proposal. I think
>there's a fair amount of consensus around these three points:
>
> * Cancellation is a normal exception.
> * If a cancellation exception is destroyed, the cancellation request
> is re-entered, and acted on again at the next cancellation point.
> * Cancellation is disabled during unwinding.
>
>But there are still some open questions:
>
> * Which of the POSIX cancellation points are cancellation points in C++?
>
>None of the mandatory cancellation points are mentioned in the C++
>standard, so I don't see any reason to prevent them from throwing
>cancellation in C++ code.
>
>POSIX also says that the C standard I/O functions may be cancellation
>points, while the C++ standard says that they don't throw. This
>contradiction can be resolved either by allowing them to throw cancellation
>or declaring that they are not cancellation points when called from C++
>code; if we choose the latter, an implementation could just change them to
>never be cancellation points, since that is allowed by POSIX.
>
>Dave Butenhof mentioned that on Tru64 printf is not a cancellation point,
>to avoid having to deal with cleaning up internal state. But what about
>scanf, which can block? One of the convenient things about pthread
>cancellation is that it wakes up a blocked thread. Does this not happen on
>Tru64 if the thread is using stdio functions?
>
>My preference is still to amend the C++ standard to allow stdio functions
>to throw cancellation.
>
>
Since most platforms likely to support C++ cancellation already support
POSIX cancellation, making the rules compatible would be "nice".
(Perhaps even essential for wide acceptance.)
As such, the obvious path for C++ would be to start with, and extend as
necessary, the Single UNIX Specification (SUS) rules (which are in turn
extensions of the base POSIX rules to cover interfaces not defined by
POSIX). If you did this, you're starting with two cancellation point
lists: mandatory and optional. Implementations MUST raise cancel for all
required cancellation points, and MAY (but need not) for the optional
points. Applications, meanwhile, can depend portably on cancellation
from the mandatory points; while they always must be prepared for (but
cannot portably depend upon) cancellation from the optional points.
The general logic for the division between mandatory and obsolete is
based on both "traditional UNIX implementation" (mandatory points are
almost always direct kernel syscalls while the optional points are
generally user library routines) and also on the efficiency/logic that
mandatory points ALWAYS (or at least "nearly always") perform operations
subject to blocking, while the optional points SOMETIMES perform such
operations. (E.g., "read" always reads from a file unless there's an
error... while scanf reads from a file only when any existing buffer is
empty; you might make several scanf or printf calls purely from a local
stdio buffer.) The twin logic forks are therefore that the syscalls
(e.g., file access) are cancellation points; while "higher level"
operations that use these syscalls are allowed to act as cancellation
points only when they actually make a syscall. But that was a plausible
excuse: the real reason for mandatory cancellation points was that we
couldn't force everyone to analyze and substantially redesign their
stdio packages (in particular) to deal with cancellation and cleanup, so
we wanted to allow them to simply disable cancellation.
The idea was that this would be "transitional", but of course nothing
ever works out that way. Tru64's libc, like many, provides a set of
"nocancel" syscall stubs for internal use, and printf() (for example)
calls write_nc() instead of write() so that it never needs to deal with
cancellation. The issue for Tru64 is one of packaging, primarily; our
exception library (libexc) has a long and twisted history going back to
our original DCE OSF/1 implementation on MIPS R2000, using (along with
Mach and BSD and OSF/1) a bunch of MIPSCO IP... including Mark
Himmelstein's exceptions. It's big and a little unwieldy, and nobody was
willing to either merge it into libc (which I always thought was the
right solution) or to make libc depend on it. Thus there's simply no way
for libc code to handle exceptions, and "we" simply had no way to
implement the optional cancellation points.
The mandatory cancellation points, as I said, were deliberately those
blocking entries that are "pure syscalls"; where user-mode cleanup isn't
an issue.
> * Which bits of the C++ library are cancellation points?
>
>I would think pretty much all I/O code, and nothing else.
>
>
Not just "I/O", but in general any explicit control point that might
"indefinitely block". Except for some low-level blocking operations,
like mutex lock, where we felt that requiring all calls to prepare for
cancellation would be impractical.
>Closely related to this is the question of what happens if a cancellation
>exception is thrown under a formatted I/O function; currently it would be
>caught and discarded, so it would only escape on a flush or the like. I
>think it should escape from formatted I/O as well. This could be
>implemented by explicitly rethrowing cancel, by limiting the set of
>exceptions trapped, or by calling pthread_testcancel after the try/catch
>block.
>
>If formatted I/O functions continue to trap cancellation exceptions, they
>would not be cancellation points; a cancellation point in the C++ binding
>would be a function which can throw a cancellation exception.
>
>
Any C++ runtime function is in much the same category as the user-mode C
runtime functions. With the "exception" that the C++ runtime definitely
CAN deal with exceptions. Still, though, presumably any C++ formatted
I/O is buffered, and therefore may not on each operation make a true
"I/O call". Life is easier for programmers if they can depend on
behavior with no exceptions, arguing all cancellation points ought to be
mandatory and unconditional -- which would mean testing for cancel
explicitly when not otherwise making a cancellable call. On the other
hand, life is easier for C++ runtime developers if they're not required
to ensure that this happens in all possible code paths. And, like most C
runtime libraries, C++ runtimes may be written without preparation for
cancellation (or indeed exceptions in any form) in most of these code
paths, since the developers knew where THEY might raise exceptions, and
nobody else could do it to them.
Idealism suggests supporting the application developers' desire for
consistency and predictability. Pragmatism argues against forcing all
C++ runtimes to be substantially analyzed and modified. Pragmatism won
in POSIX as it usually did, and many of the arguments I've seen in this
group suggest (unscientifically) that C++ committee members might share
some similar biases.
> * Should cancellation also be disabled in destructors run during normal
> execution? In catch blocks?
>
>IMO, no and no.
>
>
Cancellation should NOT be disabled in destructors? Did you mean to say
that?
> * How can C++ code interact with a cancellation exception?
>
>I think everyone agrees that it should be possible to catch a cancel by
>name. We still need to specify that name and any additional operations the
>cancel object might support.
>
>
Additional operations on the cancel object. Interesting. Like, for
example, if the cancel object destructor were to automatically re-pend
the cancel unless the handler had already declared "cancel.finalize()"?
(Could or should this be done automatically be the runtime for
'catch(cancel)' as opposed to 'catch(...)'?)
> * What about pthread_exit?
>
>I'm happy with the g++ status quo whereby destroying a pthread_exit
>exception calls terminate. Unlike cancellation, the position of a call to
>pthread_exit is deterministic, so the user is responsible for making sure
>that it can propagate.
>
>
Well, yes; although it also seems better to make one new rule for the
new "thread terminating exceptions" rather than two separate new rules.
>Anything else?
>
>
Yes; but I don't yet know what it is. ;-)
--
/--------------------[ David.Butenhof at hp.com ]--------------------\
| Hewlett-Packard Company Tru64 UNIX & VMS Thread Architect |
| My book: http://www.awl.com/cseng/titles/0-201-63392-2/ |
\----[ http://homepage.mac.com/dbutenhof/Threads/Threads.html ]---/
More information about the c++-pthreads
mailing list