From jason at redhat.com Mon Jul 11 15:18:06 2005 From: jason at redhat.com (Jason Merrill) Date: Mon, 11 Jul 2005 11:18:06 -0400 Subject: pthread_cancel and EH: let's try this again Message-ID: Previous discussion on this topic ended in something of a stalemate. Unfortunately, the practical result of this on linux has been very unfortunate for users: code that uses both pthread_cancel and catch(...) blocks aborts at runtime, where it worked on previous releases, and continues to work on other platforms. This is the worst of both worlds for users, and needs to change. In previous discussions, my favored solution was: 1a) Cancellation is disabled during stack unwinding, to avoid trying to throw out of a destructor. 1b) Make cancellation a normal exception that can be caught and discarded, but have the destructor for the exception re-assert cancellation so that the process will begin again at the next cancellation point. Apparently this is also the Boost.Threads design. Then there's the Ada-equivalent model: 2a) Cancellation is disabled during destructors and empty exception specs. 2b) Cancellation exceptions are not caught by (...). And the current status quo in GCC: 3) #1, except that the destructor for the exception calls abort(). Additional inelegant possibilities for the destructor would be killing just the thread, throwing a new exception, or doing nothing (leaving the thread in a sort of zombie state). The main difference here is handling of (...). I can think of four uses of catch (...): Cleanup without using a destructor (catch and rethrow). This works under #1 and #3, and doesn't work under #2. OTOH, this is already considered inelegant, and a #2 system could simply say that for a program to be pthread_cancel-safe it needs to put all cleanups in destructors. Destructor exception safety (catch and discard). This works fine under all models because cancellation is disabled during cleanup, so no cancellation exception is thrown. Thread robustness (catch and retry). A thread could have a catch (...) at the top level to try to recover from errors, on the principle that limping along is better than total failure. Previous discussion seemed to assume that the users would want this to catch cancellation as well, but I think that's wrong; if someone specifically told the thread to go away, they don't want it to recover, they want it to go away. Having implemented #3, Red Hat has gotten a couple of bug reports from users with this sort of code; before we implemented the cancellation exception the thread went away like it was supposed to, but now we end up calling terminate() because they don't rethrow the exception. This isn't very helpful. #2 has the desired semantics for this situation, backward compatible with existing pthread_cleanup_push/pop code; under a #1 system users would need to add code to specifically look for cancellation exceptions in order to let them through. #3 modified to only kill the current thread would probably work with most cases. Inter-language glue (catch and throw something else). #1 handles this by waiting and throwing another cancellation exception at the next cancellation point encountered, or doing whatever the other language does to handle cancellation. #2 handles this by ignoring it and just propagating the cancellation (which should be handled properly by all languages sharing the EH runtime). #3 blows up. Ulrich Drepper insists that #1 is impossible, because pthread cancellation is an irreversible state change. But I'm not sure why you can't just flip various flags back to where they were before. My current inclination is to go with model #2; backwards compatibility with code written to work with pthread_cleanup_push/pop seems like a powerful argument in its favor. People who want model #1 can use a different threading library, such as Boost.Threads. Archives: http://www.codesourcery.com/archives/c++-pthreads/threads.html http://gcc.gnu.org/ml/gcc-patches/2003-04/msg02246.html http://gcc.gnu.org/ml/gcc-patches/2003-05/msg00000.html Jason From pdimov at mmltd.net Mon Jul 11 17:29:48 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Mon, 11 Jul 2005 20:29:48 +0300 Subject: [cpp-threads] pthread_cancel and EH: let's try this again References: Message-ID: <001501c5863e$25ad0ec0$6501a8c0@pdimov> Some comments... Jason Merrill wrote: [...] > In previous discussions, my favored solution was: > 1a) Cancellation is disabled during stack unwinding, to avoid trying > to throw out of a destructor. > 1b) Make cancellation a normal exception that can be caught and > discarded, but have the destructor for the exception re-assert > cancellation so that the process will begin again at the next > cancellation point. > Apparently this is also the Boost.Threads design. > > Then there's the Ada-equivalent model: > 2a) Cancellation is disabled during destructors and empty exception > specs. > 2b) Cancellation exceptions are not caught by (...). > > And the current status quo in GCC: > 3) #1, except that the destructor for the exception calls abort(). > Additional inelegant possibilities for the destructor would be > killing just the thread, throwing a new exception, or doing nothing > (leaving the thread in a sort of zombie state). 1. Boost.Threads doesn't support cancellation. Very possibly never will. 2. The arguments in favor of ... not catching the cancellation exception can be summarized as: 2a. We can break perfectly valid catch(...)+rethrow cleanup code because it's inelegant. 2b. Some people that use catch(...) don't really want catch(...) semantics. 3. Non-empty exception specifications may terminate() on cancellation. (These are even less elegant than catch+rethrow, of course.) This is also true in cases where the original code avoided terminate() by remapping exceptions: void f() throw( MyException ) { try { g(); } catch( MyException const & ) { throw; } catch( ... ) { throw MyBadException(); } } (Remapping via unexpected() will work, though, if the cancellation exception plays by the rules.) 4. Inter-language communication is usually done by translating the exception into a return code, squeezing that through an extern "C" interface, then optionally throwing at the other end. It isn't just catch and rethrow something else. 5. Disabling cancellation during empty exception specs is too coarse: int f() throw() { try { return lengthy_operation(); } catch(...) { return EXCEPTION; } } I want cancellation to be active during lengthy_operation. Summary: I'm in favor of 1 minus the "destructor reasserts" part (it's not needed). I'm undecided on whether the cancellation request is (implicitly) cleared when the cancellation exception is thrown. There are good arguments in favor of either approach, and a reasonable compromise would be to not clear the cancellation request and provide a function for clearing it explicitly for the cases where this is desired. Finally, > People who want model #1 can use a different threading library, such as > Boost.Threads. this is impossible on a number of levels. :-) From gshiman at commvault.com Mon Jul 11 19:26:46 2005 From: gshiman at commvault.com (George Shimanovich) Date: Mon, 11 Jul 2005 15:26:46 -0400 Subject: [c++-pthreads] pthread_cancel and EH: let's try this again Message-ID: <52CA6BC0D0E9EE4E93208DB39A3218FEA4589B@EXCHANGE.gp.cv.commvault.com> >This works under #1 and #3, and doesn't work under #2. I would like to read overview of #1, #2 and #3 but cannot find it in recent posting of this thread. Can anyone provide a link or date? I really want to understand why #1 is so good that Linux pthread stays so bad for so long. George Shimanovich -------------- next part -------------- An HTML attachment was scrubbed... URL: From mark at codesourcery.com Mon Jul 11 20:36:22 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Mon, 11 Jul 2005 13:36:22 -0700 Subject: [c++-pthreads] pthread_cancel and EH: let's try this again In-Reply-To: References: Message-ID: <42D2D846.8000607@codesourcery.com> Jason Merrill wrote: > Previous discussion on this topic ended in something of a stalemate. Thank you for re-starting the discussion. I wasn't happy with the stalemate, but I didn't have the fortitude to try again! > In previous discussions, my favored solution was: > 1a) Cancellation is disabled during stack unwinding, to avoid trying to > throw out of a destructor. > 1b) Make cancellation a normal exception that can be caught and discarded, > but have the destructor for the exception re-assert cancellation so that > the process will begin again at the next cancellation point. I think this is a reasonable solution. I think I'd still prefer just to have the handler catch the exception and discard it, but not strongly enough to try to stand in the way of progress. If you can build consensus around this option, I'll support it fully. Both your model, and the variant I suggest, preserve the pleasant property that code which already handles "random" exceptions (like that in libraries designed to plug into applications) continues to behave reasonably well in the presence of cancellation. Code that doesn't handle random exceptions probably doesn't handle thread-cancellation either; if it's relying on certain functions throwing only certain exceptions, then it's probably written to work in a relatively controlled environment. (Of course, if it were compiled with headers that say that cancellation point functions throw no exceptions, then it would be completely hosed, under any of these models.) > Then there's the Ada-equivalent model: > 2a) Cancellation is disabled during destructors and empty exception specs. > 2b) Cancellation exceptions are not caught by (...). I think this ought to be considered a non-starter. Ignoring "catch (...)" blocks in C++ is worse than just killing the thread. Style considerations aside, there's a ton of code that relies on that to clean up resources, or to otherwise restore state; and running destructors after skipping "catch (...)" blocks is just plain wrong, in my opinion. Maybe in workstation/server applications this makes sense to some people, but I don't think it makes any sense at all on an embedded system, where the system is often set up to handle complete process death, but not weird inconsistencies. You'd be breaking people's program verification regimes, as well. > Thread robustness (catch and retry). A thread could have a catch (...) > at the top level to try to recover from errors, on the principle that > limping along is better than total failure. Previous discussion seemed > to assume that the users would want this to catch cancellation as well, > but I think that's wrong; if someone specifically told the thread to go > away, they don't want it to recover, they want it to go away. I agree. In fact, despite my oft-stated opinion that it should be possible to catch cancellation exceptions, I agree that actually doing that -- and never restarting the cancellation process -- would generally be a bug in user code. The reason I'm OK with catching the exception is to do things like: try { ... } catch (Cancellation) { cancelled = 1; } /* Other stuff here. We have no finally clauses in C++. */ if (cancelled) { throw Cancellation; // Or, maybe a different exception type, that // tells the top level to cancel the thread. } Your auto-recancel semantics are probably good enough in this kind of situation. > Ulrich Drepper insists that #1 is impossible, because pthread cancellation > is an irreversible state change. But I'm not sure why you can't just flip > various flags back to where they were before. Yes, I've asked Ulrich about this several times, and have never gotten an explanation. > My current inclination is to go with model #2; backwards compatibility > with code written to work with pthread_cleanup_push/pop seems like a > powerful argument in its favor. People who want model #1 can use a > different threading library, such as Boost.Threads. Oh, no... I thought up until this paragraph that we were going to be on the same page. I think that if #1 really is impossible, #2 might be second-best. But, I'd very much like an explanation of why #1 is impossible. While I have very high confidence in Ulrich's technical abilities, I don't think we should have to take his opinions on faith. -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From nathan at codesourcery.com Mon Jul 11 22:04:40 2005 From: nathan at codesourcery.com (Nathan Sidwell) Date: Mon, 11 Jul 2005 23:04:40 +0100 Subject: [c++-pthreads] pthread_cancel and EH: let's try this again In-Reply-To: References: Message-ID: <42D2ECF8.3000303@codesourcery.com> Jason Merrill wrote: > In previous discussions, my favored solution was: > 1a) Cancellation is disabled during stack unwinding, to avoid trying to > throw out of a destructor. > 1b) Make cancellation a normal exception that can be caught and discarded, > but have the destructor for the exception re-assert cancellation so that > the process will begin again at the next cancellation point. > Apparently this is also the Boost.Threads design. > > Then there's the Ada-equivalent model: > 2a) Cancellation is disabled during destructors and empty exception specs. > 2b) Cancellation exceptions are not caught by (...). I disagree that #2 is preferable. My view is that #1 is the better solution. Implementing #2 breaks the C++ idiom that using try {} catch(...) {...; throw;} is equivalent to using a destructor for cleanups. It might be frowned upon, but it exists in the language, and in code. As I previously wrote, a pathelogical case, that can only be written with catch (...) is applying va_end on an exception path (va_end must be called in the same function that called va_start or va_copy). If I understand #2a correctly, this will require nothrow functions to disable and reenable thread cancellation on entry and exit. This sounds suboptimal. I suppose it would be possible to determine one was inside a nothrow function during the stack scanning phase of exception handling, and then not throw the exception if that were the case. But this relies on 2-phase unwinding and restartable exceptions. And, AFAICT, one would then need to disable thread cancellation in some manner to prevent attempting to throw the cancellation request at every subsequent cancellation point met within the nothrow function. > Ulrich Drepper insists that #1 is impossible, because pthread cancellation > is an irreversible state change. But I'm not sure why you can't just flip > various flags back to where they were before. Likewise. > My current inclination is to go with model #2; backwards compatibility > with code written to work with pthread_cleanup_push/pop seems like a > powerful argument in its favor. People who want model #1 can use a > different threading library, such as Boost.Threads. This is not a good idea. My understanding is that posix thread cancellation doesn't address cleanups at all, Boost.Threads does. Given we're trying to meld threads and a language with cleanups, we should endeavour to support all the cleanup mechanisms of the language and the experience of Boost.Threads, than invent something different. To summarize, both option 1 and option 2 break somethings and preserve other things. #1. Preserves C++'s link between catch (...) {...; throw;} and regular destructors. Breaks catch (...) {} at the outermost level of a thread. Breaks nothrow functions that call functions that contain cancellation points. #2. Allows catch (...) {} at the outermost level to DTRT (probably) Breaks (silently) catch (...) {...; throw;} Allows nothrow functions to 'just work' in the face of thread cancellation. Adds a non-exception path cost to nothrow functions. IMHO #1 is better, for it also allows us to say 'thread cancellation is *exactly* like exception handling'. nathan -- Nathan Sidwell :: http://www.codesourcery.com :: CodeSourcery LLC nathan at codesourcery.com :: http://www.planetfall.pwp.blueyonder.co.uk From dave at boost-consulting.com Mon Jul 11 22:29:25 2005 From: dave at boost-consulting.com (David Abrahams) Date: Mon, 11 Jul 2005 18:29:25 -0400 Subject: pthread_cancel and EH: let's try this again References: <42D2D846.8000607@codesourcery.com> Message-ID: Mark Mitchell writes: > Jason Merrill wrote: >> Previous discussion on this topic ended in something of a stalemate. > > Thank you for re-starting the discussion. I wasn't happy with the > stalemate, but I didn't have the fortitude to try again! > >> In previous discussions, my favored solution was: >> 1a) Cancellation is disabled during stack unwinding, to avoid trying to >> throw out of a destructor. >> 1b) Make cancellation a normal exception that can be caught and discarded, >> but have the destructor for the exception re-assert cancellation so that >> the process will begin again at the next cancellation point. > > I think this is a reasonable solution. > > I think I'd still prefer just to have the handler catch the exception > and discard it, Me too. I don't see any need to make this exception special. > but not strongly enough to try to stand in the way of progress. Me too. I haven't thought through the arguments about whether this re-cancel behavior is a good idea. In fact, I don't know what they are, so if someone could summarize that would be great. > If you can build consensus around this option, I'll support > it fully. > > Both your model, and the variant I suggest, preserve the pleasant > property that code which already handles "random" exceptions (like that > in libraries designed to plug into applications) continues to behave > reasonably well in the presence of cancellation. Yep, that's important to me. > Code that doesn't handle random exceptions probably doesn't handle > thread-cancellation either; if it's relying on certain functions > throwing only certain exceptions, then it's probably written to work in > a relatively controlled environment. (Of course, if it were compiled > with headers that say that cancellation point functions throw no > exceptions, then it would be completely hosed, under any of these models.) Unless the code doesn't call any of those cancellation point functions. >> Then there's the Ada-equivalent model: >> 2a) Cancellation is disabled during destructors and empty exception specs. >> 2b) Cancellation exceptions are not caught by (...). > > I think this ought to be considered a non-starter. Ignoring "catch > (...)" blocks in C++ is worse than just killing the thread. Style > considerations aside, there's a ton of code that relies on that to clean > up resources, or to otherwise restore state; and running destructors > after skipping "catch (...)" blocks is just plain wrong, in my opinion. Agree. > Maybe in workstation/server applications this makes sense to some > people, but I don't think it makes any sense at all on an embedded > system, where the system is often set up to handle complete process > death, but not weird inconsistencies. You'd be breaking people's > program verification regimes, as well. The platform doesn't matter. Destructors have to be able to rely on program invariants being maintained, and as you imply, skipping a catch(...) block in the middle of unwinding is likely to break those invariants. >> Thread robustness (catch and retry). A thread could have a catch (...) >> at the top level to try to recover from errors, on the principle that >> limping along is better than total failure. Previous discussion seemed >> to assume that the users would want this to catch cancellation as well, >> but I think that's wrong; if someone specifically told the thread to go >> away, they don't want it to recover, they want it to go away. > > I agree. In fact, despite my oft-stated opinion that it should be > possible to catch cancellation exceptions, I agree that actually doing > that -- and never restarting the cancellation process -- would generally > be a bug in user code. Almost. If the thread (optionally issues some kind of report and) exits -- an entirely plausible response to an exception ending up in catch(...) because you didn't recognize it -- I think that's not quite bad enough to be a bug, and technically it does not amount to restarting the cancellation process. That would entail re-throwing a cancellation exception IMO. > The reason I'm OK with catching the exception is to do things like: > > try { ... } catch (Cancellation) { > cancelled = 1; > } > /* Other stuff here. We have no finally clauses in C++. */ > if (cancelled) { > throw Cancellation; // Or, maybe a different exception type, that > // tells the top level to cancel the thread. > } As Peter D. suggested, something similar happens when C++ interoperates with Python (and I'm sure many other systems written in 'C'). Usually "Other stuff here" is actually a few stack frames of 'C' code. > Your auto-recancel semantics are probably good enough in this kind of > situation. I'd like more detail on how it helps (and of course any arguments against it too). >> Ulrich Drepper insists that #1 is impossible, because pthread cancellation >> is an irreversible state change. But I'm not sure why you can't just flip >> various flags back to where they were before. Agree. > Yes, I've asked Ulrich about this several times, and have never gotten > an explanation. > >> My current inclination is to go with model #2; backwards compatibility >> with code written to work with pthread_cleanup_push/pop seems like a >> powerful argument in its favor. People who want model #1 can use a >> different threading library, such as Boost.Threads. > > Oh, no... I thought up until this paragraph that we were going to be on > the same page. Whoa! Me too! > I think that if #1 really is impossible, #2 might be second-best. But, > I'd very much like an explanation of why #1 is impossible. While I have > very high confidence in Ulrich's technical abilities, I don't think we > should have to take his opinions on faith. Yah. Number 2 breaks too many programs and libraries that ought to be correct in the presence of threads. -- Dave Abrahams Boost Consulting www.boost-consulting.com From dave at boost-consulting.com Mon Jul 11 22:34:13 2005 From: dave at boost-consulting.com (David Abrahams) Date: Mon, 11 Jul 2005 18:34:13 -0400 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> Message-ID: Nathan Sidwell writes: > IMHO #1 is better, for it also allows us to say 'thread cancellation is > *exactly* like exception handling'. It's more than that. #2 changes the exception handling model. Simplicity of definition and programming model is crucial. People already have enough trouble coming to grips with exception safety. Introducing #2 complicates the EH model, so I oppose it on those grounds also. -- Dave Abrahams Boost Consulting www.boost-consulting.com From jakub at redhat.com Mon Jul 11 22:52:35 2005 From: jakub at redhat.com (Jakub Jelinek) Date: Mon, 11 Jul 2005 18:52:35 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D2ECF8.3000303@codesourcery.com> Message-ID: <20050711225235.GO4884@devserv.devel.redhat.com> On Mon, Jul 11, 2005 at 06:34:13PM -0400, David Abrahams wrote: > Nathan Sidwell writes: > > > IMHO #1 is better, for it also allows us to say 'thread cancellation is > > *exactly* like exception handling'. > > It's more than that. #2 changes the exception handling model. > Simplicity of definition and programming model is crucial. People > already have enough trouble coming to grips with exception safety. > Introducing #2 complicates the EH model, so I oppose it on those > grounds also. Can you explain why? Nothing says that what pthread_cancel does is throwing an exception. So what exactly it does is outside of the scope of the current C++ standard. Jakub From dave at boost-consulting.com Tue Jul 12 00:50:20 2005 From: dave at boost-consulting.com (David Abrahams) Date: Mon, 11 Jul 2005 20:50:20 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <20050711225235.GO4884@devserv.devel.redhat.com> (Jakub Jelinek's message of "Mon, 11 Jul 2005 18:52:35 -0400") References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: Jakub Jelinek writes: > On Mon, Jul 11, 2005 at 06:34:13PM -0400, David Abrahams wrote: >> Nathan Sidwell writes: >> >> > IMHO #1 is better, for it also allows us to say 'thread cancellation is >> > *exactly* like exception handling'. >> >> It's more than that. #2 changes the exception handling model. >> Simplicity of definition and programming model is crucial. People >> already have enough trouble coming to grips with exception safety. >> Introducing #2 complicates the EH model, so I oppose it on those >> grounds also. > > Can you explain why? Nothing says that what pthread_cancel does is throwing > an exception. So what exactly it does is outside of the scope of the > current C++ standard. Of course it's outside of the scope of the current C++ standard, but I don't see how that's relevant. All the proposals in this thread have pthread_cancel throwing an exception. The mental model one develops for exception handling based on standard C++ includes invariants such as catch(...) { whatever; throw; } is equivalent to a destructor that does "whatever" when unwinding and If a destructor executes due to stack unwinding, one catch block of every try block between the point of the throw and that destructor has executed. These invariants no longer hold in scheme #2. You get something sort of like these invariants, but they are complicated by special cases to deal with thread cancellation behavior. -- Dave Abrahams Boost Consulting www.boost-consulting.com From terekhov at web.de Tue Jul 12 07:04:55 2005 From: terekhov at web.de (Alexander Terekhov) Date: Tue, 12 Jul 2005 09:04:55 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: <42D36B97.8900462@web.de> David Abrahams wrote: [...] > The mental model one develops for exception handling based on standard > C++ includes invariants such as > > catch(...) { whatever; throw; } > > is equivalent to > > a destructor that does "whatever" when unwinding Nah, a destructor that does "whatever" when unwinding is equivalent to // Doesn't participate in search phase weak_catch(...) { no_throw{ whatever; } throw; } ;-) regards, alexander. From terekhov at web.de Tue Jul 12 08:11:43 2005 From: terekhov at web.de (Alexander Terekhov) Date: Tue, 12 Jul 2005 10:11:43 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> Message-ID: <42D37B3F.E81F5274@web.de> Nathan Sidwell wrote: [...] > I suppose it would be possible to determine one was inside a nothrow function > during the stack scanning phase of exception handling, and then not throw the > exception if that were the case. But this relies on 2-phase unwinding and > restartable exceptions. What do you mean by "restartable exceptions"? 2-phase EH exposing conditional throw is sufficient. http://tinyurl.com/cxdc7 regards, alexander. From nathan at codesourcery.com Tue Jul 12 09:07:57 2005 From: nathan at codesourcery.com (Nathan Sidwell) Date: Tue, 12 Jul 2005 10:07:57 +0100 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D37B3F.E81F5274@web.de> References: <42D2ECF8.3000303@codesourcery.com> <42D37B3F.E81F5274@web.de> Message-ID: <42D3886D.10604@codesourcery.com> Alexander Terekhov wrote: > Nathan Sidwell wrote: > [...] > >>I suppose it would be possible to determine one was inside a nothrow function >>during the stack scanning phase of exception handling, and then not throw the >>exception if that were the case. But this relies on 2-phase unwinding and >>restartable exceptions. > > > What do you mean by "restartable exceptions"? 2-phase EH exposing > conditional throw is sufficient. that's what I thought. However, this is relying on implementation details of the exception handling that are not expressible in the language (so someother implementation might not be able to do this). It's also not clear to me how one would implement the necessary delay to retrying the thread cancellation until one had returned from the nothrow function. nathan -- Nathan Sidwell :: http://www.codesourcery.com :: CodeSourcery LLC nathan at codesourcery.com :: http://www.planetfall.pwp.blueyonder.co.uk From terekhov at web.de Tue Jul 12 09:32:13 2005 From: terekhov at web.de (Alexander Terekhov) Date: Tue, 12 Jul 2005 11:32:13 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <42D37B3F.E81F5274@web.de> <42D3886D.10604@codesourcery.com> Message-ID: <42D38E1D.F96AF744@web.de> Nathan Sidwell wrote: [...] > It's also not clear to me how one would implement the necessary > delay to retrying the thread cancellation until one had returned > from the nothrow function. You mean another cancellation point (async cancel regions aside for a moment) in the "same" dynamic context with unexpected cancellation exception? Even without any optimizations, that overhead of repetitive search is not a big deal since it would occur only when cancellation request is pending. regards, alexander. From dave at boost-consulting.com Tue Jul 12 11:44:48 2005 From: dave at boost-consulting.com (David Abrahams) Date: Tue, 12 Jul 2005 07:44:48 -0400 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D36B97.8900462@web.de> Message-ID: Alexander Terekhov writes: > David Abrahams wrote: > [...] >> The mental model one develops for exception handling based on standard >> C++ includes invariants such as >> >> catch(...) { whatever; throw; } >> >> is equivalent to >> >> a destructor that does "whatever" when unwinding > > Nah, > > a destructor that does "whatever" when unwinding > > is equivalent to > > // Doesn't participate in search phase > weak_catch(...) { no_throw{ whatever; } throw; } > > ;-) Yeah, I definitely got a mental model for what weak_catch does based on standard C++. Riiiight. No need to keep flogging that horse; I know you want new C++ features like 2-phase EH and nothrow regions. They probably have some advantages especially where thread cancellation is concerned. But let's just keep distinct things issues in this conversation, please. -- Dave Abrahams Boost Consulting www.boost-consulting.com From jason at redhat.com Tue Jul 12 15:39:27 2005 From: jason at redhat.com (Jason Merrill) Date: Tue, 12 Jul 2005 11:39:27 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: (David Abrahams's message of "Mon, 11 Jul 2005 20:50:20 -0400") References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: OK, let me clarify my position. For a new C++ threading library, I would continue to prefer scheme #1. But this isn't a new library, it's an extension of an existing library. The main benefit of scheme #2 is that existing pthread_cancel-safe C++ code written to use pthread_cleanup_push/pop continues to work. This seems like a basic requirement for an implementation of pthread_cancel, and one that the current implementation on linux systems violates. This is currently causing real problems for real users; we are breaking their code that used to work under linux and continues to work on other platforms. Choosing scheme #2 requires us to choose to say, as Jakub suggests, that cancellation is NOT logically an exception. We just happen to implement it using the EH infrastructure. This is the same choice that Ada made, and one that I have become more sympathetic to. http://www.codesourcery.com/archives/c++-pthreads/msg00069.html Compatibility with existing pthreads code is more important than consistency with C++ exceptions. The effect of this is that where before pthread_cancel-safe code needed to use pthread_cleanup_push/pop for cleanups, now users can just put their code in destructors. Or they can continue to use pthread_cleanup_push/pop. This is a pure extension, whereas the current implementation and scheme #1 are incompatible changes. Tangent follows: ---------------- WRT scheme #1, various people have wondered why re-asserting cancellation in the exception's destructor is necessary. It's necessary because as I said in my first message, if someone specifically told the thread to go away, they don't want it to recover, they want it to go away. The thread doesn't get to second-guess that request, it has to go away. It can take arbitrarily long to get around to actually going away, but it can't actually decide not to. It especially can't decide this implicitly, as a side-effect of code written to handle exceptions. This is also the rationale for choosing not to make cancellation a proper exception, which leads to scheme #2. Jason From terekhov at web.de Tue Jul 12 16:33:12 2005 From: terekhov at web.de (Alexander Terekhov) Date: Tue, 12 Jul 2005 18:33:12 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: <42D3F0C8.6389E21B@web.de> Jason Merrill wrote: [...] > Tangent follows: > ---------------- > WRT scheme #1, various people have wondered why re-asserting cancellation > in the exception's destructor is necessary. It's necessary because as I > said in my first message, if someone specifically told the thread to go > away, they don't want it to recover, they want it to go away. The thread > doesn't get to second-guess that request, it has to go away. It can take > arbitrarily long to get around to actually going away, but it can't > actually decide not to. Sure it can. Exception handling aside for a moment, a thread can disable cancellation permanently. > It especially can't decide this implicitly, as a > side-effect of code written to handle exceptions. > > This is also the rationale for choosing not to make cancellation a proper > exception, which leads to scheme #2. http://groups.google.de/group/comp.programming.threads/msg/5566e2c89974c3d5 http://groups.google.de/group/comp.programming.threads/msg/302cab27618daf4c regards, alexander. From dave at boost-consulting.com Tue Jul 12 17:02:59 2005 From: dave at boost-consulting.com (David Abrahams) Date: Tue, 12 Jul 2005 13:02:59 -0400 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D36B97.8900462@web.de> Message-ID: David Abrahams writes: > No need to keep flogging that horse; I know you want new C++ features > like 2-phase EH and nothrow regions. They probably have some > advantages especially where thread cancellation is concerned. But > let's just keep distinct things issues in this conversation, please. Sorry, I meant, let's just keep different issues distinct in this conversation, please. -- Dave Abrahams Boost Consulting www.boost-consulting.com From dave at boost-consulting.com Wed Jul 13 00:07:55 2005 From: dave at boost-consulting.com (David Abrahams) Date: Tue, 12 Jul 2005 20:07:55 -0400 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: Jason Merrill writes: > OK, let me clarify my position. For a new C++ threading library, I would > continue to prefer scheme #1. But this isn't a new library, it's an > extension of an existing library. > > The main benefit of scheme #2 is that existing pthread_cancel-safe C++ code > written to use pthread_cleanup_push/pop continues to work. What do you mean by "work?" Can you explain the issues here, and show just what would be broken by scheme #1? > Tangent follows: > ---------------- > WRT scheme #1, various people have wondered why re-asserting cancellation > in the exception's destructor is necessary. It's necessary because as I > said in my first message, if someone specifically told the thread to go > away, they don't want it to recover, they want it to go away. The thread > doesn't get to second-guess that request, it has to go away. It can take > arbitrarily long to get around to actually going away, but it can't > actually decide not to. It especially can't decide this implicitly, as a > side-effect of code written to handle exceptions. > > This is also the rationale for choosing not to make cancellation a proper > exception, which leads to scheme #2. As Alexander says, a thread can always disable cancellation and never re-enable it. AFAICT, the idea that we can somehow force a thread to cancel via a synchronous notification is just a myth. I don't think we can make any sensible decisions until face reality. -- Dave Abrahams Boost Consulting www.boost-consulting.com From r-smith at ihug.co.nz Wed Jul 13 10:50:35 2005 From: r-smith at ihug.co.nz (Ross Smith) Date: Wed, 13 Jul 2005 22:50:35 +1200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: Message-ID: <200507132250.35542.r-smith@ihug.co.nz> On Wednesday, 13 July 2005 03:39, Jason Merrill wrote: > > WRT scheme #1, various people have wondered why re-asserting > cancellation in the exception's destructor is necessary. It's > necessary because as I said in my first message, if someone > specifically told the thread to go away, they don't want it to > recover, they want it to go away. The thread doesn't get to > second-guess that request, it has to go away. It can take > arbitrarily long to get around to actually going away, but it can't > actually decide not to. It especially can't decide this implicitly, > as a side-effect of code written to handle exceptions. I am firmly convinced that attempting to distinguish between "arbitrarily long" and "never" is, to put it mildly, fairly pointless. -- Ross Smith ........ r-smith at ihug.co.nz ........ Auckland, New Zealand "Plausible rockets are rare. Plausible space travel is rare. Most SF authors could not calculate a mass ratio if you put them in a sunken pit filled with ravenous sliderules." -- James Nicoll From terekhov at web.de Wed Jul 13 13:06:02 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 13 Jul 2005 15:06:02 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: <42D511BA.D527EDE8@web.de> David Abrahams wrote: [...] > face reality. http://groups.google.de/group/comp.lang.c++.moderated/msg/58ac57cb5e3bdbcb Might help. ;-) regards, alexander. From jason at redhat.com Wed Jul 13 14:16:22 2005 From: jason at redhat.com (Jason Merrill) Date: Wed, 13 Jul 2005 10:16:22 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: (David Abrahams's message of "Tue, 12 Jul 2005 20:07:55 -0400") References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: On Tue, 12 Jul 2005 20:07:55 -0400, David Abrahams wrote: > Jason Merrill writes: > >> OK, let me clarify my position. For a new C++ threading library, I would >> continue to prefer scheme #1. But this isn't a new library, it's an >> extension of an existing library. >> >> The main benefit of scheme #2 is that existing pthread_cancel-safe C++ code >> written to use pthread_cleanup_push/pop continues to work. > > What do you mean by "work?" Can you explain the issues here, and show > just what would be broken by scheme #1? Thread robustness code like the following: while (true) try { body(); } catch (...) { recover(); } Under the old non-EH implementation this thread cancelled properly. Under #1 it doesn't; it goes into an infinite loop of throw/recover. >> if someone specifically told the thread to go away, they don't want it >> to recover, they want it to go away. The thread doesn't get to >> second-guess that request, it has to go away. It can take arbitrarily >> long to get around to actually going away, but it can't actually decide >> not to. It especially can't decide this implicitly, as a side-effect of >> code written to handle exceptions. > > As Alexander says, a thread can always disable cancellation and never > re-enable it. AFAICT, the idea that we can somehow force a thread to > cancel via a synchronous notification is just a myth. I don't think > we can make any sensible decisions until face reality. Sure, a thread can disable cancellation. I consider that "taking arbitrarily long," because if it ever enables it again the request is still there and will be acted on. Furthermore, if you find that your cancel isn't being processed, it's easy enough to grep for pthread_setcancelstate. Finding the random code written to deal with program-generated exceptions which is now interfering with cancellation is not as simple. Incidentally, my list of uses of catch(...) omitted the use in iostreams, which is much like the inter-language glue case, except that it's just glue to another error reporting mechanism. As in that case, #1 handles the iostream use by re-asserting cancel later on. #2 handles it by just continuing to run cleanups if the function is allowed to throw, or by disabling cancellation within the function if it isn't allowed to throw. #3 blows up. Jason From nathan at codesourcery.com Wed Jul 13 14:35:30 2005 From: nathan at codesourcery.com (Nathan Sidwell) Date: Wed, 13 Jul 2005 15:35:30 +0100 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: <42D526B2.9000701@codesourcery.com> Jason Merrill wrote: > OK, let me clarify my position. For a new C++ threading library, I would > continue to prefer scheme #1. But this isn't a new library, it's an > extension of an existing library. thanks for this rationale. I better understand the problem that needs to be solved now. > Compatibility with existing pthreads code is more important than > consistency with C++ exceptions. Another point of interest, which I'm sure you've considered, is that standard C functions such as write are deemed to be nothrow by C++, yet are cancellation points in pthreads. Scheme #2 stops this blowing up (by deferring cancellation inside such function). Scheme #1 blows up by calling std::unexpected. nathan -- Nathan Sidwell :: http://www.codesourcery.com :: CodeSourcery LLC nathan at codesourcery.com :: http://www.planetfall.pwp.blueyonder.co.uk From terekhov at web.de Wed Jul 13 15:28:50 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 13 Jul 2005 17:28:50 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: <42D53332.17B76749@web.de> Jason Merrill wrote: [...] > while (true) > try > { > body(); > } > catch (...) > { > recover(); > } > > Under the old non-EH implementation this thread cancelled properly. You mean with omitted recovery? That's hardly "properly". Cancel-unaware code is not meant to be canceled. It's as simply as that. while (true) try { body(); } catch (...) { recover(); handle_thread_termination_request(); /* http://tinyurl.com/8q3qt */ } regards, alexander. From jason at redhat.com Wed Jul 13 15:39:42 2005 From: jason at redhat.com (Jason Merrill) Date: Wed, 13 Jul 2005 11:39:42 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D53332.17B76749@web.de> (Alexander Terekhov's message of "Wed, 13 Jul 2005 17:28:50 +0200") References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> Message-ID: On Wed, 13 Jul 2005 17:28:50 +0200, Alexander Terekhov wrote: > Jason Merrill wrote: > [...] >> while (true) >> try >> { >> body(); >> } >> catch (...) >> { >> recover(); >> } >> >> Under the old non-EH implementation this thread cancelled properly. > > You mean with omitted recovery? That's hardly "properly". > > Cancel-unaware code is not meant to be canceled. > > It's as simply as that. A customer of ours has code along those lines in a package that uses pthread_cleanup_push/pop to handle cleanups on cancellation. It works fine under Solaris, tru64, and older linux systems. It IS cancel-aware. The problem is that allowing catch(...) to catch cancellation changes what it MEANS to be cancel-aware in an incompatible way. Jason From dave at boost-consulting.com Wed Jul 13 16:22:59 2005 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 13 Jul 2005 12:22:59 -0400 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D511BA.D527EDE8@web.de> Message-ID: Alexander Terekhov writes: > David Abrahams wrote: > [...] >> face reality. > > http://groups.google.de/group/comp.lang.c++.moderated/msg/58ac57cb5e3bdbcb > > Might help. ;-) How? -- Dave Abrahams Boost Consulting www.boost-consulting.com From dave at boost-consulting.com Wed Jul 13 16:26:37 2005 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 13 Jul 2005 12:26:37 -0400 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: Jason Merrill writes: > On Tue, 12 Jul 2005 20:07:55 -0400, David Abrahams wrote: > >> Jason Merrill writes: >> >>> The main benefit of scheme #2 is that existing pthread_cancel-safe C++ code >>> written to use pthread_cleanup_push/pop continues to work. >> >> What do you mean by "work?" Can you explain the issues here, and show >> just what would be broken by scheme #1? > > Thread robustness code like the following: > > while (true) > try > { > body(); > } > catch (...) > { > recover(); > } > > Under the old non-EH implementation this thread cancelled properly. Under > #1 it doesn't; it goes into an infinite loop of throw/recover. The only places I've seen code like that, you absolutely need recover() to execute, even if the next thing you're going to do is terminate, or terminate the thread. Otherwise, you end up with corrupted or lost data. In those cases, there is absolutely no advantage to being able to stop the thread and have all the destructors execute but not execute the catch(...) block. Do you have a counterexample? I'm not sure I would be convinced by one, but at least one counterexample is definitely a prerequisite for me to be convinced. > Sure, a thread can disable cancellation. I consider that "taking > arbitrarily long," because if it ever enables it again the request > is still there and will be acted on. As someone else has said, there's no practical difference between "arbitrarily long" and "never." > Furthermore, if you find that your cancel isn't being processed, it's easy > enough to grep for pthread_setcancelstate. Finding the random code written > to deal with program-generated exceptions which is now interfering with > cancellation is not as simple. You have a point, but I consider it a very weak argument. Most programs don't have many catch(...) blocks, and it's usually pretty easy to see whether they are going to rethrow. > Incidentally, my list of uses of catch(...) omitted the use in iostreams, > which is much like the inter-language glue case, except that it's just glue > to another error reporting mechanism. As in that case, #1 handles the > iostream use by re-asserting cancel later on. #2 handles it by just > continuing to run cleanups if the function is allowed to throw, or by > disabling cancellation within the function if it isn't allowed to throw. > #3 blows up. Right, now I remember. I guess that makes the "re-asserting cancel" idea somewhat more compelling. -- Dave Abrahams Boost Consulting www.boost-consulting.com From dave at boost-consulting.com Wed Jul 13 16:27:45 2005 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 13 Jul 2005 12:27:45 -0400 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D526B2.9000701@codesourcery.com> Message-ID: Nathan Sidwell writes: Nathan Sidwell writes: > Jason Merrill wrote: >> OK, let me clarify my position. For a new C++ threading library, I would >> continue to prefer scheme #1. But this isn't a new library, it's an >> extension of an existing library. > > thanks for this rationale. I better understand the problem that needs to be > solved now. > >> Compatibility with existing pthreads code is more important than >> consistency with C++ exceptions. > > Another point of interest, which I'm sure you've considered, is that standard C > functions such as write are deemed to be nothrow by C++, yet are cancellation > points in pthreads. Scheme #2 stops this blowing up (by deferring cancellation > inside such function). Scheme #1 blows up by calling std::unexpected. One way to look at it is that scheme #1 blows up, true. But not necessarily by calling std::unexpected. Those functions do not implicitly acquire an empty exception-specification -- they are simply required not to throw. If they start throwing, they break user code by violating its expectations. A more correct way to look at it, IMO, is that an implementation of C++ that throws from standard 'C' functions by default (other than when the user does something documented to cause undefined behavior) is nonconforming to the C++ standard. In other words, those functions simply can't throw in C++, at least not without explicitly being given permission by the program. I would: 0. Continue to forbid those functions to throw in C++, to preserve conformance 1. Add a non-throwing mechanism to report cancellation from those functions, such as extended values of errno. 2. Optional: As an extension, provide a parallel set of functions (in a namespace other than :: or std:: ) that can throw. 3. Optional: As an extension, provide a way to enable the normal 'C' library to throw cancellation -- Dave Abrahams Boost Consulting www.boost-consulting.com From jason at redhat.com Wed Jul 13 16:56:59 2005 From: jason at redhat.com (Jason Merrill) Date: Wed, 13 Jul 2005 12:56:59 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: (David Abrahams's message of "Wed, 13 Jul 2005 11:40:45 -0400") References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: On Wed, 13 Jul 2005 11:40:45 -0400, David Abrahams wrote: > Jason Merrill writes: >>> while (true) >> try >> { >> body(); >> } >> catch (...) >> { >> recover(); >> } >> >> Under the old non-EH implementation this thread cancelled properly. Under >> #1 it doesn't; it goes into an infinite loop of throw/recover. > > The only places I've seen code like that, you absolutely need > recover() to execute, even if the next thing you're going to do is > terminate, or terminate the thread. Otherwise, you end up with > corrupted or lost data. In those cases, there is absolutely no > advantage to being able to stop the thread and have all the > destructors execute but not execute the catch(...) block. > > Do you have a counterexample? I'm not sure I would be convinced by > one, but at least one counterexample is definitely a prerequisite for > me to be convinced. https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=111548 We've gotten other private bug reports, too. Unfortunately, that bug report got marginalized because the reporter used async cancel in his reduced testcase...I would guess that the original code doesn't, but I haven't looked yet. I'm sorry, my example above is misleading; in other the bug report that motivated me to bring this up again there is no recover(), just catch(...){}. All the recovery has been done by registered cleanups, the above loop is just there to keep the thread alive. Which it shouldn't in the case of cancellation. Jason From david.butenhof at hp.com Wed Jul 13 17:15:00 2005 From: david.butenhof at hp.com (Dave Butenhof) Date: Wed, 13 Jul 2005 13:15:00 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> Message-ID: <42D54C14.4090505@hp.com> Jason Merrill wrote: >On Wed, 13 Jul 2005 17:28:50 +0200, Alexander Terekhov wrote: > > >>Jason Merrill wrote: >>[...] >> >> >>>while (true) >>> try >>> { >>> body(); >>> } >>> catch (...) >>> { >>> recover(); >>> } >>> >>>Under the old non-EH implementation this thread cancelled properly. >>> >>> >>You mean with omitted recovery? That's hardly "properly". >> >>Cancel-unaware code is not meant to be canceled. >> >>It's as simply as that. >> >> >A customer of ours has code along those lines in a package that uses >pthread_cleanup_push/pop to handle cleanups on cancellation. It works fine >under Solaris, tru64, and older linux systems. > > If we're talking C++ code using pthread_cleanup_push/pop, which I infer to be the case, then it did NOT work on Tru64 UNIX -- though the customer may have failed to notice that it didn't work. While the C language macros would COMPILE under C++ they didn't work usefully. We'd always told people NOT to use the macros in C++. Cancellation was always intended to be an exception, even in C. It's just that ISO C and POSIX don't possess the semantics or syntax. Tru64 UNIX however has real exception support, and The Digital/Compaq/HP C ("GEM C") compiler has extensions to interact with that exception support. If compiling under the "ideal" C compiler, the POSIX macros used real exceptions -- but otherwise they use the crufty old setjmp/longjmp portable "exception" package, which does not interoperate with the native Tru64 exception support (and thus with frames built by Ada, C++, or GEM C). Unwinding through a frame using pthread_cleanup_push/pop that wasn't compiled with GEM C will break interleaved frames with any real exception handling -- including C++ object destructors. pthread_cleanup_push/pop is an artifact of the limitations of the POSIX C binding, not intended (nor portably supported) for use in any other language, including C++. C++ code that uses POSIX cleanup is straddling the line between two contradictory standards. While it's true that any use of threads in C++ is beyond the help of either standard, there are reasonable and widely implemented mechanisms on which developers can rely with reasonable safety -- a mutex WILL work when called from C++, the C++ compiler will not implicitly generate code that defies multithread coherency requirements. Cancel is NOT in that category. The problems are on the same scope as combining threads and UNIX signals; two radically different specifications and implementations intended to do much the same (but one substantially limited by environmental constraints). They don't mix easily or conveniently. The best way to make signals and threads cooperate might have been to recast signals as a special type of thread, but that wasn't practical. What we have instead is a mess, with a lot of rough edges and a lot of restrictions; but with care it can be made to work, and the combination provides significant advantages. >It IS cancel-aware. The problem is that allowing catch(...) to catch >cancellation changes what it MEANS to be cancel-aware in an incompatible >way. > > Where? Again on Tru64 UNIX and with any C++ using the native Tru64 exception support in a compatible and conforming way, catch(...) WILL catch cancel, and always has. Some code depends on this; so REMOVING the capability "changes what it means to be cancel-aware in an incompatible way". C++ is not C, despite trivial and unfortunately common misconceptions. POSIX threads is a C language binding, but serves only as an abstract representation (not a concrete implementation) of the capabilities that ought to be provided for a different language binding. Cancellation IS an exception, and was always designed to BE an exception, nothing else. It was only the representational limitations of ISO C and POSIX that lead to the current ambiguous specification. POSIX contains an explicit statement of intent that languages with exceptions should use them rather than implementing cleanup push/pop; however even if a binding chose to ignore that advice, the C++ implementation of cleanup push/pop must interoperate with C++ exceptions and object destructors in a way that a C implementation cannot. There are many complicated compatibility issues in modelling something like POSIX cancellation in C++ without breaking some usage patterns of C++ exceptions. There's no way around that. In particular, arguments of "it has to be this way because" or "it can't be this way because" miss the point. Or rather, if you're going to insist that IS the point then it just can't be done and we should face that any C++ code using cancel is inherently broken. Otherwise, existing usage patterns are going to change, and a lot of code will be adversely impacted by the changes; either to traditional C++ exception usage patterns or to traditional POSIX cancellation usage patterns. One of the biggest issues is reconciling the global nature of cancellation state with C++ "no throw zones". Many years ago I had thought of making our CMA "alert" state dynamic by grabbing reserved bits off the VAX stack frame masks, so that each call could automatically set the desired local cancel state without any additional overhead, and we'd work it all out when a cancel exception was actually thrown. The problem is that at each frame that doesn't declare its own intent, its state is dependent on the last outer frame that did, which means traversing further down the stack before initiating the real unwind. (This is beyond even a normal 2-phase EH, because the search phase often needs to continue beyond the frame that expresses unwind intent unless the call sequence propagates the state.) -------------- next part -------------- A non-text attachment was scrubbed... Name: david.butenhof.vcf Type: text/x-vcard Size: 476 bytes Desc: not available URL: From dave at boost-consulting.com Wed Jul 13 15:40:45 2005 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 13 Jul 2005 11:40:45 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: (Jason Merrill's message of "Wed, 13 Jul 2005 10:16:22 -0400") References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: Jason Merrill writes: > On Tue, 12 Jul 2005 20:07:55 -0400, David Abrahams wrote: > >> Jason Merrill writes: >> >>> The main benefit of scheme #2 is that existing pthread_cancel-safe C++ code >>> written to use pthread_cleanup_push/pop continues to work. >> >> What do you mean by "work?" Can you explain the issues here, and show >> just what would be broken by scheme #1? > > Thread robustness code like the following: > > while (true) > try > { > body(); > } > catch (...) > { > recover(); > } > > Under the old non-EH implementation this thread cancelled properly. Under > #1 it doesn't; it goes into an infinite loop of throw/recover. The only places I've seen code like that, you absolutely need recover() to execute, even if the next thing you're going to do is terminate, or terminate the thread. Otherwise, you end up with corrupted or lost data. In those cases, there is absolutely no advantage to being able to stop the thread and have all the destructors execute but not execute the catch(...) block. Do you have a counterexample? I'm not sure I would be convinced by one, but at least one counterexample is definitely a prerequisite for me to be convinced. > Sure, a thread can disable cancellation. I consider that "taking > arbitrarily long," because if it ever enables it again the request > is still there and will be acted on. As someone else has said, there's no practical difference between "arbitrarily long" and "never." > Furthermore, if you find that your cancel isn't being processed, it's easy > enough to grep for pthread_setcancelstate. Finding the random code written > to deal with program-generated exceptions which is now interfering with > cancellation is not as simple. You have a point, but I consider it a very weak argument. Most programs don't have many catch(...) blocks, and it's usually pretty easy to see whether they are going to rethrow. > Incidentally, my list of uses of catch(...) omitted the use in iostreams, > which is much like the inter-language glue case, except that it's just glue > to another error reporting mechanism. As in that case, #1 handles the > iostream use by re-asserting cancel later on. #2 handles it by just > continuing to run cleanups if the function is allowed to throw, or by > disabling cancellation within the function if it isn't allowed to throw. > #3 blows up. Right, now I remember. I guess that makes the "re-asserting cancel" idea somewhat more compelling. -- Dave Abrahams Boost Consulting www.boost-consulting.com From mark at codesourcery.com Wed Jul 13 17:22:15 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Wed, 13 Jul 2005 10:22:15 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> Message-ID: <42D54DC7.2090803@codesourcery.com> Jason Merrill wrote: > A customer of ours has code along those lines in a package that uses > pthread_cleanup_push/pop to handle cleanups on cancellation. It works fine > under Solaris, tru64, and older linux systems. If you wanted to offer a mode in which no stack unwinding was done, but the old just-run-pthread-cleanups semantics were honored, I would have no objection. Using that mode requires a lot of care, in that the stack is not unwound and destructors not run, but it's a consistent model. My objection is to a model in which "catch (...)" is ignored. -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From gshiman at commvault.com Wed Jul 13 17:24:21 2005 From: gshiman at commvault.com (George Shimanovich) Date: Wed, 13 Jul 2005 13:24:21 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again Message-ID: <52CA6BC0D0E9EE4E93208DB39A3218FEA458DF@EXCHANGE.gp.cv.commvault.com> Below is my old note to Jakub with description of failure in my Linux pthread test program which is based on thread pool implementation, i.e. it has to catch exceptions thrown by cancelled worker thread. That illustrates why we could not use Linux pthread. From my point of view this is caused by use of EH to implement thread cancellation. - George -----Original Message----- From: George Shimanovich Sent: Thursday, June 24, 2004 3:52 PM To: 'Jakub Jelinek' Subject: RE: Bug 111548: calling pthread_cancel in a muti-thread c++ application abort()s the app - 'cancel state' workaround Jakub, I just implemented workaround that you suggested - for deferred threads, - with the same result: 1) disable cancel state at the beginning of new thread 2) enable it before each call to pthread_testcancel() 3) disable cancel state after each call to pthread_testcancel() Just to make sure I explicitly set pending cancel type. The result is the same: program crashed with 'FATAL: exception not rethrown' even though I faithfully rethrow exception. It is worth noting that cancel point did not seem to work and thread was wacked before call to pthread_testcancel(). The main problem as I see it is this: Linux pthreads crashes the process when unwinding stack of cancelled thread: it throws system (non C++ exception) which crashes the program in both cases: - when caught and rethrown - when not caught C++-pthreads spend a lot of time on discussing whether to issue or not to issue an exception when thread is cancelled but does not mention the fact that program crashes in the way outlined above. It is not an issue of what is better: to throw or not to throw. It is simply that pthreads in current state is unusable for multi-threading. George Shimanovich -------------- next part -------------- An HTML attachment was scrubbed... URL: From drow at false.org Wed Jul 13 15:53:42 2005 From: drow at false.org (Daniel Jacobowitz) Date: Wed, 13 Jul 2005 11:53:42 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D526B2.9000701@codesourcery.com> References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D526B2.9000701@codesourcery.com> Message-ID: <20050713155342.GA29756@nevyn.them.org> On Wed, Jul 13, 2005 at 03:35:30PM +0100, Nathan Sidwell wrote: > >Compatibility with existing pthreads code is more important than > >consistency with C++ exceptions. > > Another point of interest, which I'm sure you've considered, is that > standard C functions such as write are deemed to be nothrow by C++, yet are > cancellation points in pthreads. Scheme #2 stops this blowing up (by > deferring cancellation inside such function). Scheme #1 blows up by > calling std::unexpected. Um, if you defer cancellation inside all of the standard library functions which C++ considers nothrow (which is pretty much all of the cancellation points), then how do you ever get cancelled? -- Daniel Jacobowitz CodeSourcery, LLC From dave at boost-consulting.com Wed Jul 13 15:57:39 2005 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 13 Jul 2005 11:57:39 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D526B2.9000701@codesourcery.com> (Nathan Sidwell's message of "Wed, 13 Jul 2005 15:35:30 +0100") References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D526B2.9000701@codesourcery.com> Message-ID: Nathan Sidwell writes: > Jason Merrill wrote: >> OK, let me clarify my position. For a new C++ threading library, I would >> continue to prefer scheme #1. But this isn't a new library, it's an >> extension of an existing library. > > thanks for this rationale. I better understand the problem that needs to be > solved now. > >> Compatibility with existing pthreads code is more important than >> consistency with C++ exceptions. > > Another point of interest, which I'm sure you've considered, is that standard C > functions such as write are deemed to be nothrow by C++, yet are cancellation > points in pthreads. Scheme #2 stops this blowing up (by deferring cancellation > inside such function). Scheme #1 blows up by calling std::unexpected. One way to look at it is that scheme #1 blows up, true. But not necessarily by calling std::unexpected. Those functions do not implicitly acquire an empty exception-specification -- they are simply required not to throw. If they start throwing, they break user code by violating its expectations. A more correct way to look at it, IMO, is that an implementation of C++ that throws from standard 'C' functions by default (other than when the user does something documented to cause undefined behavior) is nonconforming to the C++ standard. In other words, those functions simply can't throw in C++, at least not without explicitly being given permission by the program. I would: 0. Continue to forbid those functions to throw in C++, to preserve conformance 1. Add a non-throwing mechanism to report cancellation from those functions, such as extended values of errno. 2. Optional: As an extension, provide a parallel set of functions (in a namespace other than :: or std:: ) that can throw. 3. Optional: As an extension, provide a way to enable the normal 'C' library to throw cancellation -- Dave Abrahams Boost Consulting www.boost-consulting.com From dave at boost-consulting.com Wed Jul 13 17:53:04 2005 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 13 Jul 2005 13:53:04 -0400 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: Jason Merrill writes: > On Wed, 13 Jul 2005 11:40:45 -0400, David Abrahams wrote: > >> Do you have a counterexample? I'm not sure I would be convinced by >> one, but at least one counterexample is definitely a prerequisite >> for me to be convinced. > > https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=111548 > > We've gotten other private bug reports, too. Unfortunately, that > bug report got marginalized because the reporter used async cancel > in his reduced testcase...I would guess that the original code > doesn't, but I haven't looked yet. > > I'm sorry, my example above is misleading; in other the bug report > that motivated me to bring this up again there is no recover(), just > catch(...){}. All the recovery has been done by registered > cleanups, the above loop is just there to keep the thread alive. Okay, I understand why you might want to do that. > Which it shouldn't in the case of cancellation. But, speaking of how easy it is to deal with, aren't cases like this 100% trivial to work around when you switch to scheme #1? -- Dave Abrahams Boost Consulting www.boost-consulting.com From dave at boost-consulting.com Wed Jul 13 17:58:56 2005 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 13 Jul 2005 13:58:56 -0400 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> Message-ID: Dave Butenhof writes: > There are many complicated compatibility issues in modelling something > like POSIX cancellation in C++ without breaking some usage patterns of > C++ exceptions. There's no way around that. In particular, arguments of > "it has to be this way because" or "it can't be this way because" miss > the point. Or rather, if you're going to insist that IS the point then > it just can't be done and we should face that any C++ code using cancel > is inherently broken. Otherwise, existing usage patterns are going to > change, and a lot of code will be adversely impacted by the changes; > either to traditional C++ exception usage patterns or to traditional > POSIX cancellation usage patterns. Agree. However, I think it's a good idea to think about which usage patterns would be disrupted, and by how much, and how harmful that disruption turns out to be. So far, it looks to me as though #1 does a lot less harm than #2. In particular, I'm not much disturbed if in the example Jason posted the author of the outer catch(...) block has to add a catch(cancellation&) { return; } That's a nicely localized sort of change. -- Dave Abrahams Boost Consulting www.boost-consulting.com From terekhov at web.de Wed Jul 13 18:11:10 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 13 Jul 2005 20:11:10 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> Message-ID: <42D5593E.C8052736@web.de> Jason Merrill wrote: > > On Wed, 13 Jul 2005 17:28:50 +0200, Alexander Terekhov wrote: > > > Jason Merrill wrote: > > [...] > >> while (true) > >> try > >> { > >> body(); > >> } > >> catch (...) > >> { > >> recover(); > >> } > >> > >> Under the old non-EH implementation this thread cancelled properly. > > > > You mean with omitted recovery? That's hardly "properly". > > > > Cancel-unaware code is not meant to be canceled. > > > > It's as simply as that. > > A customer of ours has code along those lines in a package that uses > pthread_cleanup_push/pop to handle cleanups on cancellation. It works fine > under Solaris, tru64, and older linux systems. ^^^^^ Uhmm, regarding Compaq Tru64 UNIX V5.1B (Rev. 2650)... > > It IS cancel-aware. The problem is that allowing catch(...) to catch > cancellation changes what it MEANS to be cancel-aware in an incompatible > way. spe147.testdrive.hp.com> cxx -pthread -o jason jason.cpp spe147.testdrive.hp.com> ./jason Throwing cancel exception... C++ catch... Throwing cancel exception... PTHREAD_CATCH_NP(pthread_cancel_e)... Exception: Thread has been canceled (dce / thd) pthread_cancel_e has been raised and swallowed twice, Jason. spe147.testdrive.hp.com> cat jason.cpp #include #include #include extern "C" void tru64_native_pthread_exception_handling() { pthread_cancel(pthread_self()); PTHREAD_TRY_NP { printf("Throwing cancel exception...\n"); pthread_testcancel(); } PTHREAD_CATCH_NP(pthread_cancel_e) { printf("PTHREAD_CATCH_NP(pthread_cancel_e)...\n"); pthread_exc_report_np(PTHREAD_THIS_CATCH_NP); } PTHREAD_ENDTRY_NP } int main() { pthread_cancel(pthread_self()); try { printf("Throwing cancel exception...\n"); pthread_testcancel(); } catch(...) { int state; printf("C++ catch...\n"); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &state); tru64_native_pthread_exception_handling(); } printf("pthread_cancel_e has been raised and swallowed twice, Jason.\n"); } spe147.testdrive.hp.com> regards, alexander. From terekhov at web.de Wed Jul 13 19:31:44 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 13 Jul 2005 21:31:44 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D511BA.D527EDE8@web.de> Message-ID: <42D56C20.E20394A2@web.de> David Abrahams wrote: > > Alexander Terekhov writes: > > > David Abrahams wrote: > > [...] > >> face reality. > > > > http://groups.google.de/group/comp.lang.c++.moderated/msg/58ac57cb5e3bdbcb > > > > Might help. ;-) > > How? As a ready synthesis, of course. Dialectic, y'know. ;-) regards, alexander. From terekhov at web.de Wed Jul 13 19:32:50 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 13 Jul 2005 21:32:50 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D526B2.9000701@codesourcery.com> Message-ID: <42D56C62.C7A80D9A@web.de> David Abrahams wrote: [...] > 3. Optional: As an extension, provide a way to enable the normal 'C' > library to throw cancellation That's what "-pthread" does. In (posix) threaded C/C++, normal 'C' library is enabled to throw cancellation unless you disable it... intelligent cancel delivery (i.e. no delivery to std::unexpected() on part of the implementation) aside for a moment. There's no other (sensible) way to resolve the issue. regards, alexander. From gdr at integrable-solutions.net Wed Jul 13 19:52:14 2005 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 13 Jul 2005 21:52:14 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> Message-ID: David Abrahams writes: | Dave Butenhof writes: | | > There are many complicated compatibility issues in modelling something | > like POSIX cancellation in C++ without breaking some usage patterns of | > C++ exceptions. There's no way around that. In particular, arguments of | > "it has to be this way because" or "it can't be this way because" miss | > the point. Or rather, if you're going to insist that IS the point then | > it just can't be done and we should face that any C++ code using cancel | > is inherently broken. Otherwise, existing usage patterns are going to | > change, and a lot of code will be adversely impacted by the changes; | > either to traditional C++ exception usage patterns or to traditional | > POSIX cancellation usage patterns. | | Agree. However, I think it's a good idea to think about which usage | patterns would be disrupted, and by how much, and how harmful that | disruption turns out to be. | | So far, it looks to me as though #1 does a lot less harm than #2. In | particular, I'm not much disturbed if in the example Jason posted the | author of the outer catch(...) block has to add a | | catch(cancellation&) { return; } | | That's a nicely localized sort of change. I think cancellation should be left as ordinary C++, catchable through catch(...). I don't think we should second guess client code and design a new model of exception. -- Gaby From dave at boost-consulting.com Wed Jul 13 20:24:01 2005 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 13 Jul 2005 16:24:01 -0400 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D511BA.D527EDE8@web.de> <42D56C20.E20394A2@web.de> Message-ID: Alexander Terekhov writes: > David Abrahams wrote: >> >> Alexander Terekhov writes: >> >> > David Abrahams wrote: >> > [...] >> >> face reality. >> > >> > http://groups.google.de/group/comp.lang.c++.moderated/msg/58ac57cb5e3bdbcb >> > >> > Might help. ;-) >> >> How? > > As a ready synthesis, of course. Dialectic, y'know. ;-) Wow. No, I don't. -- Dave Abrahams Boost Consulting www.boost-consulting.com From jason at redhat.com Wed Jul 13 21:58:48 2005 From: jason at redhat.com (Jason Merrill) Date: Wed, 13 Jul 2005 17:58:48 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: (Gabriel Dos Reis's message of "13 Jul 2005 21:52:14 +0200") References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> Message-ID: On 13 Jul 2005 21:52:14 +0200, Gabriel Dos Reis wrote: > I think cancellation should be left as ordinary C++, catchable through > catch(...). I don't think we should second guess client code and > design a new model of exception. My point is that making it an exception is also second-guessing client code which is written to use the POSIX C binding. Jason From gdr at integrable-solutions.net Thu Jul 14 01:14:05 2005 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 14 Jul 2005 03:14:05 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> Message-ID: Jason Merrill writes: | On 13 Jul 2005 21:52:14 +0200, Gabriel Dos Reis wrote: | | > I think cancellation should be left as ordinary C++, catchable through | > catch(...). I don't think we should second guess client code and | > design a new model of exception. | | My point is that making it an exception is also second-guessing client | code which is written to use the POSIX C binding. Even when it has been made clear that POSIX cancellation has always been thought and conceived as exceptions? I understand the issue is though, but I don't see much gain in having another exception model with subtly different semantics. It is true that many codes have been written with POSIX C binding, more has to come as C++ codes. I'm not convinced that we should compromise the future. -- Gaby From terekhov at web.de Thu Jul 14 10:11:57 2005 From: terekhov at web.de (Alexander Terekhov) Date: Thu, 14 Jul 2005 12:11:57 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> Message-ID: <42D63A6D.18E61B93@web.de> Jason Merrill wrote: > > On 13 Jul 2005 21:52:14 +0200, Gabriel Dos Reis wrote: > > > I think cancellation should be left as ordinary C++, catchable through > > catch(...). I don't think we should second guess client code and > > design a new model of exception. > > My point is that making it an exception is also second-guessing client > code which is written to use the POSIX C binding. Code conforming to POSIX won't notice it. Your client wants to have a totally brain-damaged POSIX C++ bindings with thread cancellation acting as a sorta abnormal exception that would either ignore catch(...){} and throw() and "unwind the stack correctly", or would "not bother to unwind the stack" apart from the stack of POSIX push/pop cleanup handlers -- "it should work as it did before". https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=111548 If cancellation can't unwind the stack correctly while ignoring any throw() or catch(...){} code that would impede a normal exception, then it should work as it did before and not bother to unwind the stack. And that's only because you've refused to make cancellation act as a normal exception in C++ simply letting your client himself distinguish it from other exceptions that he really intended to be swallowed by his catch(...){}. That's my second-guess. ;-) regards, alexander. From dave at boost-consulting.com Thu Jul 14 15:09:43 2005 From: dave at boost-consulting.com (David Abrahams) Date: Thu, 14 Jul 2005 11:09:43 -0400 Subject: [List Administration] GMane and X-No-Archive Message-ID: This mailing list is mirrored at nttp://news.gmane.org/gmane.comp.lang.c++.pthreads but, apparently because many of the messages had an X-No-Archive header, they have been deleted from the server there. That makes it a bit harder to browse the message history. I wonder if the list administrator might like to send Lars an mbox of the message history with the X-No-Archive headers stripped so that we can read everything at GMane? Thanks, -- Dave Abrahams Boost Consulting www.boost-consulting.com From jason at redhat.com Thu Jul 14 18:59:33 2005 From: jason at redhat.com (Jason Merrill) Date: Thu, 14 Jul 2005 14:59:33 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: (Gabriel Dos Reis's message of "14 Jul 2005 03:14:05 +0200") References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> Message-ID: On 14 Jul 2005 03:14:05 +0200, Gabriel Dos Reis wrote: > Jason Merrill writes: > > | On 13 Jul 2005 21:52:14 +0200, Gabriel Dos Reis wrote: > | > | > I think cancellation should be left as ordinary C++, catchable through > | > catch(...). I don't think we should second guess client code and > | > design a new model of exception. > | > | My point is that making it an exception is also second-guessing client > | code which is written to use the POSIX C binding. > > Even when it has been made clear that POSIX cancellation has always > been thought and conceived as exceptions? Yes. If there had been a POSIX C++ binding years ago, based on the Tru64 model, it could have used exceptions. If we somehow managed to throw together a C++ binding this year, it probably could still use exceptions. But I don't think that's likely to happen, and in its absence the C binding is the de facto C++ binding, and I think we need to support it. I should state that more strongly: I would be very much in favor of a POSIX C++ binding that made cancellation an exception. But we need it last year, and as far as I know there isn't even a subcommittee working on it; this mailing list doesn't have any formal standing. > I understand the issue is tough, but I don't see much gain in having > another exception model with subtly different semantics. It's not that subtle, it just does stack unwinding, like a sequence of returns. > It is true that many codes have been written with POSIX C binding, more > has to come as C++ codes. I'm not convinced that we should compromise > the future. The future can use a different interface. Or extend pthread_setcanceltype. PTHREAD_CANCEL_DEFERRED_EXCEPTION, anyone? Jason From mark at codesourcery.com Thu Jul 14 23:52:24 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Thu, 14 Jul 2005 16:52:24 -0700 Subject: [c++-pthreads] [List Administration] GMane and X-No-Archive In-Reply-To: References: Message-ID: <42D6FAB8.6060901@codesourcery.com> David Abrahams wrote: > This mailing list is mirrored at > nttp://news.gmane.org/gmane.comp.lang.c++.pthreads > but, apparently because many of the messages had an X-No-Archive > header, they have been deleted from the server there. That makes it a > bit harder to browse the message history. I wonder if the list > administrator might like to send Lars an mbox of the message history > with the X-No-Archive headers stripped so that we can read everything > at GMane? I've copied Ricardo Anguiano, who is the list administrator. I have the feeling that we explicitly added the X-No-Archive header at some point, in response to some other request -- but I can't remember anything about why... -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From mark at codesourcery.com Fri Jul 15 00:24:57 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Thu, 14 Jul 2005 17:24:57 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> Message-ID: <42D70259.6050808@codesourcery.com> Jason Merrill wrote: > On 13 Jul 2005 21:52:14 +0200, Gabriel Dos Reis wrote: > > >>I think cancellation should be left as ordinary C++, catchable through >>catch(...). I don't think we should second guess client code and >>design a new model of exception. > > > My point is that making it an exception is also second-guessing client > code which is written to use the POSIX C binding. I do think it's possible to argue for an exception-less mode, following the old GNU/Linux practice of just running pthread_cleanup_push'd code. It is reasonable, though perhaps not entirely desirable, to just say "On its face, POSIX says X, so we did X, and no more." But, what doesn't seem reasonable is skipping "catch (...)". I'm having a hard time overcoming the fact that all of Nathan, David, myself, and you -- before your conversion to plan #2 -- seemed to agree that #1 was better. That's a pretty experienced set of people, with judgement I tend to trust. Why not just have two modes, controlled by an environment variable, link-time option, or run-time variable? In the first mode, cancellation would not be an exception and nothing but pthread_cleanup_push'd code is run, and stack unwinding of all kinds is totally ignored. In the second mode, cancellation would be an exception; nothing more, nothing less. -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From dave at boost-consulting.com Fri Jul 15 01:10:06 2005 From: dave at boost-consulting.com (David Abrahams) Date: Thu, 14 Jul 2005 21:10:06 -0400 Subject: [List Administration] GMane and X-No-Archive References: <42D6FAB8.6060901@codesourcery.com> Message-ID: Mark Mitchell writes: > David Abrahams wrote: >> This mailing list is mirrored at >> nttp://news.gmane.org/gmane.comp.lang.c++.pthreads >> but, apparently because many of the messages had an X-No-Archive >> header, they have been deleted from the server there. That makes it a >> bit harder to browse the message history. I wonder if the list >> administrator might like to send Lars an mbox of the message history >> with the X-No-Archive headers stripped so that we can read everything >> at GMane? > > I've copied Ricardo Anguiano, who is the list administrator. I have the > feeling that we explicitly added the X-No-Archive header at some point, > in response to some other request -- but I can't remember anything about > why... Well, it seems to be gone again, thank goodness. -- Dave Abrahams Boost Consulting www.boost-consulting.com From jakub at redhat.com Fri Jul 15 07:05:12 2005 From: jakub at redhat.com (Jakub Jelinek) Date: Fri, 15 Jul 2005 03:05:12 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D70259.6050808@codesourcery.com> References: <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> Message-ID: <20050715070512.GM4884@devserv.devel.redhat.com> On Thu, Jul 14, 2005 at 05:24:57PM -0700, Mark Mitchell wrote: > Why not just have two modes, controlled by an environment variable, > link-time option, or run-time variable? In the first mode, cancellation > would not be an exception and nothing but pthread_cleanup_push'd code is > run, and stack unwinding of all kinds is totally ignored. In the second > mode, cancellation would be an exception; nothing more, nothing less. There is big amount of code in Linux after a few past years that already has pthread_cleanup_{push,pop} internally implemented as a C++ object with a destructor. So this is really not a workable option. Jakub From mark at codesourcery.com Fri Jul 15 07:19:38 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Fri, 15 Jul 2005 00:19:38 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <20050715070512.GM4884@devserv.devel.redhat.com> References: <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> Message-ID: <42D7638A.10309@codesourcery.com> Jakub Jelinek wrote: > On Thu, Jul 14, 2005 at 05:24:57PM -0700, Mark Mitchell wrote: > >>Why not just have two modes, controlled by an environment variable, >>link-time option, or run-time variable? In the first mode, cancellation >>would not be an exception and nothing but pthread_cleanup_push'd code is >>run, and stack unwinding of all kinds is totally ignored. In the second >>mode, cancellation would be an exception; nothing more, nothing less. > > > There is big amount of code in Linux after a few past years that already > has pthread_cleanup_{push,pop} internally implemented as a C++ object > with a destructor. So this is really not a workable option. Really? In that case, I think you're at impasse. Skipping "catch (...)" really just doesn't make sense to most of us. But, your customer doesn't want catch clauses to be run. So, if it's impossible to restore "classic" POSIX C semantics, then you're out of luck. -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From jakub at redhat.com Fri Jul 15 07:22:28 2005 From: jakub at redhat.com (Jakub Jelinek) Date: Fri, 15 Jul 2005 03:22:28 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D7638A.10309@codesourcery.com> References: <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> Message-ID: <20050715072228.GA30077@devserv.devel.redhat.com> On Fri, Jul 15, 2005 at 12:19:38AM -0700, Mark Mitchell wrote: > Jakub Jelinek wrote: > >On Thu, Jul 14, 2005 at 05:24:57PM -0700, Mark Mitchell wrote: > > > >>Why not just have two modes, controlled by an environment variable, > >>link-time option, or run-time variable? In the first mode, cancellation > >>would not be an exception and nothing but pthread_cleanup_push'd code is > >>run, and stack unwinding of all kinds is totally ignored. In the second > >>mode, cancellation would be an exception; nothing more, nothing less. > > > > > >There is big amount of code in Linux after a few past years that already > >has pthread_cleanup_{push,pop} internally implemented as a C++ object > >with a destructor. So this is really not a workable option. > > Really? has: # ifdef __cplusplus /* Class to handle cancellation handler invocation. */ class __pthread_cleanup_class { void (*__cancel_routine) (void *); void *__cancel_arg; int __do_it; int __cancel_type; public: __pthread_cleanup_class (void (*__fct) (void *), void *__arg) : __cancel_routine (__fct), __cancel_arg (__arg), __do_it (1) { } ~__pthread_cleanup_class () { if (__do_it) __cancel_routine (__cancel_arg); } void __setdoit (int __newval) { __do_it = __newval; } void __defer () { pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &__cancel_type); } void __restore () const { pthread_setcanceltype (__cancel_type, 0); } }; /* Install a cleanup handler: ROUTINE will be called with arguments ARG when the thread is canceled or calls pthread_exit. ROUTINE will also be called with arguments ARG when the matching pthread_cleanup_pop is executed with non-zero EXECUTE argument. pthread_cleanup_push and pthread_cleanup_pop are macros and must always be used in matching pairs at the same nesting level of braces. */ # define pthread_cleanup_push(routine, arg) \ do { \ __pthread_cleanup_class __clframe (routine, arg) /* Remove a cleanup handler installed by the matching pthread_cleanup_push. If EXECUTE is non-zero, the handler function is called. */ # define pthread_cleanup_pop(execute) \ __clframe.__setdoit (execute); \ } while (0) ... Jakub From mark at codesourcery.com Fri Jul 15 07:29:05 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Fri, 15 Jul 2005 00:29:05 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <20050715072228.GA30077@devserv.devel.redhat.com> References: <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> Message-ID: <42D765C1.4060504@codesourcery.com> Jakub Jelinek wrote: > On Fri, Jul 15, 2005 at 12:19:38AM -0700, Mark Mitchell wrote: > >>Jakub Jelinek wrote: >> >>>On Thu, Jul 14, 2005 at 05:24:57PM -0700, Mark Mitchell wrote: >>> >>> >>>>Why not just have two modes, controlled by an environment variable, >>>>link-time option, or run-time variable? In the first mode, cancellation >>>>would not be an exception and nothing but pthread_cleanup_push'd code is >>>>run, and stack unwinding of all kinds is totally ignored. In the second >>>>mode, cancellation would be an exception; nothing more, nothing less. >>> >>> >>>There is big amount of code in Linux after a few past years that already >>>has pthread_cleanup_{push,pop} internally implemented as a C++ object >>>with a destructor. So this is really not a workable option. >> >>Really? > > has: Sorry, I didn't mean that I didn't believe you; it's just that my RHEL 3 box doesn't have that, so I was slightly surprised. That means that, as you say, you've committed to using an exception to implement thread cancellation. So, now you get the semantics of exceptions -- including that they can be caught by "catch (...)". -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From jakub at redhat.com Fri Jul 15 07:36:49 2005 From: jakub at redhat.com (Jakub Jelinek) Date: Fri, 15 Jul 2005 03:36:49 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D765C1.4060504@codesourcery.com> References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> Message-ID: <20050715073649.GB30077@devserv.devel.redhat.com> On Fri, Jul 15, 2005 at 12:29:05AM -0700, Mark Mitchell wrote: > Sorry, I didn't mean that I didn't believe you; it's just that my RHEL 3 > box doesn't have that, so I was slightly surprised. In RHEL3 it is in /usr/include/nptl/pthread.h. > That means that, as you say, you've committed to using an exception to > implement thread cancellation. So, now you get the semantics of > exceptions -- including that they can be caught by "catch (...)". I wouldn't say that. NPTL simply requires that class destructors are run during cancellation's forced unwinding. I don't see why it would imply something about catch (...) though, it still doesn't mean cancellation is an exception, just that some mechanism runs the class destructors. Jakub From mark at codesourcery.com Fri Jul 15 07:53:40 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Fri, 15 Jul 2005 00:53:40 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <20050715073649.GB30077@devserv.devel.redhat.com> References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> Message-ID: <42D76B84.5010604@codesourcery.com> Jakub Jelinek wrote: > I wouldn't say that. NPTL simply requires that class destructors > are run during cancellation's forced unwinding. I don't see why it would > imply something about catch (...) though, it still doesn't mean cancellation > is an exception, just that some mechanism runs the class destructors. It's not NPTL that says something about "catch (...)" -- it's C++ that says that. The whole point of destructors and exceptions in C++ is that you are guaranteed that all exits from a block will result in a particular set of cleanup code -- including both destructors and the bodies of catch clauses -- being run in a particular order. Jason's proposal #2 splits two things which are considered equivalent by programmers (destructors and catch clauses) into distinct classes, running some but not the other. That's not in the spirit of C++, IMO. As Nathan has demonstrated, there are cases where you *must* use a catch clause to manage cleanups. The justification for approach #2 is compatibility with the POSIX C bindings -- but real compatibility would be not to run any cleanup code at all, not to run some cleanup code, but not all of it. If it's not technically feasible to avoid running destructors other than those for the magic pthread cleanup class, then the only palatable solution is to run all cleanup code, including "catch(...)" clauses. -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From terekhov at web.de Fri Jul 15 10:14:16 2005 From: terekhov at web.de (Alexander Terekhov) Date: Fri, 15 Jul 2005 12:14:16 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> Message-ID: <42D78C78.14BDC117@web.de> Mark Mitchell wrote: ... http://groups.google.de/group/comp.programming.threads/msg/05c0dc6fb9caae17 You might want to read this entire thread. regards, alexander. From nathan at codesourcery.com Fri Jul 15 10:50:21 2005 From: nathan at codesourcery.com (Nathan Sidwell) Date: Fri, 15 Jul 2005 11:50:21 +0100 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> Message-ID: <42D794ED.50805@codesourcery.com> Jason Merrill wrote: > It's not that subtle, it just does stack unwinding, like a sequence of > returns. two parts of scheme #2 is unclear to me. If a cancellation is initiated inside a nothrow function, the cancellation is deferred until the nothrow function is exited. correct? question 1. What if the function is, say, throw (X)? do we delay cancellation? question 2. What if the active function is not nothrow, but is called from a nothrow function (containing suitable try .. catch). Do we delay cancellation? The caller of the intermediate nothrow function might well been optimized base on the knowledge that no unwinding will occur out of the called function. Perhaps I'm just restating the original question here :) What I find inconsistent is that if the cancellation is deferred when the active function is nothrow, why is it not delayed when any function in the call stack is nothrow? nathan -- Nathan Sidwell :: http://www.codesourcery.com :: CodeSourcery LLC nathan at codesourcery.com :: http://www.planetfall.pwp.blueyonder.co.uk From david.butenhof at hp.com Fri Jul 15 11:23:05 2005 From: david.butenhof at hp.com (Dave Butenhof) Date: Fri, 15 Jul 2005 07:23:05 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> Message-ID: <42D79C99.6050709@hp.com> Jason Merrill wrote: >>It is true that many codes have been written with POSIX C binding, more >>has to come as C++ codes. I'm not convinced that we should compromise >>the future. >> >> >The future can use a different interface. Or extend pthread_setcanceltype. >PTHREAD_CANCEL_DEFERRED_EXCEPTION, anyone? > > That would be a serious mistake. C and C++ are so interoperable that interleaved frames are common. Bad current implementations (that don't have a common exception model between POSIX cleanup and C++/Ada/Modula/Java exceptions) are broken when two C frames with cancellation cleanup have intervening C++ frames -- destructors in those frames will be skipped. But it'd be no less bad for a "C++ cancel" to skip interleaved C frame cleanup handlers. You can try to say that C frames using POSIX cleanup cannot be interleaved with C++ frames; and that C++ frames using C++ cancel cannot be interleaved with frames using POSIX cleanup. But that makes no conceivable sense, and in practice is an unreasonable and infeasible restriction. They have to interoperate. They have to be the same. There has to be ONE cancellation mechanism. It has to propagate and behave as an exception because there's a vast body of existing code in many languages that already provides cleanup mechanisms based on exceptions, and POSIX cancel cleanup can also be implemented as an exception. -------------- next part -------------- A non-text attachment was scrubbed... Name: david.butenhof.vcf Type: text/x-vcard Size: 476 bytes Desc: not available URL: From dave at boost-consulting.com Fri Jul 15 12:16:52 2005 From: dave at boost-consulting.com (David Abrahams) Date: Fri, 15 Jul 2005 08:16:52 -0400 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> <42D79C99.6050709@hp.com> Message-ID: Dave Butenhof writes: > You can try to say that C frames using POSIX cleanup cannot be > interleaved with C++ frames; and that C++ frames using C++ cancel cannot > be interleaved with frames using POSIX cleanup. But that makes no > conceivable sense, and in practice is an unreasonable and infeasible > restriction. They have to interoperate. They have to be the same. I'm sure I'm missing something important here, but I'm going to barrel ahead with my misconceptions anyway so that someone will set me straight. It's currently *very common* to write C++ code that assumes C++ exceptions must not propagate across the boundary between C++ and other languages. That is the status quo for many systems and compilers. Many, many C programs are not written with embedded thread cleanups, and IMO it's almost unreasonably hard for a C program to register all the cleanups it would need to maintain invariants, because C lacks the necessary language support. It's typical that a C++ exception will be translated into something that ordinary C code can understand in those cases. "Ordinary" error handling is hard enough in C. So it would seem to me that the rule that "C frames using POSIX cleanup cannot be interleaved with C++ frames" is probably already being followed in a great deal of code. > There has to be ONE cancellation mechanism. It has to propagate and > behave as an exception because there's a vast body of existing code in > many languages that already provides cleanup mechanisms based on > exceptions, and POSIX cancel cleanup can also be implemented as an > exception. Yeah, but there's also a vast body of existing code that for practical reasons has to assume that exceptions can't propagate across language boundaries, and so has put other mechanisms in place to handle that situation. -- Dave Abrahams Boost Consulting www.boost-consulting.com From david.butenhof at hp.com Fri Jul 15 13:49:19 2005 From: david.butenhof at hp.com (Dave Butenhof) Date: Fri, 15 Jul 2005 09:49:19 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> <42D79C99.6050709@hp.com> Message-ID: <42D7BEDF.2020004@hp.com> David Abrahams wrote: >Dave Butenhof writes: > > >>There has to be ONE cancellation mechanism. It has to propagate and >>behave as an exception because there's a vast body of existing code in >>many languages that already provides cleanup mechanisms based on >>exceptions, and POSIX cancel cleanup can also be implemented as an >>exception. >> >> >Yeah, but there's also a vast body of existing code that for practical >reasons has to assume that exceptions can't propagate across language >boundaries, and so has put other mechanisms in place to handle that >situation. > > OK, I'll admit to being in the privileged elite -- my principle development environment has been OpenVMS and Tru64 UNIX, both of which had architected common exception environments from the start and C compiler support to participate. This is especially true on OpenVMS where basic operation of the system relies on exceptions. While Tru64 UNIX is more of a plain UNIX heritage, language and library developers routinely exploited the exception library. C++ destructors have always run when a POSIX exit or cancel *exception*, or an Ada or Java exception, propagates; just because that's how it clearly ought to work, it was easy to do, and why would anyone want to implement anything else? Similarly, Ada finally clauses, and POSIX cleanup handlers, will fire on propagation of a C++ exception. How could it not? Why would anyone not want it to? This is the way it SHOULD work. The only way it CAN work in the long run. Unless you're planning to say "C++ is C++, and you can't mix it with anything else." (A very "UNIX" philosophy, perhaps; but one with which I strongly disagree... and I think also one that's highly impractical and unrealistic in our current universe.) In the long process of developing the IA64 ABI for UNIX98 (which unfortunately was abandoned for political reasons), I invested a lot of time in convincing not only the general ABI committee but also the C++ committee that exception-based cancel, on top of a common platform exception library shared by C, C++, Ada, Java, and anyone else, was an absolute basic necessity. I succeeded, incidentally, and a variant of an existing C++ exception package generalized to support a common cross-language exception model was proposed. It wouldn't have been a big deal for anyone with a C++ implementation to provide such a library. So, OK; I don't have a strong vested interest at this point in trying to build a decent C++ threading model. I've spent an enormous amount of time and energy doing that several times before; it's all been wasted, and I'm tired. I'm trying to provide some background and assistance to help you guys do it all yet again for the nth time without dropping the ball, but if you're going to go a different way, that's your business. I'll just shut up and listen. -------------- next part -------------- A non-text attachment was scrubbed... Name: david.butenhof.vcf Type: text/x-vcard Size: 476 bytes Desc: not available URL: From gdr at integrable-solutions.net Fri Jul 15 14:02:21 2005 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 15 Jul 2005 16:02:21 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> <42D79C99.6050709@hp.com> Message-ID: David Abrahams writes: | Dave Butenhof writes: | | > You can try to say that C frames using POSIX cleanup cannot be | > interleaved with C++ frames; and that C++ frames using C++ cancel cannot | > be interleaved with frames using POSIX cleanup. But that makes no | > conceivable sense, and in practice is an unreasonable and infeasible | > restriction. They have to interoperate. They have to be the same. | | I'm sure I'm missing something important here, but I'm going to barrel | ahead with my misconceptions anyway so that someone will set me | straight. there are codes that register callbacks as 'extern "C"' functions to libraries that are written in C (following the urban legend "what is good for C is good enough for C++"). Such callbacks may happen to throw exceptions, either directly from user codes or as the result of standard library functions throwing. The pratice is widespread enough for compilers to support that. That is the model by deftault with the Sun compiler (at least the ones I test with). GCC/gcc uses -fexceptions to support that too. -- Gaby From dave at boost-consulting.com Fri Jul 15 14:37:22 2005 From: dave at boost-consulting.com (David Abrahams) Date: Fri, 15 Jul 2005 10:37:22 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D7BEDF.2020004@hp.com> (Dave Butenhof's message of "Fri, 15 Jul 2005 09:49:19 -0400") References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> <42D79C99.6050709@hp.com> <42D7BEDF.2020004@hp.com> Message-ID: Dave Butenhof writes: > David Abrahams wrote: > >>Dave Butenhof writes: >> >> >>> There has to be ONE cancellation mechanism. It has to propagate and >>> behave as an exception because there's a vast body of existing code >>> in many languages that already provides cleanup mechanisms based on >>> exceptions, and POSIX cancel cleanup can also be implemented as an >>> exception. >>> >>> >>Yeah, but there's also a vast body of existing code that for practical >>reasons has to assume that exceptions can't propagate across language >>boundaries, and so has put other mechanisms in place to handle that >>situation. >> >> > OK, I'll admit to being in the privileged elite -- my principle > development environment has been OpenVMS and Tru64 UNIX, both of which > had architected common exception environments from the start and C > compiler support to participate. This is especially true on OpenVMS > where basic operation of the system relies on exceptions. While Tru64 > UNIX is more of a plain UNIX heritage, language and library developers > routinely exploited the exception library. C++ destructors have always > run when a POSIX exit or cancel *exception*, or an Ada or Java > exception, propagates; just because that's how it clearly ought to work, > it was easy to do, and why would anyone want to implement anything else? > Similarly, Ada finally clauses, and POSIX cleanup handlers, will fire on > propagation of a C++ exception. How could it not? Why would anyone not > want it to? Sure, in an ideal world all languages' exception systems should interoperate. > This is the way it SHOULD work. The only way it CAN work in the long > run. Unless you're planning to say "C++ is C++, and you can't mix it > with anything else." (A very "UNIX" philosophy, perhaps; but one > with which I strongly disagree... Me too. Why would I want to isolate C++ that way? > and I think also one that's highly impractical and unrealistic in > our current universe.) And becoming less realistic as the IA64 ABI propagates itself. However, it does seem likely that interpreted languages such as Python will not be able to easily achieve such smooth interoperability, even where the ABI is adopted. > In the long process of developing the IA64 ABI for UNIX98 (which > unfortunately was abandoned for political reasons), I invested a lot > of time in convincing not only the general ABI committee but also > the C++ committee ?? I'm pretty sure I would have noticed any traffic from you in the C++ committee reflectors on exceptions during that period. > that exception-based cancel, on top of a common platform exception > library shared by C, C++, Ada, Java, and anyone else, was an > absolute basic necessity. I succeeded, incidentally, and a variant > of an existing C++ exception package generalized to support a common > cross-language exception model was proposed. It wouldn't have been a > big deal for anyone with a C++ implementation to provide such a > library. > > So, OK; I don't have a strong vested interest at this point in > trying to build a decent C++ threading model. I've spent an enormous > amount of time and energy doing that several times before; it's all > been wasted, and I'm tired. I'm trying to provide some background > and assistance to help you guys do it all yet again for the nth time > without dropping the ball, but if you're going to go a different > way, that's your business. I'll just shut up and listen. Whoa, dude; chill. It's my impression that most of us are debating in order to achieve clarity, not to try to force a particular decision. BTW, I still haven't seen a clear statement of your position in the scheme #1,2,3 contest. -- Dave Abrahams Boost Consulting www.boost-consulting.com From gshiman at commvault.com Fri Jul 15 16:22:17 2005 From: gshiman at commvault.com (George Shimanovich) Date: Fri, 15 Jul 2005 12:22:17 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again Message-ID: <52CA6BC0D0E9EE4E93208DB39A3218FEA458F9@EXCHANGE.gp.cv.commvault.com> >Jason Merrill [jason at redhat.com] wrote: >And the current status quo in GCC: >3) #1, except that the destructor for the exception calls abort(). Additional inelegant possibilities for the destructor >would be killing just the thread, throwing a new exception, or doing nothing (leaving the thread in a sort of zombie >state). >From the point of view of mere mortal, why GCC implementation calls abort()? Unusable better describes current GCC implementation then 'status quo' as instead of terminating cancelled thread entire program is aborted. Unless signal handler does not return, of course, - but that is unacceptable for thread pool implementations where threads need to be reused. Why not kill the thread in that case? That way cancelled thread will go away which is what cancellation is supposed to do. George Shimanovich CommVault Systems, Inc. -------------- next part -------------- An HTML attachment was scrubbed... URL: From pdimov at mmltd.net Fri Jul 15 17:40:40 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Fri, 15 Jul 2005 20:40:40 +0300 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com><20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: Jason Merrill wrote: > OK, let me clarify my position. For a new C++ threading library, I > would continue to prefer scheme #1. But this isn't a new library, > it's an extension of an existing library. But if it becomes part of the C++ standard, it becomes part of all C++ libraries, including new C++ threading libraries. > Tangent follows: > ---------------- > WRT scheme #1, various people have wondered why re-asserting > cancellation in the exception's destructor is necessary. It's > necessary because as I said in my first message, if someone > specifically told the thread to go away, they don't want it to > recover, they want it to go away. The thread doesn't get to > second-guess that request, it has to go away. It can take > arbitrarily long to get around to actually going away, but it can't > actually decide not to. It especially can't decide this implicitly, > as a side-effect of code written to handle exceptions. Keeping the cancellation request active doesn't need to be done by reasserting in the destructor. It can simply be left active. Since cancellation is implicitly disabled during stack unwinding, the request will automatically "reassert itself" when the exception is caught, independent of how many times the exception is copied and destroyed. Providing a way to clear a cancellation request is useful when tasks are executed in a thread pool and it's only the task that needs to be cancelled, not its thread shell. If a thread has been explicitly written to oppose cancellations, there is little to be gained by twisting the rules to make it cancellable. The thread has been designed as uncancellable. It will probably break if cancelled. From mark at codesourcery.com Fri Jul 15 18:07:31 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Fri, 15 Jul 2005 11:07:31 -0700 Subject: [c++-pthreads] Re: Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D2ECF8.3000303@codesourcery.com><20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: <42D7FB63.4080308@codesourcery.com> Peter Dimov wrote: >>WRT scheme #1, various people have wondered why re-asserting >>cancellation in the exception's destructor is necessary. I think that this is a tangent we should avoid for the moment. The variant of #1 in which the cancellation exception is handled, ending cancellation, and the variant of #1 in which cancellation is re-asserted when the cancellation exception is handled are very similar. So, if we got consensus that we wanted one of these two variants, that would be a major step forward. From my point of view, either of these is OK. The key idea behind this whole discussion is that we're trying to make existing code work; if there were no existing code, it seems that everyone would agree that one of the variants of #1 is best. But, what we don't agree about is what we mean by "existing code". Jason means code that was written to use pthread_cleanup_{push,pop} on GNU/Linux before it was a proper exception, and which therefore does not expect unwinding to occur. However, the customer code in question is apparently able to tolerate destructors being run, even while skipping over catch clauses. I certainly believe that this is true of some code, but that's completely untrue in the general case. Another kind of existing code is cross-platform, exception-safe libraries. These, if written well, can handle arbitrary exceptions passing through them, but do not, in general, handle things that behave like exceptions, expect that catch clauses are not run. The counter-argument here is that such libraries may require changes to handle thread cancellation anyhow, if they call POSIX cancellation points without expecting them to throw exceptions. That's true -- but many of them don't. They do, however, call user functions which may take arbitrary action, including throwing exceptions. I'm not sure how compelling either existing code argument is, but I don't see that the first argument is anywhere near strong enough to cause us to develop an informal standard around the model that everyone seems to agree is inferior in the abstract. -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From jason at redhat.com Fri Jul 15 20:44:29 2005 From: jason at redhat.com (Jason Merrill) Date: Fri, 15 Jul 2005 16:44:29 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D76B84.5010604@codesourcery.com> (Mark Mitchell's message of "Fri, 15 Jul 2005 00:53:40 -0700") References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> Message-ID: On Fri, 15 Jul 2005 00:53:40 -0700, Mark Mitchell wrote: > The whole point of destructors and exceptions in C++ is that you are > guaranteed that all exits from a block will result in a particular set > of cleanup code -- including both destructors and the bodies of catch > clauses -- being run in a particular order. Not all exits. A return, break or goto from within a try block skips catch clauses. Jason From mark at codesourcery.com Fri Jul 15 21:03:11 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Fri, 15 Jul 2005 14:03:11 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> Message-ID: <42D8248F.8090007@codesourcery.com> Jason Merrill wrote: > On Fri, 15 Jul 2005 00:53:40 -0700, Mark Mitchell wrote: > > >>The whole point of destructors and exceptions in C++ is that you are >>guaranteed that all exits from a block will result in a particular set >>of cleanup code -- including both destructors and the bodies of catch >>clauses -- being run in a particular order. > > > Not all exits. A return, break or goto from within a try block skips catch > clauses. True, as does falling off the end of the try block. However, the point remains; people put cleanup code in "catch (...)" blocks. In fact, that approach works fine with cancellation on current GNU/Linux systems, so long as you re-throw at the end of the catch clause -- and #2 would break that body of code. -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From gshiman at commvault.com Fri Jul 15 21:16:26 2005 From: gshiman at commvault.com (George Shimanovich) Date: Fri, 15 Jul 2005 17:16:26 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again Message-ID: <52CA6BC0D0E9EE4E93208DB39A3218FEA45904@EXCHANGE.gp.cv.commvault.com> -----Original Message----- From: Mark Mitchell [mailto:mark at codesourcery.com] Sent: Friday, July 15, 2005 5:03 PM To: Jason Merrill Cc: Jakub Jelinek; Gabriel Dos Reis; c++-pthreads at codesourcery.com Subject: Re: [c++-pthreads] Re: pthread_cancel and EH: let's try this again Mark Mitchell wrote: >Jason Merrill wrote: >> On Fri, 15 Jul 2005 00:53:40 -0700, Mark Mitchell >> wrote: >> >> >>>The whole point of destructors and exceptions in C++ is that you are >>>guaranteed that all exits from a block will result in a particular set >>>of cleanup code -- including both destructors and the bodies of catch >>>clauses -- being run in a particular order. >> >> >> Not all exits. A return, break or goto from within a try block skips >> catch clauses. > >True, as does falling off the end of the try block. > >However, the point remains; people put cleanup code in "catch (...)" blocks. > >In fact, that approach works fine with cancellation on current GNU/Linux >systems, so long as you re-throw at the end of the catch clause -- and >#2 would break that body of code. According to my colleges and mine experience using pthread in GNU/Linux entire program crashes when thread is cancelled due to abort() or cancelled thread hangs in system space. That is collaborated by this quote from Jason: >And the current status quo in GCC: >(3) #1, except that the destructor for the exception calls abort()) George Shimanovich CommVault Systems, Inc. From mark at codesourcery.com Fri Jul 15 21:35:51 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Fri, 15 Jul 2005 14:35:51 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <52CA6BC0D0E9EE4E93208DB39A3218FEA45904@EXCHANGE.gp.cv.commvault.com> References: <52CA6BC0D0E9EE4E93208DB39A3218FEA45904@EXCHANGE.gp.cv.commvault.com> Message-ID: <42D82C37.2090005@codesourcery.com> George Shimanovich wrote: > According to my colleges and mine experience using pthread in GNU/Linux > entire program crashes when thread is cancelled due to abort() or > cancelled thread hangs in system space. That is collaborated by this > quote from Jason: > >And the current status quo in GCC: > >(3) #1, except that the destructor for the exception calls > abort()) I believe that happens only if the catch handler does not rethrow the exception. -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From gshiman at commvault.com Fri Jul 15 21:50:06 2005 From: gshiman at commvault.com (George Shimanovich) Date: Fri, 15 Jul 2005 17:50:06 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again Message-ID: <52CA6BC0D0E9EE4E93208DB39A3218FEA45905@EXCHANGE.gp.cv.commvault.com> Mark Mitchell >George Shimanovich wrote: > >> According to my colleges and mine experience using pthread in >> GNU/Linux entire program crashes when thread is cancelled due to >> abort() or cancelled thread hangs in system space. That is >> collaborated by this quote from Jason: >> >And the current status quo in GCC: >> >(3) #1, except that the destructor for the exception calls >> abort()) > >I believe that happens only if the catch handler does not rethrow the >exception. Thanks for answering. Unfortunately no. I definitely tried rethrowing exception. And, after thread cancellation, depending on the Linux system used, the program either crashed or cancelled thread hung in system part of the stack. Because of that Linux remains the only OS where we do not use pthreads. Attached is my 1 year old post to this list with more details. George Shimanovich CommVault Systems, Inc. -------------- next part -------------- An embedded message was scrubbed... From: "George Shimanovich" Subject: [c++-pthreads] Complete fix to cancellation/stack unwinding problem of deferred Posix threads Date: Fri, 25 Jun 2004 17:49:12 -0400 Size: 3768 URL: From wil at bogo.xs4all.nl Fri Jul 15 22:45:55 2005 From: wil at bogo.xs4all.nl (Wil Evers) Date: Sat, 16 Jul 2005 00:45:55 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D76B84.5010604@codesourcery.com> References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> Message-ID: <42D83CA3.8080600@bogo.xs4all.nl> Mark Mitchell wrote: > It's not NPTL that says something about "catch (...)" -- it's C++ that > says that. > > The whole point of destructors and exceptions in C++ is that you are > guaranteed that all exits from a block will result in a particular set > of cleanup code -- including both destructors and the bodies of catch > clauses -- being run in a particular order. > > Jason's proposal #2 splits two things which are considered equivalent by > programmers (destructors and catch clauses) into distinct classes, > running some but not the other. That's not in the spirit of C++, IMO. > As Nathan has demonstrated, there are cases where you *must* use a > catch clause to manage cleanups. I agree, but please note that the handling of catch (...) blocks is not the only distinction between model #1 and model #2. In model #2, cancellation is disabled in all destructors; in model #1, cancellation is only disabled when destructors are called while unwinding the stack. In other words, #2 has the desirable property that it does not break existing code that assumes destructors *never* throw. I suspect that a lot of code relies on that assumption, and I know for sure that practically all of my code does. Supposing model #1 is accepted, then how do we cope with existing code that assumes destructors never throw, or, more generally, with code that was not written to deal with exceptions thrown from cancellation points? A reasonable thing to do would be to disable cancellation by default (using pthread_setcancelstate()), and to selectively enable cancellation in sections of code that were written with cancellation in mind. RAII-like objects could be used to ensure the thread's cancellation state is restored on all exits from a block, both exceptional and non-exceptional. An interesting side-effect of this approach is that once it is in place, there is no reason for the system's cancellation machinery to manipulate a thread's cancellation state at all; it could be managed exclusively from user code. In addition to protecting sections of code from unexpected cancellation exceptions, it could also be used to *enable* cancellation in sections that would otherwise be run with system-disabled cancellation. - Wil From mark at codesourcery.com Fri Jul 15 22:57:46 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Fri, 15 Jul 2005 15:57:46 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D83CA3.8080600@bogo.xs4all.nl> References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> Message-ID: <42D83F6A.3010709@codesourcery.com> Wil Evers wrote: > I agree, but please note that the handling of catch (...) blocks is not > the only distinction between model #1 and model #2. > > In model #2, cancellation is disabled in all destructors; in model #1, > cancellation is only disabled when destructors are called while > unwinding the stack. > > In other words, #2 has the desirable property that it does not break > existing code that assumes destructors *never* throw. I suspect that a > lot of code relies on that assumption, and I know for sure that > practically all of my code does. Good point. However, that seems orthogonal to the other issues; we could certainly have #1 disallow cancellation in all destructors, if we wanted. I don't really know how we plan to do that in #2, without inserting additional code in every destructor, which seems unfortunate. > Supposing model #1 is accepted, then how do we cope with existing code > that assumes destructors never throw, or, more generally, with code that > was not written to deal with exceptions thrown from cancellation points? The compiler must know that cancellation points may throw exceptions, as otherwise it may have optimized away exception unwind information, as it would when calling any "nothrow" function. However, I realize that you're asking about user code, more than about the compiler. -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From gdr at integrable-solutions.net Fri Jul 15 23:01:28 2005 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 16 Jul 2005 01:01:28 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D83CA3.8080600@bogo.xs4all.nl> References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> Message-ID: Wil Evers writes: | Mark Mitchell wrote: | | > It's not NPTL that says something about "catch (...)" -- it's C++ | > that says that. | > The whole point of destructors and exceptions in C++ is that you are | > guaranteed that all exits from a block will result in a particular | > set of cleanup code -- including both destructors and the bodies of | > catch clauses -- being run in a particular order. | > Jason's proposal #2 splits two things which are considered | > equivalent by programmers (destructors and catch clauses) into | > distinct classes, running some but not the other. That's not in the | > spirit of C++, IMO. As Nathan has demonstrated, there are cases | > where you *must* use a catch clause to manage cleanups. | | I agree, but please note that the handling of catch (...) blocks is | not the only distinction between model #1 and model #2. | | In model #2, cancellation is disabled in all destructors; in model #1, | cancellation is only disabled when destructors are called while | unwinding the stack. | | In other words, #2 has the desirable property that it does not break | existing code that assumes destructors *never* throw. I suspect that a | lot of code relies on that assumption, and I know for sure that | practically all of my code does. | | Supposing model #1 is accepted, then how do we cope with existing code | that assumes destructors never throw, or, more generally, with code | that was not written to deal with exceptions thrown from cancellation | points? Destructors that throw usually lead to brittle codes. The problems are with those destructors, not with the cancellation model implemented for C++. The destructors should be fixed, because that problem is independent of multithreading. -- Gaby From david.butenhof at hp.com Fri Jul 15 23:50:20 2005 From: david.butenhof at hp.com (Dave Butenhof) Date: Fri, 15 Jul 2005 19:50:20 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> <42D79C99.6050709@hp.com> <42D7BEDF.2020004@hp.com> Message-ID: <42D84BBC.7060504@hp.com> David Abrahams wrote: >Dave Butenhof writes: > > >>OK, I'll admit to being in the privileged elite -- my principle >>development environment has been OpenVMS and Tru64 UNIX, both of which >>had architected common exception environments from the start and C >>compiler support to participate. >> >> >Sure, in an ideal world all languages' exception systems should >interoperate. > > The problem here for me is that so many consider this a "nice but unrealistic" goal; but it's something I've relied on and taken for granted for most of my professional career on OpenVMS and Tru64 UNIX. There's nothing unrealistic. And if you can implement a C++ exception runtime, you can implement and deploy a language-independent exception runtime everyone can share. This isn't rocket science -- just basic computer science. >>This is the way it SHOULD work. The only way it CAN work in the long >>run. Unless you're planning to say "C++ is C++, and you can't mix it >>with anything else." (A very "UNIX" philosophy, perhaps; but one >>with which I strongly disagree... >> >> >Me too. Why would I want to isolate C++ that way? > > Good. >>and I think also one that's highly impractical and unrealistic in >>our current universe.) >> >> >And becoming less realistic as the IA64 ABI propagates itself. >However, it does seem likely that interpreted languages such as Python >will not be able to easily achieve such smooth interoperability, even >where the ABI is adopted. > > Java does. Of course it's 'semi-compiled'. So is Perl, and perhaps Python although I know little about Python. (The last whitespace dependent language I tried to learn was RPG-II [OK, that's an extreme example], and I can't dredge up any interest in dealing with another. ;-) ) >>In the long process of developing the IA64 ABI for UNIX98 (which >>unfortunately was abandoned for political reasons), I invested a lot >>of time in convincing not only the general ABI committee but also >>the C++ committee >> >> >?? I'm pretty sure I would have noticed any traffic from you in the >C++ committee reflectors on exceptions during that period. > > I don't recall much email discussion on the ABI working groups -- this was almost exclusively teleconferences, and the status and reports weren't on any established C++ email list. >>that exception-based cancel, on top of a common platform exception >>library shared by C, C++, Ada, Java, and anyone else, was an >>absolute basic necessity. I succeeded, incidentally, and a variant >>of an existing C++ exception package generalized to support a common >>cross-language exception model was proposed. It wouldn't have been a >>big deal for anyone with a C++ implementation to provide such a >>library. >> >>So, OK; I don't have a strong vested interest at this point in >>trying to build a decent C++ threading model. I've spent an enormous >>amount of time and energy doing that several times before; it's all >>been wasted, and I'm tired. I'm trying to provide some background >>and assistance to help you guys do it all yet again for the nth time >>without dropping the ball, but if you're going to go a different >>way, that's your business. I'll just shut up and listen. >> >> >Whoa, dude; chill. It's my impression that most of us are debating in >order to achieve clarity, not to try to force a particular decision. > > OK, so I'm being overdramatic. Comes from living with 2 daughters who are into acting, I suppose. Still, it's frustrating to have the same issues crop up over and again. And, yeah, part of the point was precisely that I really can chill -- this isn't my job or my problem, and I can cut back and sit it out rather than drive myself crazy arguing the same stuff over again. And I'm about to chill (despite the heat and humidity here in New England) because tomorrow I leave for a week on a quiet island in Lake Winnipesauke with no internet. >BTW, I still haven't seen a clear statement of your position in the >scheme #1,2,3 contest. > > My goals are along different lines. 1. POSIX cancel and exit, C++ exceptions, Ada exceptions, and so forth, are all implemented under a common unified runtime model. 2. Propagation of any of these "structured unwinds" (by whatever name and purpose) will run appropriate language-specified cleanup, including POSIX cleanup handlers, C++ destructors, Ada finally clauses, and so forth; no matter how various language frames may be interleaved. Although I have personal preferences, I really don't care that much whether C++ allows catching cancel/exit with catch(...), whether a re-raise is forced or discretionary, whether it has a class name that can be caught explicitly. MY involvement is not as an expert in C++ language (standards or common usage); but as a casual C++ user with a lot of experience in threads and with several comprehensive exception models that have worked in practice. There are many corners into which C++ is trapped by existing standards and practices. (Some for perfectly good reasons, but it really doesn't matter now since nobody's going to tear the language apart and start over.) To put it another way, MY points 1 and 2 affect the ability to correctly and cleanly integrate POSIX threads and C++. The distinctions between schemes 1, 2, and 3 outlined in this discussion thread are "internal C++ politics". I don't consider any of them IDEAL, nor do I think does anyone else. The world will muddle through with any of them if necessary. But I suppose that's not really answering the implicit challenge, is it? If I had to make a counter-proposal, I'd probably have to suggest "#4": the cancel & exit EXCEPTIONS have names. They can be caught AND FINALIZED (legally not re-thrown) BY NAME (only). If caught anonymously, they must be re-thrown. I don't like automatically re-throwing on destruction (though it's a clever compromise for some scenerios, I'm trying to approximate some abstract idealism here so we'll discount that), so destruction (e.g., 'catch(...)' without a rethrow) should abort with some brilliantly enlightening usage message. Where things get complicated is dealing with destructors, 'throw' and and nothrow clauses. I don't know; and I tried to write up paragraphs of ideas a few times, but deleted them. Managing a dynamic scoping system by throw clauses has some merit -- no throw restrictions, or a throw specification that includes cancel, makes the frame cancellable; nothrow or a throw clause omitting cancel is non-cancellable. (This might make large chunks of code that ought to be, or even want to be cancellable, non-cancellable.) (I'm sure I'll be thrilled to be greeted by the followup when I get back on the 25th!) -------------- next part -------------- A non-text attachment was scrubbed... Name: david.butenhof.vcf Type: text/x-vcard Size: 476 bytes Desc: not available URL: From terekhov at web.de Sat Jul 16 13:48:36 2005 From: terekhov at web.de (Alexander Terekhov) Date: Sat, 16 Jul 2005 15:48:36 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> <42D79C99.6050709@hp.com> <42D7BEDF.2020004@hp.com> <42D84BBC.7060504@hp.com> Message-ID: <42D91034.555BA7F2@web.de> Dave Butenhof wrote: [...] > the cancel & exit EXCEPTIONS have names. They can be caught AND > FINALIZED (legally not re-thrown) BY NAME Yes. > (only). If caught anonymously, they must be re-thrown. This "compromise" makes no sense. void test_cancel() throw(thread_cancel_request) { pthread_testcancel(); } This try { testcancel(); // can throw only thread_cancel_request } catch(thread_cancel_request const &) { } is oughta be the same as try { testcancel(); // can throw only thread_cancel_request } catch(...) { } Uhmm, unless you seriously want the above be written as try { testcancel(); // can throw only thread_cancel_request } catch(...) { stop_stupid_abort(); } void stop_stupid_abort() { try { throw; } catch(thread_cancel_request const &) { } } regards, alexander. From terekhov at web.de Sat Jul 16 14:37:42 2005 From: terekhov at web.de (Alexander Terekhov) Date: Sat, 16 Jul 2005 16:37:42 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com><20050711225235.GO4884@devserv.devel.redhat.com> Message-ID: <42D91BB6.E63D4D19@web.de> Peter Dimov wrote: [...] > Keeping the cancellation request active doesn't need to be done by > reasserting in the destructor. It can simply be left active. Since > cancellation is implicitly disabled during stack unwinding, No. Intelligent cancel delivery aside for a moment, it's explicitly disabled only after delivery (and pthread_exit()). Consider: some_dtor() throw() { if (active_exception(0)) { pthread_cancel(pthread_self()); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &errno); try { fclose(temp_dataset); // no need to flush } catch(...) { } } else { try { fclose(temp_dataset); // no need to flush if we hit cancel } catch(...) { // canceled pthread_cancel(pthread_self()); } } } regards, alexander. From terekhov at web.de Sat Jul 16 14:43:00 2005 From: terekhov at web.de (Alexander Terekhov) Date: Sat, 16 Jul 2005 16:43:00 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com><20050711225235.GO4884@devserv.devel.redhat.com> <42D91BB6.E63D4D19@web.de> Message-ID: <42D91CF4.F049ED3@web.de> Alexander Terekhov wrote: > > Peter Dimov wrote: > [...] > > Keeping the cancellation request active doesn't need to be done by > > reasserting in the destructor. It can simply be left active. Since > > cancellation is implicitly disabled during stack unwinding, > > No. Intelligent cancel delivery aside for a moment, it's explicitly > disabled only after delivery (and pthread_exit()). Consider: > > some_dtor() throw() { > if (active_exception(0)) { > pthread_cancel(pthread_self()); > pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &errno); > try { > fclose(temp_dataset); // no need to flush > } > catch(...) { } > } > else { > try { > fclose(temp_dataset); // no need to flush if we hit cancel > } > catch(...) { // canceled > pthread_cancel(pthread_self()); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &errno); > } > } > } regards, alexander. From pdimov at mmltd.net Sat Jul 16 15:22:11 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Sat, 16 Jul 2005 18:22:11 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com><20050711225235.GO4884@devserv.devel.redhat.com> <42D91BB6.E63D4D19@web.de> Message-ID: <003b01c58a1a$24fc1450$6501a8c0@pdimov2> Alexander Terekhov wrote: > Peter Dimov wrote: > [...] >> Keeping the cancellation request active doesn't need to be done by >> reasserting in the destructor. It can simply be left active. Since >> cancellation is implicitly disabled during stack unwinding, > > No. Intelligent cancel delivery aside for a moment, it's explicitly > disabled only after delivery (and pthread_exit()). Consider: > > some_dtor() throw() { > if (active_exception(0)) { > pthread_cancel(pthread_self()); > pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &errno); > try { > fclose(temp_dataset); // no need to flush > } > catch(...) { } > } > else { > try { > fclose(temp_dataset); // no need to flush if we hit cancel > } > catch(...) { // canceled > pthread_cancel(pthread_self()); > } > } > } I don't get it. What is this code supposed to achieve? From terekhov at web.de Sat Jul 16 15:37:03 2005 From: terekhov at web.de (Alexander Terekhov) Date: Sat, 16 Jul 2005 17:37:03 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com><20050711225235.GO4884@devserv.devel.redhat.com> <42D91BB6.E63D4D19@web.de> <003b01c58a1a$24fc1450$6501a8c0@pdimov2> Message-ID: <42D9299F.1ED629EF@web.de> Peter Dimov wrote: [...] > I don't get it. What is this code supposed to achieve? It's a dtor. The logic is this: Detect whether unwinding caused by cancel delivery is taking place yes: reassert cancellation; invoke fclose() -- it will throw (and most likely not flush), but will close/free resources nevertheless; catch and finalize cancel exception; no: invoke fclose() fully prepared to hit cancel, and if canceled (see above) simply reassert cancellation; regards, alexander. From pdimov at mmltd.net Sat Jul 16 15:58:08 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Sat, 16 Jul 2005 18:58:08 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com><20050711225235.GO4884@devserv.devel.redhat.com> <42D91BB6.E63D4D19@web.de> <003b01c58a1a$24fc1450$6501a8c0@pdimov2> <42D9299F.1ED629EF@web.de> Message-ID: <005f01c58a1f$2a3f54e0$6501a8c0@pdimov2> Alexander Terekhov wrote: > Peter Dimov wrote: > [...] >> I don't get it. What is this code supposed to achieve? > > It's a dtor. The logic is this: > > Detect whether unwinding caused by cancel delivery is taking place > > yes: > > reassert cancellation; > invoke fclose() -- it will throw (and most likely not flush), > but will close/free resources nevertheless; > catch and finalize cancel exception; > > no: > > invoke fclose() fully prepared to hit cancel, and if canceled > (see above) simply reassert cancellation; And what is gained compared to ~X() throw() { fclose( file ); } ? Not that fclose should be a cancellation point, of course. Do you mean something along the lines of ~X() throw() { try { lengthy_or_blocking_operation(); } catch( ... ) { } } where one would want to have cancellation enabled in lengthy_or_blocking_operation, even when ~X is called by stack unwinding? I'm not sure how compelling is this example. From terekhov at web.de Sat Jul 16 16:21:04 2005 From: terekhov at web.de (Alexander Terekhov) Date: Sat, 16 Jul 2005 18:21:04 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com><20050711225235.GO4884@devserv.devel.redhat.com> <42D91BB6.E63D4D19@web.de> <003b01c58a1a$24fc1450$6501a8c0@pdimov2> <42D9299F.1ED629EF@web.de> <005f01c58a1f$2a3f54e0$6501a8c0@pdimov2> Message-ID: <42D933F0.B910D628@web.de> Peter Dimov wrote: [...] > And what is gained compared to > > ~X() throw() > { > fclose( file ); > } > > ? Currently (e.g. on Tru64 or OpenVMS) it can simply abort(). ;-) With intelligent cancel delivery (or when unwinding is caused by thread cancel/exit) it always will perform (potentially) "lengthy" operation... even when its "lenghty" part is not really needed (i.e. in the case if thread cancel). The code I've sketched is different in this respect. > > Not that fclose should be a cancellation point, of course. > > Do you mean something along the lines of > > ~X() throw() > { > try > { > lengthy_or_blocking_operation(); > } > catch( ... ) > { > } > } > > where one would want to have cancellation enabled in > lengthy_or_blocking_operation, even when ~X is called by stack unwinding? Yup. regards, alexander. From terekhov at web.de Sat Jul 16 16:47:55 2005 From: terekhov at web.de (Alexander Terekhov) Date: Sat, 16 Jul 2005 18:47:55 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D2ECF8.3000303@codesourcery.com><20050711225235.GO4884@devserv.devel.redhat.com> <42D91BB6.E63D4D19@web.de> <003b01c58a1a$24fc1450$6501a8c0@pdimov2> <42D9299F.1ED629EF@web.de> <005f01c58a1f$2a3f54e0$6501a8c0@pdimov2> Message-ID: <42D93A3B.2C3B36D0@web.de> Peter Dimov wrote: [...] > Not that fclose should be a cancellation point, of course. The thing is that write() is a mandatory "shall occur" cancellation point. Hence while fclose() is indeed an optional "may also occur" cancellation point (and for that reason I should have better used close(), not fclose()), it doesn't really make much of a difference unless you impose "already_flushed(stream) == 0" precondition on it. regards, alexander. From wil at bogo.xs4all.nl Sat Jul 16 22:23:45 2005 From: wil at bogo.xs4all.nl (Wil Evers) Date: Sun, 17 Jul 2005 00:23:45 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D83F6A.3010709@codesourcery.com> References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> Message-ID: <42D988F1.2050300@bogo.xs4all.nl> Mark Mitchell wrote: > Wil Evers wrote: > >> I agree, but please note that the handling of catch (...) blocks is >> not the only distinction between model #1 and model #2. >> >> In model #2, cancellation is disabled in all destructors; in model #1, >> cancellation is only disabled when destructors are called while >> unwinding the stack. >> >> In other words, #2 has the desirable property that it does not break >> existing code that assumes destructors *never* throw. I suspect that a >> lot of code relies on that assumption, and I know for sure that >> practically all of my code does. > > Good point. > > However, that seems orthogonal to the other issues; we could certainly > have #1 disallow cancellation in all destructors, if we wanted. I agree. > I don't > really know how we plan to do that in #2, without inserting additional > code in every destructor, which seems unfortunate. Again, I agree. IIRC, in the previous round of discussions on this mailing list, Jason said he feared the performance impact of having to disable cancellation in every destructor. >> Supposing model #1 is accepted, then how do we cope with existing code >> that assumes destructors never throw, or, more generally, with code >> that was not written to deal with exceptions thrown from cancellation >> points? > > The compiler must know that cancellation points may throw exceptions, as > otherwise it may have optimized away exception unwind information, as it > would when calling any "nothrow" function. > > However, I realize that you're asking about user code, more than about > the compiler. It seems to me you may have missed the point I was trying to make at the end of my previous message, which is that it seems feasible - or even desirable - to use a model in which the cancellation machinery doesn't implicitly disable cancellation at all, not even when unwinding the stack. Please consider this example: class cancellation_manager { public : explicit cancellation_manager(bool enable) { pthread_setcancelstate( enable ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, &saved_state); } ~cancellation_manager() { pthread_setcancelstate(&saved_state, 0); } private : cancellation_manager(const cancellation_manager&); void operator=(const cancellation_manager&); int saved_state; }; void *thread_routine(void *) { cancellation_manager disabler(false); std::ofstream outfile("filename"); // lots of legacy code... outfile << "some output" << std::endl; { cancellation_manager enabler(true); some_cancellation_point(); } // more legacy code... return 0; } I believe the code above is immune to the surprises caused by changing ordinary system calls into functions that can throw cancellation exceptions. In particular, we can be sure that outfile's destructor (which may invoke write() to flush its outbuf buffer) will never throw. This is because the programmer decided to disable cancellation by default, and to only enable it for limited sections of code that were written with cancellation in mind. IMO, not having the cancellation machinery implicitly disable cancellation has two distinct advantages: (*) It provides a clear migration path for existing multi-threaded C++ code that was not written to expect cancellation exceptions (see above). (*) It doesn't impose any particular cancellation handling policy, leaving it to the programmer to decide when and how to respond to cancellation requests. - Wil From wil at bogo.xs4all.nl Sat Jul 16 22:39:44 2005 From: wil at bogo.xs4all.nl (Wil Evers) Date: Sun, 17 Jul 2005 00:39:44 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> Message-ID: <42D98CB0.40404@bogo.xs4all.nl> Gabriel Dos Reis wrote: > Wil Evers writes: > | In other words, #2 has the desirable property that it does not break > | existing code that assumes destructors *never* throw. I suspect that a > | lot of code relies on that assumption, and I know for sure that > | practically all of my code does. > | > | Supposing model #1 is accepted, then how do we cope with existing code > | that assumes destructors never throw, or, more generally, with code > | that was not written to deal with exceptions thrown from cancellation > | points? > > Destructors that throw usually lead to brittle codes. The > problems are with those destructors, not with the cancellation model > implemented for C++. The destructors should be fixed, because that > problem is independent of multithreading. I disagree; one of the problems with mapping cancellation requests to C++ exceptions is that certain system calls that did not throw before are changed into functions that do, and that existing (destructor or non-destructor) code won't always be able to deal with that. - Wil From gdr at integrable-solutions.net Sat Jul 16 23:10:12 2005 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 17 Jul 2005 01:10:12 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D98CB0.40404@bogo.xs4all.nl> References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D98CB0.40404@bogo.xs4all.nl> Message-ID: Wil Evers writes: | Gabriel Dos Reis wrote: | | > Wil Evers writes: | | > | In other words, #2 has the desirable property that it does not break | > | existing code that assumes destructors *never* throw. I suspect that a | > | lot of code relies on that assumption, and I know for sure that | > | practically all of my code does. | > | | Supposing model #1 is accepted, then how do we cope with | > existing code | > | that assumes destructors never throw, or, more generally, with code | > | that was not written to deal with exceptions thrown from cancellation | > | points? | > Destructors that throw usually lead to brittle codes. The | > problems are with those destructors, not with the cancellation model | > implemented for C++. The destructors should be fixed, because that | > problem is independent of multithreading. | | I disagree; one of the problems with mapping cancellation requests to | C++ exceptions is that certain system calls that did not throw before | are changed into functions that do, and that existing (destructor or | non-destructor) code won't always be able to deal with that. If the function (or destructor) has a throw() specification, it will continue not to throw. If it did not have that annotation then it was assumed to throw. If you want to have fine grained control, you might want to consider telling std::terminate() and friends not to abort(). -- Gaby From dave at boost-consulting.com Sun Jul 17 01:04:31 2005 From: dave at boost-consulting.com (David Abrahams) Date: Sat, 16 Jul 2005 21:04:31 -0400 Subject: pthread_cancel and EH: let's try this again References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D98CB0.40404@bogo.xs4all.nl> Message-ID: Gabriel Dos Reis writes: > Wil Evers writes: > > | Gabriel Dos Reis wrote: > | > | > Wil Evers writes: > | > | > | In other words, #2 has the desirable property that it does not break > | > | existing code that assumes destructors *never* throw. I suspect that a > | > | lot of code relies on that assumption, and I know for sure that > | > | practically all of my code does. > | > | | Supposing model #1 is accepted, then how do we cope with > | > existing code > | > | that assumes destructors never throw, or, more generally, with code > | > | that was not written to deal with exceptions thrown from cancellation > | > | points? > | > Destructors that throw usually lead to brittle codes. The > | > problems are with those destructors, not with the cancellation model > | > implemented for C++. The destructors should be fixed, because that > | > problem is independent of multithreading. > | > | I disagree; one of the problems with mapping cancellation requests to > | C++ exceptions is that certain system calls that did not throw before > | are changed into functions that do, and that existing (destructor or > | non-destructor) code won't always be able to deal with that. > > If the function (or destructor) has a throw() specification, it will > continue not to throw. Yeah, but at what cost? Termination does not seem like a very desirable response to a cancellation request that happens to occur before a 'C' library call that ordinarily wouldn't throw. > If it did not have that annotation then it was assumed to throw. By the compiler, maybe, but not to programmers in general. Few programmers habitually use throw() on their destructors, but nearly everybody who has learned to write exception-safe code assumes that no destructor throws unless otherwise specified. > If you want to have fine grained control, you might want to consider > telling std::terminate() and friends not to abort(). What do you have in mind? -- Dave Abrahams Boost Consulting www.boost-consulting.com From gdr at integrable-solutions.net Sun Jul 17 01:52:55 2005 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 17 Jul 2005 03:52:55 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D98CB0.40404@bogo.xs4all.nl> Message-ID: David Abrahams writes: [...] | > If it did not have that annotation then it was assumed to throw. | | By the compiler, By the language rules. | > If you want to have fine grained control, you might want to consider | > telling std::terminate() and friends not to abort(). | | What do you have in mind? Change the default behaviour from abort() to -- Gaby From pdimov at mmltd.net Sun Jul 17 12:07:46 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Sun, 17 Jul 2005 15:07:46 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> Message-ID: <005b01c58ac8$27964920$6501a8c0@pdimov2> Wil Evers wrote: > It seems to me you may have missed the point I was trying to make at > the end of my previous message, which is that it seems feasible - or > even desirable - to use a model in which the cancellation machinery > doesn't implicitly disable cancellation at all, not even when > unwinding the stack. Please consider this example: [...] > void *thread_routine(void *) > { > cancellation_manager disabler(false); > std::ofstream outfile("filename"); > > // lots of legacy code... > > outfile << "some output" << std::endl; > > { > cancellation_manager enabler(true); > some_cancellation_point(); > } > > // more legacy code... > > return 0; > } > > I believe the code above is immune to the surprises caused by changing > ordinary system calls into functions that can throw cancellation > exceptions. Whether cancellation is enabled during stack unwinding does not affect your example at all. Leaving cancellation enabled during stack unwinding has the following effects: 1. Cancellation points called from destructors or catch+rethrow blocks may not complete, but throw; 2. The exception being propagated may be replaced with a cancellation exception somewhere along the path. (1) may or may not be desirable depending on context (it's 75% undesirable if you ask me), and I can't imagine a case where (2) would be desirable. > IMO, not having the cancellation machinery implicitly disable > cancellation has two distinct advantages: > > (*) It provides a clear migration path for existing multi-threaded C++ > code that was not written to expect cancellation exceptions (see > above). I think that this migration path is available under all models described so far. > (*) It doesn't impose any particular cancellation handling policy, > leaving it to the programmer to decide when and how to respond to > cancellation requests. From pdimov at mmltd.net Sun Jul 17 12:21:13 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Sun, 17 Jul 2005 15:21:13 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <005b01c58ac8$27964920$6501a8c0@pdimov2> Message-ID: <007f01c58aca$0762ceb0$6501a8c0@pdimov2> Peter Dimov wrote: > Whether cancellation is enabled during stack unwinding does not > affect your example at all. This is ambiguous. What I meant was that: Whether stack unwinding suppresses cancellation exceptions doesn't affect your example. I now realize that you may have been talking about the "cancellation enabled" flag as returned by pthread_setcancelstate. I agree that it can be left enabled. From dave at boost-consulting.com Sun Jul 17 19:45:41 2005 From: dave at boost-consulting.com (David Abrahams) Date: Sun, 17 Jul 2005 15:45:41 -0400 Subject: pthread_cancel and EH: let's try this again References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D98CB0.40404@bogo.xs4all.nl> Message-ID: Gabriel Dos Reis writes: > David Abrahams writes: > > [...] > > | > If it did not have that annotation then it was assumed to throw. > | > | By the compiler, > > By the language rules. The language rules don't make assumptions. Only people, and by proxy, the programs they write, can do that. > | > If you want to have fine grained control, you might want to consider > | > telling std::terminate() and friends not to abort(). > | > | What do you have in mind? > > Change the default behaviour from abort() to Is there a standard mechanism for doing that? -- Dave Abrahams Boost Consulting www.boost-consulting.com From wil at bogo.xs4all.nl Sun Jul 17 20:39:53 2005 From: wil at bogo.xs4all.nl (Wil Evers) Date: Sun, 17 Jul 2005 22:39:53 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <005b01c58ac8$27964920$6501a8c0@pdimov2> References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <005b01c58ac8$27964920$6501a8c0@pdimov2> Message-ID: <42DAC219.8050506@bogo.xs4all.nl> Peter Dimov wrote: > Wil Evers wrote: > >> It seems to me you may have missed the point I was trying to make at >> the end of my previous message, which is that it seems feasible - or >> even desirable - to use a model in which the cancellation machinery >> doesn't implicitly disable cancellation at all, not even when >> unwinding the stack. Please consider this example: > > [...] > >> void *thread_routine(void *) >> { >> cancellation_manager disabler(false); >> std::ofstream outfile("filename"); >> >> // lots of legacy code... >> >> outfile << "some output" << std::endl; >> >> { >> cancellation_manager enabler(true); >> some_cancellation_point(); >> } >> >> // more legacy code... >> >> return 0; >> } >> >> I believe the code above is immune to the surprises caused by changing >> ordinary system calls into functions that can throw cancellation >> exceptions. > > Whether cancellation is enabled during stack unwinding does not affect > your example at all. Exactly. However, there are (under model #1) significant differences between the example above and the code that would result if we removed the cancellation managers. My objection to model #1 (and, to some extent, #2 as well) is that is breaks some commonly used assumptions such as 'destructors do not throw' (#1) or 'system calls do not throw' (#1 and #2). Implicitly disabling cancellation during stack unwinding solves some of the problems that are introduced by mapping cancellation requests to C++ exceptions, but not all of them. It seems to me that a complete solution compatible with #1 - one that preserves existing semantics, except for the places where we are know we are able to deal with cancellation exceptions - requires the use of an idiom like the one I tried to illustrate above. And - I'm repeating myself here - once the user has put all this in place, there is no need for the cancellation machinery to implicitly disable cancellation at all. It makes no difference any more - just as you observed. > Leaving cancellation enabled during stack unwinding has the following > effects: > > 1. Cancellation points called from destructors or catch+rethrow blocks > may not complete, but throw; > > 2. The exception being propagated may be replaced with a cancellation > exception somewhere along the path. > > (1) may or may not be desirable depending on context (it's 75% > undesirable if you ask me), and I can't imagine a case where (2) would > be desirable. Let's add (3): the program will terminate if (1) occurs while the stack is already unwinding. Highly undesirable too, so clearly, something must be done to prevent all of this. What I'm trying to do is present an alternative to the IMO incomplete solution #1 provides. - Wil From wil at bogo.xs4all.nl Sun Jul 17 20:49:04 2005 From: wil at bogo.xs4all.nl (Wil Evers) Date: Sun, 17 Jul 2005 22:49:04 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <007f01c58aca$0762ceb0$6501a8c0@pdimov2> References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <005b01c58ac8$27964920$6501a8c0@pdimov2> <007f01c58aca$0762ceb0$6501a8c0@pdimov2> Message-ID: <42DAC440.4030208@bogo.xs4all.nl> Peter Dimov wrote: > Peter Dimov wrote: > >> Whether cancellation is enabled during stack unwinding does not >> affect your example at all. > > This is ambiguous. What I meant was that: > > Whether stack unwinding suppresses cancellation exceptions doesn't > affect your example. > > I now realize that you may have been talking about the "cancellation > enabled" flag as returned by pthread_setcancelstate. I agree that it can > be left enabled. No - I was talking about the actual part of a thread's state that causes a cancellation request to be either put on hold, or result in an exception. - Wil From pdimov at mmltd.net Sun Jul 17 21:47:44 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Mon, 18 Jul 2005 00:47:44 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <005b01c58ac8$27964920$6501a8c0@pdimov2> <42DAC219.8050506@bogo.xs4all.nl> Message-ID: <001e01c58b19$2b37fd20$6501a8c0@pdimov2> Wil Evers wrote: > My objection to model #1 (and, to some extent, #2 as well) is that is > breaks some commonly used assumptions such as 'destructors do not > throw' (#1) or 'system calls do not throw' (#1 and #2). Implicitly > disabling cancellation during stack unwinding solves some of the > problems that are introduced by mapping cancellation requests to C++ > exceptions, but not all of them. > > It seems to me that a complete solution compatible with #1 - one that > preserves existing semantics, except for the places where we are know > we are able to deal with cancellation exceptions - requires the use > of an idiom like the one I tried to illustrate above. And - I'm > repeating myself here - once the user has put all this in place, > there is no need for the cancellation machinery to implicitly disable > cancellation at all. It makes no difference any more - just as you > observed. I agree that if people always disable cancellation in destructors implicit suppression doesn't matter. But we have a number of conflicting goals. We want: 1. To specify sensible C++ cancellation semantics for new C++MT code. 2. To not break existing C++ code much. 3. To not break existing Posix code much. Since Posix semantics are approximated quite well by just suppressing cancellation during stack unwinding, and since this suppression (arguably) doesn't affect old C++ code or new C++ code in a negative way (*), it seems a good compromise. We also want 4. To not break C++ exception handling or introduce special cases. which is why I think that #1 with implicit suppression is the best alternative of those described so far. (*) A function that tells us whether stack unwinding is in progress could even prove useful for new C++ code. From ncm at cantrip.org Sun Jul 17 22:37:48 2005 From: ncm at cantrip.org (Nathan Myers) Date: Sun, 17 Jul 2005 15:37:48 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D988F1.2050300@bogo.xs4all.nl> References: <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> Message-ID: <20050717223748.GA4125@tofu.dreamhost.com> It strikes me that Wil Evers has posted the most practical suggestion I have seen, on this list, since its inception. On Sun, Jul 17, 2005 at 12:23:45AM +0200, Wil Evers wrote: > > ... it seems feasible - or even > desirable - to use a model in which the cancellation machinery doesn't > implicitly disable cancellation at all, not even when unwinding the > stack. > ... > cancellation_manager::cancellation_manager(bool enable) > { > pthread_setcancelstate( > enable ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, > &saved_state); > } > cancellation_manager::~cancellation_manager() > { pthread_setcancelstate(&saved_state, 0); } > ... > (*) It provides a clear migration path for existing multi-threaded C++ > code that was not written to expect cancellation exceptions (see > above). > > (*) It doesn't impose any particular cancellation handling policy, > leaving it to the programmer to decide when and how to respond to > cancellation requests. Like any suggestion, Wil's might benefit from refinements. I hope that Wil can maintain a summary that may form the basis for a specification. (Can somebody suggest a Wiki where we might add an appropriate page?) We have several advantages, in discussing a C++ binding, that those before us (e.g. those designing C bindings) did not have, and a few disadvantages. For advantages, (1) we have a much more powerful language that can express our intent directly; (2) there is no coherent body of existing practice, so we can proceed sensibly; and (3) we have much less political bias to skew our choices. Our disadvantages might be that we are that we are more ambitious than our predecessors, and that what we choose is less directly influential. Both of the latter may be turned to our favor: they force us toward a design that is inherently compelling, leading users outside our circle to demand that their vendors adopt, and even standardize, it. We can implement it and deploy it more easily than most, exposing potential users to our chosen semantics. (A distinct advantage to us this time around is that no one shrieks "Zero Uptake! Zero Uptake!" whenever a suggestion arises that is compatible with Standard C++ semantics.) We are more ambitious in that we mean to preserve the usefulness, within threads that might be cancelled, of a much larger body of existing library code, both in C and in C++, written without awareness of the possibility of cancellation. We mean to evolve a design without serious pitfalls for those less experienced with thread semantics, or who (like most) have never heard of cancellation. Here are some goals I hope we can mostly agree on: 1. Existing C libraries that *do* try to take cancellation into account should still work, where practical. Existing C++ code that relies on C cancellation behavior should be easy to adapt, presuming it really worked, before, and not only by accident. 2. Existing thread-safe and exception-safe C and C++ libraries that do *not* take cancellation into account should still work. (This implies that C library calls, including system calls, never throw, by default or during normal operation; likewise for C++ destructors, and C++ functions with any throw specification.) 3. We have no need to preserve existing "thread-main" code without changes. That code is rarely very portable, and in ported code routinely has #ifdefs scattered through it already. As much as possible, the need to know about cancellation should be confined to thread-main and program-main code. 4. We must not assume that C libraries, in general, can handle propagating an exception safely (e.g. from a C++ callback), because C doesn't provide the tools to enable it, POSIX cancellation apparatus notwithstanding. 5. Thread- and exception-safe libraries that do not deliberately interact with cancellation machinery should not normally need to be recompiled. Accommodating possible cancellation events should not slow down normal code execution. 6. We need make no artificial distinction between "discarding cancellation" and "indefinitely delaying" thread termination, unless the distinction becomes helpful. 7. We may assume we can hijack/shadow standard system and library calls and add our own semantics, such as causing them to report failure (perhaps with distinguished ERRNO codes) under circumstances where they would otherwise have succeeded, or (under C cancellation) entered some sort of cleanup mode. (Scott Lamb has experience in this area.) 8. A C++ cancellation event need not map to any POSIX C cancellation construct; any attempt to cancel a thread in a C++ program must be routed to code with the semantics we choose, independently of whatever the C runtime would try to impose. If it's useful to initiate a C cancellation, at some point in the process (perhaps at the end, after stack unwinding) we might do so. I'll stop here. Combining Wil's suggestion and mine (in which most system calls are made to fail) seems to me to solve most of the problem. What seems to remain is breaking out of long-running computations that perform no system calls. Adding a distinguished signal (which handler, like any signal handler, would not be allowed to throw) might help there. Nathan Myers ncm at codesourcery.com ncm at cantrip.org From pdimov at mmltd.net Sun Jul 17 23:15:35 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Mon, 18 Jul 2005 02:15:35 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> Message-ID: <000c01c58b25$79d3c660$6501a8c0@pdimov2> Nathan Myers wrote: > 2. Existing thread-safe and exception-safe C and C++ libraries that do > *not* take cancellation into account should still work. Even when cancelled? > (This implies > that C library calls, including system calls, never throw, by default > or during normal operation; likewise for C++ destructors, and C++ > functions with any throw specification.) [...] > 7. We may assume we can hijack/shadow standard system and library > calls and add our own semantics, such as causing them to report > failure (perhaps with distinguished ERRNO codes) under circumstances > where they would otherwise have succeeded, or (under C cancellation) > entered some sort of cleanup mode. (Scott Lamb has experience in this > area.) I don't see how this is going to work. Consider a pure C program that calls a cancellation point, 'fwrite' for instance. fwrite "throws" - unwinds the stack and calls Posix cleanup handlers. Now consider a pure C++ program that calls that same 'fwrite'. It doesn't throw, it signals failure. But what does fwrite do in a mixed C/C++ program? "Throw" when called from C code and return failure when called from the C++ part? What if a C function calls fwrite and is itself called by C++ code? No matter what fwrite does, it will break the C part or the C++ part, or maybe both. From terekhov at web.de Mon Jul 18 00:20:10 2005 From: terekhov at web.de (Alexander Terekhov) Date: Mon, 18 Jul 2005 02:20:10 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> Message-ID: <42DAF5BA.21BE0DCB@web.de> Wil Evers wrote: [...] > { > cancellation_manager enabler(true); > some_cancellation_point(); > } Never do that in "library" code. http://www.opengroup.org/onlinepubs/009695399/functions/pthread_setcancelstate.html RATIONALE The pthread_setcancelstate() and pthread_setcanceltype() functions control the points at which a thread may be asynchronously canceled. For cancellation control to be usable in modular fashion, some rules need to be followed. An object can be considered to be a generalization of a procedure. It is a set of procedures and global variables written as a unit and called by clients not known by the object. Objects may depend on other objects. First, cancelability should only be disabled on entry to an object, never explicitly enabled. On exit from an object, the cancelability state should always be restored to its value on entry to the object. This follows from a modularity argument: if the client of an object (or the client of an object that uses that object) has disabled cancelability, it is because the client does not want to be concerned about cleaning up if the thread is canceled while executing some sequence of actions. If an object is called in such a state and it enables cancelability and a cancellation request is pending for that thread, then the thread is canceled, contrary to the wish of the client that disabled. Second, the cancelability type may be explicitly set to either deferred or asynchronous upon entry to an object. But as with the cancelability state, on exit from an object the cancelability type should always be restored to its value on entry to the object. regards, alexander. P.S. http://groups.google.de/group/comp.lang.c++.moderated/msg/c897f898de7a97cd From gdr at integrable-solutions.net Sun Jul 17 23:52:26 2005 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 18 Jul 2005 01:52:26 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <20050717223748.GA4125@tofu.dreamhost.com> References: <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> Message-ID: Nathan Myers writes: [...] | 7. We may assume we can hijack/shadow standard system and library | calls and add our own semantics, such as causing them to report Similar experiment has been tried in a previous version of Standard C++. It led to complete disaster, installing non-portability as the de facto norm as far as inherited C-headers are concerned, in both the and form. I don't think it is an option we can contemplate. -- Gaby From ncm at cantrip.org Mon Jul 18 00:07:39 2005 From: ncm at cantrip.org (Nathan Myers) Date: Sun, 17 Jul 2005 17:07:39 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: References: <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> Message-ID: <20050718000739.GB4125@tofu.dreamhost.com> On Mon, Jul 18, 2005 at 01:52:26AM +0200, Gabriel Dos Reis wrote: > Nathan Myers writes: > > [...] > > | 7. We may assume we can hijack/shadow standard system and library > | calls and add our own semantics, such as causing them to report > > Similar experiment has been tried in a previous version of Standard > C++. It led to complete disaster, installing non-portability as the > de facto norm as far as inherited C-headers are concerned, in both the > and form. I don't think it is an option we can > contemplate. This is the opposite of that case: no changes to the header files is contemplated; instead, just a different binding of dynamic link entry points, as occurs routinely whenever (e.g.) you upgrade your libc. Nathan Myers ncm at codesourcery.com ncm at cantrip.org From ncm at cantrip.org Mon Jul 18 03:31:22 2005 From: ncm at cantrip.org (Nathan Myers) Date: Sun, 17 Jul 2005 20:31:22 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <000c01c58b25$79d3c660$6501a8c0@pdimov2> References: <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> Message-ID: <20050718033122.GC4125@tofu.dreamhost.com> On Mon, Jul 18, 2005 at 02:15:35AM +0300, Peter Dimov wrote: > Nathan Myers wrote: > > >2. Existing thread-safe and exception-safe C and C++ libraries that do > >*not* take cancellation into account should still work. > > Even when cancelled? Of course. Otherwise what's the point? > >(This implies > >that C library calls, including system calls, never throw, by default > >or during normal operation; likewise for C++ destructors, and C++ > >functions with any throw specification.) > > [...] > > >7. We may assume we can hijack/shadow standard system and library > >calls and add our own semantics, such as causing them to report > >failure (perhaps with distinguished ERRNO codes) under circumstances > >where they would otherwise have succeeded, or (under C cancellation) > >entered some sort of cleanup mode. (Scott Lamb has experience in this > >area.) > > I don't see how this is going to work. > > Consider a pure C program that calls a cancellation point, 'fwrite' for > instance. fwrite "throws" - unwinds the stack and calls Posix cleanup > handlers. > > Now consider a pure C++ program that calls that same 'fwrite'. It doesn't > throw, it signals failure. > > But what does fwrite do in a mixed C/C++ program? "Throw" when called > from C code and return failure when called from the C++ part? What if > a C function calls fwrite and is itself called by C++ code? No matter > what fwrite does, it will break the C part or the C++ part, or maybe > both. A program has either a C++ main() or a C main(). It never has both. If main() is C, we have nothing to say about it: POSiX defines cancellation for C programs. If main() is C++, that's what this list is about. If you're calling a C-cancellation-safe library from C++, you might choose to call it from within one of Wil's cancellation contexts, using a mode that matches POSiX C cancellation semantics. Regardless, correct code checks for fwrite() failure -- which can happen anyway, cancellation or no -- and deals with it. A library function that consistently fails to satisfy its post-conditions must eventually return to the C++ context that called it, reporting failure. That C++ code, likewise, will fail to secure its own postconditions, and also report failure, perhaps by exception. Whether the exception it throws is a cancellation exception or some other doesn't really matter much. What does matter is that control does ultimately return to the thread main, which we may presume to understand cancellation, and to die cleanly. Is it possible to write code that doesn't behave well? Yes, always; nobody has ever tried to do prevent that, and I don't propose to change the policy. However, it is possible, and universally encouraged, to write code that *does* behave well. There's lots of it, and we can provide support for that code. For the rest, nothing we do can save it under any circumstances, so there's no point in talking about it. Nathan Myers ncm at codesourcery.com ncm at cantrip.org From terekhov at web.de Mon Jul 18 08:57:30 2005 From: terekhov at web.de (Alexander Terekhov) Date: Mon, 18 Jul 2005 10:57:30 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> Message-ID: <42DB6EFA.173AB035@web.de> Nathan Myers wrote: > > On Mon, Jul 18, 2005 at 02:15:35AM +0300, Peter Dimov wrote: > > Nathan Myers wrote: > > > > >2. Existing thread-safe and exception-safe C and C++ libraries that do > > >*not* take cancellation into account should still work. > > > > Even when cancelled? > > Of course. Otherwise what's the point? [... ECANCELED ...] That's impossible. At best, existing cancel-unaware "thread-safe" C++ library will throw "internal errors" from its ctors and simply swallow (if not abort() due to unexpected error) cancel requests that happen to hit its dtors (undesirable delivery at really-no- cancel points/regions with or without silly stickiness aside for a moment). You're trying to solve unsolvable. Cancel-unaware code is simply meant to be run with cancellation disabled. regards, alexander. From ncm at cantrip.org Mon Jul 18 09:18:10 2005 From: ncm at cantrip.org (Nathan Myers) Date: Mon, 18 Jul 2005 02:18:10 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DB6EFA.173AB035@web.de> References: <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <42DB6EFA.173AB035@web.de> Message-ID: <20050718091810.GD4125@tofu.dreamhost.com> On Mon, Jul 18, 2005 at 10:57:30AM +0200, Alexander Terekhov wrote: > > Nathan Myers wrote: > > > > On Mon, Jul 18, 2005 at 02:15:35AM +0300, Peter Dimov wrote: > > > Nathan Myers wrote: > > > > > > >2. Existing thread-safe and exception-safe C and C++ libraries > > > >that do *not* take cancellation into account should still work. > > > > > > Even when cancelled? > > > > Of course. Otherwise what's the point? [... ECANCELED ...] > > That's impossible. Alexander, please pay attention. If, per Wil's proposal, any response to cancellation whatsoever is disabled by default, then absent specific action by the user *all* code will execute exactly as if no cancellation happened. If users add a degree of responsiveness to certain regions of code (anything between "certain system calls report failure" on up to "pretend this is POSiX C and hope for the best"), a wide variety of existing libraries may be accommodated safely. Yes, thread termination might be delayed -- maybe even indefinitely -- but that's safe. Users who need more responsiveness will know what to do. Nathan Myers ncm at cantrip.org ncm at codesourcery.com From terekhov at web.de Mon Jul 18 09:45:43 2005 From: terekhov at web.de (Alexander Terekhov) Date: Mon, 18 Jul 2005 11:45:43 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <42DB6EFA.173AB035@web.de> <20050718091810.GD4125@tofu.dreamhost.com> Message-ID: <42DB7A47.A972F843@web.de> Nathan Myers wrote: [...] > Alexander, please pay attention. If, per Wil's proposal, any response > to cancellation whatsoever is disabled by default, then absent specific > action by the user *all* code will execute exactly as if no > cancellation happened. If users add a degree of responsiveness to > certain regions of code Don't know what you mean with "users", but "libraries" are not supposed to enable cancellation (apart from hypothetical stuff reasserting cancel request on cancel unwinding path to avoid lengthy and unneeded parts of compound "cleanup" operations followed by catch-and-swallow that I've showed), only disable it. The rest of Wil's proposal boils down to rather obvios use of http://www.google.com/search?q=cancel_off_guard and that's nothing new and/or particularly exiting. The discussion here has been going in circles for years, unfortunately. regards, alexander. From pdimov at mmltd.net Mon Jul 18 11:50:01 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Mon, 18 Jul 2005 14:50:01 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> Message-ID: <003801c58b8e$d66dbca0$6501a8c0@pdimov2> Nathan Myers wrote: > On Mon, Jul 18, 2005 at 02:15:35AM +0300, Peter Dimov wrote: >> Nathan Myers wrote: >> >>> 2. Existing thread-safe and exception-safe C and C++ libraries that >>> do *not* take cancellation into account should still work. >> >> Even when cancelled? > > Of course. Otherwise what's the point? I just wanted to highlight that this is a more ambitious goal than the rest. Code that was never supposed to be cancel-safe and has never been tested under such circumstances is dragged kicking and screaming into the new millenium. This comes at a cost. First, the behavior of the standard C library (and the various Posix functions) changes depending on whether 'main' is C++. As a consequence, the behavior of C libraries changes when called from C++, so their test suites that call them from C (and cancel them from C) now don't test their C++ behavior. Second, new C++ code is forced to use an outdated (and rejected) model. The natural way to signal cancellation is with an exception, not an error code and a multitude of ifs. The exception model has obviously been considered superior by the Posix folks, so superior that they even defined their own EH mechanism in the C binding. Third, you seem to propose a further deviation from Posix, starting the thread in "cancellation disabled" mode. All this in an attempt to make existing cancellation-unaware C++ code cancellation-safe. Making C functions not throw under C++ and throw under C is almost surreal. I can follow your trail of arguments in its entirety, but the end result is still hard to swallow. The language that supports exceptions doesn't use them and vice versa. From baker at cs.fsu.edu Mon Jul 18 12:27:11 2005 From: baker at cs.fsu.edu (Ted Baker) Date: Mon, 18 Jul 2005 08:27:11 -0400 Subject: [SPAM] - [c++-pthreads] Re: pthread_cancel and EH: let's try this again - Email found in subject In-Reply-To: References: Message-ID: <20050718122711.GC29627@cs.fsu.edu> I've been reading this thread from the beginning, and holding back from commenting because my views on this subject are likely to be dismissed as biased by my Ada background. However, among this discussion (as in the last incarnation) is not converging very well. I have observed a few points in the discussion that are consistent with my experience and may deserve repeating. Both thread cancellation (POSIX style) and what I'll loosely call "asynchronous" exceptions (whether raised in a truly asynchronous manner or by polling for a flag that can be set by an asynchronous event) may be seductive intellectually, but they are a nightmare when it comes to both implementation and to use in any application where reliability and efficiency matter. Ada is now stuck with them. I think C programmers should refrain from using thread cancellation, and C++ would be better off not opening this Pandora's box. (I speak as a convert. I was one of the strongest proponents of adding asynchronous task abort to the Ada 95 language, and it is probably true that if I had opposed it then this feature might not have been part of the language.) In particular, I would recommend that you simply specify that the uses of thread cancellation and C++ are incompatible. If you want to use C++ you don't use thread cancellation. This could be enforced fairly simply with cooperation from the implementors of the C thread libraries. Given all the discussions up to this point, I don't think you can honestly expect to define a solution that will deliver thread cancellation in form that can be used by C++ programmers without some nasty surprises. Responsibility for exposing the world to these new hazards will be a burden you will have to live with for the rest of your life. If you insist on having thread cancellation and/or asynchronous exceptions in C++, you must be prepared to give up one one or more of the design goals that have been expressed in this discussion. At worst, you will end up compromising on *every* goal. It would be better to focus on ranking what you are willing to give up in order to have this feature, and then pick a solution that compromises least on the goals that matter most to you. If you have thread cancellation or asynchronous exceptions, you need to guarantee that they do not interrupt at least certain blocks of code, which must be run to completion in order to preserve critical invariants (both in the runtime system and application). The best way to do this is to make protection the default, i.e., implement cancellation or async. exceptions by polling code that is inserted by the compiler and/or runtime system, and further have an application-settable flag that can enable/suppress the polling effect where desired. This seems to have been the prevailing thinking behind POSIX thread cancellation. C++ destructors are examples of blocks of code that should by default not be interruptible by asynchronous exceptions, and which one should normally be able to assume will never throw (or propagate) an exception. Anything less leads to chaos. (The more you think about it, the more things you will decide ought to be atomic with respect to thread cancellation/async. exceptions, and the more you will wonder whether they are such a good thing.) Library routines written in C may "throw" cancellation. This is a big deal, since before you added thread cancellation or async. exceptions there was no way C-language code could throw an exception. (Of course it could call some C++ code that throws an exception, but that is unlikely, and is fairly easy to avoid or narrowly constrain by programming practice. It is routine, normal and practically necessary for C++ code to be able make use of C libraries.) This is not purely a problem created by making thread cancellation into an exception. If you had cancellation at all, you already had the problem that some C code you call may call a function includes a thread cancellation point. However, if you used thread cancellation with C++ code that expects C++ cleanup on stack unwinding you knew you were operating outside the safe confines of well defined behavior. The new problem with legitimizing this as a proper C++ exception is that people will now think it is OK to use thread cancellation with C++, and they will expect that normal C++ cleanup mechanisms (including destructors) will work correctly with thread cancellation. I don't think you can deliver a safe solution, with acceptable overhead and comprehensible to ordinary programmers. So, wouldn't it be more responsible to declare this combination as unsafe, and let this discussion die? --Ted ... > > | I disagree; one of the problems with mapping cancellation requests to > > | C++ exceptions is that certain system calls that did not throw before > > | are changed into functions that do, and that existing (destructor or > > | non-destructor) code won't always be able to deal with that. > > > > If the function (or destructor) has a throw() specification, it will > > continue not to throw. > > Yeah, but at what cost? Termination does not seem like a very > desirable response to a cancellation request that happens to occur > before a 'C' library call that ordinarily wouldn't throw. > > > If it did not have that annotation then it was assumed to throw. > > By the compiler, maybe, but not to programmers in general. Few > programmers habitually use throw() on their destructors, but nearly > everybody who has learned to write exception-safe code assumes that no > destructor throws unless otherwise specified. From dave at boost-consulting.com Mon Jul 18 13:33:33 2005 From: dave at boost-consulting.com (David Abrahams) Date: Mon, 18 Jul 2005 09:33:33 -0400 Subject: [SPAM] - [c++-pthreads] Re: pthread_cancel and EH: let's try this again - Email found in subject References: <20050718122711.GC29627@cs.fsu.edu> Message-ID: Ted Baker writes: > Both thread cancellation (POSIX style) and what I'll loosely call > "asynchronous" exceptions (whether raised in a truly asynchronous > manner or by polling for a flag that can be set by an asynchronous > event) Please choose different terminology. When most of us speak of "asynchronous" exceptions we're talking about those that can be thrown from anywhere, including from expressions that are ordinarily not supposed to throw. Exceptions raised by polling are not asynchronous by that definition, unless of course the function doing the polling and throwing lies and claims it doesn't throw. -- Dave Abrahams Boost Consulting www.boost-consulting.com From pdimov at mmltd.net Mon Jul 18 13:48:43 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Mon, 18 Jul 2005 16:48:43 +0300 Subject: [c++-pthreads] pthread_cancel and EH: let's try this again References: <20050718122711.GC29627@cs.fsu.edu> Message-ID: <001201c58b9f$6afa59e0$6501a8c0@pdimov2> Ted Baker wrote: > I don't think you can deliver a safe solution, with acceptable > overhead and comprehensible to ordinary programmers. So, wouldn't > it be more responsible to declare this combination as unsafe, > and let this discussion die? That's even more surreal. C, a language that has no exceptions and no concept of exception safety, enables programmers to use thread cancellation via a mechanism that is (admittedly) lifted from C++... ... but C++, a language with exceptions and almost a decade of experience in exception safety declares cancellation unsafe and actively prohibits its use? Responsible? From baker at cs.fsu.edu Mon Jul 18 15:31:35 2005 From: baker at cs.fsu.edu (Ted Baker) Date: Mon, 18 Jul 2005 11:31:35 -0400 Subject: [SPAM] - Re: [c++-pthreads] pthread_cancel and EH: let's try this again - Email found in subject In-Reply-To: <001201c58b9f$6afa59e0$6501a8c0@pdimov2> References: <20050718122711.GC29627@cs.fsu.edu> <001201c58b9f$6afa59e0$6501a8c0@pdimov2> Message-ID: <20050718153135.GA2645@cs.fsu.edu> On Mon, Jul 18, 2005 at 04:48:43PM +0300, Peter Dimov wrote: > That's even more surreal. > > C, a language that has no exceptions and no concept of exception safety, > enables programmers to use thread cancellation ... But being able to do do something is not the same as being able to do something safely. > ... via a mechanism that is (admittedly) lifted from C++... I don't know where you got that idea. AFIK the mechanism predateds C++. > ... but C++, a language with exceptions and almost a decade of experience > in exception safety declares cancellation unsafe and actively prohibits its > use? Yes, because it is unsafe, and C++ wants to be safer than C. > Responsible? Yes, this is the only responsible thing. In C, thread cancellation is difficult to use correctly, and usage is easily broken when one composes a system out of modules/libraries written by different individuals (possibly without access to sources). --Ted From pdimov at mmltd.net Mon Jul 18 15:53:23 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Mon, 18 Jul 2005 18:53:23 +0300 Subject: [c++-pthreads] pthread_cancel and EH: let's try this again References: <20050718122711.GC29627@cs.fsu.edu> <001201c58b9f$6afa59e0$6501a8c0@pdimov2> <20050718153135.GA2645@cs.fsu.edu> Message-ID: <019001c58bb0$d5c723f0$6701a8c0@pdimov> Ted Baker wrote: > On Mon, Jul 18, 2005 at 04:48:43PM +0300, Peter Dimov wrote: >> ... but C++, a language with exceptions and almost a decade of >> experience in exception safety declares cancellation unsafe and >> actively prohibits its use? > > Yes, because it is unsafe, and C++ wants to be safer than C. I'm not sure I follow. In what way is a cancellation exception less safe than any other exception? From baker at cs.fsu.edu Mon Jul 18 15:56:51 2005 From: baker at cs.fsu.edu (Ted Baker) Date: Mon, 18 Jul 2005 11:56:51 -0400 Subject: [SPAM] - [c++-pthreads] Re: [SPAM] - [c++-pthreads] Re: pthread_cancel and EH: let's try this again - Email found in subject - Email found in subject In-Reply-To: References: Message-ID: <20050718155651.GB2645@cs.fsu.edu> On Mon, Jul 18, 2005 at 09:33:33AM -0400, David Abrahams wrote: > ... supposed to throw. Exceptions raised by polling are not asynchronous > by that definition, unless of course the function doing the polling > and throwing lies and claims it doesn't throw. Exactly! If the polling can occur at unknown points, including C-language functions in a chain of library calls below your level of visibility, then the effect can be indistinguishable. --Ted From terekhov at web.de Mon Jul 18 16:07:37 2005 From: terekhov at web.de (Alexander Terekhov) Date: Mon, 18 Jul 2005 18:07:37 +0200 Subject: [SPAM] - Re: [c++-pthreads] pthread_cancel and EH: let's try this again - Email found in subject References: <20050718122711.GC29627@cs.fsu.edu> <001201c58b9f$6afa59e0$6501a8c0@pdimov2> <20050718153135.GA2645@cs.fsu.edu> Message-ID: <42DBD3C9.7A8A1196@web.de> Ted Baker wrote: > > On Mon, Jul 18, 2005 at 04:48:43PM +0300, Peter Dimov wrote: > > That's even more surreal. > > > > C, a language that has no exceptions and no concept of exception safety, > > enables programmers to use thread cancellation ... > > But being able to do do something is not the same as being > able to do something safely. > > > ... via a mechanism that is (admittedly) lifted from C++... > > I don't know where you got that idea. AFIK the mechanism predateds C++. Right. Modula 2+ predates ARM C++. ;-) http://gatekeeper.dec.com/pub/DEC/SRC/research-reports/SRC-020.pdf (*alert*) http://foldoc.doc.ic.ac.uk/foldoc/foldoc.cgi?Modula-2%2B Modula-2 plus exceptions and threads developed by P. Rovner et al of DEC SRC, Palo Alto CA in 1984. regards, alexander. From dave at boost-consulting.com Mon Jul 18 16:36:24 2005 From: dave at boost-consulting.com (David Abrahams) Date: Mon, 18 Jul 2005 12:36:24 -0400 Subject: [SPAM] - [c++-pthreads] Re: [SPAM] - [c++-pthreads] Re: pthread_cancel and EH: let's try this again - Email found in subject - Email found in subject References: <20050718155651.GB2645@cs.fsu.edu> Message-ID: Ted Baker writes: > On Mon, Jul 18, 2005 at 09:33:33AM -0400, David Abrahams wrote: >> ... supposed to throw. Exceptions raised by polling are not asynchronous >> by that definition, unless of course the function doing the polling >> and throwing lies and claims it doesn't throw. > > Exactly! If the polling can occur at unknown points, including > C-language functions in a chain of library calls below your > level of visibility, then the effect can be indistinguishable. That's a big "if." You can't lump all flag-polling schemes into the "asynchronous" bucket just because some do fall there. I'm asking you to be precise and make the distinction, because whether flag-polling will be effectively asynchronous for some classes of C++ programs is one of the points we're trying to decide. -- Dave Abrahams Boost Consulting www.boost-consulting.com From baker at cs.fsu.edu Mon Jul 18 16:56:47 2005 From: baker at cs.fsu.edu (Ted Baker) Date: Mon, 18 Jul 2005 12:56:47 -0400 Subject: [SPAM] - Re: [c++-pthreads] pthread_cancel and EH: let's try this again - Email found in subject In-Reply-To: <019001c58bb0$d5c723f0$6701a8c0@pdimov> References: <20050718122711.GC29627@cs.fsu.edu> <001201c58b9f$6afa59e0$6501a8c0@pdimov2> <20050718153135.GA2645@cs.fsu.edu> <019001c58bb0$d5c723f0$6701a8c0@pdimov> Message-ID: <20050718165647.GA3289@cs.fsu.edu> On Mon, Jul 18, 2005 at 06:53:23PM +0300, Peter Dimov wrote: > >Yes, because it is unsafe, and C++ wants to be safer than C. > > I'm not sure I follow. In what way is a cancellation exception less safe > than any other exception? In this context, I was thinking of the problem of not knowing when and where such an exception might be thrown. As others have pointed out, when you are calling a library function written in C (whether part of the standard C library or some other library) you don't know whether it will call something that qualifies as a thread cancellation point. This is a problem with C, already, and wrapping it in C++ does not make the problem go away. I was also thinking of some of the baroque semantic proposals I've seen on this e-mail thread, and the difficulty of getting every programmer to understand these rules sufficiently well to avoid making errors in usage (especially when those errors are unlikely to show up in testing). If people in this group are having trouble understanding each other's proposals, what about the "clones" who write most of the world's code? --Ted BTW, I can't resist the temptation to make the following peripheral comments, which I hope will not distract from the above. 1) If providing access in C++ to everything one can do in C is so important, why not provide access to the full C signal handling model? 2) Are exceptions safe, in general? In the Ada world, I recall some people interested in safety certification ruled out the use of exceptions entirely. The core of their arguments that I remember had to do with: (1) formal verification; (2) test coverage analysis. I believe the problem with formal verification had to do with the proliferation of control paths. Simple syntax-directed proof methods, like the classic Hoare precondition-postcondition assertion rules, rely on having a fixed and known set of "come from" points for each point for which an assertion is to be proven. Exceptional control flow complicates this greatly. I believe the problem with test coverage analysis is also with the proliferation of control paths, but goes a bit further. Some forms of certification require that all instructions, branches, or paths be demonstrated to have been executed in testing. It is very difficult to generate tests that will force execution of all exception handlers, much less all paths that may lead through an exception handler. While I am not arguing for removing exceptions from any language, my experience as a professor has supported a degree of skepticism about the ability of most people to write and maintain correct code that makes use of exceptions. I have seen many errors, usually involving unwarranted assumptions inside an exception handler about where the exception originated and the state of variables at the point the handler got control. I have also seen correct exception handling code broken, by adding new points from which an exception can be thrown, or by the addition of a new handler (catch) that intercepts an exception before it reaches the old handler. Of course, there are some simple patterns of usage that are safe and very useful. In this regard, there is a strong analogy between exceptions today and "gotos" before the advent of structured programming constructs. From pdimov at mmltd.net Mon Jul 18 17:17:29 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Mon, 18 Jul 2005 20:17:29 +0300 Subject: [c++-pthreads] pthread_cancel and EH: let's try this again References: <20050718122711.GC29627@cs.fsu.edu> <001201c58b9f$6afa59e0$6501a8c0@pdimov2> <20050718153135.GA2645@cs.fsu.edu> <019001c58bb0$d5c723f0$6701a8c0@pdimov> <20050718165647.GA3289@cs.fsu.edu> Message-ID: <01ed01c58bbc$99c23000$6701a8c0@pdimov> Ted Baker wrote: > On Mon, Jul 18, 2005 at 06:53:23PM +0300, Peter Dimov wrote: >>> Yes, because it is unsafe, and C++ wants to be safer than C. >> >> I'm not sure I follow. In what way is a cancellation exception less >> safe than any other exception? > > In this context, I was thinking of the problem of not knowing when > and where such an exception might be thrown. As others have > pointed out, when you are calling a library function written > in C (whether part of the standard C library or some other library) > you don't know whether it will call something that qualifies as > a thread cancellation point. This is a problem with C, already, > and wrapping it in C++ does not make the problem go away. In other words, the answer is a qualified "none". When you are calling a function written in C++ you don't know whether it will throw unless this is documented. It is true that so far we've been able to assume that a function written in C doesn't throw when thread cancellation is not in use. But we'll still be able to assume that. > I was also thinking of some of the baroque semantic proposals I've > seen on this e-mail thread, ... Well, if a cancellation exception is given semantics that make it different from any other exception, it can be less safe, I agree. If it isn't, it won't. > 2) Are exceptions safe, in general? We've spent the last decade in learning how to use them safely. It doesn't make sense to discard this knowledge. When 'new' was changed to throw this broke millions of lines of code, and C++ survived the transition. The introduction of cancellation points - even into the C part of the standard library - is almost a non-event compared to that. From gdr at integrable-solutions.net Mon Jul 18 20:38:30 2005 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 18 Jul 2005 22:38:30 +0200 Subject: [c++-pthreads] pthread_cancel and EH: let's try this again In-Reply-To: <01ed01c58bbc$99c23000$6701a8c0@pdimov> References: <20050718122711.GC29627@cs.fsu.edu> <001201c58b9f$6afa59e0$6501a8c0@pdimov2> <20050718153135.GA2645@cs.fsu.edu> <019001c58bb0$d5c723f0$6701a8c0@pdimov> <20050718165647.GA3289@cs.fsu.edu> <01ed01c58bbc$99c23000$6701a8c0@pdimov> Message-ID: "Peter Dimov" writes: [...] | > 2) Are exceptions safe, in general? | | We've spent the last decade in learning how to use them safely. It | doesn't make sense to discard this knowledge. Indeed, we don't need to prove them safe in general. We only need to know how to use them safely in appropriate circumstances. Just like, say pointers. I hope we won't be distracted too much :-) -- Gaby From baker at cs.fsu.edu Mon Jul 18 20:57:09 2005 From: baker at cs.fsu.edu (Ted Baker) Date: Mon, 18 Jul 2005 16:57:09 -0400 Subject: [SPAM] - Re: [c++-pthreads] pthread_cancel and EH: let's try this again - Email found in subject In-Reply-To: References: <01ed01c58bbc$99c23000$6701a8c0@pdimov> Message-ID: <20050718205709.GA7285@cs.fsu.edu> On Mon, Jul 18, 2005 at 10:38:30PM +0200, Gabriel Dos Reis wrote: > "Peter Dimov" writes: > > > [...] > > | > 2) Are exceptions safe, in general? > | > | We've spent the last decade in learning how to use them safely. It > | doesn't make sense to discard this knowledge. > > Indeed, we don't need to prove them safe in general. We only need to > know how to use them safely in appropriate circumstances. Just like, > say pointers. Thanks for the more up-to-date analogy. :) My analogy was "gotos", for which the safe pattern eventually made their way into standard control structures. In Java, an attempt was made to do something similar for pointers, like it or not. Maybe it is time for a language to look at exceptions along the same lines, i.e., to build in structures for exceptions that rule out the most frequent forms of erroneous usage. --Ted From gdr at integrable-solutions.net Mon Jul 18 21:12:44 2005 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 18 Jul 2005 23:12:44 +0200 Subject: [SPAM] - Re: [c++-pthreads] pthread_cancel and EH: let's try this again - Email found in subject In-Reply-To: <20050718205709.GA7285@cs.fsu.edu> References: <01ed01c58bbc$99c23000$6701a8c0@pdimov> <20050718205709.GA7285@cs.fsu.edu> Message-ID: Ted Baker writes: | On Mon, Jul 18, 2005 at 10:38:30PM +0200, Gabriel Dos Reis wrote: | > "Peter Dimov" writes: | > | > | > [...] | > | > | > 2) Are exceptions safe, in general? | > | | > | We've spent the last decade in learning how to use them safely. It | > | doesn't make sense to discard this knowledge. | > | > Indeed, we don't need to prove them safe in general. We only need to | > know how to use them safely in appropriate circumstances. Just like, | > say pointers. | | Thanks for the more up-to-date analogy. :) | | My analogy was "gotos", for which the safe pattern | eventually made their way into standard control structures. | | In Java, an attempt was made to do something similar for pointers, | like it or not. I would guess the natural question is whether it succeeded. I would not bet money, when I encounter things NullPointerException where I have been told there is no pointer. But, I guess we're getting deeper into distractions :-) | Maybe it is time for a language to look at exceptions along the | same lines, i.e., to build in structures for exceptions that rule | out the most frequent forms of erroneous usage. yeah, I doubt it would be C++ ;-p -- Gaby From baker at cs.fsu.edu Mon Jul 18 21:25:50 2005 From: baker at cs.fsu.edu (Ted Baker) Date: Mon, 18 Jul 2005 17:25:50 -0400 Subject: [c++-pthreads] Re: [SPAM] - Re: [c++-pthreads] pthread_cancel and EH: let's try this again - Email found in subject In-Reply-To: <20050718205709.GA7285@cs.fsu.edu> References: <01ed01c58bbc$99c23000$6701a8c0@pdimov> <20050718205709.GA7285@cs.fsu.edu> Message-ID: <20050718212550.GA7608@cs.fsu.edu> > My analogy was "gotos", for which the safe pattern > eventually made their way into standard control structures. > > In Java, an attempt was made to do something similar for pointers, > like it or not. > > Maybe it is time for a language to look at exceptions along the > same lines, i.e., to build in structures for exceptions that rule > out the most frequent forms of erroneous usage. I forgot another analogy. Several languages, including Concurrent Pascal and Ada, have built in monitor-like structures that enforce safe patterns for concurrent programming that can prevent the most common errors one makes when using low-level synchronization primitives like POSIX mutexes and condition variables, such as forgetting to release a lock, trying to seize a lock that one already holds, trying to sleep on a condition without holding the lock, waking up without rechecking the logical condition associated with the sleep, etc. Apologies for harping on the same chord. My point is still that (raw) exceptions are not a simple feature to use correctly, generally tend to get programmers in trouble, and don't need any "help" that will encourage people to try to use them for more unsafe things. The idea of thread cancellation is very simple and very appealing, so programmers to are told about it will seize on it as a panacea. I've seen this among students in the courses where I teach programming with threads (using C). Such naive programmers will write a program using threads, and then try to shut a thread or threads down by just cancelling them. They do not fully understand the ramifications of the thread cancellation model, use whatever libraries are at hand, and do not design from the beginning with cancellation in mind. As a result, they run into trouble, such as lockups due to cancellation or threads that are holding mutexes on which another thread is depending for a pthread_cond_signal to wake up. --Ted From dave at boost-consulting.com Mon Jul 18 21:34:05 2005 From: dave at boost-consulting.com (David Abrahams) Date: Mon, 18 Jul 2005 17:34:05 -0400 Subject: [SPAM] - Re: [c++-pthreads] pthread_cancel and EH: let's try this again - Email found in subject References: <01ed01c58bbc$99c23000$6701a8c0@pdimov> <20050718205709.GA7285@cs.fsu.edu> Message-ID: Ted Baker writes: > Maybe it is time for a language to look at exceptions along the > same lines, i.e., to build in structures for exceptions that rule > out the most frequent forms of erroneous usage. The most frequent forms of erroneous usage are the same ones that crop up with other error reporting mechanisms. In other words, writing exception safe code isn't hard -- writing code that's correct in the face of "errors" (postcondition failures, really) is hard. -- Dave Abrahams Boost Consulting www.boost-consulting.com From wil at bogo.xs4all.nl Mon Jul 18 21:55:38 2005 From: wil at bogo.xs4all.nl (Wil Evers) Date: Mon, 18 Jul 2005 23:55:38 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DAF5BA.21BE0DCB@web.de> References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <42DAF5BA.21BE0DCB@web.de> Message-ID: <42DC255A.7080609@bogo.xs4all.nl> Alexander Terekhov wrote: > Wil Evers wrote: > [...] > >> { >> cancellation_manager enabler(true); >> some_cancellation_point(); >> } > > > Never do that in "library" code. > > http://www.opengroup.org/onlinepubs/009695399/functions/pthread_setcancelstate.html That's great advice. This should work too: X::~X() { try { cancellation_manager enabler(true); some_blocking_operation(); } catch (const cancellation & ex) { // log ex // don't rethrow } } - Wil From ncm at cantrip.org Mon Jul 18 22:10:07 2005 From: ncm at cantrip.org (Nathan Myers) Date: Mon, 18 Jul 2005 15:10:07 -0700 Subject: [c++-pthreads] pthread_cancel and EH: let's try this again In-Reply-To: <01ed01c58bbc$99c23000$6701a8c0@pdimov> References: <20050718122711.GC29627@cs.fsu.edu> <001201c58b9f$6afa59e0$6501a8c0@pdimov2> <20050718153135.GA2645@cs.fsu.edu> <019001c58bb0$d5c723f0$6701a8c0@pdimov> <20050718165647.GA3289@cs.fsu.edu> <01ed01c58bbc$99c23000$6701a8c0@pdimov> Message-ID: <20050718221007.GB21905@tofu.dreamhost.com> On Mon, Jul 18, 2005 at 08:17:29PM +0300, Peter Dimov wrote: > Ted Baker wrote: > >On Mon, Jul 18, 2005 at 06:53:23PM +0300, Peter Dimov wrote: > >>I'm not sure I follow. In what way is a cancellation exception less > >>safe than any other exception? > > > >In this context, I was thinking of the problem of not knowing when > >and where such an exception might be thrown. As others have > >pointed out, when you are calling a library function written > >in C (whether part of the standard C library or some other library) > >you don't know whether it will call something that qualifies as > >a thread cancellation point. This is a problem with C, already, > >and wrapping it in C++ does not make the problem go away. > > In other words, the answer is a qualified "none". > > When you are calling a function written in C++ you don't know whether it > will throw unless this is documented. To have cancellation exceptions come from C functions breaks all code that was written assuming C functions don't throw: i.e., all existing C++ code that calls C functions. That's rather more than "none". It's possible that lots (not all) of exception-safe C++ code would, as part of being prepared for exceptions from C++ functions called nearby, survive throws from C functions. It doesn't matter: C libraries equipped to exit safely via exception are, for all practical purposes, nonexistent. > It is true that so far we've been able to assume that a function > written in C doesn't throw when thread cancellation is not in use. > But we'll still be able to assume that. Very funny. > >2) Are exceptions safe, in general? > > We've spent the last decade in learning how to use them safely. It > doesn't make sense to discard this knowledge. > > When 'new' was changed to throw this broke millions of lines of code, > and C++ survived the transition. The introduction of cancellation > points - even into the C part of the standard library - is almost a > non-event compared to that. At least four orders of magnitude more C++ code is in production use than when the change to operator new took place. Thread cancellation is far from important enough to consider causing even a little of such breakage. Need cancellation only work accidentally (i.e. not) in threads that rely on libraries? If so, cancellation is not really worth discussing: C++ code that doesn't use libraries might as well be C code. If cancellation is supposed to be useful for any real programs, common libraries must not be broken by it. We know how to do that. We need not be confused by what POSiX has chosen to do to its own private version of C. Nathan Myers ncm at codesourcery.com ncm at cantrip.org From gdr at integrable-solutions.net Mon Jul 18 22:38:01 2005 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 19 Jul 2005 00:38:01 +0200 Subject: [c++-pthreads] pthread_cancel and EH: let's try this again In-Reply-To: <20050718221007.GB21905@tofu.dreamhost.com> References: <20050718122711.GC29627@cs.fsu.edu> <001201c58b9f$6afa59e0$6501a8c0@pdimov2> <20050718153135.GA2645@cs.fsu.edu> <019001c58bb0$d5c723f0$6701a8c0@pdimov> <20050718165647.GA3289@cs.fsu.edu> <01ed01c58bbc$99c23000$6701a8c0@pdimov> <20050718221007.GB21905@tofu.dreamhost.com> Message-ID: Nathan Myers writes: | On Mon, Jul 18, 2005 at 08:17:29PM +0300, Peter Dimov wrote: | > Ted Baker wrote: | > >On Mon, Jul 18, 2005 at 06:53:23PM +0300, Peter Dimov wrote: | > >>I'm not sure I follow. In what way is a cancellation exception less | > >>safe than any other exception? | > > | > >In this context, I was thinking of the problem of not knowing when | > >and where such an exception might be thrown. As others have | > >pointed out, when you are calling a library function written | > >in C (whether part of the standard C library or some other library) | > >you don't know whether it will call something that qualifies as | > >a thread cancellation point. This is a problem with C, already, | > >and wrapping it in C++ does not make the problem go away. | > | > In other words, the answer is a qualified "none". | > | > When you are calling a function written in C++ you don't know whether it | > will throw unless this is documented. | | To have cancellation exceptions come from C functions breaks all code | that was written assuming C functions don't throw: i.e., all existing | C++ code that calls C functions. This is clear exaggeration. -- Gaby From terekhov at web.de Mon Jul 18 22:52:42 2005 From: terekhov at web.de (Alexander Terekhov) Date: Tue, 19 Jul 2005 00:52:42 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <42DAF5BA.21BE0DCB@web.de> <42DC255A.7080609@bogo.xs4all.nl> Message-ID: <42DC32BA.E6480726@web.de> Wil Evers wrote: [...] > > X::~X() > { > try { > cancellation_manager enabler(true); > some_blocking_operation(); > } catch (const cancellation & ex) { > // log ex > // don't rethrow > } > } Nope. It will break X's client logic relying on modularity of X in the sense of its capability to defer cancellation and perform cancelable effects (subject any other failure modes, if any) when cancellation is been disabled by X's client. In verbose form, you probably want this: void some_cancelable_cleanup_operation() throw(X, Y, Z, cancellation); X::~X() throw() { // Unwinding caused by cancellation delivery? if (unwinding(this) && active_exception(0)) { pthread_cancel(pthread_self()); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &errno); try { // "shall occur" (apart from X, Y, Z) cancellation point some_cancelable_cleanup_operation(); } catch(const cancellation &) { // don't rethrow } catch(...) { // X, Y, Z pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &errno); // log ex // don't rethrow } } else { try { some_cancelable_cleanup_operation(); } catch(const cancellation &) { pthread_cancel(pthread_self()); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &errno); // don't rethrow } catch(...) { // X, Y, Z // log ex // don't rethrow } } } regards, alexander. From ncm at cantrip.org Mon Jul 18 23:08:33 2005 From: ncm at cantrip.org (Nathan Myers) Date: Mon, 18 Jul 2005 16:08:33 -0700 Subject: [c++-pthreads] pthread_cancel and EH: let's try this again In-Reply-To: References: <20050718122711.GC29627@cs.fsu.edu> <001201c58b9f$6afa59e0$6501a8c0@pdimov2> <20050718153135.GA2645@cs.fsu.edu> <019001c58bb0$d5c723f0$6701a8c0@pdimov> <20050718165647.GA3289@cs.fsu.edu> <01ed01c58bbc$99c23000$6701a8c0@pdimov> <20050718221007.GB21905@tofu.dreamhost.com> Message-ID: <20050718230833.GD21905@tofu.dreamhost.com> On Tue, Jul 19, 2005 at 12:38:01AM +0200, Gabriel Dos Reis wrote: > Nathan Myers writes: > | > | To have cancellation exceptions come from C functions breaks all code > | that was written assuming C functions don't throw: i.e., all existing > | C++ code that calls C functions. > > This is clear exaggeration. Is there some large body of code written under the assumption that C functions *do* throw C++ exceptions? I don't know of any. You omitted the following paragraph in which I pointed out that it doesn't matter how much of the C++ code is broken by the change. Let's try to stay on topic. Nathan Myers ncm at codesourcery.com ncm at cantrip.org From ncm at cantrip.org Mon Jul 18 23:21:27 2005 From: ncm at cantrip.org (Nathan Myers) Date: Mon, 18 Jul 2005 16:21:27 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DAF5BA.21BE0DCB@web.de> References: <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <42DAF5BA.21BE0DCB@web.de> Message-ID: <20050718232127.GE21905@tofu.dreamhost.com> On Mon, Jul 18, 2005 at 02:20:10AM +0200, Alexander Terekhov wrote: > Wil Evers wrote: > [...] > > { > > cancellation_manager enabler(true); > > some_cancellation_point(); > > } > > Never do that in "library" code. First, it's not in "library code". It's in thread-main. Second, when the default is to have cancellation off, design heurisitics change accordingly. It would be perfectly reasonable to enable (some form of) cancellation, temporarily, inside a library that necessarily must have been called with it turned off. Nathan Myers ncm at codesourcery.com ncm at cantrip.org From terekhov at web.de Mon Jul 18 23:20:38 2005 From: terekhov at web.de (Alexander Terekhov) Date: Tue, 19 Jul 2005 01:20:38 +0200 Subject: pthread_cancel and EH: let's try this again References: <20050718122711.GC29627@cs.fsu.edu> <001201c58b9f$6afa59e0$6501a8c0@pdimov2> <20050718153135.GA2645@cs.fsu.edu> <019001c58bb0$d5c723f0$6701a8c0@pdimov> <20050718165647.GA3289@cs.fsu.edu> <01ed01c58bbc$99c23000$6701a8c0@pdimov> <20050718221007.GB21905@tofu.dreamhost.com> <20050718230833.GD21905@tofu.dreamhost.com> Message-ID: <42DC3946.A0094ADD@web.de> Nathan Myers wrote: > > On Tue, Jul 19, 2005 at 12:38:01AM +0200, Gabriel Dos Reis wrote: > > Nathan Myers writes: > > | > > | To have cancellation exceptions come from C functions breaks all code > > | that was written assuming C functions don't throw: i.e., all existing > > | C++ code that calls C functions. > > > > This is clear exaggeration. > > Is there some large body of code written under the assumption that > C functions *do* throw C++ exceptions? I don't know of any. Contact Hillel Y. Sims. Ok, ok, http://groups.google.com/groups?q=CANCEL_GUARD regards, alexander. From terekhov at web.de Mon Jul 18 23:51:34 2005 From: terekhov at web.de (Alexander Terekhov) Date: Tue, 19 Jul 2005 01:51:34 +0200 Subject: pthread_cancel and EH: let's try this again References: <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <42DAF5BA.21BE0DCB@web.de> <20050718232127.GE21905@tofu.dreamhost.com> Message-ID: <42DC4086.BFCE7DCE@web.de> Nathan Myers wrote: > > On Mon, Jul 18, 2005 at 02:20:10AM +0200, Alexander Terekhov wrote: > > Wil Evers wrote: > > [...] > > > { > > > cancellation_manager enabler(true); > > > some_cancellation_point(); > > > } > > > > Never do that in "library" code. > > First, it's not in "library code". It's in thread-main. new_thread(library_call, arg); Where's "thread-main"? > > Second, when the default is to have cancellation off, design > heurisitics change accordingly. It would be perfectly reasonable > to enable (some form of) cancellation, temporarily, inside a library > that necessarily must have been called with it turned off. And how would you really turn it off (depending on client's need/context), then? regards, alexander. From gdr at integrable-solutions.net Tue Jul 19 01:52:22 2005 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 19 Jul 2005 03:52:22 +0200 Subject: [c++-pthreads] pthread_cancel and EH: let's try this again In-Reply-To: <20050718230833.GD21905@tofu.dreamhost.com> References: <20050718122711.GC29627@cs.fsu.edu> <001201c58b9f$6afa59e0$6501a8c0@pdimov2> <20050718153135.GA2645@cs.fsu.edu> <019001c58bb0$d5c723f0$6701a8c0@pdimov> <20050718165647.GA3289@cs.fsu.edu> <01ed01c58bbc$99c23000$6701a8c0@pdimov> <20050718221007.GB21905@tofu.dreamhost.com> <20050718230833.GD21905@tofu.dreamhost.com> Message-ID: Nathan Myers writes: | On Tue, Jul 19, 2005 at 12:38:01AM +0200, Gabriel Dos Reis wrote: | > Nathan Myers writes: | > | | > | To have cancellation exceptions come from C functions breaks all code | > | that was written assuming C functions don't throw: i.e., all existing | > | C++ code that calls C functions. | > | > This is clear exaggeration. | | Is there some large body of code written under the assumption that | C functions *do* throw C++ exceptions? I don't know of any. That does make your claim match reality. | You omitted the following paragraph in which I pointed out that it | doesn't matter how much of the C++ code is broken by the change. It was irrelevant. | Let's try to stay on topic. Yes, please. -- Gaby From dave at boost-consulting.com Tue Jul 19 02:54:02 2005 From: dave at boost-consulting.com (David Abrahams) Date: Mon, 18 Jul 2005 22:54:02 -0400 Subject: [SPAM] - Re: [c++-pthreads] pthread_cancel and EH: let's try this again - Email found in subject References: <01ed01c58bbc$99c23000$6701a8c0@pdimov> <20050718205709.GA7285@cs.fsu.edu> <20050718212550.GA7608@cs.fsu.edu> Message-ID: Ted Baker writes: >> My analogy was "gotos", for which the safe pattern > > My point is still that (raw) exceptions are not a simple feature > to use correctly, generally tend to get programmers in trouble, > and don't need any "help" that will encourage people to try to > use them for more unsafe things. That's as wrong as saying that exceptions magically solve all your error handling problems. > The idea of thread cancellation is very simple and very appealing, > so programmers to are told about it will seize on it as a panacea. > I've seen this among students in the courses where I teach > programming with threads (using C). > > Such naive programmers will write a program using threads, and > then try to shut a thread or threads down by just cancelling them. > They do not fully understand the ramifications of the thread > cancellation model, use whatever libraries are at hand, and do not > design from the beginning with cancellation in mind. As a result, > they run into trouble, such as lockups due to cancellation or > threads that are holding mutexes on which another thread is > depending for a pthread_cond_signal to wake up. All of that is totally independent of exception-handling. -- Dave Abrahams Boost Consulting www.boost-consulting.com From wil at bogo.xs4all.nl Tue Jul 19 04:49:26 2005 From: wil at bogo.xs4all.nl (Wil Evers) Date: Tue, 19 Jul 2005 06:49:26 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DC32BA.E6480726@web.de> References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <42DAF5BA.21BE0DCB@web.de> <42DC255A.7080609@bogo.xs4all.nl> <42DC32BA.E6480726@web.de> Message-ID: <42DC8656.4060503@bogo.xs4all.nl> Alexander Terekhov wrote: > Wil Evers wrote: > [...] > >>X::~X() >>{ >> try { >> cancellation_manager enabler(true); >> some_blocking_operation(); >> } catch (const cancellation & ex) { >> // log ex >> // don't rethrow >> } >>} > > > Nope. It will break X's client logic relying on modularity of X in the > sense of its capability to defer cancellation and perform cancelable > effects (subject any other failure modes, if any) when cancellation is > been disabled by X's client. You've lost me. Maybe you're assuming that a cancellation request will only cause a single cancellation exeception, in other words, that cancellation is not "sticky"? - Wil From terekhov at web.de Tue Jul 19 08:04:56 2005 From: terekhov at web.de (Alexander Terekhov) Date: Tue, 19 Jul 2005 10:04:56 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <42DAF5BA.21BE0DCB@web.de> <42DC255A.7080609@bogo.xs4all.nl> <42DC32BA.E6480726@web.de> <42DC8656.4060503@bogo.xs4all.nl> Message-ID: <42DCB428.E9C99FC9@web.de> Wil Evers wrote: > > Alexander Terekhov wrote: > > Wil Evers wrote: > > [...] > > > >>X::~X() > >>{ > >> try { > >> cancellation_manager enabler(true); > >> some_blocking_operation(); > >> } catch (const cancellation & ex) { > >> // log ex > >> // don't rethrow > >> } > >>} > > > > > > Nope. It will break X's client logic relying on modularity of X in the > > sense of its capability to defer cancellation and perform cancelable > > effects (subject any other failure modes, if any) when cancellation is > > been disabled by X's client. > > You've lost me. Maybe you're assuming that a cancellation request will > only cause a single cancellation exeception, in other words, that > cancellation is not "sticky"? When cancellation is been disabled by X's client, it doesn't matter whether cancellation is "sticky" or not "sticky" because it's been suppressed entirely by X's client. regards, alexander. From ncm at cantrip.org Tue Jul 19 17:59:12 2005 From: ncm at cantrip.org (Nathan Myers) Date: Tue, 19 Jul 2005 10:59:12 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DC4086.BFCE7DCE@web.de> References: <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <42DAF5BA.21BE0DCB@web.de> <20050718232127.GE21905@tofu.dreamhost.com> <42DC4086.BFCE7DCE@web.de> Message-ID: <20050719175912.GA8407@tofu.dreamhost.com> On Tue, Jul 19, 2005 at 01:51:34AM +0200, Alexander Terekhov wrote: > Nathan Myers wrote: > > On Mon, Jul 18, 2005 at 02:20:10AM +0200, Alexander Terekhov wrote: > > > Wil Evers wrote: > > > > { > > > > cancellation_manager enabler(true); > > > > some_cancellation_point(); > > > > } > > > > > > Never do that in "library" code. > > > > First, it's not in "library code". It's in thread-main. > > new_thread(library_call, arg); > > Where's "thread-main"? "Thread-main" is a conventional term in thread programming for the function whose activation record is at the bottom of the thread's stack. This function cannot return without terminating the thread, just as program main() cannot return without exiting the program. > > Second, when the default is to have cancellation off, design > > heurisitics change accordingly. It would be perfectly reasonable > > to enable (some form of) cancellation, temporarily, inside a library > > that necessarily must have been called with it turned off. > > And how would you really turn it off (depending on client's > need/context), then? If *I* didn't want the thread cancelled, I would simply choose not to cancel it. If the client calls into a library that promises to throw if it can't satisfy its postconditions, then it might get an exception to deal with. What was the question? Nathan Myers ncm at codesourcery.com ncm at cantrip.org From wil at bogo.xs4all.nl Tue Jul 19 19:40:06 2005 From: wil at bogo.xs4all.nl (Wil Evers) Date: Tue, 19 Jul 2005 21:40:06 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DCB428.E9C99FC9@web.de> References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <42DAF5BA.21BE0DCB@web.de> <42DC255A.7080609@bogo.xs4all.nl> <42DC32BA.E6480726@web.de> <42DC8656.4060503@bogo.xs4all.nl> <42DCB428.E9C99FC9@web.de> Message-ID: <42DD5716.1040304@bogo.xs4all.nl> Alexander Terekhov wrote: > When cancellation is been disabled by X's client, it doesn't matter > whether cancellation is "sticky" or not "sticky" because it's been > suppressed entirely by X's client. That's odd. I always thought that a cancellation request would be remembered until the target thread enables cancellation, while you seem to suggest the cancellation request is simply ignored when the target thread runs with cancellation disabled. Any references? Thanks, - Wil From terekhov at web.de Tue Jul 19 19:45:39 2005 From: terekhov at web.de (Alexander Terekhov) Date: Tue, 19 Jul 2005 21:45:39 +0200 Subject: pthread_cancel and EH: let's try this again References: <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <42DAF5BA.21BE0DCB@web.de> <20050718232127.GE21905@tofu.dreamhost.com> <42DC4086.BFCE7DCE@web.de> <20050719175912.GA8407@tofu.dreamhost.com> Message-ID: <42DD5863.61D10550@web.de> Nathan Myers wrote: [...] > > new_thread(library_call, arg); > > > > Where's "thread-main"? > > "Thread-main" is a conventional term in thread programming for the > function whose activation record is at the bottom of the thread's > stack. This function cannot return without terminating the thread, > just as program main() cannot return without exiting the program. I suppose you're after exit(main()) in initial thread and pthread_exit(start_routine(arg)) in other threads. What makes you think that library_call isn't start_routine (aka conventional "thread-main" in your thread programming neighborhood), or its equivalent apart from "activation records"? > > > > Second, when the default is to have cancellation off, design > > > heurisitics change accordingly. It would be perfectly reasonable > > > to enable (some form of) cancellation, temporarily, inside a library > > > that necessarily must have been called with it turned off. > > > > And how would you really turn it off (depending on client's > > need/context), then? > > If *I* didn't want the thread cancelled, I would simply choose not to > cancel it. If the client calls into a library that promises to throw > if it can't satisfy its postconditions, then it might get an exception > to deal with. What was the question? Same question. If you never cancel a thread, it's all moot. My question was about control of cancellation in a thread that can be a target of pthread_cancel(). regards, alexander. From terekhov at web.de Tue Jul 19 20:02:44 2005 From: terekhov at web.de (Alexander Terekhov) Date: Tue, 19 Jul 2005 22:02:44 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D54C14.4090505@hp.com> <42D70259.6050808@codesourcery.com> <20050715070512.GM4884@devserv.devel.redhat.com> <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <42DAF5BA.21BE0DCB@web.de> <42DC255A.7080609@bogo.xs4all.nl> <42DC32BA.E6480726@web.de> <42DC8656.4060503@bogo.xs4all.nl> <42DCB428.E9C99FC9@web.de> <42DD5716.1040304@bogo.xs4all.nl> Message-ID: <42DD5C64.7239948D@web.de> Wil Evers wrote: > > Alexander Terekhov wrote: > > > When cancellation is been disabled by X's client, it doesn't matter > > whether cancellation is "sticky" or not "sticky" because it's been > > suppressed entirely by X's client. > > That's odd. I always thought that a cancellation request would be > remembered until the target thread enables cancellation, Request is remembered but cancellation remains "suppressed entirely" as long as it remains disabled. Pending cancel is guaranteed to fire when the target has its cancellation enabled and hits a "shall occur" cancellation point. Pending cancel may also fire when the target has its cancellation enabled and hits a "may also occur" cancellation point. Pending cancel may also fire at any point within async.cancel region when the target has its cancellation enabled. > while you seem > to suggest the cancellation request is simply ignored when the target > thread runs with cancellation disabled. It depends on what you main by "ignored". See above. regards, alexander. From ncm at cantrip.org Tue Jul 19 20:43:17 2005 From: ncm at cantrip.org (Nathan Myers) Date: Tue, 19 Jul 2005 13:43:17 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DD5863.61D10550@web.de> References: <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <42DAF5BA.21BE0DCB@web.de> <20050718232127.GE21905@tofu.dreamhost.com> <42DC4086.BFCE7DCE@web.de> <20050719175912.GA8407@tofu.dreamhost.com> <42DD5863.61D10550@web.de> Message-ID: <20050719204317.GB8407@tofu.dreamhost.com> On Tue, Jul 19, 2005 at 09:45:39PM +0200, Alexander Terekhov wrote: > > Nathan Myers wrote: > > > new_thread(library_call, arg); > > What makes you > think that library_call isn't start_routine (aka conventional > "thread-main" in your thread programming neighborhood), or its > equivalent apart from "activation records"? As I said, it doesn't matter if it is or isn't. You may read that again right here: > > > > Second, when the default is to have cancellation off, design > > > > heuristics change accordingly. It would be perfectly > > > > reasonable to enable (some form of) cancellation, temporarily, > > > > inside a library that necessarily must have been called with it > > > > turned off. > > > > > > And how would you really turn it off (depending on client's > > > need/context), then? > > > > ... If the client calls into a library that promises to > > throw if it can't satisfy its postconditions, then it might get an > > exception to deal with. > > My question was about control of cancellation in a thread that can > be a target of pthread_cancel(). Any pthread can be a target of pthread_cancel(). If you want some mechanism to ensure that a thread always ignores cancellations, regardless of any calls it, or libraries it uses, perform, I have nothing to propose. What we're talking about here is mechanisms to control what happens when a thread is already in a cancelled state. As Wil had proposed, a thread in a C++ program starts out with the cancel state having no effect on any operation. If the thread turns on some form of response (by constructing one of Wil's objects, however implemented), then at any point within its scope where something is supposed to happen (e.g. a cancellation point), something happens. Precisely what happens then would depend on what sort of Wil-object is in scope. If "what happens" is an exception, then the client sees an exception. (Library clients don't generally get to say whether they want to handle exceptions, iostreams notwithstanding). Note that I am not assuming this is all built on top of some existing POSiX C pthreads implementation, although maybe with some tricky linker manipulations it could be. I interpret Wil's example code only as a welcome attempt inject some concreteness into the discussion. Nathan Myers ncm at codesourcery.com ncm at cantrip.org From wil at bogo.xs4all.nl Tue Jul 19 21:08:48 2005 From: wil at bogo.xs4all.nl (Wil Evers) Date: Tue, 19 Jul 2005 23:08:48 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <003801c58b8e$d66dbca0$6501a8c0@pdimov2> References: <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> Message-ID: <42DD6BE0.7070100@bogo.xs4all.nl> Peter Dimov wrote: > The natural way to signal cancellation is with an exception, not an > error code and a multitude of ifs. The exception model has obviously > been considered superior by the Posix folks, so superior that they even > defined their own EH mechanism in the C binding. I disagree. IMO, a cancellation request is just another external event (usually) triggered by something outside of the current thread - much like data arriving on a socket, or the signalling of a condition variable. As we all know, such events are best dealt with when the target thread is ready for them. As the discussion on this list illustrates, mapping cancellation requests to exceptions is causing real headaches. This is because cancellation requests are piggybacked onto system calls originally designed for other purposes. In addition, and contrary to common usage of exceptions, a cancellation request is *not* an error in the sense that it immediately prevents the current thread from progressing any further. A cancellation request is simply one of the things a thread is supposed to (eventually) handle - if the application's design demands so. That said, I realize it is far too late to change the decisions made by the POSIX folks. All we can do is try to find ways to handle cancellation exceptions gracefully. - Wil From pdimov at mmltd.net Tue Jul 19 22:44:49 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Wed, 20 Jul 2005 01:44:49 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> Message-ID: <003c01c58cb3$7a199a20$6501a8c0@pdimov2> Wil Evers wrote: > As the discussion on this list illustrates, mapping cancellation > requests to exceptions is causing real headaches. Mapping cancellation to an (ordinary C++) exception has been proven to work in practice. The primary source of real headaches is the discussion itself. > In addition, and contrary to common usage of exceptions, a > cancellation request is *not* an error in the sense that it > immediately prevents the current thread from progressing any further. A cancellation request is a request for a thread to not progress any further. It's pretty much a textbook example for using exceptions - a long-distance return all the way up, with the middle layers nearly never needing to not propagate it. From mark at codesourcery.com Tue Jul 19 22:54:34 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Tue, 19 Jul 2005 15:54:34 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <003c01c58cb3$7a199a20$6501a8c0@pdimov2> References: <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> Message-ID: <42DD84AA.6020606@codesourcery.com> Peter Dimov wrote: > Wil Evers wrote: > >> As the discussion on this list illustrates, mapping cancellation >> requests to exceptions is causing real headaches. > > > Mapping cancellation to an (ordinary C++) exception has been proven to > work in practice. The primary source of real headaches is the discussion > itself. Personally, I think everyone's stated their opinions well enough; it doesn't seem like we're getting anywhere. I'd like to hear from Jason Merrill, as he was the person brave enough to restart this discussion, and as he's probably the person most motivated to actually do something... Jason, have any of us persuaded you of anything, or are you just wallowing in your own despair? -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From gshiman at commvault.com Tue Jul 19 23:06:06 2005 From: gshiman at commvault.com (George Shimanovich) Date: Tue, 19 Jul 2005 19:06:06 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again Message-ID: <52CA6BC0D0E9EE4E93208DB39A3218FEA45920@EXCHANGE.gp.cv.commvault.com> > Wil Evers wrote: > > Mapping cancellation to an (ordinary C++) exception has been proven to > work in practice. The primary source of real headaches is the discussion > itself. That is not the case in Linux pthread implementation, as I replied to Mark Mitchel (see my earlier email). Jason indicated in #3 that abort() is called cancellation exception is rethrown - and that is consistent with my experience. BTW, even if this discussion did not converge, I enjoyed technical aspect of it immensely. Thanks to all. George Shimanovich CommVault Systems, Inc. -----Original Message----- From: Mark Mitchell [mailto:mark at codesourcery.com] Sent: Tuesday, July 19, 2005 6:55 PM To: Peter Dimov Cc: c++-pthreads at codesourcery.com; Jason Merrill Subject: Re: [c++-pthreads] Re: pthread_cancel and EH: let's try this again Peter Dimov wrote: > Wil Evers wrote: > >> As the discussion on this list illustrates, mapping cancellation >> requests to exceptions is causing real headaches. > > > Mapping cancellation to an (ordinary C++) exception has been proven to > work in practice. The primary source of real headaches is the discussion > itself. Personally, I think everyone's stated their opinions well enough; it doesn't seem like we're getting anywhere. I'd like to hear from Jason Merrill, as he was the person brave enough to restart this discussion, and as he's probably the person most motivated to actually do something... Jason, have any of us persuaded you of anything, or are you just wallowing in your own despair? -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From ncm at cantrip.org Wed Jul 20 06:55:39 2005 From: ncm at cantrip.org (Nathan Myers) Date: Tue, 19 Jul 2005 23:55:39 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DD84AA.6020606@codesourcery.com> References: <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> Message-ID: <20050720065539.GA24311@tofu.dreamhost.com> On Tue, Jul 19, 2005 at 03:54:34PM -0700, Mark Mitchell wrote: > > ... it doesn't seem like we're getting anywhere. I hate to contradict Mark, but I think we've made real progress this time around (unlike last). Pace Wil's pessimism, he has proposed a workable design, compatible with standard C++ semantics and the needs of thread coders alike. Best, it doesn't seem to depend on compiler hackery, so we might not need to depend on Jason for a reference implementation. Nathan Myers ncm at codesourcery.com ncm at cantrip.org From terekhov at web.de Wed Jul 20 10:31:13 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 20 Jul 2005 12:31:13 +0200 Subject: pthread_cancel and EH: let's try this again References: <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <42DAF5BA.21BE0DCB@web.de> <20050718232127.GE21905@tofu.dreamhost.com> <42DC4086.BFCE7DCE@web.de> <20050719175912.GA8407@tofu.dreamhost.com> <42DD5863.61D10550@web.de> <20050719204317.GB8407@tofu.dreamhost.com> Message-ID: <42DE27F1.C801107@web.de> Nathan Myers wrote: [...] > What we're talking about here is mechanisms to control what happens > when a thread is already in a cancelled state. As Wil had proposed, > a thread in a C++ program starts out with the cancel state having no > effect on any operation. If the thread turns on some form of response > (by constructing one of Wil's objects, however implemented), then at > any point within its scope where something is supposed to happen (e.g. > a cancellation point), something happens. Precisely what happens > then would depend on what sort of Wil-object is in scope. Okay. Suppose I put Wil's "enabler" in each and every "thread-main" and that all calls to your "thread-safe" library from "thread-mains" are within cancel-enabled scopes. That would be criminal, right? regards, alexander. From terekhov at web.de Wed Jul 20 11:35:25 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 20 Jul 2005 13:35:25 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D7638A.10309@codesourcery.com> <20050715072228.GA30077@devserv.devel.redhat.com> <42D765C1.4060504@codesourcery.com> <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> Message-ID: <42DE36FD.DD811A53@web.de> Peter Dimov wrote: [...] > A cancellation request is a request for a thread to not progress any > further. It's pretty much a textbook example for using exceptions - a > long-distance return all the way up, with the middle layers nearly never > needing to not propagate it. Yup. The effect of cancel delivery is (ought to be) nothing but void attempt_deliver_cancel() { int canceltype; // in the case of async cancel delivery pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &canceltype); // return all the way up (if cancel is expected) pthread_exit(PTHREAD_CANCELED); // unexpected pthread_setcanceltype(canceltype, &canceltype); } And in details... #define PTHREAD_CANCELED std::thread_canceled() struct thread_canceled { operator void * () { return &unique; } static thread_canceled unique; }; class thread_termination_request : public std::exception ... class thread_cancel_request : public std::thread_termination_request ... class thread_exit_request : public std::thread_termination_request ... template class thread_exit_value : public std::thread_exit_request ... extern "C" void pthread_exit(void * ptr) throw(std::thread_termination_request) { ptr == PTHREAD_CANCELED ? std::thread_cancel() : std::thread_exit(ptr); } template void thread_exit(T value) { int cancelstate; assert(std::thread_self().can_exit_with()); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate); throw thread_exit_value(value); } template<> void thread_exit(std::thread_canceled) { thread_cancel(); } void thread_cancel() { int cancelstate; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate); assert(cancelstate == PTHREAD_CANCEL_ENABLE) throw_if_expected std::thread_cancel_request(); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate); } Or something like that. ;-) regards, alexander. From mark at codesourcery.com Wed Jul 20 14:25:06 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Wed, 20 Jul 2005 07:25:06 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <20050720065539.GA24311@tofu.dreamhost.com> References: <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> Message-ID: <42DE5EC2.2060704@codesourcery.com> Nathan Myers wrote: > On Tue, Jul 19, 2005 at 03:54:34PM -0700, Mark Mitchell wrote: > >>... it doesn't seem like we're getting anywhere. > > > I hate to contradict Mark, but I think we've made real progress this > time around (unlike last). Good! I'd still like to hear from Jason, to know whether any kind of consensus is being reached. -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From wil at bogo.xs4all.nl Wed Jul 20 20:28:58 2005 From: wil at bogo.xs4all.nl (Wil Evers) Date: Wed, 20 Jul 2005 22:28:58 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DE27F1.C801107@web.de> References: <20050715073649.GB30077@devserv.devel.redhat.com> <42D76B84.5010604@codesourcery.com> <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <42DAF5BA.21BE0DCB@web.de> <20050718232127.GE21905@tofu.dreamhost.com> <42DC4086.BFCE7DCE@web.de> <20050719175912.GA8407@tofu.dreamhost.com> <42DD5863.61D10550@web.de> <20050719204317.GB8407@tofu.dreamhost.com> <42DE27F1.C801107@web.de> Message-ID: <42DEB40A.90802@bogo.xs4all.nl> Alexander Terekhov wrote: > Nathan Myers wrote: > [...] > >>What we're talking about here is mechanisms to control what happens >>when a thread is already in a cancelled state. As Wil had proposed, >>a thread in a C++ program starts out with the cancel state having no >>effect on any operation. If the thread turns on some form of response >>(by constructing one of Wil's objects, however implemented), then at >>any point within its scope where something is supposed to happen (e.g. >>a cancellation point), something happens. Precisely what happens >>then would depend on what sort of Wil-object is in scope. > > Okay. Suppose I put Wil's "enabler" in each and every "thread-main" and > that all calls to your "thread-safe" library from "thread-mains" are > within cancel-enabled scopes. That would be criminal, right? No. One of the aims of my suggestion is to remove any cancellation handling policy from the threads library, and put it in the hands of the user instead. So if you feel that leaving cancellation enabled at all times is appropriate, you're free to do just that. That's risky, but I wouldn't call it criminal :-). - Wil BTW - as you know, a POSIX thread always starts with cancellation enabled, so there is no need to put an enabler in your thread-main. From ncm at codesourcery.com Wed Jul 20 20:44:05 2005 From: ncm at codesourcery.com (Nathan (Jasper) Myers) Date: Wed, 20 Jul 2005 16:44:05 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DEB40A.90802@bogo.xs4all.nl> References: <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <42DAF5BA.21BE0DCB@web.de> <20050718232127.GE21905@tofu.dreamhost.com> <42DC4086.BFCE7DCE@web.de> <20050719175912.GA8407@tofu.dreamhost.com> <42DD5863.61D10550@web.de> <20050719204317.GB8407@tofu.dreamhost.com> <42DE27F1.C801107@web.de> <42DEB40A.90802@bogo.xs4all.nl> Message-ID: <20050720204405.GB2961@codesourcery.com> On Wed, Jul 20, 2005 at 10:28:58PM +0200, Wil Evers wrote: > > BTW - as you know, a POSIX thread always starts with cancellation > enabled, so there is no need to put an enabler in your thread-main. Maybe a POSIX C thread starts with cancellation enabled. Here we're talking about C++ threads, which POSIX says nothing about. We can choose to implement what works right, instead. Nathan Myers ncm at codesourcery.com From wil at bogo.xs4all.nl Wed Jul 20 21:24:51 2005 From: wil at bogo.xs4all.nl (Wil Evers) Date: Wed, 20 Jul 2005 23:24:51 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <20050720065539.GA24311@tofu.dreamhost.com> References: <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> Message-ID: <42DEC123.4040509@bogo.xs4all.nl> Nathan Myers wrote: > I hate to contradict Mark, but I think we've made real progress this > time around (unlike last). Pace Wil's pessimism, he has proposed > a workable design, compatible with standard C++ semantics and the > needs of thread coders alike. However, I believe my suggestion does imply certain requirements on the threads library. Perhaps it's time to list these, so here's model #5 (Is it really 5? I think so.) * Threads are created with cancellation enabled (this is just repeating what POSIX says, I think). * Cancellation is sticky: it causes an irreversible state change in the target thread; subsequent cancellations have no further effect. * A cancellation exception is a normal C++ exception. In particular, it can be caught by a catch (...), and there is no requirement that it must be rethrown if caught. * A thread's cancellation state is only affected by calls to pthread_setcancelstate() originating from user code. - Wil From terekhov at web.de Wed Jul 20 21:59:21 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 20 Jul 2005 23:59:21 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> Message-ID: <42DEC939.53B3E28@web.de> Wil Evers wrote: > > Nathan Myers wrote: > > > I hate to contradict Mark, but I think we've made real progress this > > time around (unlike last). Pace Wil's pessimism, he has proposed > > a workable design, compatible with standard C++ semantics and the > > needs of thread coders alike. > > However, I believe my suggestion does imply certain requirements on the > threads library. Perhaps it's time to list these, so here's model #5 > (Is it really 5? I think so.) > > * Threads are created with cancellation enabled (this is just repeating > what POSIX says, I think). Yes. > > * Cancellation is sticky: it causes an irreversible state change in the > target thread; subsequent cancellations have no further effect. Stickiness can be achieved by the user code. By mandating stickiness, you don't really solve any problems. Note that mandated stickiness would inhibit various useful things such as reuse of threads in a thread pool executor without recycling after cancellation of a "task"/"future" by means of thread cancellation. > > * A cancellation exception is a normal C++ exception. In particular, it > can be caught by a catch (...), and there is no requirement that it must > be rethrown if caught. Yes. > > * A thread's cancellation state is only affected by calls to > pthread_setcancelstate() originating from user code. Intelligent cancel delivery aside for a moment, POSIX states: "When a cancellation request is acted upon, or when a thread calls pthread_exit(), the thread first disables cancellation by setting its cancelability state to PTHREAD_CANCEL_DISABLE and its cancelability type to PTHREAD_CANCEL_DEFERRED." regards, alexander. From pdimov at mmltd.net Wed Jul 20 22:14:27 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Thu, 21 Jul 2005 01:14:27 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <42DEC939.53B3E28@web.de> Message-ID: <004501c58d78$6605df60$6501a8c0@pdimov2> Alexander Terekhov wrote: > Wil Evers wrote: >> * A thread's cancellation state is only affected by calls to >> pthread_setcancelstate() originating from user code. > > Intelligent cancel delivery aside for a moment, POSIX states: > > "When a cancellation request is acted upon, or when a thread calls > pthread_exit(), the thread first disables cancellation by setting > its cancelability state to PTHREAD_CANCEL_DISABLE and its > cancelability type to PTHREAD_CANCEL_DEFERRED." That's one of the few places where I think that we should not do what Posix says and just disable cancellation during unwinding instead. It has the same effect and solves the only real reported problem with the Tru64/OpenVMS model: that eating the cancellation exception leaves the thread running with cancelability disabled, causing the cancellation request to be lost without a trace. From terekhov at web.de Wed Jul 20 22:53:42 2005 From: terekhov at web.de (Alexander Terekhov) Date: Thu, 21 Jul 2005 00:53:42 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <42DEC939.53B3E28@web.de> <004501c58d78$6605df60$6501a8c0@pdimov2> Message-ID: <42DED5F6.9C5183C5@web.de> Peter Dimov wrote: > > Alexander Terekhov wrote: > > Wil Evers wrote: > > >> * A thread's cancellation state is only affected by calls to > >> pthread_setcancelstate() originating from user code. > > > > Intelligent cancel delivery aside for a moment, POSIX states: > > > > "When a cancellation request is acted upon, or when a thread calls > > pthread_exit(), the thread first disables cancellation by setting > > its cancelability state to PTHREAD_CANCEL_DISABLE and its > > cancelability type to PTHREAD_CANCEL_DEFERRED." > > That's one of the few places where I think that we should not do what Posix > says and just disable cancellation during unwinding instead. It has the same > effect and solves the only real reported problem with the Tru64/OpenVMS > model: that eating the cancellation exception leaves the thread running with > cancelability disabled, causing the cancellation request to be lost without > a trace. It may partially[*] solve it in the case of dtors (making dtors have implicit throw()-nothing catch-less ES [ES fixed edition so to speak] by default and mandating intelligent cancel delivery would solve it much better and won't inhibit use of cancellation inside dtors), but what about "unwinding" using catch-rethrow "dtors" that can also eat exceptions? try { operation(); } catch(...) { // End of stack unwinding try { cleanup(); } catch(...) { // eat exception } throw; // Begin of another stack unwinding } http://www.boost.org/libs/smart_ptr/sp_techniques.html "should be wrapped in a try {} catch(...) {} block that ignores exceptions" http://lists.boost.org/MailArchives/boost/msg53471.php I mean. [*] Consider: struct X { X() { pthread_cancel(pthread_self()); } ~X() throw() { printf("may go boom"); } }; int main() { X x; } Where's no stack unwinding here. "The process of calling destructors for automatic objects constructed on the path from a try block to a throw-expression is called 'stack unwinding.'" But with intelligent cancel delivery it won't go boom. And it would have zero overhead (no need to modify any flags) when you don't have cancel requests pending. Many programs never call pthread_cancel() and there is no reason (apart from misguided reluctance to mandate 2-phase EH and fix ES) to penalize them. regards, alexander. From pdimov at mmltd.net Wed Jul 20 23:37:41 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Thu, 21 Jul 2005 02:37:41 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <42DEC939.53B3E28@web.de> <004501c58d78$6605df60$6501a8c0@pdimov2> <42DED5F6.9C5183C5@web.de> Message-ID: <006701c58d84$0de0c140$6501a8c0@pdimov2> Alexander Terekhov wrote: > It may partially[*] solve it in the case of dtors (making dtors have > implicit throw()-nothing catch-less ES [ES fixed edition so to speak] > by default and mandating intelligent cancel delivery would solve it > much better and won't inhibit use of cancellation inside dtors), but > what about "unwinding" using catch-rethrow "dtors" that can also eat > exceptions? > > try { > operation(); > } > catch(...) { > // End of stack unwinding > try { > cleanup(); > } > catch(...) { > // eat exception > } > throw; // Begin of another stack unwinding > } The stack unwinding doesn't end when the catch block is entered. That's when the exception is "caught" - uncaught_exception() starts returning true - but it's not until the catch block ends when the exception is considered "finished". > [*] Consider: > > struct X { > > X() { > pthread_cancel(pthread_self()); > } > > ~X() throw() { > printf("may go boom"); > } > > }; > > int main() { > X x; > } Yes, this can terminate() under most "non-intelligent" models, except the one where destructors disable cancellation. The cause of the termination is the throw() specification, though, not the destructor - you can replace ~X with an ordinary function. This is one of the motivating examples for the ECANCEL school of thought. From ncm at codesourcery.com Thu Jul 21 00:09:07 2005 From: ncm at codesourcery.com (Nathan (Jasper) Myers) Date: Wed, 20 Jul 2005 20:09:07 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DEC123.4040509@bogo.xs4all.nl> References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> Message-ID: <20050721000907.GA3218@codesourcery.com> On Wed, Jul 20, 2005 at 11:24:51PM +0200, Wil Evers wrote: > Nathan Myers wrote: > (Is it really 5? I think so.) > > * Threads are created with cancellation enabled (this is just repeating > what POSIX says, I think). > > * Cancellation is sticky: it causes an irreversible state change in the > target thread; subsequent cancellations have no further effect. > > * A cancellation exception is a normal C++ exception. In particular, it > can be caught by a catch (...), and there is no requirement that it must > be rethrown if caught. > > * A thread's cancellation state is only affected by calls to > pthread_setcancelstate() originating from user code. This strikes me as still unnecessarily complicated. Do we need a #6? So be it. In #6, * Threads are initiated with cancellation disabled. * Cancellation is sticky. * On construction of a cancellation_context object C, if the thread is in a cancelled state, an ordinary exception is thrown. * During the lifetime of C, the semantics of destructors and catch blocks are undefined if the thread is cancelled and a POSIX C cancellation point is encountered. Any cleanup ends at the scope of C, and control leaves this scope via an ordinary exception. * Outside the scope of a cancellation_context, the effect of pthread_cleanup_push etc. is undefined. * Other context types provided may have different semantics, such as one in which certain system calls fail if the thread is cancelled. This shouldn't need any compiler support, and the thread runtime shouldn't need to know any details about the exception mechanism. Nathan Myers ncm at codesourcery.com From mark at codesourcery.com Thu Jul 21 00:42:57 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Wed, 20 Jul 2005 17:42:57 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <20050721000907.GA3218@codesourcery.com> References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> Message-ID: <42DEEF91.3040704@codesourcery.com> Nathan (Jasper) Myers wrote: > * During the lifetime of C, the semantics of destructors and catch > blocks are undefined if the thread is cancelled and a POSIX C > cancellation point is encountered. Any cleanup ends at the scope > of C, and control leaves this scope via an ordinary exception. > > * Outside the scope of a cancellation_context, the effect of > pthread_cleanup_push etc. is undefined. It sounds like you're coming up with entirely new thread semantics that have nothing much to do with POSIX thread cancellation, in that they seem to leave the POSIX thread cancellation behavior undefined. The "pthreads" in "c++-pthreads" is specifically because the charter for this list is to work out how to combine C++ and *POSIX* threads. Any proposal that does not handle POSIX threads is out-of-scope. If you can generalize that to handle all threads, great -- but the primary goal is to determine the behavior of a C++ program that uses POSIX threads. For example, this program presently works on GNU/Linux (tested on RHEL 3): #include #include #include #include void* thread_main (void *arg) { try { fprintf (stderr, "thread: Alive.\n"); sleep (2); pthread_testcancel (); } catch (...) { fprintf (stderr, "thread: In handler.\n"); throw; } fprintf (stderr, "thread: Not cancelled?\n"); return NULL; } int main () { pthread_t thread; fprintf (stderr, "main: Creating thread\n"); pthread_create (&thread, NULL, &thread_main, NULL); sleep (1); pthread_cancel (thread); pthread_join (thread, NULL); fprintf (stderr, "main: Exiting\n"); } and prints: main: Creating thread thread: Alive. thread: In handler. main: Exiting Most users seem reasonably happy with this behavior. However, if you remove the "throw;" in the handler, the program aborts: main: Creating thread thread: Alive. thread: In handler. FATAL: exception not rethrown Aborted Nobody likes this behavior. Jason's approach #2 changes the behavior of the unmodified program so that the handler is ignored, but destructors continue to be run. I don't think anybody except Jason has argued in favor of this proposal, and even Jason seemed to have misgivings. Absent intervention from Jason, I'm assuming that idea is no longer under consideration. So, I think we should assume the unmodified program continues as it presently does, maintaining compatibility with current GNU/Linux. That means that the most important question we should answer is what to do for the program above, when the "throw;" is removed. I think the only reasonable choices are: 1) Fall off the end of the catch clause in the usual way, but the thread is still cancelled. Encountering another cancellation point will result in re-raising the cancellation exception. 2) Fall off the end of the catch clause in the usual way, but the thread is no longer cancelled. It can be re-cancelled, but until it is, it will operate normally. -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From gdr at integrable-solutions.net Thu Jul 21 01:41:45 2005 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 21 Jul 2005 03:41:45 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DEEF91.3040704@codesourcery.com> References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> Message-ID: Mark Mitchell writes: | Nathan (Jasper) Myers wrote: | > * During the lifetime of C, the semantics of destructors and catch | > blocks are undefined if the thread is cancelled and a POSIX C | > cancellation point is encountered. Any cleanup ends at the scope | > of C, and control leaves this scope via an ordinary exception. | > * Outside the scope of a cancellation_context, the effect of | > pthread_cleanup_push etc. is undefined. | | It sounds like you're coming up with entirely new thread semantics | that have nothing much to do with POSIX thread cancellation, in that | they seem to leave the POSIX thread cancellation behavior undefined. | | The "pthreads" in "c++-pthreads" is specifically because the charter | for this list is to work out how to combine C++ and *POSIX* threads. | Any proposal that does not handle POSIX threads is out-of-scope. If | you can generalize that to handle all threads, great -- but the | primary goal is to determine the behavior of a C++ program that uses | POSIX threads. And I would add that any semantics makes a dichotomy between C++ and C frames become unmanageable, less useful in practice. -- Gaby From ncm at codesourcery.com Thu Jul 21 01:50:17 2005 From: ncm at codesourcery.com (Nathan (Jasper) Myers) Date: Wed, 20 Jul 2005 21:50:17 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DEEF91.3040704@codesourcery.com> References: <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> Message-ID: <20050721015017.GA3634@codesourcery.com> On Wed, Jul 20, 2005 at 05:42:57PM -0700, Mark Mitchell wrote: > Nathan (Jasper) Myers wrote: > > * During the lifetime of C, the semantics of destructors and catch > > blocks are undefined if the thread is cancelled and a POSIX C > > cancellation point is encountered. Any cleanup ends at the scope > > of C, and control leaves this scope via an ordinary exception. > > > > * Outside the scope of a cancellation_context, the effect of > > pthread_cleanup_push etc. is undefined. > > It sounds like you're coming up with entirely new thread semantics that > have nothing much to do with POSIX thread cancellation, in that they > seem to leave the POSIX thread cancellation behavior undefined. Within a cancellation context scope, you have bog-standard POSIX C cancellation semantics. Outside it, you have standard C++ semantics. There is no interaction between POSIX cancellation cleanup and C++ exceptions, so no possibility of surprises, and no hard choices. (Anybody who provides definitions can do it without breaking any code that doesn't depend on them.) The point is to keep POSIX thread cancellation from breaking every library. C++ code is mostly useless without libraries, and libraries as a rule know nothing about cancellation. > For example, this program presently works on GNU/Linux (tested on RHEL 3): > ... Of course testing doesn't tell you whether it has defined behavior. Most users don't use cancellation because it doesn't work right with C++. The only people who using cancellation with C++, and happy, are self-selected: the ones who don't care that it doesn't really work. > That means that the most important question we should answer is what to > do for the program above, when the "throw;" is removed. > > I think the only reasonable choices are: > > 1) Fall off the end of the catch clause in the usual way, but the thread > is still cancelled. Encountering another cancellation point will result > in re-raising the cancellation exception. > > 2) Fall off the end of the catch clause in the usual way, but the thread > is no longer cancelled. It can be re-cancelled, but until it is, it > will operate normally. It doesn't matter much which it does; probably (1) is fine, as far as that goes. Neither choice addresses the problem that the libraries we all depend on are unusable -- or worse, seem usable until it matters -- in threads that might be cancelled. Testing doesn't reliably tell you if it matters. Making the spec depend on compiler support practically guarantees that most users won't get anything reasonable, because that depends on "uptake" by people implacably hostile to C++. That's whey we're at this impasse in the first place. Nathan Myers ncm at cantrip.org From mark at codesourcery.com Thu Jul 21 02:00:35 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Wed, 20 Jul 2005 19:00:35 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <20050721015017.GA3634@codesourcery.com> References: <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <20050721015017.GA3634@codesourcery.com> Message-ID: <42DF01C3.80904@codesourcery.com> Nathan (Jasper) Myers wrote: > On Wed, Jul 20, 2005 at 05:42:57PM -0700, Mark Mitchell wrote: > >>Nathan (Jasper) Myers wrote: >> >>>* During the lifetime of C, the semantics of destructors and catch >>> blocks are undefined if the thread is cancelled and a POSIX C >>> cancellation point is encountered. Any cleanup ends at the scope >>> of C, and control leaves this scope via an ordinary exception. >>> >>>* Outside the scope of a cancellation_context, the effect of >>> pthread_cleanup_push etc. is undefined. >> >>It sounds like you're coming up with entirely new thread semantics that >>have nothing much to do with POSIX thread cancellation, in that they >>seem to leave the POSIX thread cancellation behavior undefined. > > > Within a cancellation context scope, you have bog-standard POSIX C > cancellation semantics. Outside it, you have standard C++ semantics. That wasn't clear to me. I'd be OK with that -- but most people seem to want POSIX thread cancellation to throw an exception in contrast with: > There is no interaction between POSIX cancellation cleanup and C++ > exceptions, so no possibility of surprises, and no hard choices. and GNU/Linux started implementing pthread_cleanup_push as a destructor a while back. So, now, there's no way to run pthread cleanups without also doing stack unwinding. To do bog-standard POSIX C cancellation semantics (i.e., without running destructors) would require changes to GLIBC (to put it back the way it used to be), and, of course, recompilation of all pthread_cleanup-using binaries. > Of course testing doesn't tell you whether it has defined behavior. True -- but that is in fact the behavior that was defined in the last iteration of that debate that the behavior shown was what was wanted. That behavior isn't an accident. >>I think the only reasonable choices are: >> >>1) Fall off the end of the catch clause in the usual way, but the thread >>is still cancelled. Encountering another cancellation point will result >>in re-raising the cancellation exception. >> >>2) Fall off the end of the catch clause in the usual way, but the thread >>is no longer cancelled. It can be re-cancelled, but until it is, it >>will operate normally. > > It doesn't matter much which it does; probably (1) is fine, as far as > that goes. I agree that the choice doesn't matter much. Heck, this whole issue doesn't matter much to me; I'm just trying to keep us from going in some really bad direction... > Making the spec depend on compiler support practically guarantees > that most users won't get anything reasonable, because that depends > on "uptake" by people implacably hostile to C++. That's whey we're > at this impasse in the first place. Nothing we're talking about requires compiler support per se; it's all C library support -- including your proposal, if I understand it correctly, since you want to not do unwinding when inside a cancellation region, which requires changing pthread_cleanup_push not to be a destructor. -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From ncm at codesourcery.com Thu Jul 21 06:25:37 2005 From: ncm at codesourcery.com (Nathan (Jasper) Myers) Date: Thu, 21 Jul 2005 02:25:37 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DF01C3.80904@codesourcery.com> References: <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <20050721015017.GA3634@codesourcery.com> <42DF01C3.80904@codesourcery.com> Message-ID: <20050721062537.GA2266@codesourcery.com> On Wed, Jul 20, 2005 at 07:00:35PM -0700, Mark Mitchell wrote: > Nathan (Jasper) Myers wrote: > >On Wed, Jul 20, 2005 at 05:42:57PM -0700, Mark Mitchell wrote: > >>Nathan (Jasper) Myers wrote: > >> > >>>* During the lifetime of object C, the semantics of destructors and > >>> catch blocks are undefined if the thread is cancelled and a POSIX C > >>> cancellation point is encountered. Any cleanup ends at the scope > >>> of object C, and control leaves this scope via an ordinary exception. > >>> > >>>* Outside the scope of a cancellation_context, the effect of > >>> pthread_cleanup_push etc. is undefined. > >> > >>It sounds like you're coming up with entirely new thread semantics that > >>have nothing much to do with POSIX thread cancellation, in that they > >>seem to leave the POSIX thread cancellation behavior undefined. > > > >Within a cancellation context scope, you have bog-standard POSIX C > >cancellation semantics. Outside it, you have standard C++ semantics. > > That wasn't clear to me. > > I'd be OK with that -- but most people seem to want POSIX thread > cancellation to throw an exception in contrast with: > > >There is no interaction between POSIX cancellation cleanup and C++ > >exceptions, so no possibility of surprises, and no hard choices. > > and GNU/Linux started implementing pthread_cleanup_push as a destructor > a while back. So, now, there's no way to run pthread cleanups without > also doing stack unwinding. To do bog-standard POSIX C cancellation > semantics (i.e., without running destructors) would require changes to > GLIBC (to put it back the way it used to be), and, of course, > recompilation of all pthread_cleanup-using binaries. POSIX doesn't forbid running destructors; it says nothing about them. The specification above says that if there are any of the users' to be run, the effect is undefined. Run them, don't run them, crash, whatever you like. It's easy to conform, because it demands nothing beyond what J. Random POSIX C does already. All I propose requiring is that whatever it does, it stop running cleanup handlers where the cancellation_context object is, and throw. Conveniently, it also guarantees that in portable code there are no more cleanup handlers to be run. So, maybe the cancellation_context registers a cleanup handler that throws an exception, short-circuiting a cleanup loop; or maybe it does nothing, because an exception is what has been running those cleanup handlers, and will now go on to run the users' destructors and catch clauses. Either way conforms, and you don't have to know much about your C library to implement either one. > >Of course testing doesn't tell you whether it has defined behavior. > > True -- but that is in fact the behavior that was defined in the last > iteration of that debate that the behavior shown was what was wanted. > That behavior isn't an accident. Wanted by whom? As I recall, the "zero uptake!" crowd meant for no library (C or C++) to work right unless it had been written with full expectation of system calls and C library functions throwing exceptions, even in destructors, even during ordinary-exception unwinding. Falling out of the catch clause was just one sticky detail. > >>I think the only reasonable choices are: > >> > >>1) Fall off the end of the catch clause in the usual way, but the > >>thread is still cancelled. Encountering another cancellation point > >>will result in re-raising the cancellation exception. > >> > >>2) Fall off the end of the catch clause in the usual way, but the > >>thread is no longer cancelled. It can be re-cancelled, but until it > >>is, it will operate normally. > > > >It doesn't matter much which it does; probably (1) is fine, as far as > >that goes. > > I agree that the choice doesn't matter much. Heck, this whole issue > doesn't matter much to me; I'm just trying to keep us from going in > some really bad direction... They did that a long time ago. Our only hope is to undo the damage within the context of C++ programs. > >Making the spec depend on compiler support practically guarantees > >that most users won't get anything reasonable, because that depends > >on "uptake" by people implacably hostile to C++. That's whey we're > >at this impasse in the first place. > > Nothing we're talking about requires compiler support per se; it's > all C library support -- including your proposal, if I understand it > correctly, since you want to not do unwinding when inside a > cancellation region, which requires changing pthread_cleanup_push > not to be a destructor. OK, not compiler support; compiler-runtime support. People have been posting about how to keep cancellation from happening during ordinary-exception unwinding, or while a destructor is active. (Most who think it's fine to throw from C-library functions -- specified by the standard never to throw -- pause at exceptions coming out of random destructors.) All this requires an intimate relationship between the exception ABI and the cancellation apparatus. Nothing I wrote says that pthread cleanup mustn't be done with a destructor, underneath. There's no way for a conforming program to tell. That makes it easy to implement without knowing any ABI details of how unwinding is done. That's half the point: it means third parties probably can implement it independently of what their C library vendor has done -- or has categorically refused to do -- just by reimplementing a few pthread functions. The other half is that regular libraries can have well-defined semantics in real threaded C++ programs, even with POSIX-standard cancellation bombs exploding left and right, and without depending on blind luck. If we don't rescue the libraries, whatever we do end up with won't matter to real-world programmers. Nathan Myers ncm at codesourcery.com From mark at codesourcery.com Thu Jul 21 07:58:04 2005 From: mark at codesourcery.com (Mark Mitchell) Date: Thu, 21 Jul 2005 00:58:04 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <20050721062537.GA2266@codesourcery.com> References: <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <20050721015017.GA3634@codesourcery.com> <42DF01C3.80904@codesourcery.com> <20050721062537.GA2266@codesourcery.com> Message-ID: <42DF558C.5080304@codesourcery.com> Nathan (Jasper) Myers wrote: > POSIX doesn't forbid running destructors; it says nothing about them. > The specification above says that if there are any of the users' to > be run, the effect is undefined. Run them, don't run them, crash, > whatever you like. It's easy to conform, because it demands nothing > beyond what J. Random POSIX C does already. But the mission of this list is precisely to define the behavior, not to leave it undefined. >>True -- but that is in fact the behavior that was defined in the last >>iteration of that debate that the behavior shown was what was wanted. >>That behavior isn't an accident. > > Wanted by whom? As I recall, the "zero uptake!" crowd meant for no > library (C or C++) to work right unless it had been written with full > expectation of system calls and C library functions throwing exceptions, > even in destructors, even during ordinary-exception unwinding. Falling > out of the catch clause was just one sticky detail. It was posited that cancellation mapped to an exception, and that so long as this exception was rethrown, stack unwinding happened in the usual way. I understand that you think that mapping cancellation to an exception, and thereby changing C functions that did not previously throw exceptions into functions that do, is a bad idea. However, I think one of the axioms for this discussion was that this is in fact a good idea. In other words, I think the context here is that we're assuming POSIX cancellation points throw a cancellation exception; the question is how things behave from there. I don't think that throwing out this assumption is productive, because I don't think you'll ever get the broader community to accept anything else. I'm not necessarily disliking what you're saying; I'm just don't see it as pragmatic. However, if you can do it all at user level, and people like your solution, more power to you! All in all, I think I've once again spent quite enough time on this discussion. The status quo is actually OK with me, in that if your program does not abort, it behaves in a way I find plausible. So, until there's some indication that someone is going to try to actually implement something, I'll just go back to worrying about other things. -- Mark Mitchell CodeSourcery, LLC mark at codesourcery.com (916) 791-8304 From terekhov at web.de Thu Jul 21 10:47:42 2005 From: terekhov at web.de (Alexander Terekhov) Date: Thu, 21 Jul 2005 12:47:42 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <42DEC939.53B3E28@web.de> <004501c58d78$6605df60$6501a8c0@pdimov2> <42DED5F6.9C5183C5@web.de> <006701c58d84$0de0c140$6501a8c0@pdimov2> Message-ID: <42DF7D4E.1F3E5F7@web.de> Peter Dimov wrote: > > Alexander Terekhov wrote: > > > It may partially[*] solve it in the case of dtors (making dtors have > > implicit throw()-nothing catch-less ES [ES fixed edition so to speak] > > by default and mandating intelligent cancel delivery would solve it > > much better and won't inhibit use of cancellation inside dtors), but > > what about "unwinding" using catch-rethrow "dtors" that can also eat > > exceptions? > > > > try { > > operation(); > > } > > catch(...) { > > // End of stack unwinding > > try { > > cleanup(); > > } > > catch(...) { > > // eat exception > > } > > throw; // Begin of another stack unwinding > > } > > The stack unwinding doesn't end when the catch block is entered. That's when > the exception is "caught" - uncaught_exception() starts returning true - but > it's not until the catch block ends when the exception is considered > "finished". Really? Read the definition. There are different try blocks. Each throw expression starts new stack unwinding (if there are any destructors on the path to the handler; exception specs and EH termination aside for a moment). And, BTW, uncaught_exception() is totally busted because in C++ there can be multiple active exceptions. #include using namespace std; int ex_count = 0; int foo(); struct object { ~object() { foo(); } }; int foo() { int ex = ex_count++; try { if (ex < 10) { object obj; std::cout << "throw " << ex << std::endl; throw ex; } else { std::cout << "Okay, enough active exceptions and stack unwindings." << endl; } } catch(int ex_caught) { std::cout << "caught " << ex_caught << std::endl; } return ex; } int main() { return foo(); } Here we've got ten try blocks, ten throw expressions, and ten "stack unwindings". See also http://groups.google.de/group/comp.lang.c++.moderated/msg/4b355d902b123bf3 (exception_scope() and active_exception(int)) > > > [*] Consider: > > > > struct X { > > > > X() { > > pthread_cancel(pthread_self()); > > } > > > > ~X() throw() { > > printf("may go boom"); > > } > > > > }; > > > > int main() { > > X x; > > } > > Yes, this can terminate() under most "non-intelligent" models, except the > one where destructors disable cancellation. The cause of the termination is > the throw() specification, though, not the destructor - you can replace ~X > with an ordinary function. This is one of the motivating examples for the > ECANCEL school of thought. Yes, plus mandated stickiness. The thing is that it doesn't solve anything. Cancel-unaware code was not designed to deal with cancel delivery in the first place. Think of ungetc() and stuff like that. It doesn't matter what happens afterwards or what's used as reporting mechanism. See it? regards, alexander. From pdimov at mmltd.net Thu Jul 21 11:45:54 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Thu, 21 Jul 2005 14:45:54 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <42DEC939.53B3E28@web.de> <004501c58d78$6605df60$6501a8c0@pdimov2> <42DED5F6.9C5183C5@web.de> <006701c58d84$0de0c140$6501a8c0@pdimov2> <42DF7D4E.1F3E5F7@web.de> Message-ID: <005a01c58dea$51a74eb0$6501a8c0@pdimov2> Alexander Terekhov wrote: > Peter Dimov wrote: >> >> The stack unwinding doesn't end when the catch block is entered. >> That's when the exception is "caught" - uncaught_exception() starts >> returning true - but it's not until the catch block ends when the >> exception is considered "finished". > > Really? Read the definition. OK, let's not talk about stack unwinding to avoid the terminology trap. The point is that under one of the models being discussed, cancel delivery is suppressed until the exception is finished. From terekhov at web.de Thu Jul 21 11:50:18 2005 From: terekhov at web.de (Alexander Terekhov) Date: Thu, 21 Jul 2005 13:50:18 +0200 Subject: pthread_cancel and EH: let's try this again References: <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <20050721015017.GA3634@codesourcery.com> <42DF01C3.80904@codesourcery.com> <20050721062537.GA2266@codesourcery.com> Message-ID: <42DF8BFA.28B4D78B@web.de> "Nathan (Jasper) Myers" wrote: [...] > If we don't rescue the libraries That's not what you're after. You want magically turn cancel-unaware stuff into cancel-safe. That's impossible. You should simply accept the limitation of cancel-unaware libraries and let the clients ensure that such code won't get canceled. Clients can use "cancel_off_guard" around calls to such libraries or (it would be much better in my theory) use ES fences and/or no_cancel{} scopes with the same effect http://groups.google.de/group/comp.std.c++/msg/8e15996a760d7ea4 and rely on intelligent cancel delivery. regards, alexander. From terekhov at web.de Thu Jul 21 11:58:51 2005 From: terekhov at web.de (Alexander Terekhov) Date: Thu, 21 Jul 2005 13:58:51 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <42DEC939.53B3E28@web.de> <004501c58d78$6605df60$6501a8c0@pdimov2> <42DED5F6.9C5183C5@web.de> <006701c58d84$0de0c140$6501a8c0@pdimov2> <42DF7D4E.1F3E5F7@web.de> <005a01c58dea$51a74eb0$6501a8c0@pdimov2> Message-ID: <42DF8DFB.C1578B88@web.de> Peter Dimov wrote: > > Alexander Terekhov wrote: > > Peter Dimov wrote: > >> > >> The stack unwinding doesn't end when the catch block is entered. > >> That's when the exception is "caught" - uncaught_exception() starts > >> returning true - but it's not until the catch block ends when the > >> exception is considered "finished". > > > > Really? Read the definition. > > OK, let's not talk about stack unwinding to avoid the terminology trap. The > point is that under one of the models being discussed, cancel delivery is > suppressed until the exception is finished. I don't like that. It's way too inhibitive. regards, alexander. From gshiman at commvault.com Thu Jul 21 13:25:47 2005 From: gshiman at commvault.com (George Shimanovich) Date: Thu, 21 Jul 2005 09:25:47 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again Message-ID: <52CA6BC0D0E9EE4E93208DB39A3218FEA45946@EXCHANGE.gp.cv.commvault.com> Mark Mitchell wrote: >That means that the most important question we should answer is what to >do for the program above, when the "throw;" is removed. > >I think the only reasonable choices are: > >1) Fall off the end of the catch clause in the usual way, but the thread >is still cancelled. Encountering another cancellation point will result >in re-raising the cancellation exception. > >2) Fall off the end of the catch clause in the usual way, but the thread >is no longer cancelled. It can be re-cancelled, but until it is, it >will operate normally. There is one more problem with current catch(...)/throw implementation. It may be beneficial in early stages of development NOT to use catch(...) in order to generate coredumps at point of system crash. Unwinding cancelled thread with C++ exception does not have that problem. From application developer point of view the following seems the best practical solution: C++ exception/throw/no throw - thread is still cancelled. That is leaving aside stack unwinding and DTOR issues of approach with C++ exceptions. George Shimanovich CommVault Systems From pdimov at mmltd.net Thu Jul 21 13:44:47 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Thu, 21 Jul 2005 16:44:47 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> Message-ID: <000d01c58dfa$612062e0$6601a8c0@pdimov> Mark Mitchell wrote: > That means that the most important question we should answer is what > to do for the program above, when the "throw;" is removed. > > I think the only reasonable choices are: > > 1) Fall off the end of the catch clause in the usual way, but the > thread is still cancelled. Encountering another cancellation point > will result in re-raising the cancellation exception. > > 2) Fall off the end of the catch clause in the usual way, but the > thread is no longer cancelled. It can be re-cancelled, but until it > is, it will operate normally. A real problem with the straightforward approach (2) is that cancellation requests can be lost. The thread that invokes pthread_cancel has no idea that the receiving thread has encountered an exception-eating catch block, so it doesn't know that it needs to retry the pthread_cancel call. This problem has motivated several (proposed or real) drastic modifications of (2), including banning catch without rethrow via std::terminate, not invoking catch(...) blocks at all, or banning catch without rethrow in a coding standard and loudly condemning its use in public forums. In my opinion, it is much easier and cleaner to just address the actual problem instead - deprecating or crippling catch(...) is not within the charter of the group. :-) In other words, we need to make sure that cancellation requests aren't lost easily. One additional detail is that under the POSIX rules, cancelability is disabled just before "stack unwinding" starts. Not a problem under pure POSIX C, because cancellation is impossible to finalize. A problem under both (1) or (2), though. Even under (1), where cancellation is sticky and the request isn't lost, encountering a cancellation point will not re-raise a cancellation exception, because cancelability is left disabled. Therefore, a useful model will at least have the following properties: A. cancellation is sticky, requests aren't lost easily; B. cancelability is not left disabled after a cancellation exception has been finalized. A simple solution is to adopt (1) and re-enable cancellation at the end of the catch clause. This solution is not without its merits and is actually a workable approximation of the "ideal" model, but it has the following problem: the proper value of the cancelability state after the exception is finalized may be "disabled". In the example below: // #1 try { f(); } catch( ... ) { } // #2 the cancelability state at #2 ought to be the same as the cancelability state at #1, provided that its only explicit manipulation is via a RAII guards that always restore it to its previous value. Remembering the state at the cancellation point doesn't work; it may've been asynchronous. It may even have been disabled if the cancellation exception originated from an explicit user throw. All this leads me to propose the following model: C. the cancelability state only changes if pthread_setcancelstate is invoked (deviation from POSIX which resets it at the throw point to deferred+disabled); D. to match POSIX semantics, cancellation points don't throw if there is an unfinished exception. (D) makes no distinction between cancellation exceptions and other exceptions for the following reasons: - every special case introduced into the core language will create more problems than it solves; - the point of cancellation is to initiate stack unwinding, and when an exception is active, stack unwinding is already under way; and - given std::unfinished_exception(), the semantics of cancellation are also implementable in user code or libraries and do not need compiler support. The last remaining issue is that (2) has one advantage over (1) - it enables the user to ignore a cancellation request. There are use cases that can take advantage of that - if you are interested I can go into more detail. But under the model described so far, a cancellation request is a bit too sticky; it's impossible to ignore. To address this, I propose that we provide an explicit API to clear a pending cancellation request... or at least specify it in case someone wants to revise his opinion on the irreversibility of cancellation. ;-) From gshiman at commvault.com Thu Jul 21 14:17:31 2005 From: gshiman at commvault.com (George Shimanovich) Date: Thu, 21 Jul 2005 10:17:31 -0400 Subject: FW: [c++-pthreads] Re: pthread_cancel and EH: let's try this again Message-ID: <52CA6BC0D0E9EE4E93208DB39A3218FEA4594A@EXCHANGE.gp.cv.commvault.com> Peter Dimov wrote: >But under the model described so far, a cancellation request is a bit too >sticky; it's impossible to ignore. > >To address this, I propose that we provide an explicit API to clear a >pending cancellation request... or at least specify it in case someone >wants >to revise his opinion on the irreversibility of cancellation. ;-) Exactly. The reason why some applications cannot rethrow caught cancellation exception (Linux/gcc) was that worker threads in typical thread pool implementation are reusable. Explicit call to clear pending cancellation request will allow cancelled worker thread to return to list of idle threads. George Shimanovich CommVault Systems From terekhov at web.de Thu Jul 21 15:11:52 2005 From: terekhov at web.de (Alexander Terekhov) Date: Thu, 21 Jul 2005 17:11:52 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> Message-ID: <42DFBB38.791F2DDC@web.de> Peter Dimov wrote: [...] > A simple solution is to adopt (1) and re-enable cancellation at the end of > the catch clause. > > This solution is not without its merits and is actually a workable > approximation of the "ideal" model, but it has the following problem: the > proper value of the cancelability state after the exception is finalized may > be "disabled". In the example below: > > // #1 > > try > { > f(); > } > catch( ... ) > { > } > > // #2 > > the cancelability state at #2 ought to be the same as the cancelability > state at #1, provided that its only explicit manipulation is via a RAII > guards that always restore it to its previous value. Let the user code do it. It's not that hard. // #1 int cancelstate = std::thread_cancelstate(); try { f(); } catch( ... ) { stick_cancel_and_ignore_exit(cancelstate); } // #2 with void stick_cancel_and_ignore_exit(int cancelstate) throw() { try { throw; } catch(const thread_termination_request & request) { if (cancelstate == PTHREAD_CANCEL_ENABLE) pthread_setcancelstate(cancelstate, &cancelstate); if (request.exit_value_ptr() == PTHREAD_CANCELED) pthread_cancel(pthread_self()); else ; // do whatever (if anything) so that it won't leak } catch(...) { } } > Remembering the state at the cancellation point doesn't work; it may've > been asynchronous. It may even have been disabled if the cancellation > exception originated from an explicit user throw. Such explicit user throw would violate the contract. It's sorta like insisting that some user's operator new(size_t, const std::nothrow_t &) shall be able to exit with std::bad_alloc from explicit user throw and all should work just fine. But anyway, see above. > - the point of cancellation is to initiate stack unwinding, and when an > exception is active, stack unwinding is already under way; That's not true under standard definition of stack unwinding. > > and > > - given std::unfinished_exception(), the semantics of cancellation are also > implementable in user code or libraries You mean wrapping all cancellation points and async-cancel regions with disable_cancel_if_uncaught_exception_returns_true guard; objects? Ugly. regards, alexander. From terekhov at web.de Thu Jul 21 15:22:47 2005 From: terekhov at web.de (Alexander Terekhov) Date: Thu, 21 Jul 2005 17:22:47 +0200 Subject: FW: Re: pthread_cancel and EH: let's try this again References: <52CA6BC0D0E9EE4E93208DB39A3218FEA4594A@EXCHANGE.gp.cv.commvault.com> Message-ID: <42DFBDC7.1582326D@web.de> George Shimanovich wrote: [...] > Exactly. The reason why some applications cannot rethrow caught > cancellation exception (Linux/gcc) was that worker threads in typical > thread pool implementation are reusable. Explicit call to clear pending > cancellation request will allow cancelled worker thread to return to > list of idle threads. #include // C++ extras void clear_pending_cancellation_request() { try { // it has throw(std::thread_cancel_request) ES std::pthread_testcancel(); } catch(...) { std::pthread_setcancelstate(PTHREAD_CANCEL_ENABLE); } } regards, alexander. From terekhov at web.de Thu Jul 21 15:49:42 2005 From: terekhov at web.de (Alexander Terekhov) Date: Thu, 21 Jul 2005 17:49:42 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> Message-ID: <42DFC416.ED79651@web.de> Peter Dimov wrote: [...] > D. to match POSIX semantics, cancellation points don't throw if there is an > unfinished exception. It actually breaks straight POSIX semantics. int main() { pthread_cancel(pthread_self()); try { throw 0; } catch(...) { pthread_testcancel(); } printf("Never reach this point under straight POSIX."); } This probably won't please Tru64 and OpenVMS folk. regards, alexander. From dave at boost-consulting.com Thu Jul 21 20:14:24 2005 From: dave at boost-consulting.com (David Abrahams) Date: Thu, 21 Jul 2005 16:14:24 -0400 Subject: [List Administration] GMane and X-No-Archive References: <42D6FAB8.6060901@codesourcery.com> Message-ID: David Abrahams writes: > Mark Mitchell writes: > >> David Abrahams wrote: >>> This mailing list is mirrored at >>> nttp://news.gmane.org/gmane.comp.lang.c++.pthreads >>> but, apparently because many of the messages had an X-No-Archive >>> header, they have been deleted from the server there. That makes it a >>> bit harder to browse the message history. I wonder if the list >>> administrator might like to send Lars an mbox of the message history >>> with the X-No-Archive headers stripped so that we can read everything >>> at GMane? >> >> I've copied Ricardo Anguiano, who is the list administrator. I have the >> feeling that we explicitly added the X-No-Archive header at some point, >> in response to some other request -- but I can't remember anything about >> why... > > Well, it seems to be gone again, thank goodness. Now I'm really concerned again, because messages from the "Restating the Jason Model" thread have started disappearing. I don't see any X-No-Archive headers in what's showing up on the list these days, but I'm no longer confident that that is why Gmane is disposing of them. -- Dave Abrahams Boost Consulting www.boost-consulting.com From pdimov at mmltd.net Fri Jul 22 21:50:41 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Sat, 23 Jul 2005 00:50:41 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> Message-ID: <008001c58f07$68b5b8d0$6501a8c0@pdimov2> Alexander Terekhov wrote: > Peter Dimov wrote: > [...] >> D. to match POSIX semantics, cancellation points don't throw if >> there is an unfinished exception. > > It actually breaks straight POSIX semantics. > > int main() { > pthread_cancel(pthread_self()); > try { throw 0; } catch(...) { pthread_testcancel(); } > printf("Never reach this point under straight POSIX."); > } Yes, it does change the behavior of such programs. I'm hoping that it doesn't break them, though, because it only delays the cancellation exception a while, and there is usually a race between the pthread_cancel and the pthread_testcancel in real code. > This probably won't please Tru64 and OpenVMS folk. The only way to find out is to implement these semantics and see what happens. From terekhov at web.de Sat Jul 23 13:53:56 2005 From: terekhov at web.de (Alexander Terekhov) Date: Sat, 23 Jul 2005 15:53:56 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> Message-ID: <42E24BF4.EE6513F9@web.de> Peter Dimov wrote: > > Alexander Terekhov wrote: > > Peter Dimov wrote: > > [...] > >> D. to match POSIX semantics, cancellation points don't throw if > >> there is an unfinished exception. > > > > It actually breaks straight POSIX semantics. > > > > int main() { > > pthread_cancel(pthread_self()); > > try { throw 0; } catch(...) { pthread_testcancel(); } > > printf("Never reach this point under straight POSIX."); > > } > > Yes, it does change the behavior of such programs. I'm hoping that it > doesn't break them, though, because it only delays the cancellation > exception a while, and there is usually a race between the pthread_cancel > and the pthread_testcancel in real code. Race or no race, there's nothing particularly unusual to have things like pthread_cond_wait() in the dynamic or static context of conventional catch. Your change may result in threads blocked forever. > > > This probably won't please Tru64 and OpenVMS folk. > > The only way to find out is to implement these semantics and see what > happens. I'd rather save the embarrassment. ;-) regards, alexander. From pdimov at mmltd.net Sat Jul 23 14:38:29 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Sat, 23 Jul 2005 17:38:29 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> Message-ID: <001501c58f94$35556d90$6501a8c0@pdimov2> Alexander Terekhov wrote: > Race or no race, there's nothing particularly unusual to have > things like pthread_cond_wait() in the dynamic or static context > of conventional catch. Your change may result in threads blocked > forever. Yes, I know. I don't insist on this particular model. I'm in favor of a family of models whose characteristic is no implicit cancel state manipulation and conditional cancel delivery. The actual condition can be "no unfinished exception", but it can also be "no uncaught exception", "no unfinished cancellation exception", and so on. Whichever works best and is acceptable to implementors. Simple heuristics such as "no unfinished exception" are obviously technically inferior to intelligent 2-phase query-based conditions with implicit throw() injections on destructors during unwinding, but they are much simpler to implement. From terekhov at web.de Sat Jul 23 18:11:34 2005 From: terekhov at web.de (Alexander Terekhov) Date: Sat, 23 Jul 2005 20:11:34 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> Message-ID: <42E28856.6C2377CE@web.de> Peter Dimov wrote: [...] > I don't insist on this particular model. I'm in favor of a family of models > whose characteristic is no implicit cancel state manipulation and > conditional cancel delivery. > > The actual condition can be "no unfinished exception", but it can also be > "no uncaught exception", "no unfinished cancellation exception", and so on. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ where the "finish" is manifested via enabling cancellation by the user code. > Whichever works best and is acceptable to implementors. > > Simple heuristics such as "no unfinished exception" are obviously > technically inferior to intelligent 2-phase query-based conditions with > implicit throw() injections on destructors during unwinding, but they are > much simpler to implement. FYI, POSIX wording about explicit manipulation of cancel state and cancel type on part of the implementation when it delivers cancellation or acts upon pthread_exit() (cancel type is not an issue in this case) was added to POSIX by the recent TC in response to http://opengroup.org/austin/mailarchives/austin-group-l/msg05202.html http://opengroup.org/austin/mailarchives/austin-review-l/msg01449.html http://opengroup.org/austin/mailarchives/austin-review-l/msg01450.html http://opengroup.org/austin/mailarchives/austin-review-l/msg01451.html The driving force behind the DRs was a realization that being a mere C (99) extension, POSIX just can't mandated EH query machinery of expected_exception<>. I do still believe that in absence of expected_exception<> machinery, it was a pretty good approximation for most (if not all) applications. The C++ (threaded) extension can do better, of course... but it's too late to "undo" POSIX 2004 TC2 (if coexistence matters), I'm afraid. regards, alexander. From pdimov at mmltd.net Sat Jul 23 18:30:34 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Sat, 23 Jul 2005 21:30:34 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> Message-ID: <001401c58fb4$9ff07b70$6501a8c0@pdimov2> Alexander Terekhov wrote: > Peter Dimov wrote: > [...] >> I don't insist on this particular model. I'm in favor of a family of >> models whose characteristic is no implicit cancel state manipulation >> and conditional cancel delivery. >> >> The actual condition can be "no unfinished exception", but it can >> also be "no uncaught exception", "no unfinished cancellation >> exception", and so on. > > where the "finish" is manifested via enabling cancellation by the user > code. But the problem is with existing user code that doesn't reenable cancellation. The cancellation exception is swallowed by the catch-all clause, the request is lost, and the cancel state remains disabled. As you can see, this leads to fixes that break catch(...) in a variety of creative ways. > http://opengroup.org/austin/mailarchives/austin-review-l/msg01450.html So it was _your_ idea. ;-) From terekhov at web.de Sat Jul 23 18:48:10 2005 From: terekhov at web.de (Alexander Terekhov) Date: Sat, 23 Jul 2005 20:48:10 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> <001401c58fb4$9ff07b70$6501a8c0@pdimov2> Message-ID: <42E290EA.29AD78D@web.de> Peter Dimov wrote: > > Alexander Terekhov wrote: > > Peter Dimov wrote: > > [...] > >> I don't insist on this particular model. I'm in favor of a family of > >> models whose characteristic is no implicit cancel state manipulation > >> and conditional cancel delivery. > >> > >> The actual condition can be "no unfinished exception", but it can > >> also be "no uncaught exception", "no unfinished cancellation > >> exception", and so on. > > > > where the "finish" is manifested via enabling cancellation by the user > > code. > > But the problem is with existing user code that doesn't reenable > cancellation. That's either a bug or a feature of "existing user code". Make it cancel-aware. Complain about lack of portable C++ exception type identity for cancellation exception so that it can be distinguished from other exceptions (when you can catch multiple). > The cancellation exception is swallowed by the catch-all > clause, the request is lost, and the cancel state remains disabled. See above. > > As you can see, this leads to fixes that break catch(...) in a variety of > creative ways. > > > http://opengroup.org/austin/mailarchives/austin-review-l/msg01450.html > > So it was _your_ idea. ;-) It did came to my mind... but its was Butenhof who authored the patch: http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05916.html http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05987.html http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05989.html ;-) regards, alexander. From pdimov at mmltd.net Sat Jul 23 19:08:16 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Sat, 23 Jul 2005 22:08:16 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> <001401c58fb4$9ff07b70$6501a8c0@pdimov2> <42E290EA.29AD78D@web.de> Message-ID: <003c01c58fb9$e34181d0$6501a8c0@pdimov2> Alexander Terekhov wrote: > Peter Dimov wrote: >> But the problem is with existing user code that doesn't reenable >> cancellation. > > That's either a bug or a feature of "existing user code". Make it > cancel-aware. Complain about lack of portable C++ exception type > identity for cancellation exception so that it can be distinguished > from other exceptions (when you can catch multiple). > >> The cancellation exception is swallowed by the >> catch-all clause, the request is lost, and the cancel state remains >> disabled. > > See above. What happens in practice is not people making their code cancel-aware, it's either implementations breaking catch(...), coding standards banning catch(...), or both. (Such a coding standard makes perfect sense under such an implementation, of course.) It boils down to this. The implementation of pthread_testcancel is: if( request pending && cancelstate == ENABLE ) { set cancelstate to DISABLE clear request throw pthread_cancel_exception } but I think that a better alternative is: if( request pending && cancelstate == ENABLE && not suppressed ) { suppress cancellation throw pthread_cancel_exception } with some kind of automatic un-suppression when the exception is finalized. The implementation may even have a separate "suppressed" flag and clear it at the point where the current GCC calls terminate. Or the suppression flag may be inferred from the current EH state in some way. Ironically, this implementation was rendered invalid by the resolution of your DR. From terekhov at web.de Sat Jul 23 19:26:25 2005 From: terekhov at web.de (Alexander Terekhov) Date: Sat, 23 Jul 2005 21:26:25 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> <001401c58fb4$9ff07b70$6501a8c0@pdimov2> <42E290EA.29AD78D@web.de> <003c01c58fb9$e34181d0$6501a8c0@pdimov2> Message-ID: <42E299E1.8E141015@web.de> Peter Dimov wrote: [...] > It boils down to this. The implementation of pthread_testcancel is: > > if( request pending && cancelstate == ENABLE ) > { > set cancelstate to DISABLE > clear request > throw pthread_cancel_exception > } > > but I think that a better alternative is: > > if( request pending && cancelstate == ENABLE && not suppressed ) > { > suppress cancellation > throw pthread_cancel_exception > } > > with some kind of automatic un-suppression when the exception is finalized. > The implementation may even have a separate "suppressed" flag and clear it > at the point where the current GCC calls terminate. Or the suppression flag > may be inferred from the current EH state in some way. > > Ironically, this implementation was rendered invalid by the resolution of > your DR. Yup. But That's because the only thing related to "suppress" *in POSIX* is the thread cancel state. Blame Stroustrup & Co. behind C/C++ split, not me. With undefined (and not exposed) "suppressed", POSIX was clearly defective with respect to thread cancel. You were taking about "unfinished_exception()"... well, good luck at trying to get it through http://www.opengroup.org/austin. regards, alexander. From wil at bogo.xs4all.nl Sat Jul 23 20:23:02 2005 From: wil at bogo.xs4all.nl (Wil Evers) Date: Sat, 23 Jul 2005 22:23:02 +0200 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DEC939.53B3E28@web.de> References: <42D83CA3.8080600@bogo.xs4all.nl> <42D83F6A.3010709@codesourcery.com> <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <42DEC939.53B3E28@web.de> Message-ID: <42E2A726.503@bogo.xs4all.nl> Alexander Terekhov wrote: >>* Cancellation is sticky: it causes an irreversible state change in the >>target thread; subsequent cancellations have no further effect. > > Stickiness can be achieved by the user code. By mandating stickiness, > you don't really solve any problems. Note that mandated stickiness > would inhibit various useful things such as reuse of threads in a > thread pool executor without recycling after cancellation of a > "task"/"future" by means of thread cancellation. Not sure about this one. I can think of two ways of achieving stickiness through user code: (*) Have the destructor of the cancellation exception re-cancel the current thread. The problem with this is that the user has no real choice here - in your example, it would imply that the threads in the thread pool cannot be recycled. (*) Have the user code re-cancel the current thread when a cancellation exception is caught and finalized. The problem with this is that it requires the user to explicitly catch a cancellation exception by name. It won't happen if the cancellation exception is finalized in a 'catch (...)' block; instead, the cancellation request will go unnoticed. [snip] >>* A thread's cancellation state is only affected by calls to >>pthread_setcancelstate() originating from user code. > > Intelligent cancel delivery aside for a moment, POSIX states: > > "When a cancellation request is acted upon, or when a thread calls > pthread_exit(), the thread first disables cancellation by setting > its cancelability state to PTHREAD_CANCEL_DISABLE and its > cancelability type to PTHREAD_CANCEL_DEFERRED." Yes, this is incompatible with the rule I stated above. Damn. Not sure how serious it is, though. Under the design I suggested, the first thing a thread's user code would do is disable cancellation, only to re-enable it for selected regions of code. I would expect any exception finalization to take place *outside* of those regions; therefore, if the thread continues to run, cancellation will necessarily have been re-enabled before the user code hits another intended cancellation point. So it seems that, for the sake of POSIX compatibility, the rule I stated above can be dropped without risking unintended suppression of cancellation requests. - Wil From david.butenhof at hp.com Sat Jul 23 23:51:29 2005 From: david.butenhof at hp.com (Dave Butenhof) Date: Sat, 23 Jul 2005 19:51:29 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42D91034.555BA7F2@web.de> References: <42D2ECF8.3000303@codesourcery.com> <20050711225235.GO4884@devserv.devel.redhat.com> <42D53332.17B76749@web.de> <42D54C14.4090505@hp.com> <42D79C99.6050709@hp.com> <42D7BEDF.2020004@hp.com> <42D84BBC.7060504@hp.com> <42D91034.555BA7F2@web.de> Message-ID: <42E2D801.1030000@hp.com> Alexander Terekhov wrote: >> (only). If caught anonymously, they must be re-thrown. >> >> >This "compromise" makes no sense. > > Of course it "makes sense" -- you just don't agree. You're correct that in your specific contrived example, "catch only cancel" and "catch anything in a context where there can be nothing but cancel in the first place" end up the same; however that's a very specific counterexample. In the general case, there's no way to be sure the author knows that "catch(...)" is semantically equivalent to "catch(thread_cancel_request const &)" -- and even when the compiler and runtime could know, I'd rather not have it making special cases like that. For example, change the context to allow a second exception, and now the catch(...) is ambiguous. But this is also an example of my quandary in this discussion, and why I've often tried to stay quiet. I don't want to be here as a C++ consultant -- I don't qualify in that respect. I'm trying to help out as a thread semantics consultant, because I do have a lot to offer in that respect. I really don't want to get into arguing the details of C++ syntax and semantics; just the general mechanisms and rules of interaction at the interface between "language" and "threads". It's a tenuous boundary that's often difficult to chart, to be sure; but I think you're trying to pull me over the line and I'd rather resist. ;-) I've just returned from a week vacation, including a fairly nasty thunderstorm our last night that left the camp without power and with a lot of downed trees and such. It was probably foolish to even connect to my work email today, but I did, and I'm faced with what appears at a quick scan to be on the order of 100 messages in this discussion. Ouch. I've done my token declaration of return by taking Alexander's isolated response to my message, but I'm not going to even approach the others until I've gotten back "into the swing" next week. -------------- next part -------------- A non-text attachment was scrubbed... Name: david.butenhof.vcf Type: text/x-vcard Size: 476 bytes Desc: not available URL: From ncm at codesourcery.com Sun Jul 24 07:17:42 2005 From: ncm at codesourcery.com (Nathan (Jasper) Myers) Date: Sun, 24 Jul 2005 00:17:42 -0700 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42DF8BFA.28B4D78B@web.de> References: <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <20050721015017.GA3634@codesourcery.com> <42DF01C3.80904@codesourcery.com> <20050721062537.GA2266@codesourcery.com> <42DF8BFA.28B4D78B@web.de> Message-ID: <20050724071742.GA8327@codesourcery.com> On Thu, Jul 21, 2005 at 01:50:18PM +0200, Alexander Terekhov wrote: > > "Nathan (Jasper) Myers" wrote: > [...] > > If we don't rescue the libraries > > That's not what you're after. You want magically turn cancel-unaware > stuff into cancel-safe. That's impossible. It's trivially possible, and it's hardly magic. All it needs is to accept that what POSIX attendees decided for C based on essentially no understanding of exceptions, is not the only way to do things. However, the only (other) people still posting here appear to be those who long since gave up on making thread cancelling work in real-world programs. Whatever you guys come up with, if anything, will affect perhaps a few dozen people in all the world. Vendors, mostly. The rest of us will return to understanding that thread cancellation doesn't and won't work usably in real programs, and forget about it -- just as practically everybody coding C did long ago. Given that, the best you can do here is to specify something truly trivial to implement (even for vendors who haven't implemented C cancellation), so that vendors can mark their checkboxes, and then forget about it too. Nathan Myers ncm at codesourcery.com From pdimov at mmltd.net Sun Jul 24 12:20:45 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Sun, 24 Jul 2005 15:20:45 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <20050721015017.GA3634@codesourcery.com> <42DF01C3.80904@codesourcery.com> <20050721062537.GA2266@codesourcery.com> <42DF8BFA.28B4D78B@web.de> <20050724071742.GA8327@codesourcery.com> Message-ID: <001301c5904a$2143d380$6501a8c0@pdimov2> Nathan (Jasper) Myers wrote: > The rest of us will return to understanding that thread cancellation > doesn't and won't work usably in real programs, and forget about it > -- just as practically everybody coding C did long ago. Do you have a reference for that? If true, this would be a strong argument in support of your position. From david.butenhof at hp.com Tue Jul 26 13:04:14 2005 From: david.butenhof at hp.com (Dave Butenhof) Date: Tue, 26 Jul 2005 09:04:14 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <42E290EA.29AD78D@web.de> References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> <001401c58fb4$9ff07b70$6501a8c0@pdimov2> <42E290EA.29AD78D@web.de> Message-ID: <42E634CE.2010705@hp.com> Alexander Terekhov wrote: >>As you can see, this leads to fixes that break catch(...) in a variety of >>creative ways. >> >> Yes; and of course the basic issue is that in POSIX (and C99) there's nothing vaguely equivalent to "catch(...)"; and therefore no way the standard can address this. >>>http://opengroup.org/austin/mailarchives/austin-review-l/msg01450.html >>> >>> >>So it was _your_ idea. ;-) >> >> >It did came to my mind... but its was Butenhof who authored the patch: > >http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05916.html >http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05987.html >http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05989.html > > Alexander pointed out a problem in the "C Language binding to POSIX API", and I suggested a fix for that problem also in the context of that standard... the only context that was relevant. Perhaps needless to say, I never thought that was ideal. There's just no way to express "ideal" without adding exceptions. POSIX made the decision that it wasn't remotely "in scope" to try to add "POSIX exceptions"; that this needed to be done by ISO C. POSIX cleanup (cancel and thread exit) cannot be finalized -- cleanup handlers are like Ada/Modula "finally" or C++ destructors, not like "catch" -- they cleanup, the return, and the unwind continues irrevokably until the call stack is empty and the thread terminates. What was important, and relevant, was to make the cleanup handlers (and TSD destructors) reliable by specifying the state of cancellation. The original INTENT of the working group had been that cancellation was disabled implicitly by delivery, and most code is written presuming that state. Making all cleanup handlers and destructors that don't explicitly disable cancel suddenly "non-conforming" wouldn't have been a particularly useful amendment. (And it would also have been silly because all code a conforming application can run in the thread before termination ought to be non-cancellable as it's doing nothing but termination cleanup.) As has been implied here, in my implementation, cancel re-enable, in the event that something outside "standard POSIX C" finalizes a cancel unwind, is the responsibility of the caller. That is, a C program that explicitly catches pthread_cancel_e, or identifies a CATCH_ALL exception as pthread_cancel_e, should itself enable cancellation if it wants the thread to become cancellable. A C++ binding could certainly choose to make that implicit, perhaps as part of the exception destructor. That the current implementation on Tru64 and OpenVMS doesn't do this is irrelevant to any future standardization. (Tru64 is being strangled to death along with Alpha, while OpenVMS never pretended to any more than a reasonable level of "convenience conformance" to POSIX or other UNIX-based standards anyway. That's not why people buy OpenVMS.) -------------- next part -------------- A non-text attachment was scrubbed... Name: david.butenhof.vcf Type: text/x-vcard Size: 476 bytes Desc: not available URL: From dave at boost-consulting.com Tue Jul 26 13:36:41 2005 From: dave at boost-consulting.com (David Abrahams) Date: Tue, 26 Jul 2005 09:36:41 -0400 Subject: I'm Lost Message-ID: I got lost in this discussion a week or two ago, but my sense is that not much progress is being made because we are getting stuck in details. I think we have to try to deal with some large principles of importance to the various participants. For example, it's important to me that Otherwise-correct C++ code not written to explicitly deal with cancellation should have a good chance of remaining correct in a POSIX environment with cancellation exceptions However, it may yet be possible to convince me to give that one up. I think it's important to sort out the big principles and then weed out any major incompatibilities among them, prioritize if necessary, and when all that's done, think about how (or if) they can be implemented. Of course, maybe you guys are all going like gangbusters and I'm just too stupid to keep up. If so, please forge on ahead without me! -- Dave Abrahams Boost Consulting www.boost-consulting.com From wil at bogo.xs4all.nl Tue Jul 26 21:19:56 2005 From: wil at bogo.xs4all.nl (Wil Evers) Date: Tue, 26 Jul 2005 23:19:56 +0200 Subject: [c++-pthreads] I'm Lost In-Reply-To: References: Message-ID: <42E6A8FC.7050708@bogo.xs4all.nl> David Abrahams wrote: > For example, it's important to me that > > Otherwise-correct C++ code not written to explicitly deal with > cancellation should have a good chance of remaining correct in a > POSIX environment with cancellation exceptions > > However, it may yet be possible to convince me to give that one up. The problem is not to convince you. The problem is to convince the otherwise-correct C++ code to behave like it used to. > I think it's important to sort out the big principles and then weed out > any major incompatibilities among them, prioritize if necessary, and > when all that's done, think about how (or if) they can be implemented. I'd say it's time to face the truth, which is that POSIX cancellation semantics are incompatible with commonly established C++ coding practices. As you may have noticed, my preferred solution is to selectively apply POSIX cancellation to small regions of code specifically written with cancellation in mind. > Of course, maybe you guys are all going like gangbusters and I'm just > too stupid to keep up. I doubt that :-). > If so, please forge on ahead without me! That doesn't sound like a good idea at all. - Wil From terekhov at web.de Wed Jul 27 11:31:43 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 27 Jul 2005 13:31:43 +0200 Subject: I'm Lost References: <42E6A8FC.7050708@bogo.xs4all.nl> Message-ID: <42E7709F.AE07F97A@web.de> Wil Evers wrote: [...] > I'd say it's time to face the truth, which is that POSIX cancellation > semantics are incompatible with commonly established C++ coding > practices. It's incompatible with cancel-unaware C++ code. Note that it's incompatible with cancel-unaware C code as well, but that didn't stop POSIX and ongoing creation of cancel-safe code in both C and C++ languages. Very many tons of cancel-safe code. regards, alexander. From david.butenhof at hp.com Wed Jul 27 13:07:25 2005 From: david.butenhof at hp.com (Dave Butenhof) Date: Wed, 27 Jul 2005 09:07:25 -0400 Subject: [c++-pthreads] Re: I'm Lost In-Reply-To: <42E7709F.AE07F97A@web.de> References: <42E6A8FC.7050708@bogo.xs4all.nl> <42E7709F.AE07F97A@web.de> Message-ID: <42E7870D.70407@hp.com> Alexander Terekhov wrote: >Wil Evers wrote: >[...] > > >>I'd say it's time to face the truth, which is that POSIX cancellation >>semantics are incompatible with commonly established C++ coding >>practices. >> >> >It's incompatible with cancel-unaware C++ code. Note that it's >incompatible with cancel-unaware C code as well, but that didn't >stop POSIX and ongoing creation of cancel-safe code in both C >and C++ languages. Very many tons of cancel-safe code. > > Indeed. The only real (and unfortunately the hardest) questions are how to reconcile the (apparent) contradictions between cancel scope and C++ throw specs (explicit or implicit as in destructors), and cultural investment in catch(...). Perhaps integration would be simplified if threads created using native C++ mechanisms (rather than the C pthread_create) started with cancellation disabled, allowing C++ programs to enable where desired. Then again, though, it's important to keep in mind that a thread is not subject to cancellation unless some thread with access to the thread ID CHOOSES to cancel it; nobody can force cancellation on a thread without its ID, and thread IDs are not generally available. And while any routine can cancel the current thread (pthread_self), doing this without certain knowledge that the thread's call stack can handle it is a pretty stupid programming error. Cancellation is not like 'kill ', forced arbitrarily from outside forces unknown; it's a COOPERATIVE request from friendly code. Only code running inside the thread, or code that closely collaborates with the creation or management of the thread (by prior agreement) can ever cancel a thread. And the C++ committee could define C++ threading without cancellation; I think that would be a mistake in the real world, and I know many others will, but the committee need not care. However, if C++ has cancellation it has to be cleanly integrated with C/POSIX cancel and cleanup, and the only viable language/implementation model is to make cancel an exception. -------------- next part -------------- A non-text attachment was scrubbed... Name: david.butenhof.vcf Type: text/x-vcard Size: 476 bytes Desc: not available URL: From terekhov at web.de Wed Jul 27 13:59:41 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 27 Jul 2005 15:59:41 +0200 Subject: I'm Lost References: <42E6A8FC.7050708@bogo.xs4all.nl> <42E7709F.AE07F97A@web.de> <42E7870D.70407@hp.com> Message-ID: <42E7934D.59F3F1FD@web.de> Dave Butenhof wrote: [...] > Indeed. The only real (and unfortunately the hardest) questions are how > to reconcile the (apparent) contradictions between cancel scope and C++ > throw specs (explicit or implicit as in destructors), Fix ES (get rid of ugly implicit catch(...) semantics and totally idiotic transfer of terminate()/unexpected() handlers up-stack along with unexpected exception), mandate 2-phase EH and intelligent cancel delivery. http://groups.google.de/group/comp.lang.c++.moderated/msg/c897f898de7a97cd > and cultural > investment in catch(...). Invest in weak_catch(). > > Perhaps integration would be simplified if threads created using native > C++ mechanisms (rather than the C pthread_create) started with > cancellation disabled, allowing C++ programs to enable where desired. That would go against the premise of POSIX's modulary argument http://www.codesourcery.com/archives/c++-pthreads/msg00419.html and would not really solve any problems. http://www.codesourcery.com/archives/c++-pthreads/msg00425.html http://www.codesourcery.com/archives/c++-pthreads/msg00445.html regards, alexander. From pdimov at mmltd.net Wed Jul 27 14:28:11 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Wed, 27 Jul 2005 17:28:11 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> <001401c58fb4$9ff07b70$6501a8c0@pdimov2> <42E290EA.29AD78D@web.de> <42E634CE.2010705@hp.com> Message-ID: <002c01c592b7$6bd37da0$6501a8c0@pdimov2> Dave Butenhof wrote: > What was important, and relevant, was to make the cleanup handlers > (and TSD destructors) reliable by specifying the state of > cancellation. The original INTENT of the working group had been that > cancellation was disabled implicitly by delivery, and most code is > written presuming that state. Making all cleanup handlers and > destructors that don't explicitly disable cancel suddenly > "non-conforming" wouldn't have been a particularly useful amendment. Nobody's arguing against that. The point is that the clarification made it mandatory to implement these semantics via the equivalent of issuing a pthread_setcancelstate call at the cancellation point. Before that, an implementation that used a separate "cleanup mode" flag (which has the advantage of not interfering with the client's cancelstate calls) was conforming. This was good, because - in my current opinion - this model makes more sense if the cleanup is allowed to not complete, as is the case in C++. It's certainly questionable whether a cleanup handler (TSD destructor) that explicitly enables cancellation and calls a cancellation point should re-cancel itself... and if it does, whether it should re-invoke itself, so it might be argued that this clarification introduced a new problem instead of fixing the old. From pdimov at mmltd.net Wed Jul 27 14:45:32 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Wed, 27 Jul 2005 17:45:32 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> <001401c58fb4$9ff07b70$6501a8c0@pdimov2> <42E290EA.29AD78D@web.de> <42E634CE.2010705@hp.com> <002c01c592b7$6bd37da0$6501a8c0@pdimov2> Message-ID: <003901c592b9$d9c10d80$6501a8c0@pdimov2> Peter Dimov wrote: > It's certainly questionable whether a cleanup handler (TSD > destructor) that explicitly enables cancellation and calls a > cancellation point should re-cancel itself... and if it does, whether > it should re-invoke itself, so it might be argued that this > clarification introduced a new problem instead of fixing the old. Scratch that, if this: "The cancelability state shall remain set to PTHREAD_CANCEL_DISABLE until the thread has terminated. The behavior is undefined if a cancellation cleanup handler or thread-specific data destructor routine changes the cancelability state to PTHREAD_CANCEL_ENABLE." made it into the TC, it specifically prohibits the scenario I described. It also appears to prohibit enabling cancellation after catch(pthread_cancel_e) without rethrow, effectively disallowing catch without rethrow ("shall remain set to..."). int pthread_cancelenabled(void); RETURN VALUE Nonzero if the current thread's cancelability state is PTHREAD_CANCEL_ENABLE and the call is not made from within a cleanup handler or a TSD destructor, zero otherwise. could have been much simpler. From terekhov at web.de Wed Jul 27 14:57:17 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 27 Jul 2005 16:57:17 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> <001401c58fb4$9ff07b70$6501a8c0@pdimov2> <42E290EA.29AD78D@web.de> <42E634CE.2010705@hp.com> <002c01c592b7$6bd37da0$6501a8c0@pdimov2> Message-ID: <42E7A0CD.C81B2856@web.de> Peter Dimov wrote: [...] > Before that, an implementation that used a separate "cleanup mode" flag > (which has the advantage of not interfering with the client's cancelstate > calls) was conforming. Nope. Because http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html#tag_02_09_05_01 says nothing about "separate cleanup mode flag" and hence per XSH 2.9.5, http://opengroup.org/austin/mailarchives/austin-review-l/msg01450.html can be written as .... int state; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); if (PTHREAD_CANCEL_ENABLE == state) { pthread_setcancelstate(state, &state); pthread_cancel(pthread_self()); pthread_testcancel(); errno = ECANCELED; perror("NON-CONFORMING IMPLEMENTATION"); abort(); } .... that's apart from .... int state; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); if (PTHREAD_CANCEL_ENABLE == state) { pthread_setcancelstate(state, &state); // Uh... //pthread_cancel(pthread_self()); //pthread_testcancel(); pthread_exit(PTHREAD_CANCELED); } .... Of course, the "real" fix would be introduction of int pthread_expectedcancel() incapsulating expected_exception() query and cancel state check. .... if (pthread_expectedcancel()) { pthread_cancel(pthread_self()); pthread_testcancel(); errno = ECANCELED; perror("IMPLEMNATION BUG"); abort(); } .... .... if (pthread_expectedcancel()) { pthread_exit(PTHREAD_CANCELED); } .... but without (2-phase) EH machinery, POSIX just can't do that. regards, alexander. From terekhov at web.de Wed Jul 27 15:04:21 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 27 Jul 2005 17:04:21 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> <001401c58fb4$9ff07b70$6501a8c0@pdimov2> <42E290EA.29AD78D@web.de> <42E634CE.2010705@hp.com> <002c01c592b7$6bd37da0$6501a8c0@pdimov2> <003901c592b9$d9c10d80$6501a8c0@pdimov2> Message-ID: <42E7A275.752FDEC1@web.de> Peter Dimov wrote: [...] > "The cancelability state shall remain set to PTHREAD_CANCEL_DISABLE until > the thread has terminated. The behavior is undefined if a cancellation > cleanup handler or thread-specific data destructor routine changes the > cancelability state to PTHREAD_CANCEL_ENABLE." > > made it into the TC, it specifically prohibits the scenario I described. Well, see http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05987.html http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05988.html http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05989.html http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05989.html regards, alexander. From terekhov at web.de Wed Jul 27 15:16:24 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 27 Jul 2005 17:16:24 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> <001401c58fb4$9ff07b70$6501a8c0@pdimov2> <42E290EA.29AD78D@web.de> <42E634CE.2010705@hp.com> <002c01c592b7$6bd37da0$6501a8c0@pdimov2> <003901c592b9$d9c10d80$6501a8c0@pdimov2> Message-ID: <42E7A548.B50C302B@web.de> Peter Dimov wrote: [...] > int pthread_cancelenabled(void); > > RETURN VALUE > > Nonzero if the current thread's cancelability state is PTHREAD_CANCEL_ENABLE > and the call is not made from within a cleanup handler or a TSD destructor, ^^^^^^^^^^^^^^^^^^^^^^^^ > zero otherwise. > > could have been much simpler. With cancel request pending, mandatory cancel points are required to throw within a cleanup handler invoked by pthread_cleanup_pop() ["(if /execute/ is non-zero)"] when cancel state is PTHREAD_CANCEL_ENABLE. regards, alexander. From pdimov at mmltd.net Wed Jul 27 15:13:17 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Wed, 27 Jul 2005 18:13:17 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> <001401c58fb4$9ff07b70$6501a8c0@pdimov2> <42E290EA.29AD78D@web.de> <42E634CE.2010705@hp.com> <002c01c592b7$6bd37da0$6501a8c0@pdimov2> <003901c592b9$d9c10d80$6501a8c0@pdimov2> <42E7A275.752FDEC1@web.de> Message-ID: <005601c592bd$d0eec3b0$6501a8c0@pdimov2> Alexander Terekhov wrote: > Peter Dimov wrote: > [...] >> "The cancelability state shall remain set to PTHREAD_CANCEL_DISABLE >> until the thread has terminated. The behavior is undefined if a >> cancellation cleanup handler or thread-specific data destructor >> routine changes the cancelability state to PTHREAD_CANCEL_ENABLE." >> >> made it into the TC, it specifically prohibits the scenario I >> described. > > Well, see > > http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05987.html Yep, it seems you beat me to it. "To me, these bits are somewhat biased toward "don't catch-and- finalize pthread_cancel_e exception" (pthread_exit_e aside for a moment) and sort of "justifies" {current-}NTPL-like "forced unwinding" silliness. I'm kinda surprised. I'd feel much better if the final version would simply OMIT these bits... or, idealy try to explain it in a way as close as possible to "the truth" with catchable/finalizable exceptions and throw()-nothing dtors (for cleanup handlers and thread-specific data destructor routines). Oder?" From terekhov at web.de Wed Jul 27 15:17:49 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 27 Jul 2005 17:17:49 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> <001401c58fb4$9ff07b70$6501a8c0@pdimov2> <42E290EA.29AD78D@web.de> <42E634CE.2010705@hp.com> <002c01c592b7$6bd37da0$6501a8c0@pdimov2> <003901c592b9$d9c10d80$6501a8c0@pdimov2> <42E7A275.752FDEC1@web.de> Message-ID: <42E7A59D.D37538DE@web.de> Alexander Terekhov wrote: [...] > http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05987.html > http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05988.html > http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05989.html > http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05989.html Err. http://www.opengroup.org/austin/mailarchives/austin-group-l/msg05990.html regards, alexander. From david.butenhof at hp.com Wed Jul 27 15:35:00 2005 From: david.butenhof at hp.com (Dave Butenhof) Date: Wed, 27 Jul 2005 11:35:00 -0400 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again In-Reply-To: <003901c592b9$d9c10d80$6501a8c0@pdimov2> References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> <001401c58fb4$9ff07b70$6501a8c0@pdimov2> <42E290EA.29AD78D@web.de> <42E634CE.2010705@hp.com> <002c01c592b7$6bd37da0$6501a8c0@pdimov2> <003901c592b9$d9c10d80$6501a8c0@pdimov2> Message-ID: <42E7A9A4.8080702@hp.com> Peter Dimov wrote: > Peter Dimov wrote: > >> It's certainly questionable whether a cleanup handler (TSD >> destructor) that explicitly enables cancellation and calls a >> cancellation point should re-cancel itself... and if it does, whether >> it should re-invoke itself, so it might be argued that this >> clarification introduced a new problem instead of fixing the old. > > Scratch that, if this: > > "The cancelability state shall remain set to PTHREAD_CANCEL_DISABLE > until the thread has terminated. The behavior is undefined if a > cancellation cleanup handler or thread-specific data destructor > routine changes the cancelability state to PTHREAD_CANCEL_ENABLE." > > made it into the TC, it specifically prohibits the scenario I > described. It also appears to prohibit enabling cancellation after > catch(pthread_cancel_e) without rethrow, effectively disallowing catch > without rethrow ("shall remain set to..."). That's an intrinsic requirement of the C binding to POSIX; there's no catch, only cleanup handlers which implicitly and irrevokably "rethrow". (And aren't allowed to interfere in any way with the unwind.) It's not just cleanup handlers that need cancel disabled, but also TSD destructors, which run only when the thread has been fully unwound. We can't say "if", because in POSIX there's no if... the thread IS fully unwound, and TSD destructors DO run; but concession to a catchable cancel in some other language binding would mean breaking those scopes in two... possible, yes; but more complicated and pretty hard to justify in the current standards environment that's C-only and exception-phobic. -------------- next part -------------- A non-text attachment was scrubbed... Name: david.butenhof.vcf Type: text/x-vcard Size: 476 bytes Desc: not available URL: From terekhov at web.de Wed Jul 27 17:38:44 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 27 Jul 2005 19:38:44 +0200 Subject: FW: RE: [c++-pthreads] Re: I'm Lost Message-ID: <87219549@web.de> < Foward Quoted > "Meredith, Alisdair" schrieb am 27.07.05 13:59:12: > > [Sorry for personal email, I seem to have lost my list subscription - could you forward this onto the main list too please?] > > The problem as I see it is that we have 2 distinct communities of programmers, with a small intersection - Posix thread users and C++ users. > > The C++ community addresses a wide variety of problem domains and deals with many users who never need Posix cancellation - indeed may never run on any Posix system. > > Likewise, many Posix threaders may code in C or other posix-friendly lanuages without worrying about C++. The posix-cancellation rules were developed for this set of customers. > > C++ has very clear resource acquisition/release semantics through object construction/destruction that apply across its broad spectrum of users. This is a fundamental, invioble rule of the language. > > What I am reading here is that this large group of users now need to be aware of some quite complicated posix-specific semantics to understand when and why their guarantees will not hold, and learn some as-yet unclear new fundamental technique to wrap resources in any 'portable' code they wish to publish. > > Quite simply, I believe that is far too great a burden for the casual C++ user. They are already struggling under the burden of a complicated language without us expecting them to understand intricacies of thread safety and lifetimes. > > The people actively working in the posix/C++ subset are much more familiar with these complex issues, and I believe the burden is on them to find a compromise that will not impact on the non-expert user who is NOT using this combination. I do not pretend this is an easy task though ;?) > > AlisdairM > [going back to lurk mode] > > > -----Original Message----- > > From: news [mailto:news at sea.gmane.org] On Behalf Of Alexander Terekhov > > Sent: Wednesday 27 July 2005 12:32 > > To: c++-pthreads at codesourcery.com > > Subject: [c++-pthreads] Re: I'm Lost > > > > > > Wil Evers wrote: > > [...] > > > I'd say it's time to face the truth, which is that POSIX cancellation > > > semantics are incompatible with commonly established C++ coding > > > practices. > > > > It's incompatible with cancel-unaware C++ code. Note that it's > > incompatible with cancel-unaware C code as well, but that didn't > > stop POSIX and ongoing creation of cancel-safe code in both C > > and C++ languages. Very many tons of cancel-safe code. > > > > regards, > > alexander. > --------------------------------------------------------------------- > > For further information on Renault F1 visit our web site at www.renaultf1.com. > > WARNING: please ensure that you have adequate virus protection in place before you open or detach any documents attached to this email. > > This e-mail may constitute privileged information. If you are not the intended recipient, you have received this confidential email and any attachments transmitted with it in error and you must not disclose, copy, circulate or in any other way use or rely on this information. > > E-mails to and from the Renault F1 Team are monitored for operational reasons and in accordance with lawful business practices. > > The contents of this email are those of the individual and do not necessarily represent the views of the company. > > Please note that this e-mail has been created in the knowledge that Internet e-mail is not a 100% secure communications medium. We advise that you understand and observe this lack of security when e-mailing us. > > If you have received this email in error please forward to: is.helpdesk at uk.renaultf1.com quoting the sender, then delete the message and any attached documents > --------------------------------------------------------------------- _________________________________________________________________________ Mit der Gruppen-SMS von WEB.DE FreeMail k?nnen Sie eine SMS an alle Freunde gleichzeitig schicken: http://freemail.web.de/features/?mc=021179 From kevlin at curbralan.com Wed Jul 27 17:37:01 2005 From: kevlin at curbralan.com (Kevlin Henney) Date: Wed, 27 Jul 2005 19:37:01 +0200 Subject: [c++-pthreads] Re: I'm Lost In-Reply-To: <42E7709F.AE07F97A@web.de> References: <42E6A8FC.7050708@bogo.xs4all.nl> <42E7709F.AE07F97A@web.de> Message-ID: <6wBozHb9Y85CFw+r@curbralan.com> In message <42E7709F.AE07F97A at web.de>, Alexander Terekhov writes > >Wil Evers wrote: >[...] >> I'd say it's time to face the truth, which is that POSIX cancellation >> semantics are incompatible with commonly established C++ coding >> practices. > >It's incompatible with cancel-unaware C++ code. Note that it's >incompatible with cancel-unaware C code as well, but that didn't >stop POSIX and ongoing creation of cancel-safe code in both C >and C++ languages. Very many tons of cancel-safe code. To the best of my knowledge there have been zero lines of cancel-safe C++ code written against the C++ binding of POSIX threads. Of course, C and C++ have an intimate relationship, but that does not mean to say that they are the same or that C++ must slavishly follow the same model that C has decided on. There is a question of interoperability, but that is not the same as portability. The discussion so far seems to have taken the latter view, which is subtly different. If the C++ binding chooses to throw exceptions for cancellation, no C++ code will be broken by silent changes. Code written in C++ that is correct against the C binding will continue to be correct against that binding. But should the program be modified to take advantage of a C++ binding, that guarantee no longer holds. However, this is unsurprising and is to be expected of any migration between APIs. Of course, it makes sense to minimise gratuitous differences, but minimal difference is not the same as no difference. Kevlin -- ____________________________________________________________ Kevlin Henney phone: +44 117 942 2990 mailto:kevlin at curbralan.com mobile: +44 7801 073 508 http://www.curbralan.com fax: +44 870 052 2289 Curbralan: Consultancy + Training + Development + Review ____________________________________________________________ From dave at boost-consulting.com Wed Jul 27 18:18:57 2005 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 27 Jul 2005 14:18:57 -0400 Subject: I'm Lost References: <42E6A8FC.7050708@bogo.xs4all.nl> <42E7709F.AE07F97A@web.de> <42E7870D.70407@hp.com> Message-ID: Dave Butenhof writes: > Alexander Terekhov wrote: > >>Wil Evers wrote: >>[...] >> >> >>>I'd say it's time to face the truth, which is that POSIX cancellation >>>semantics are incompatible with commonly established C++ coding >>>practices. >>> >>> >> It's incompatible with cancel-unaware C++ code. Note that it's >> incompatible with cancel-unaware C code as well, but that didn't >> stop POSIX and ongoing creation of cancel-safe code in both C and >> C++ languages. Very many tons of cancel-safe code. >> >> > Indeed. The only real (and unfortunately the hardest) questions are how > to reconcile the (apparent) contradictions between cancel scope and C++ > throw specs (explicit or implicit as in destructors), and cultural > investment in catch(...). Well, you guys just dove right back into the detail as far as I can tell. I guess I'm going to remain lost, but it's probably not a big loss to the discussion. Regards, -- Dave Abrahams Boost Consulting www.boost-consulting.com From baker at cs.fsu.edu Wed Jul 27 18:34:42 2005 From: baker at cs.fsu.edu (Ted Baker) Date: Wed, 27 Jul 2005 14:34:42 -0400 Subject: [SPAM] - FW: RE: [c++-pthreads] Re: I'm Lost - Email found in subject In-Reply-To: <87219549@web.de> References: <87219549@web.de> Message-ID: <20050727183442.GA10672@cs.fsu.edu> | ... Quite simply, I believe that is far too great a burden for the | casual C++ user. They are already struggling under the burden of | a complicated language without us expecting them to understand | intricacies of thread safety and lifetimes. ... With this encouragement, I dare repeat what I suggested earlier, i.e., that thread cancellation should just be omitted from the C++ thread API. It is very easy to say that anyone who uses thread cancellation and C++ should take care to write code that is safe for cancellation (whatever way it is defined to act in the new API). It is another thing for the rank and file of ordinary C++ programmers to actually do this thing, reliably and consistently. I see adding a standard C++ API with thread cancellation in the same category as giving loaded guns to babies. Say whatever you want, but people will see this is as a blessing that cancellation is a generally good thing, and that the gods of standards and implementations have seen to making it safe for mortal use. I can attest that I have been burned using Ada's equivalent to thread cancellation (the "select...then...abort...end select;" construct) to time out certain occasionally long-running computations. I missed some code that was unsafe to abort, and then wasted a few days tracking down and intermittent error. Rather than patch that one hole, and hope that I had not misssed any others, I decided to do the conservative (and simpler) thing. I switched over to a polling solution, inserting over-time checks at a three key points in the computations. Of course, polling won't help with cases where a thread is stuck on a blocking system call, but then one does have (dare I say it?) pthread_kill(). If there is no standard API for thread cancellation, then implementors are to quietly do that they think is the right thing for cases where a user goes outside the standards, e.g., by mixing C++ into a C application that uses thread cancellation (e.g., the implementation could execute any C++ finalizers that are found along the way during stack unrolling). To make sure this does not happen too easily, the implementor can provide a link-time or run-time hack that must be invoked to allow this inter-mixture. (For example, I guess that a little bit of header-file magic with macros and symbol redefinition could cause the linker to reject calls to pthread_cancel() from code that includes pthread.h when they are linked with modules compiled using the C++ thread API header.) --Ted From terekhov at web.de Wed Jul 27 19:20:51 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 27 Jul 2005 21:20:51 +0200 Subject: [SPAM] - FW: RE: [c++-pthreads] Re: I'm Lost - Email found in subject References: <87219549@web.de> <20050727183442.GA10672@cs.fsu.edu> Message-ID: <42E7DE93.8358C2F1@web.de> Ted Baker wrote: [...] > Of course, polling won't help with cases where a thread is stuck > on a blocking system call, but then one does > have (dare I say it?) pthread_kill(). You mean EINTR "cancellation" hack? You'd need a pselect()-like logic and sigmask arguments If sigmask is not a null pointer, then the pselect() function shall replace the signal mask of the caller by the set of signals pointed to by sigmask before examining the descriptors, and shall restore the signal mask of the calling thread before returning. added to all blocking system calls to make that castrated "cancellation" really work (not being subject to a race with respect to reaching interruptible state and signal delivery). regards, alexander. From baker at cs.fsu.edu Wed Jul 27 19:52:28 2005 From: baker at cs.fsu.edu (Ted Baker) Date: Wed, 27 Jul 2005 15:52:28 -0400 Subject: [SPAM] - [c++-pthreads] Re: [SPAM] - FW: RE: [c++-pthreads] Re: I'm Lost - Email found in subject - Email found in subject In-Reply-To: <42E7DE93.8358C2F1@web.de> References: <87219549@web.de> <20050727183442.GA10672@cs.fsu.edu> <42E7DE93.8358C2F1@web.de> Message-ID: <20050727195228.GB11001@cs.fsu.edu> I'm just saying that an application programmer who has a need to cancel threads, and is willing to take the trouble to make sure all the code in the cancellable thread is safe for use with cancellation, could just as well "roll his own" solution, and then will know for certain what is the overhead and how it will work. In a single-threaded POSIX/UNIX application, the only standard way to break it out of a catonic state is via a signal. Therefore, potentially blocking POSIX calls can return EINTR when a thread receives a a signal and the signal is succesfully handled. IFAIK, every blocking call that POSIX guarantees will be interrupted by pthread_cancel can also be interrupted by signals. Although many (most?) programmers seems to ignore this fact, fully conformant code is suppose to have recovery logic for every one of these interruptible system calls, that will either retry the call or take other appropriate action if the call returns prematurely due to interruption. I'm just saying that this recovery code provides a natural place to insert application-specific polling for a request that the thread cancel itself. Another thread can post such a "die" request in a volatile global variable before using pthread_kill to send a signal to a given thread. The thread will notice this at the next point where it polls for a "die" request. As you imply, the code must deal with a window between the thread polling the "die" variable and the thread doing the blocking call, during which a signal might come in and not wake up the thread. You can get around the race problems pretty simply if the changes to the "die" request variable monotonic, which will be the case if you insist that a once-cancelled thread must terminate. With this simplification you can also provide a binary "ack" variable that is set by the target thread once it has recognized that it has been told to die. The killer thread has to periodically retry the pthread_kill() until the target thread acknowledges. By the way, even if this seems ugly, it may not too far from what your friendly C-language implementation of pthread_cancel is doing. In fact, I suspect that is why POSIX defined thread cancelation as being a one-shot thing. --Ted On Wed, Jul 27, 2005 at 09:20:51PM +0200, Alexander Terekhov wrote: > > Ted Baker wrote: > [...] > > Of course, polling won't help with cases where a thread is stuck > > on a blocking system call, but then one does > > have (dare I say it?) pthread_kill(). > > You mean EINTR "cancellation" hack? You'd need a pselect()-like > logic and sigmask arguments > > If sigmask is not a null pointer, then the pselect() function > shall replace the signal mask of the caller by the set of > signals pointed to by sigmask before examining the descriptors, > and shall restore the signal mask of the calling thread before > returning. > > added to all blocking system calls to make that castrated > "cancellation" really work (not being subject to a race with > respect to reaching interruptible state and signal delivery). From pdimov at mmltd.net Wed Jul 27 20:01:24 2005 From: pdimov at mmltd.net (Peter Dimov) Date: Wed, 27 Jul 2005 23:01:24 +0300 Subject: [c++-pthreads] Re: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> <001401c58fb4$9ff07b70$6501a8c0@pdimov2> <42E290EA.29AD78D@web.de> <42E634CE.2010705@hp.com> <002c01c592b7$6bd37da0$6501a8c0@pdimov2> <003901c592b9$d9c10d80$6501a8c0@pdimov2> <42E7A548.B50C302B@web.de> Message-ID: <004701c592e5$f90a1200$6501a8c0@pdimov2> Alexander Terekhov wrote: > Peter Dimov wrote: > [...] >> int pthread_cancelenabled(void); >> >> RETURN VALUE >> >> Nonzero if the current thread's cancelability state is >> PTHREAD_CANCEL_ENABLE and the call is not made from within a cleanup >> handler or a TSD destructor, > ^^^^^^^^^^^^^^^^^^^^^^^^ >> zero otherwise. >> >> could have been much simpler. > > With cancel request pending, mandatory cancel points are required to > throw within a cleanup handler invoked by pthread_cleanup_pop() ["(if > /execute/ is non-zero)"] when cancel state is PTHREAD_CANCEL_ENABLE. An odd requirement that could've been given the appropriate attention had something like the above been proposed. ;-) The specification of the hypothetical pthread_cancelenabled can be "fixed" to match this behavior, but I'm not sure that this is desirable. If you have two calls to 'close' in the cleanup handler and the first is canceled, the second will be skipped. From terekhov at web.de Wed Jul 27 20:17:10 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 27 Jul 2005 22:17:10 +0200 Subject: [SPAM] - [c++-pthreads] Re: [SPAM] - FW: RE: [c++-pthreads] Re: I'm Lost - Email found in subject - Email found in subject References: <87219549@web.de> <20050727183442.GA10672@cs.fsu.edu> <42E7DE93.8358C2F1@web.de> <20050727195228.GB11001@cs.fsu.edu> Message-ID: <42E7EBC6.66A00B84@web.de> Ted Baker wrote: [...] > receives a a signal and the signal is succesfully handled. IFAIK, > every blocking call that POSIX guarantees will be interrupted by > pthread_cancel can also be interrupted by signals. "The pthread_join() function shall not return an error code of [EINTR]." And I can go on and on (including stuff like "may fail" vs "shall fail" on semas, etc.), but I'll just let you check it yourself by clicking on every "shall occur" cancellation point here: http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html#tag_02_09_05_02 regards, alexander. From terekhov at web.de Wed Jul 27 20:44:20 2005 From: terekhov at web.de (Alexander Terekhov) Date: Wed, 27 Jul 2005 22:44:20 +0200 Subject: pthread_cancel and EH: let's try this again References: <42D988F1.2050300@bogo.xs4all.nl> <20050717223748.GA4125@tofu.dreamhost.com> <000c01c58b25$79d3c660$6501a8c0@pdimov2> <20050718033122.GC4125@tofu.dreamhost.com> <003801c58b8e$d66dbca0$6501a8c0@pdimov2> <42DD6BE0.7070100@bogo.xs4all.nl> <003c01c58cb3$7a199a20$6501a8c0@pdimov2> <42DD84AA.6020606@codesourcery.com> <20050720065539.GA24311@tofu.dreamhost.com> <42DEC123.4040509@bogo.xs4all.nl> <20050721000907.GA3218@codesourcery.com> <42DEEF91.3040704@codesourcery.com> <000d01c58dfa$612062e0$6601a8c0@pdimov> <42DFC416.ED79651@web.de> <008001c58f07$68b5b8d0$6501a8c0@pdimov2> <42E24BF4.EE6513F9@web.de> <001501c58f94$35556d90$6501a8c0@pdimov2> <42E28856.6C2377CE@web.de> <001401c58fb4$9ff07b70$6501a8c0@pdimov2> <42E290EA.29AD78D@web.de> <42E634CE.2010705@hp.com> <002c01c592b7$6bd37da0$6501a8c0@pdimov2> <003901c592b9$d9c10d80$6501a8c0@pdimov2> <42E7A548.B50C302B@web.de> <004701c592e5$f90a1200$6501a8c0@pdimov2> Message-ID: <42E7F224.1CA06CA@web.de> Peter Dimov wrote: [...] > > With cancel request pending, mandatory cancel points are required to > > throw within a cleanup handler invoked by pthread_cleanup_pop() ["(if > > /execute/ is non-zero)"] when cancel state is PTHREAD_CANCEL_ENABLE. > > An odd requirement that could've been given the appropriate attention had > something like the above been proposed. ;-) > > The specification of the hypothetical pthread_cancelenabled can be "fixed" > to match this behavior, but I'm not sure that this is desirable. If you have > two calls to 'close' in the cleanup handler and the first is canceled, the > second will be skipped. Yep. So you either disable cancel in such a cleanup handler that can be invoked by pthread_cleanup_pop(), or move the second cancel point to another pthread_cleanup_pop(1) handler inside the first one. regards, alexander. From baker at cs.fsu.edu Wed Jul 27 22:03:25 2005 From: baker at cs.fsu.edu (Ted Baker) Date: Wed, 27 Jul 2005 18:03:25 -0400 Subject: [SPAM] - [c++-pthreads] Re: [SPAM] - [c++-pthreads] Re: [SPAM] - FW: RE: [c++-pthreads] Re: I'm Lost - Email found in subject - Email found in subject - Email found in subject In-Reply-To: <42E7EBC6.66A00B84@web.de> References: <87219549@web.de> <20050727183442.GA10672@cs.fsu.edu> <42E7DE93.8358C2F1@web.de> <20050727195228.GB11001@cs.fsu.edu> <42E7EBC6.66A00B84@web.de> Message-ID: <20050727220325.GB13466@cs.fsu.edu> On Wed, Jul 27, 2005 at 10:17:10PM +0200, Alexander Terekhov wrote: > > Ted Baker wrote: > [...] > > receives a a signal and the signal is succesfully handled. IFAIK, > > every blocking call that POSIX guarantees will be interrupted by > > pthread_cancel can also be interrupted by signals. > > "The pthread_join() function shall not return an error code of > [EINTR]." Interesting... I should have remembered this, having implemented it once, about 15 years ago. I had forgotten how many places Pthreads calls broke the traditional POSIX signal model. > And I can go on and on (including stuff like "may fail" vs "shall > fail" on semas, etc.), Yes, POSIX allows implementations to not interrupt certain (as I recall, most) of the blocking calls, via this "may" language. On the other hand, if the system does not allow them to be interrupted a Pthread library is going to have difficulty implementing a useful (unblocking) thread cancellation point at those calls. > but I'll just let you check it yourself by > clicking on every "shall occur" cancellation point here: > > http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html#tag_02_09_05_02 --Ted From david.butenhof at hp.com Thu Jul 28 11:21:36 2005 From: david.butenhof at hp.com (Dave Butenhof) Date: Thu, 28 Jul 2005 07:21:36 -0400 Subject: FW: RE: [c++-pthreads] Re: I'm Lost In-Reply-To: <87219549@web.de> References: <87219549@web.de> Message-ID: <42E8BFC0.9080106@hp.com> < Foward Quoted > >>Quite simply, I believe that is far too great a burden for the casual C++ user. They are already struggling under the burden of a complicated language without us expecting them to understand intricacies of thread safety and lifetimes. >> >>The people actively working in the posix/C++ subset are much more familiar with these complex issues, and I believe the burden is on them to find a compromise that will not impact on the non-expert user who is NOT using this combination. I do not pretend this is an easy task though ;?) >> >> Cancellation does not affect application code (or coders) that don't want to use it. Nothing can cancel a thread without having the thread's handle through deliberate action of the thread's creator, or through pthread_self when executing within the thread. No modular "facility" can legitimately or reasonably do this to any thread to which it has not been granted "ownership" -- either by having created it within the facility or by having ownership handed to it through an explicit protocol (which is rare). Certainly some fool can chose, just for the heck of it, to cancel the thread in which it runs... but so what? It could just as easily generate a SIGSEGV and take out the whole process. That one writes an application using threads, regardless of language, doesn't require you to use, understand, or even be aware of cancellation. However when one writes a robust general-purpose facility (library) that will be used in an environment supporting cancellation, that library ought to be written to support cancellation (whether or not it actually uses cancellation on its own behalf). Such libraries are not generally tasks taken on by "casual users"; and even so while hardly ideal it's perfectly adequate to simply say "this facility isn't cancel-safe; tough luck". "Industrial strength" libraries in the environment, for example the "language runtime" itself, whether libc or STL, ought to be cancel-safe certainly. Even at that, however, because the task can be monumental, POSIX provided "cheats" -- the list of "optional" cancellation points allow a libc developer to omit all but the most critical. A C++ standard for STL *could* provide similar "cheats" to avoid requiring full implementation of cancel-safety. And again, if the user of the library (whether the main application or another library) doesn't choose to use cancellation the point is moot. And while Ted Baker has suggested that "loaded guns" shouldn't be given to "babies", one could respond cynically that it's far too late in UNIX, POSIX, C, or C++ history to worry about handing out loaded guns. (Cancellation is nothing compared to the explosive payload of an asynchronous signal, or even thread synchronization considerations.) With the existing well-stocked and easily accessible arsenal lying about, the addition of one more handgun can hardly be considered even relevant much less critical. And more importantly, there are many programmers who really DO know how to use those weapons of mass coding destruction, and need them. That's NOT a death ray over there in the corner, it's an industrial excavation tool; misuse is solely the responsibility of the user, not the manufacturer. Finally, the question is NOT whether we choose to make these weapons available, nor even whether they'll be used. They already exist, are widely (almost universally) deployed; and are used and depended upon by many real applications. None of that is going to go away no matter what the C++ committee does. The question HERE is only whether there will be a STANDARD and PORTABLE specification to aid these developers and applications in moving between the various systems. Ignoring the issue won't make it go away -- merely leave those applications and developers with cumbersome non-portable code, and force someone to resurrect this same argument all over again in another year or two. (As indeed has already happened, through several cycles.) -------------- next part -------------- A non-text attachment was scrubbed... Name: david.butenhof.vcf Type: text/x-vcard Size: 476 bytes Desc: not available URL: