From dave at boost-consulting.com Mon Mar 6 16:27:03 2006 From: dave at boost-consulting.com (David Abrahams) Date: Mon, 06 Mar 2006 08:27:03 -0800 Subject: FW: RE: Re: I'm Lost References: <87219549@web.de> <42E8BFC0.9080106@hp.com> Message-ID: Dave Butenhof writes: > 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. Picking this thread up from long ago, lete me say that I'm sort-of in agreement with the above. I say "sort of" because Dave B's statement fails to address the following point (hereafter known as "the statement"), and I can't tell what side of it he'd come down on: Any code that is already exception-safe could be automatically cancel-safe depending on our definition of "cancel-safe" and the semantics we assign to cancellation exceptions. In the definition of "cancel-safe" that allows the statement to be true, cancellation is a request, and doesn't absolutely force _anything_ to happen. IIUC, that is the status quo anyway (nobody is even forced to invoke a cancellation point). The cancellation exception semantics that allow the statement to be true are that they act like any other exception, and are not automatically rethrown at the end of catch blocks. This is the question primarily in dispute, IIUC. IMO, it is worth making cancellation exceptions like any other in order to make the statement true. It's also worthwhile to avoid complicating the mental model programmers must use to think about exception handling, which, believe me, is hard enough even for many developers of general purpose libraries to grasp (how long did it take Dinkumware to make their STL exception-safe?) Finally, and this may be counterintuitive at first, making cancellation stoppable by catch(...) like everything else is sometimes **required** in order to ensure that cancellation propagates all the way through the stack and terminates a thread as expected without crashing the program. So those who want cancellation to act more like an absolute guarantee of thread termination should support it. For example, I write a C++ library for interfacing with Python. Python is written in portable 'C' with no special treatment of cancellation exceptions or the kinds of cleanups POSIX uses to do the same thing in 'C'. If I let any sort of C/C++-level exception propagate into Python, its expectations are violated and will most likely crash. It's very common to have a layer of Python sandwiched between C++ calls on the stack. I can get proper cancellation semantics by stopping cancellation exceptions at the boundary and translating them into Python exceptions. They'll propagate through Python, and reach an exception translator on the other side that turns them back into C++ exceptions. -- Dave Abrahams Boost Consulting www.boost-consulting.com From david.butenhof at hp.com Mon Mar 6 18:49:33 2006 From: david.butenhof at hp.com (Dave Butenhof) Date: Mon, 06 Mar 2006 13:49:33 -0500 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: References: <87219549@web.de> <42E8BFC0.9080106@hp.com> Message-ID: <440C843D.8060503@hp.com> David Abrahams wrote: > Dave Butenhof writes: > > >> 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. >> > > Picking this thread up from long ago, lete me say that I'm sort-of in > agreement with the above. I say "sort of" because Dave B's statement > fails to address the following point (hereafter known as "the > statement"), and I can't tell what side of it he'd come down on: > > Any code that is already exception-safe could be automatically > cancel-safe depending on our definition of "cancel-safe" and the > semantics we assign to cancellation exceptions. > > In the definition of "cancel-safe" that allows the statement to be > true, cancellation is a request, and doesn't absolutely force > _anything_ to happen. IIUC, that is the status quo anyway (nobody is > even forced to invoke a cancellation point). > > The cancellation exception semantics that allow the statement to be > true are that they act like any other exception, and are not > automatically rethrown at the end of catch blocks. This is the > question primarily in dispute, IIUC. > This has been THE most contentious issue in every C++/threads discussion I've encountered since the beginning of (pthread) time. My preference has always been that cancellation is an exception. Period. In our initial CMA architecture, and in our exception mapping of cancellation/thread-exit onto C language exceptions in Tru64 UNIX and OpenVMS, it's possible and reasonable to finalize propagation of a cancel/exit exception. That was critical for DCE, for example, so that it could trap cancellation of an RPC server thread, bring the thread back into the server's work pool, and propagate the exception across the wire to the client. To finalize a cancel/exit under almost any normal circumstance is simply an application error. There are many worse application errors, like infinite loops, that we can't legislate around anyway. Worrying too much that someone might finalize the exception unintentionally just seemed like wasted effort. However it's also important to keep in mind that my preferences were formed with POSIX cancellation and C language (or cross-language OS) exceptions. C++ adds a lot of exception semantics and patterns on top of that. There have been plenty of people who argue that cancel "can't" be caught; and some of these arguments trace back to the ubiquity of catch(...), especially in constructors; and they have some legitimate concerns about common C++ language patterns that might pretty much prevent a cancel from ever doing what a cancel should do. There likely is no perfect solution. > IMO, it is worth making cancellation exceptions like any other in > order to make the statement true. It's also worthwhile to avoid > complicating the mental model programmers must use to think about > exception handling, which, believe me, is hard enough even for many > developers of general purpose libraries to grasp (how long did it take > Dinkumware to make their STL exception-safe?) Finally, and this may > be counterintuitive at first, > > making cancellation stoppable by catch(...) like everything else is > sometimes **required** in order to ensure that cancellation > propagates all the way through the stack and terminates a thread as > expected without crashing the program. So those who want > cancellation to act more like an absolute guarantee of thread > termination should support it. > > For example, I write a C++ library for interfacing with Python. > Python is written in portable 'C' with no special treatment of > cancellation exceptions or the kinds of cleanups POSIX uses to do the > same thing in 'C'. If I let any sort of C/C++-level exception > propagate into Python, its expectations are violated and will most > likely crash. It's very common to have a layer of Python sandwiched > between C++ calls on the stack. I can get proper cancellation > semantics by stopping cancellation exceptions at the boundary and > translating them into Python exceptions. They'll propagate through > Python, and reach an exception translator on the other side that turns > them back into C++ exceptions. > The catch lies in whether (and how far) you'll trust application developers to do the re-throw properly. If we don't clean up all frames and eventually re-throw the cancel/exit to the runtime's base frame to terminate the thread, then we don't have cancellation. On the other hand, if we prevent a catch or force a re-throw, we lose a lot of C++ (particularly in constructors). Part of the reason that you "can't tell what side of it [I'd] come down on" is that I've long recognized this as an essentially religious rather than technical argument. You'll come down on the side of the semantics toward which you feel the strongest emotional attachment. While I'm happy to express my experience and even preferences, I also recognize that "the other side" has some equally strong arguments and expectations, and they (well, most of them!) are not "wrong". Someone needs to propose and champion "the great exception compromise"; but if that's to be me I don't yet have the faintest germ of a notion what it might be. So I sure hope it's going to be someone else. ;-) -------------- 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 Mon Mar 6 19:36:37 2006 From: dave at boost-consulting.com (David Abrahams) Date: Mon, 06 Mar 2006 11:36:37 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <440C843D.8060503@hp.com> (Dave Butenhof's message of "Mon, 06 Mar 2006 13:49:33 -0500") References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> Message-ID: Dave Butenhof writes: > David Abrahams wrote: >> Dave Butenhof writes: >> >> >>> 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. >>> >> >> Picking this thread up from long ago, lete me say that I'm sort-of in >> agreement with the above. I say "sort of" because Dave B's statement >> fails to address the following point (hereafter known as "the >> statement"), and I can't tell what side of it he'd come down on: >> >> Any code that is already exception-safe could be automatically >> cancel-safe depending on our definition of "cancel-safe" and the >> semantics we assign to cancellation exceptions. >> >> In the definition of "cancel-safe" that allows the statement to be >> true, cancellation is a request, and doesn't absolutely force >> _anything_ to happen. IIUC, that is the status quo anyway (nobody is >> even forced to invoke a cancellation point). >> >> The cancellation exception semantics that allow the statement to be >> true are that they act like any other exception, and are not >> automatically rethrown at the end of catch blocks. This is the >> question primarily in dispute, IIUC. >> > This has been THE most contentious issue in every C++/threads discussion > I've encountered since the beginning of (pthread) time. > > My preference has always been that cancellation is an exception. Period. > In our initial CMA architecture, and in our exception mapping of > cancellation/thread-exit onto C language exceptions in Tru64 UNIX and > OpenVMS, it's possible and reasonable to finalize propagation of a > cancel/exit exception. That was critical for DCE, for example, so that > it could trap cancellation of an RPC server thread, bring the thread > back into the server's work pool, and propagate the exception across the > wire to the client. That sounds highly analogous to my case with Python. > To finalize a cancel/exit under almost any normal circumstance is > simply an application error. The key word being "almost." In some situations, like those we've both cited, it's absolutely necessary, to even get cancellation to work. > There are many worse application errors, like infinite loops, that > we can't legislate around anyway. Worrying too much that someone > might finalize the exception unintentionally just seemed like wasted > effort. However it's also important to keep in mind that my > preferences were formed with POSIX cancellation and C language (or > cross-language OS) exceptions. C++ adds a lot of exception semantics > and patterns on top of that. > > There have been plenty of people who argue that cancel "can't" be > caught; and some of these arguments trace back to the ubiquity of > catch(...), especially in constructors; A ctor that does catch(...) without rethrow is almost always badly designed at best. There was unfortunate advice going around for many years that you shouldn't throw from ctors, but that's exactly wrong: ctors that throw allow the establishment of strong invariants, and programming without them is much harder. On the other hand, stopping exceptions in dtors is absolutely the right thing to do. > and they have some legitimate concerns about common C++ language > patterns that might pretty much prevent a cancel from ever doing > what a cancel should do. Really, legitimate concerns? I can't think of any recommended patterns that would act that way. > The catch lies in whether (and how far) you'll trust application > developers to do the re-throw properly. If we don't clean up all > frames and eventually re-throw the cancel/exit to the runtime's base > frame to terminate the thread, then we don't have cancellation. I'm of the school that says it's futile and even dangerous to try to operate correctly in an environment where you have to assume other code is incorrect. My library will probably be equally broken if the user decides to throw out my bad_alloc exception without a proper response. > On the other hand, if we prevent a catch or force a re-throw, we > lose a lot of C++ (particularly in constructors). I don't think that should be your concern. The correct and well-written C++ we lose is generally sitting at module and language boundaries. And then there are dtors. > Part of the reason that you "can't tell what side of it [I'd] come > down on" is that I've long recognized this as an essentially > religious rather than technical argument. You'll come down on the > side of the semantics toward which you feel the strongest emotional > attachment. You don't find the idea that exception-safe code implies cancel-safe code technically compelling? I don't think that's an emotional issue. > While I'm happy to express my experience and even preferences, I > also recognize that "the other side" has some equally strong > arguments and expectations, and they (well, most of them!) are not > "wrong". I don't think either side is "wrong," either. > Someone needs to propose and champion "the great exception > compromise"; but if that's to be me I don't yet have the faintest > germ of a notion what it might be. So I sure hope it's going to be > someone else. ;-) If "finalized cancellation exceptions result in a new throw at the next cancellation point" isn't enough of a compromise, it isn't going to be me either, because I'm out of new ideas. Okay, how about this one: we count the number of times the cancellation is discarded. The cancelling thread can specify the number of discards to tolerate, where the default is infinite. After that, at the next cancellation point all pthread cancellation handlers (but not dtors or catch blocks) are run and the thread is terminated. Heck, at that point I don't care what happens; you're gambling anyway. Run all the dtors and catch blocks for all I care. A simpler approach might be to have two kinds of exception: "forced" and finalizable. At least then we can say that exception-safe code implies finalizable cancellation safety. Then "forced" synchronous cancellation can do whatever people desire. I personally think it will become a useless appendage sort of like C++ exception specifications, but at least evolution will take care of it. And if I'm wrong, evolution will wilt my finalizable cancellations. I guess I'm not totally out of ideas ;-) -- Dave Abrahams Boost Consulting www.boost-consulting.com From mark at codesourcery.com Mon Mar 6 19:59:37 2006 From: mark at codesourcery.com (Mark Mitchell) Date: Mon, 06 Mar 2006 11:59:37 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> Message-ID: <440C94A9.4020805@codesourcery.com> David Abrahams wrote: > If "finalized cancellation exceptions result in a new throw at the > next cancellation point" isn't enough of a compromise, it isn't going > to be me either, because I'm out of new ideas. That sounds fine to me. The key invariant that I feel must be preserved is that cancellation is an exception, with all that implies. (Actually I'd made one exception to that requirement: if people wanted to say that the type of the exception is unnameable, and that you cannot therefore catch it by any means other than ..., I would see that as an unnecessary, but acceptable, restriction.) Your suggestion is to make functions which already throw exceptions (in this context) throw them more often, which is OK; callers have to be prepared for them to throw exceptions anyhow. (You do have to say what happens if the thread is cancelled, catches the exceptions, sets the no-cancel bit, and then reaches a cancellation point. The answer must be that the thread is not cancelled, since, in that context, the surrounding code can reasonably be written to assume there will no exceptions.) As far as I can tell, the last time we discussed this issue, all of the C++ experts agreed that not allowing cancellation exceptions to be caught was a serious violation of C++ exception-safety principles. The key obstacle to progress here, AFAICT, is that Ulrich Drepper has claimed that once cancellation occurs it is (in some unexplained way) impossible for the thread to continue, despite the fact that it can run its cancellation handlers, etc. I've never been able to tell if he thinks this to be a POSIX requirement, a Linux kernel issue, a GLIBC implementation issue, or something else. -- Mark Mitchell CodeSourcery mark at codesourcery.com (650) 331-3385 x713 From david.butenhof at hp.com Mon Mar 6 20:54:54 2006 From: david.butenhof at hp.com (Dave Butenhof) Date: Mon, 06 Mar 2006 15:54:54 -0500 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> Message-ID: <440CA19E.5030809@hp.com> David Abrahams wrote: > Dave Butenhof writes: > >> David Abrahams wrote: >> >>> Dave Butenhof writes: >>> >>>> 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. >>>> >>> Picking this thread up from long ago, lete me say that I'm sort-of in >>> agreement with the above. I say "sort of" because Dave B's statement >>> fails to address the following point (hereafter known as "the >>> statement"), and I can't tell what side of it he'd come down on: >>> >>> Any code that is already exception-safe could be automatically >>> cancel-safe depending on our definition of "cancel-safe" and the >>> semantics we assign to cancellation exceptions. >>> >>> In the definition of "cancel-safe" that allows the statement to be >>> true, cancellation is a request, and doesn't absolutely force >>> _anything_ to happen. IIUC, that is the status quo anyway (nobody is >>> even forced to invoke a cancellation point). >>> >>> The cancellation exception semantics that allow the statement to be >>> true are that they act like any other exception, and are not >>> automatically rethrown at the end of catch blocks. This is the >>> question primarily in dispute, IIUC. >>> >> This has been THE most contentious issue in every C++/threads discussion >> I've encountered since the beginning of (pthread) time. >> >> My preference has always been that cancellation is an exception. Period. >> In our initial CMA architecture, and in our exception mapping of >> cancellation/thread-exit onto C language exceptions in Tru64 UNIX and >> OpenVMS, it's possible and reasonable to finalize propagation of a >> cancel/exit exception. That was critical for DCE, for example, so that >> it could trap cancellation of an RPC server thread, bring the thread >> back into the server's work pool, and propagate the exception across the >> wire to the client. >> > That sounds highly analogous to my case with Python. > Sure; and there are other examples. I've just found that the "inverted call stack" of this sort of server setup seems to make sense to a lot of people. >> To finalize a cancel/exit under almost any normal circumstance is >> simply an application error. >> > The key word being "almost." In some situations, like those we've > both cited, it's absolutely necessary, to even get cancellation to > work. > Absolutely. There was a strong sub-faction in POSIX that can be loosely characterized as "academics" who were determined to try to prevent constructs that might be misused. It's why the realtime people didn't get pthread_abort() to force termination without cleanup, why you can't suspend a thread, or "force unlock" a mutex that might have been abandoned, and so forth. If cancellation can't be finalized, nobody can accidentally finalize it; and that's great if you don't trust anyone to know when it SHOULD be finalized. I started out as something of an "academic" in this sense and evolved into a pramatist... if someone thinks they need it, and they're right, don't keep them from doing it. And if they're WRONG, it's their problem, not yours. ;-) Portable Java GC would have been a lot easier had POSIX included suspend/resume; and does it really matter that nearly anyone else who used it would be breaking their application? Well, it all depends on your point of view... >> There are many worse application errors, like infinite loops, that >> we can't legislate around anyway. Worrying too much that someone >> might finalize the exception unintentionally just seemed like wasted >> effort. However it's also important to keep in mind that my >> preferences were formed with POSIX cancellation and C language (or >> cross-language OS) exceptions. C++ adds a lot of exception semantics >> and patterns on top of that. >> >> There have been plenty of people who argue that cancel "can't" be >> caught; and some of these arguments trace back to the ubiquity of >> catch(...), especially in constructors; >> > A ctor that does catch(...) without rethrow is almost always badly > designed at best. There was unfortunate advice going around for many > years that you shouldn't throw from ctors, but that's exactly wrong: > ctors that throw allow the establishment of strong invariants, and > programming without them is much harder. > > On the other hand, stopping exceptions in dtors is absolutely the > right thing to do. > Yes, I may have said that backwards. As I've said before, although I use C++, it's not a "native language" for me, and a lot of this is based on opinions others have strongly stated rather than my own knowledge or experience. Another reason, incidentally, for not trying to come down too hard on one side or the other where language concerns might trump "threading" concerns. >> and they have some legitimate concerns about common C++ language >> patterns that might pretty much prevent a cancel from ever doing >> what a cancel should do. >> > Really, legitimate concerns? I can't think of any recommended patterns that would act that way. > Hmm. OK. That's interesting. Well, you're the C++ expert here. ;-) >> The catch lies in whether (and how far) you'll trust application >> developers to do the re-throw properly. If we don't clean up all >> frames and eventually re-throw the cancel/exit to the runtime's base >> frame to terminate the thread, then we don't have cancellation. >> > I'm of the school that says it's futile and even dangerous to try to > operate correctly in an environment where you have to assume other > code is incorrect. My library will probably be equally broken if the > user decides to throw out my bad_alloc exception without a proper > response. > True enough. "Over-engineering" is a persistent danger. Sometimes we just need to accept that we can't solve all problems, and that "idiot-proofing" is a losing concept, and move on. ;-) >> On the other hand, if we prevent a catch or force a re-throw, we >> lose a lot of C++ (particularly in constructors). >> > I don't think that should be your concern. The correct and > well-written C++ we lose is generally sitting at module and language > boundaries. And then there are dtors. > >> Part of the reason that you "can't tell what side of it [I'd] come >> down on" is that I've long recognized this as an essentially >> religious rather than technical argument. You'll come down on the >> side of the semantics toward which you feel the strongest emotional >> attachment. >> > You don't find the idea that exception-safe code implies cancel-safe > code technically compelling? I don't think that's an emotional issue. > Well, yes, I do, because cancel was always intended to be "just" an exception that happened to be thrown from another thread. But then, nothing is ever that simple; the asynchronous nature required controls like cancelability type and state. C++ exceptions are synchronous and non-interrupting. (The latter a consequence of the former, really.) One of the main advantages of cancellation is that it can break through an extended blocking operation; but that's unavoidably an extra condition over "exception-safety". Cancel-safe has to mean something more unless we drop interruptibility. If we drop it, then cancel-safety is just exception-safety but loses much of its value in controlling application responsiveness. In any case, though, I wasn't suggesting that you need to convince me. I'm saying there are diverse and strongly held positions that somehow need to be unified in order to get consensus on any proposal. I think that I'm the least of your worries. ;-) >> While I'm happy to express my experience and even preferences, I >> also recognize that "the other side" has some equally strong >> arguments and expectations, and they (well, most of them!) are not >> "wrong". >> > I don't think either side is "wrong," either. > >> Someone needs to propose and champion "the great exception >> compromise"; but if that's to be me I don't yet have the faintest >> germ of a notion what it might be. So I sure hope it's going to be >> someone else. ;-) >> > If "finalized cancellation exceptions result in a new throw at the > next cancellation point" isn't enough of a compromise, it isn't going > to be me either, because I'm out of new ideas. > > Okay, how about this one: we count the number of times the > cancellation is discarded. The cancelling thread can specify the > number of discards to tolerate, where the default is infinite. After > that, at the next cancellation point all pthread cancellation handlers > (but not dtors or catch blocks) are run and the thread is terminated. > Heck, at that point I don't care what happens; you're gambling anyway. > Run all the dtors and catch blocks for all I care. > I do NOT favor any model where "dtor/catch" and "cancellation handler" don't mean the same thing. I don't think the count is tenable either because although it always feels tempting to add a control dial, it doesn't solve any actual problem if there's nobody who can know to what value the dial should be set. In this case, I can't see how either the canceler OR any modular call stack could possibly provide any useful data much less a single numeric value. If "canceled" state persists when the exception is discarded, then cancel is something different from just "an exception"; which is too bad, but perhaps inevitable. You can't just catch it and continue -- you need to somehow also reset that state to recover your workgroup thread that's serially running RPC requests (or Python code, whatever). A lot of people have suggested various ways of making cancel-pending persist after the exception is launched; that's not necessarily "wrong", but it isn't "simple" either and somehow it doesn't feel right to me. > A simpler approach might be to have two kinds of exception: "forced" > and finalizable. At least then we can say that exception-safe code > implies finalizable cancellation safety. Then "forced" synchronous > cancellation can do whatever people desire. I personally think it > will become a useless appendage sort of like C++ exception > specifications, but at least evolution will take care of it. And if > I'm wrong, evolution will wilt my finalizable cancellations. > Is this the "unwind" vs "exception" idea? (Where "unwind" is like a new sort of 'throw' that triggers dtors but can't be caught/finalized.) Or something different...? > I guess I'm not totally out of ideas ;-) -------------- 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 Mon Mar 6 22:10:54 2006 From: dave at boost-consulting.com (David Abrahams) Date: Mon, 06 Mar 2006 14:10:54 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <440CA19E.5030809@hp.com> (Dave Butenhof's message of "Mon, 06 Mar 2006 15:54:54 -0500") References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> Message-ID: Dave Butenhof writes: >>> This has been THE most contentious issue in every C++/threads >>> discussion I've encountered since the beginning of (pthread) time. >>> >>> My preference has always been that cancellation is an >>> exception. Period. In our initial CMA architecture, and in our >>> exception mapping of cancellation/thread-exit onto C language >>> exceptions in Tru64 UNIX and OpenVMS, it's possible and reasonable >>> to finalize propagation of a cancel/exit exception. That was >>> critical for DCE, for example, so that it could trap cancellation >>> of an RPC server thread, bring the thread back into the server's >>> work pool, and propagate the exception across the wire to the >>> client. >>> >> That sounds highly analogous to my case with Python. >> > Sure; and there are other examples. I've just found that the "inverted > call stack" of this sort of server setup seems to make sense to a lot of > people. Okay. So there's a moderate-sized class of applications that need to do this. >>> To finalize a cancel/exit under almost any normal circumstance is >>> simply an application error. >> >> The key word being "almost." In some situations, like those we've >> both cited, it's absolutely necessary, to even get cancellation to >> work. >> > Absolutely. There was a strong sub-faction in POSIX that can be > loosely characterized as "academics" who were determined to try to > prevent constructs that might be misused. You mean, like, computers? > It's why the realtime people didn't get pthread_abort() to force > termination without cleanup, why you can't suspend a thread, or > "force unlock" a mutex that might have been abandoned, and so > forth. Oh, too bad. > If cancellation can't be finalized, nobody can accidentally > finalize it; and that's great if you don't trust anyone to know when > it SHOULD be finalized. I started out as something of an "academic" > in this sense and evolved into a pramatist... if someone thinks they > need it, and they're right, don't keep them from doing it. And if > they're WRONG, it's their problem, not yours. ;-) Portable Java GC > would have been a lot easier had POSIX included suspend/resume; and > does it really matter that nearly anyone else who used it would be > breaking their application? Well, it all depends on your point of > view... I don't know about that suspend/resume, but I don't think legitimate cases where finalization is needed are nearly so rare as you describe cases where suspend/resume is needed to be. >> A ctor that does catch(...) without rethrow is almost always badly >> designed at best. There was unfortunate advice going around for many >> years that you shouldn't throw from ctors, but that's exactly wrong: >> ctors that throw allow the establishment of strong invariants, and >> programming without them is much harder. >> >> On the other hand, stopping exceptions in dtors is absolutely the >> right thing to do. >> > Yes, I may have said that backwards. As I've said before, although I use > C++, it's not a "native language" for me, and a lot of this is based on > opinions others have strongly stated It wouldn't surprise me a bit if others had strongly stated ctors shouldn't throw. It used to be the advice in Stroustrup's books. > rather than my own knowledge or experience. Another reason, > incidentally, for not trying to come down too hard on one side or > the other where language concerns might trump "threading" concerns. > >>> and they have some legitimate concerns about common C++ language >>> patterns that might pretty much prevent a cancel from ever doing >>> what a cancel should do. >>> >> Really, legitimate concerns? I can't think of any recommended >> patterns that would act that way. >> > Hmm. OK. That's interesting. Well, you're the C++ expert here. ;-) None other than, "prevent exceptions from leaking across language boundaries." But if you don't do that, your program is broken anyway. >> You don't find the idea that exception-safe code implies cancel-safe >> code technically compelling? I don't think that's an emotional issue. >> > Well, yes, I do, find it technically compelling, or think it's an emotional issue? > because cancel was always intended to be "just" an exception that > happened to be thrown from another thread. But then, nothing is ever > that simple; the asynchronous nature required controls like > cancelability type and state. "Asynchronous nature?" I haven't even been considering asynchronous cancellation as it's completely untenable to write anything but the most restricted code that could work in the face of async cancellation. > C++ exceptions are synchronous and non-interrupting. (The latter a > consequence of the former, really.) One of the main advantages of > cancellation is that it can break through an extended blocking > operation; If you make all blocking operations cancellation points you can do that anyway. No? > but that's unavoidably an extra condition over "exception-safety". > Cancel-safe has to mean something more unless we drop > interruptibility. If we drop it, then cancel-safety is just > exception-safety but loses much of its value in controlling > application responsiveness. You lost me. I think async cancel safety should be thought of as a separate level of design. > In any case, though, I wasn't suggesting that you need to convince > me. I'm saying there are diverse and strongly held positions that > somehow need to be unified in order to get consensus on any > proposal. I think that I'm the least of your worries. ;-) Not that you have any obligation to do so, but it might be easier if you would recognize the weight your opinion carries. That might mean learning enough about C++ to form a definite opinion. That's, at least, what I've tried to do with threading. >>> Someone needs to propose and champion "the great exception >>> compromise"; but if that's to be me I don't yet have the faintest >>> germ of a notion what it might be. So I sure hope it's going to be >>> someone else. ;-) >>> >> If "finalized cancellation exceptions result in a new throw at the >> next cancellation point" isn't enough of a compromise, it isn't going >> to be me either, because I'm out of new ideas. >> >> Okay, how about this one: we count the number of times the >> cancellation is discarded. The cancelling thread can specify the >> number of discards to tolerate, where the default is infinite. After >> that, at the next cancellation point all pthread cancellation handlers >> (but not dtors or catch blocks) are run and the thread is terminated. >> Heck, at that point I don't care what happens; you're gambling anyway. >> Run all the dtors and catch blocks for all I care. >> > I do NOT favor any model where "dtor/catch" and "cancellation handler" > don't mean the same thing. Like I said, I don't care at that point. A forced cancellation is a big gamble. If "you" want to roll the dice, it's your funeral. > I don't think the count is tenable either because although it always > feels tempting to add a control dial, it doesn't solve any actual > problem if there's nobody who can know to what value the dial should be > set. Which is why I backed off to the simpler model below. > If "canceled" state persists when the exception is discarded, then > cancel is something different from just "an exception"; It already was something different. The state needed to be stored somewhere until the next cancellation point. This just says that the state persists until otherwise specified. > which is too bad, but perhaps inevitable. You can't just catch it > and continue -- you need to somehow also reset that state to recover > your workgroup thread that's serially running RPC requests (or > Python code, whatever). We could do something awful, like have catch-cancellation-by-value cause the state to be reset, while catch(...) and catch-cancellation-by-reference don't. That would preserve the convenience, at least. > A lot of people have suggested various ways of making cancel-pending > persist after the exception is launched; that's not necessarily > "wrong", but it isn't "simple" either > and somehow it doesn't feel > right to me. It's simpler, by most measures I can think of, than resetting the state upon throwing. >> A simpler approach might be to have two kinds of exception: "forced" >> and finalizable. At least then we can say that exception-safe code >> implies finalizable cancellation safety. Then "forced" synchronous >> cancellation can do whatever people desire. I personally think it >> will become a useless appendage sort of like C++ exception >> specifications, but at least evolution will take care of it. And if >> I'm wrong, evolution will wilt my finalizable cancellations. >> > Is this the "unwind" vs "exception" idea? (Where "unwind" is like a new > sort of 'throw' that triggers dtors but can't be caught/finalized.) Or > something different...? No, I wasn't suggesting anything that couldn't be caught. I was just suggesting an exception that couldn't be stopped. It could throw itself in its dtor (not that I'm advocating it, but it might satisfy the "other side"), for example. In fact, a general mechanism like: cancel( thread_id, exception_object ); is possible, where "cancel" really means throw a copy of the given exception object when the specified thread reaches the next cancellation point. We could call it throw_synchronously( thread_id, exception_object ); instead, if "cancel" really means forced execution to too many people. -- Dave Abrahams Boost Consulting www.boost-consulting.com From david.butenhof at hp.com Mon Mar 6 23:45:58 2006 From: david.butenhof at hp.com (Dave Butenhof) Date: Mon, 06 Mar 2006 18:45:58 -0500 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> Message-ID: <440CC9B6.4010502@hp.com> David Abrahams wrote: > Dave Butenhof writes: > >> Absolutely. There was a strong sub-faction in POSIX that can be >> loosely characterized as "academics" who were determined to try to >> prevent constructs that might be misused. >> > You mean, like, computers? > OK, that's the laugh for today. Yeah, well, that's certainly what you get if you take it too far to the extreme. >> It's why the realtime people didn't get pthread_abort() to force >> termination without cleanup, why you can't suspend a thread, or >> "force unlock" a mutex that might have been abandoned, and so >> forth. >> > Oh, too bad. > Yes and no. There's a line, somewhere, between something that's reasonably usable by some set of people to solve real problems, even if it can be easily and destructively misused by others; and something that makes a fun toy for a few researchers but is virtually impossible to use correctly or safely in real code. A lot of the argument hinges on where to draw that line; it's almost never "cut and dried". >> If cancellation can't be finalized, nobody can accidentally >> finalize it; and that's great if you don't trust anyone to know when >> it SHOULD be finalized. I started out as something of an "academic" >> in this sense and evolved into a pramatist... if someone thinks they >> need it, and they're right, don't keep them from doing it. And if >> they're WRONG, it's their problem, not yours. ;-) Portable Java GC >> would have been a lot easier had POSIX included suspend/resume; and >> does it really matter that nearly anyone else who used it would be >> breaking their application? Well, it all depends on your point of >> view... >> > I don't know about that suspend/resume, but I don't think legitimate > cases where finalization is needed are nearly so rare as you describe > cases where suspend/resume is needed to be. > Probably. I probably also got carried away with the analogy, because the amount of detail was largely irrelevant in this forum. >>> A ctor that does catch(...) without rethrow is almost always badly >>> designed at best. There was unfortunate advice going around for many >>> years that you shouldn't throw from ctors, but that's exactly wrong: >>> ctors that throw allow the establishment of strong invariants, and >>> programming without them is much harder. >>> >>> On the other hand, stopping exceptions in dtors is absolutely the >>> right thing to do. >>> >> Yes, I may have said that backwards. As I've said before, although I use >> C++, it's not a "native language" for me, and a lot of this is based on >> opinions others have strongly stated >> > It wouldn't surprise me a bit if others had strongly stated ctors > shouldn't throw. It used to be the advice in Stroustrup's books. > And often I think it makes sense to construct a viable object even in the face of errors, and restrict the behavior of the object later. >> rather than my own knowledge or experience. Another reason, >> incidentally, for not trying to come down too hard on one side or >> the other where language concerns might trump "threading" concerns. >> >>>> and they have some legitimate concerns about common C++ language >>>> patterns that might pretty much prevent a cancel from ever doing >>>> what a cancel should do. >>>> >>> Really, legitimate concerns? I can't think of any recommended >>> patterns that would act that way. >>> >> Hmm. OK. That's interesting. Well, you're the C++ expert here. ;-) >> > None other than, "prevent exceptions from leaking across language > boundaries." But if you don't do that, your program is broken anyway. > Well, non-exception-savvy languages, sure. But (OK, perhaps a VMS bias here) I think all languages on a platform should have a common exception model that interoperates cleanly when stack frames are interleaved. Certainly if you're interleaved for Java, or Ada, you should be able to have an exception propagate through and unwind, run destructors (or Ada finally clauses), etc., with no problems. And where ISO C is extended for exception semantics (e.g., VMS, Tru64, Windows...), C can join the club. Sigh. The best thing about the abandoned effort to build an Itanium ABI for the Single UNIX Specification was that we'd succeeded in extracting the specification of a C++ exception runtime as the beginning of a standard cross platform and cross language common exception runtime. >>> You don't find the idea that exception-safe code implies cancel-safe >>> code technically compelling? I don't think that's an emotional issue. >>> >> Well, yes, I do, >> > find it technically compelling, or think it's an emotional issue > What I meant was the former. However the fact that I, or you, find it technically compelling doesn't make it right, and certainly doesn't mean everyone will agree. And historically the disagreement has indeed been emotional. So, both are accurate. >> because cancel was always intended to be "just" an exception that >> happened to be thrown from another thread. But then, nothing is ever >> that simple; the asynchronous nature required controls like >> cancelability type and state. >> > "Asynchronous nature?" > > I haven't even been considering asynchronous cancellation as it's > completely untenable to write anything but the most restricted code > that could work in the face of async cancellation. > Ah, but cancellation is basically asynchronous with respect to the receiving thread. Even though we deliver the exception only at defined synchronous points, the cancellation request can arrive at any instant. This is mostly relevant when you talk about blocking behavior -- that a blocking operation can be interrupted anywhere in the middle IS asynchronous. "Deferred" cancelability converts that asynchronous interrupt into a synchronous exception, though the definition of the blocking operation as a cancellation point. So the cancelled thread doesn't necessarily see the exception as "asynchronous" (it called a function, and got back an exception); but that doesn't change the fact that it really was asynchronous all the same. But I don't mean it in anything like the sense of "asynchronous cancelability mode", where the exception can be raised (cancel delivered) at any arbitrary point. Asynchronous cancelability was invented for use in tight compute-bound loops, and intended to be unusable anywhere else. It's one of the things we thought reasonable at the time but that I've since become convinced should have been on the other side of the "too unsafe and rarely useful to be standardized" line. >> C++ exceptions are synchronous and non-interrupting. (The latter a >> consequence of the former, really.) One of the main advantages of >> cancellation is that it can break through an extended blocking >> operation; >> > If you make all blocking operations cancellation points you can do > that anyway. No? > That's the intent... >> but that's unavoidably an extra condition over "exception-safety". >> Cancel-safe has to mean something more unless we drop >> interruptibility. If we drop it, then cancel-safety is just >> exception-safety but loses much of its value in controlling >> application responsiveness. >> > You lost me. I think async cancel safety should be thought of as a > separate level of design. > Um, OK; I'm not sure where I lost you. I'm not talking about asynchronous cancelability. I personally don't think C++ should even briefly entertain the notion of any support for that. However, when cancellation is enabled, any blocking call (or any method/operator that makes or might make a blocking call, like "cout<<", might raise an exception. Not all code will be prepared to handle that, and much shouldn't be; it's important to be able to disable cancelability dynamically over critical scopes. It's not like most exceptions where the conditions for an exception are generally static; it could happen at any time for reasons the current thread cannot possibly anticipate. It's asynchronous simply because it's external and independent. Also, where a normal exception means "something's wrong and I can't continue on this code path", cancellation means sometime subtly different -- "I've been asked not to" rather than "I can't"; but if you must, you may. ;-) Therefore we have cancelability state to managed scoped local control over when the thread can respond to cancellation requests. (An obvious candidate, in C++, for guard objects.) >> In any case, though, I wasn't suggesting that you need to convince >> me. I'm saying there are diverse and strongly held positions that >> somehow need to be unified in order to get consensus on any >> proposal. I think that I'm the least of your worries. ;-) >> > Not that you have any obligation to do so, but it might be easier if > you would recognize the weight your opinion carries. That might mean > learning enough about C++ to form a definite opinion. That's, at > least, what I've tried to do with threading. > I'm not ignorant of C++, and I'm much less ignorant than I was 2 years ago when I started working with C++ and STL on a regular basis. Still, I am not steeped in the history and tradition of C++ as I am in threads, and probably never will be. More than that, while I have an authoritative voice on the POSIX working group and in the community, I'm not involved with the C++ committee and have no time or management support to get involved; and I won't put myself in the position of being an outside expert in some other area pretending to tell the C++ committee what it must (or even should) do. I will happily say that as a thread expert and C++ dabbler, this is what seems to make sense to me; but I reject any aura of authority in the C++ side of semantics and syntax. However my statement above wasn't in any way related to my tradition of C++ deference. I was merely stating that I've seen many opinions (other than mine) that will need to be resolved or accommodated to make a standard. >>>> Someone needs to propose and champion "the great exception >>>> compromise"; but if that's to be me I don't yet have the faintest >>>> germ of a notion what it might be. So I sure hope it's going to be >>>> someone else. ;-) >>>> >>> If "finalized cancellation exceptions result in a new throw at the >>> next cancellation point" isn't enough of a compromise, it isn't going >>> to be me either, because I'm out of new ideas. >>> >>> Okay, how about this one: we count the number of times the >>> cancellation is discarded. The cancelling thread can specify the >>> number of discards to tolerate, where the default is infinite. After >>> that, at the next cancellation point all pthread cancellation handlers >>> (but not dtors or catch blocks) are run and the thread is terminated. >>> Heck, at that point I don't care what happens; you're gambling anyway. >>> Run all the dtors and catch blocks for all I care. >>> >> I do NOT favor any model where "dtor/catch" and "cancellation handler" >> don't mean the same thing. >> > Like I said, I don't care at that point. A forced cancellation is a > big gamble. If "you" want to roll the dice, it's your funeral. > >> I don't think the count is tenable either because although it always >> feels tempting to add a control dial, it doesn't solve any actual >> problem if there's nobody who can know to what value the dial should be >> set. >> > Which is why I backed off to the simpler model below. > >> If "canceled" state persists when the exception is discarded, then >> cancel is something different from just "an exception"; >> > It already was something different. The state needed to be stored > somewhere until the next cancellation point. This just says that the > state persists until otherwise specified. > >> which is too bad, but perhaps inevitable. You can't just catch it >> and continue -- you need to somehow also reset that state to recover >> your workgroup thread that's serially running RPC requests (or >> Python code, whatever). >> > > We could do something awful, like have catch-cancellation-by-value > cause the state to be reset, while catch(...) and > catch-cancellation-by-reference don't. That would preserve the > convenience, at least. > Um, yeah; I suppose it would. But I agree more strongly about the "awful". ;-) >> A lot of people have suggested various ways of making cancel-pending >> persist after the exception is launched; that's not necessarily >> "wrong", but it isn't "simple" either >> and somehow it doesn't feel >> right to me. >> > It's simpler, by most measures I can think of, than resetting the > state upon throwing. > >>> A simpler approach might be to have two kinds of exception: "forced" >>> and finalizable. At least then we can say that exception-safe code >>> implies finalizable cancellation safety. Then "forced" synchronous >>> cancellation can do whatever people desire. I personally think it >>> will become a useless appendage sort of like C++ exception >>> specifications, but at least evolution will take care of it. And if >>> I'm wrong, evolution will wilt my finalizable cancellations. >>> >> Is this the "unwind" vs "exception" idea? (Where "unwind" is like a new >> sort of 'throw' that triggers dtors but can't be caught/finalized.) Or >> something different...? >> > No, I wasn't suggesting anything that couldn't be caught. I was just > suggesting an exception that couldn't be stopped. It could throw > itself in its dtor (not that I'm advocating it, but it might satisfy > the "other side"), for example. > The POSIX model where cancel propagates inexorably to thread termination is an inherently flawed compromise; but simply the best we could do within the context of ISO C and POSIX APIs. OUR implementation always allowed finalization, via C++ catch(...), our ISO C "CATCH_ALL" extensions, or whatever other language syntax might fit. I really wouldn't want to propagate this restriction to C++. > In fact, a general mechanism like: > > cancel( thread_id, exception_object ); > > is possible, where "cancel" really means throw a copy of the given > exception object when the specified thread reaches the next > cancellation point. > > We could call it > > throw_synchronously( thread_id, exception_object ); > > instead, if "cancel" really means forced execution to too many people. > That's actually where we started out in CMA. Resolving down to a single pre-defined exception was partly a matter of simplicity, but also represented a basic thread model that "a thread is simple; it's an asynchronous procedure call within the context of an application, not an independent application". In any case where you would need to distinguish between two separate interrupt conditions, the functions stimulated by those separate interrupts should have been assigned to separate threads and therefore only one exception is needed. While this made a lot of sense at the time, we were in a very academic and theoretical phase, and there was not that great a body of threaded code in 1987 -- and none using anything closely resembling the thread model we were inventing and that became the principal influence for POSIX. SRC's Firefly/Modula-3 had "alert", but it was so much simpler as to be a distinct variety of beast. One advantage, though, of the single cancel exception, is that it's universal. When you asynchronously issue a cancel request for a thread, you can't really know what code is executing: your's, STL, some other shared library, etc. Cancel means the same to all of them, and either is supported with commonly agreed semantics or will be ignored (by disabling cancellation in critical scopes). Once you start firing off your own arbitrary exceptions, though, anything might happen because half the time the exceptions won't belong anywhere in the call tree that's active at the time they arrive. Which brings us back to the "academic" resolution: if an exception means distinct things in different call trees, those call trees should be distinct threads and only one universal exception is necessary. ;-) -------------- 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 Mar 7 21:49:39 2006 From: dave at boost-consulting.com (David Abrahams) Date: Tue, 07 Mar 2006 13:49:39 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <440CC9B6.4010502@hp.com> (Dave Butenhof's message of "Mon, 06 Mar 2006 18:45:58 -0500") References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> <440CC9B6.4010502@hp.com> Message-ID: Dave Butenhof writes: >>> Yes, I may have said that backwards. As I've said before, although >>> I use C++, it's not a "native language" for me, and a lot of this >>> is based on opinions others have strongly stated >> >> It wouldn't surprise me a bit if others had strongly stated ctors >> shouldn't throw. It used to be the advice in Stroustrup's books. >> > And often I think it makes sense to construct a viable object even in > the face of errors, and restrict the behavior of the object later. Weak invariants are the result, if you're saying what it sounds like you're saying. Weak invariants are almost always worth avoiding. >> None other than, "prevent exceptions from leaking across language >> boundaries." But if you don't do that, your program is broken anyway. >> > Well, non-exception-savvy languages, sure. But (OK, perhaps a VMS bias > here) I think all languages on a platform should have a common exception > model that interoperates cleanly when stack frames are interleaved. That's nice unless someone decides they're going to write in standard 'C.' And most people do, right? In general, take an arbitrary Unix library or program written in 'C', and you're unlikely to find any EH support in there. > Certainly if you're interleaved for Java, or Ada, you should be able to > have an exception propagate through and unwind, run destructors (or Ada > finally clauses), etc., with no problems. And where ISO C is extended > for exception semantics (e.g., VMS, Tru64, Windows...), C can join > the club. Can, yes. But speaking broadly, it's not likely to be the case. >>>> You don't find the idea that exception-safe code implies cancel-safe >>>> code technically compelling? I don't think that's an emotional issue. >>>> >>> Well, yes, I do, >> >> find it technically compelling, or think it's an emotional issue >> > What I meant was the former. However the fact that I, or you, find > it technically compelling doesn't make it right, and certainly > doesn't mean everyone will agree. Goes without saying. > And historically the disagreement has indeed been emotional. So, > both are accurate. Whatever. >> I haven't even been considering asynchronous cancellation as it's >> completely untenable to write anything but the most restricted code >> that could work in the face of async cancellation. >> > Ah, but cancellation is basically asynchronous with respect to the > receiving thread. Not the kind of cancellation that uses cancellation points. "Asynchronous exception" means an exception that emanates from code that is not allowed to throw unless undefined behavior is invoked. Everything else is a synchronous exception. If you call some of that latter stuff "asynchronous," (a)synchronicity of exceptions becomes a useless distinction. > Even though we deliver the exception only at defined synchronous > points, the cancellation request can arrive at any instant. But exactly when it arrives is irrelevant with respect to the receiving thread. > This is mostly relevant when you talk about blocking behavior -- > that a blocking operation can be interrupted anywhere in the middle > IS asynchronous. Huh? It sounds like you're interested in some detail that I don't yet have context for. > "Deferred" cancelability converts that asynchronous interrupt into a > synchronous exception, though the definition of the blocking operation > as a cancellation point. So the cancelled thread doesn't necessarily see > the exception as "asynchronous" (it called a function, and got back an > exception); but that doesn't change the fact that it really was > asynchronous all the same. Cancellation can be as asynchronous as you like from that definition. The resulting exception is still synchronous. > But I don't mean it in anything like the sense of "asynchronous > cancelability mode", where the exception can be raised (cancel > delivered) at any arbitrary point. Good. Let's pick different terms that don't lead to this confusion, please. > Asynchronous cancelability was invented for use in tight > compute-bound loops, and intended to be unusable anywhere else. It's > one of the things we thought reasonable at the time but that I've > since become convinced should have been on the other side of the > "too unsafe and rarely useful to be standardized" line. > >>> C++ exceptions are synchronous and non-interrupting. (The latter a >>> consequence of the former, really.) One of the main advantages of >>> cancellation is that it can break through an extended blocking >>> operation; >> >> If you make all blocking operations cancellation points you can do >> that anyway. No? >> > That's the intent... > >>> but that's unavoidably an extra condition over "exception-safety". >>> Cancel-safe has to mean something more unless we drop >>> interruptibility. If we drop it, then cancel-safety is just >>> exception-safety but loses much of its value in controlling >>> application responsiveness. >>> >> You lost me. I think async cancel safety should be thought of as a >> separate level of design. >> > Um, OK; I'm not sure where I lost you. I'm not talking about > asynchronous cancelability. I personally don't think C++ should even > briefly entertain the notion of any support for that. Great. Sounds like there's no disagreement, then. > However, when cancellation is enabled, any blocking call (or any > method/operator that makes or might make a blocking call, like > "cout<<", might raise an exception. Not all code will be prepared to > handle that, and much shouldn't be; it's important to be able to > disable cancelability dynamically over critical scopes. It's not > like most exceptions where the conditions for an exception are > generally static; it could happen at any time for reasons the > current thread cannot possibly anticipate. That's exactly like most exceptions (c.f. out-of-memory). Usually conditions whose reasons can be anticipated can be effectively tested and become preconditions or simply should be reported by other means. > It's asynchronous simply because it's external and > independent. Also, where a normal exception means "something's wrong > and I can't continue on this code path", cancellation means sometime > subtly different -- "I've been asked not to" rather than "I can't"; > but if you must, you may. ;-) Once the exception is thrown, it amounts to exactly the same thing. > Therefore we have cancelability state to managed scoped local control > over when the thread can respond to cancellation requests. (An obvious > candidate, in C++, for guard objects.) Okay. Not sure what your point is, but I don't disagree. >>> In any case, though, I wasn't suggesting that you need to convince >>> me. I'm saying there are diverse and strongly held positions that >>> somehow need to be unified in order to get consensus on any >>> proposal. I think that I'm the least of your worries. ;-) >>> >> Not that you have any obligation to do so, but it might be easier if >> you would recognize the weight your opinion carries. That might mean >> learning enough about C++ to form a definite opinion. That's, at >> least, what I've tried to do with threading. >> > I'm not ignorant of C++, I didn't think so. > and I'm much less ignorant than I was 2 years ago when I started > working with C++ and STL on a regular basis. Still, I am not steeped > in the history and tradition of C++ as I am in threads, and probably > never will be. More than that, while I have an authoritative voice > on the POSIX working group and in the community, I'm not involved > with the C++ committee and have no time or management support to get > involved; and I won't put myself in the position of being an outside > expert in some other area pretending to tell the C++ committee what > it must (or even should) do. I don't think you should. There are other areas where you could make a big difference, though, like the ISO committee for C++/POSIX binding Mr. Drepper is now running. > I will happily say that as a thread expert and C++ dabbler, this is > what seems to make sense to me; but I reject any aura of authority > in the C++ side of semantics and syntax. > > However my statement above wasn't in any way related to my tradition > of C++ deference. I was merely stating that I've seen many opinions > (other than mine) that will need to be resolved or accommodated to > make a standard. Understood. That's normal. >>>> A simpler approach might be to have two kinds of exception: "forced" >>>> and finalizable. At least then we can say that exception-safe code >>>> implies finalizable cancellation safety. Then "forced" synchronous >>>> cancellation can do whatever people desire. I personally think it >>>> will become a useless appendage sort of like C++ exception >>>> specifications, but at least evolution will take care of it. And if >>>> I'm wrong, evolution will wilt my finalizable cancellations. >>>> >>> Is this the "unwind" vs "exception" idea? (Where "unwind" is like a >>> new sort of 'throw' that triggers dtors but can't be >>> caught/finalized.) Or something different...? >>> >> No, I wasn't suggesting anything that couldn't be caught. I was just >> suggesting an exception that couldn't be stopped. It could throw >> itself in its dtor (not that I'm advocating it, but it might satisfy >> the "other side"), for example. >> > The POSIX model where cancel propagates inexorably to thread termination > is an inherently flawed compromise; but simply the best we could do > within the context of ISO C and POSIX APIs. OUR implementation always > allowed finalization, via C++ catch(...), our ISO C "CATCH_ALL" > extensions, or whatever other language syntax might fit. > > I really wouldn't want to propagate this restriction to C++. Be clear, I'm not talking about a restriction. If you ask it to throw something normal, it's finalizable in the normal way. This is a way for the _cancelling_ thread to say, "I know what I'm doing; the author of the thread I'm cancelling doesn't. Force it to be killed at the next cancellation point." >> In fact, a general mechanism like: >> >> cancel( thread_id, exception_object ); >> >> is possible, where "cancel" really means throw a copy of the given >> exception object when the specified thread reaches the next >> cancellation point. >> >> We could call it >> >> throw_synchronously( thread_id, exception_object ); >> instead, if "cancel" really means forced execution to too many >> people. >> > That's actually where we started out in CMA. Resolving down to a > single pre-defined exception was partly a matter of simplicity, but > also represented a basic thread model that "a thread is simple; it's > an asynchronous procedure call within the context of an application, > not an independent application". In any case where you would need to > distinguish between two separate interrupt conditions, the functions > stimulated by those separate interrupts should have been assigned to > separate threads and therefore only one exception is needed. > > While this made a lot of sense at the time, we were in a very > academic and theoretical phase, and there was not that great a body > of threaded code in 1987 -- and none using anything closely > resembling the thread model we were inventing and that became the > principal influence for POSIX. SRC's Firefly/Modula-3 had "alert", > but it was so much simpler as to be a distinct variety of beast. > > One advantage, though, of the single cancel exception, is that it's > universal. When you asynchronously issue a cancel request for a thread, > you can't really know what code is executing: your's, STL, some other > shared library, etc. Cancel means the same to all of them, and either is > supported with commonly agreed semantics or will be ignored (by > disabling cancellation in critical scopes). Once you start firing off > your own arbitrary exceptions, though, anything might happen because > half the time the exceptions won't belong anywhere in the call tree > that's active at the time they arrive. That's not the way most exception-safe code works. It goes to the reason that exception-specifications are a failure: the particular type of exception that propagates out of a throwing function makes almost no difference to anyone. The type only becomes important where errors are reported, or where exceptions are translated -- either to other exception types or, for example, to error return codes that can propagate through other languages. So the danger of injecting an arbitrary exception type into existing code (especially libraries, which are very often exception-neutral) is very very low. > Which brings us back to the "academic" resolution: if an exception > means distinct things in different call trees, those call trees > should be distinct threads and only one universal exception is > necessary. ;-) I think you might be missing the point. I am proposing the generalized thread_throw( thread_id, exception_object ) function so that those who wish to hang themselves with homegrown unstoppable exception types can do so without forcing the standard to sanction the use of unstoppable exceptions by providing any kind of "forced cancellation." If "the other side" has A WAY to force cancellation, maybe they won't insist it has to be THE WAY. I know, wishful thinking :) -- Dave Abrahams Boost Consulting www.boost-consulting.com From david.butenhof at hp.com Wed Mar 8 02:22:32 2006 From: david.butenhof at hp.com (Dave Butenhof) Date: Tue, 07 Mar 2006 21:22:32 -0500 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> <440CC9B6.4010502@hp.com> Message-ID: <440E3FE8.4040902@hp.com> David Abrahams wrote: > Dave Butenhof writes: > I'm cutting off a lot of the top part. It's getting long, the discussion isn't really going anywhere relevant to the root topic, and we're probably better off just dropping it. That, at any rate, is my preference. ;-) >> Ah, but cancellation is basically asynchronous with respect to the >> receiving thread. >> > Not the kind of cancellation that uses cancellation points. > "Asynchronous exception" means an exception that emanates from code > that is not allowed to throw unless undefined behavior is invoked. > Everything else is a synchronous exception. If you call some of that > latter stuff "asynchronous," (a)synchronicity of exceptions becomes a > useless distinction. > The entire point of threads is that their operation is asynchronous. Everything about the design of a threaded application, a runtime and OS that support threads, a LANGUAGE that supports threads, has to be to deal with asynchrony -- with parallel call stacks running simultaneously. Anything that happens in or because of a thread is asynchronous with respect to other threads. Deferred cancellation is a "conversion interface" to allow the asynchronous external event to manifest synchronously in the target thread, for ease and consistency of cleanup. But that doesn't make the event synchronous, and I think that the distinction is important. Cancellation is asynchronous up to the point where the exception is thrown, synchronously, by the target thread to unwind and terminate. A blocking read operation isn't cancelled synchronously at the beginning or end of the operation, or even the beginning or end of the blocking part of the I/O -- it can be interrupted asynchronously somewhere in the middle. In my implementation, I initiated the unwind (the "throw") from the interrupt handler, if cancellation is enabled, rather than deferring it until the unblocked operation wakes up... though that would certainly be another alternative. >> Even though we deliver the exception only at defined synchronous >> points, the cancellation request can arrive at any instant. >> > But exactly when it arrives is irrelevant with respect to the > receiving thread. > I suppose you can reasonably argue that. I think that understanding the model is important when you making coding decisions. >> This is mostly relevant when you talk about blocking behavior -- >> that a blocking operation can be interrupted anywhere in the middle >> IS asynchronous. >> > Huh? It sounds like you're interested in some detail that I don't yet > have context for. > Perhaps I'm worried about thought models and implementation while you're concerned with appearance. Both views are certainly valid within certain domains. >> "Deferred" cancelability converts that asynchronous interrupt into a >> synchronous exception, though the definition of the blocking operation >> as a cancellation point. So the cancelled thread doesn't necessarily see >> the exception as "asynchronous" (it called a function, and got back an >> exception); but that doesn't change the fact that it really was >> asynchronous all the same. >> > Cancellation can be as asynchronous as you like from that definition. > The resulting exception is still synchronous. > Right. Cancellation is asynchronous. The exception that notifies the thread of cancellation is synchronous. There we go. That's the conversion interface. >> But I don't mean it in anything like the sense of "asynchronous >> cancelability mode", where the exception can be raised (cancel >> delivered) at any arbitrary point. >> > Good. Let's pick different terms that don't lead to this confusion, > please. > But C++ people should be good at overloading. ;-) "Asynchronous cancelability type" is (at least potentially) an asynchronous EXCEPTION in response to an asynchronous event, while "deferred cancelability type" is a synchronous (deferred) exception in response to the same asynchronous event. Does that help? Cancelability type affects only the DELIVERY of notification within the target thread, not either the "launching" or "delivery" mechanisms of cancellation. >> However, when cancellation is enabled, any blocking call (or any >> method/operator that makes or might make a blocking call, like >> "cout<<", might raise an exception. Not all code will be prepared to >> handle that, and much shouldn't be; it's important to be able to >> disable cancelability dynamically over critical scopes. It's not >> like most exceptions where the conditions for an exception are >> generally static; it could happen at any time for reasons the >> current thread cannot possibly anticipate. >> > That's exactly like most exceptions (c.f. out-of-memory). Usually > conditions whose reasons can be anticipated can be effectively tested > and become preconditions or simply should be reported by other means. > Sometimes. Exceptions are great for "out of band" notifications that may not be intended for the direct caller; they can be picked up with full state, and without additional mechanism, by anyone along the call path who cares. >> and I'm much less ignorant than I was 2 years ago when I started >> working with C++ and STL on a regular basis. Still, I am not steeped >> in the history and tradition of C++ as I am in threads, and probably >> never will be. More than that, while I have an authoritative voice >> on the POSIX working group and in the community, I'm not involved >> with the C++ committee and have no time or management support to get >> involved; and I won't put myself in the position of being an outside >> expert in some other area pretending to tell the C++ committee what >> it must (or even should) do. >> > I don't think you should. There are other areas where you could make > a big difference, though, like the ISO committee for C++/POSIX binding > Mr. Drepper is now running. > "ISO committee" is rather a strong description; it's a simple mailing list that's hoping to gain some preliminary consensus towards constructing a formal proposal to request permission to develop a charter and start a working group with the intent of building a proposal for a binding. But, yeah, OK, fine. ;-) In any case, I am following it, and contributing to the (sporadic) discussions. In fact, when I got your re-opening of this mailing list I initially thought you were writing to that one; though this discussion is rather more detailed and relevant than what we've seen so far on the other. I will get as involved as I can given my time constraints, but we'll see what that amounts to as the mailing list discussions progress. I assure you that if I hold back it's not for lack of interest or motivation. ;-) >>> No, I wasn't suggesting anything that couldn't be caught. I was just >>> suggesting an exception that couldn't be stopped. It could throw >>> itself in its dtor (not that I'm advocating it, but it might satisfy >>> the "other side"), for example. >>> >> The POSIX model where cancel propagates inexorably to thread termination >> is an inherently flawed compromise; but simply the best we could do >> within the context of ISO C and POSIX APIs. OUR implementation always >> allowed finalization, via C++ catch(...), our ISO C "CATCH_ALL" >> extensions, or whatever other language syntax might fit. >> >> I really wouldn't want to propagate this restriction to C++. >> > Be clear, I'm not talking about a restriction. If you ask it to throw > something normal, it's finalizable in the normal way. This is a way > for the _cancelling_ thread to say, "I know what I'm doing; the author > of the thread I'm cancelling doesn't. Force it to be killed at the > next cancellation point." > The whole concept of cancellation is exactly that the TARGET thread, not the cancelling thread, knows what it's doing and should control the cleanup and termination entirely. Without explicit synchronization, the cancelling thread can't know what it's doing and whether a forced abort is appropriate or safe. And if it has enough synchronization to know that, there are far better ways to gain a cooperative termination than cancellation. >> One advantage, though, of the single cancel exception, is that it's >> universal. When you asynchronously issue a cancel request for a thread, >> you can't really know what code is executing: your's, STL, some other >> shared library, etc. Cancel means the same to all of them, and either is >> supported with commonly agreed semantics or will be ignored (by >> disabling cancellation in critical scopes). Once you start firing off >> your own arbitrary exceptions, though, anything might happen because >> half the time the exceptions won't belong anywhere in the call tree >> that's active at the time they arrive. >> > That's not the way most exception-safe code works. It goes to the > reason that exception-specifications are a failure: the particular > type of exception that propagates out of a throwing function makes > almost no difference to anyone. The type only becomes important where > errors are reported, or where exceptions are translated -- either to > other exception types or, for example, to error return codes that can > propagate through other languages. So the danger of injecting an > arbitrary exception type into existing code (especially libraries, > which are very often exception-neutral) is very very low. > That's an intriguing statement. I'll need to think about that some. I've certainly always thought that exception specifications were little more than a trap into which people could mire themselves as deeply as they like. So maybe that means I agree. I'm not sure. ;-) I guess I'd have to agree that the danger of injecting another exception type is low. And mostly due to the fact that C++ has no "root exception type" onto which could be grafted some minimal universal state (an architected status code space, like VMS condition codes, a descriptive string, etc.) so that nobody would need an anonymous and semantic-free catch(...) just to be sure nothing slipped past. >> Which brings us back to the "academic" resolution: if an exception >> means distinct things in different call trees, those call trees >> should be distinct threads and only one universal exception is >> necessary. ;-) >> > I think you might be missing the point. I am proposing the generalized > > thread_throw( thread_id, exception_object ) > > function so that those who wish to hang themselves with homegrown > unstoppable exception types can do so without forcing the standard to > sanction the use of unstoppable exceptions by providing any kind of > "forced cancellation." If "the other side" has A WAY to force > cancellation, maybe they won't insist it has to be THE WAY. I know, > wishful thinking :) > I'm not sure how sanctioning generalized unstoppable exceptions is going to mollify anyone opposed to an unstoppable variety of a specific exception. At best, cancel becomes a subset of cross-thread throw with specialized additional deferral semantics. And if you're generalizing the unstoppable exception, I don't quite see how it makes sense not to generalize the deferral, and now cancel really is just a specific predefined exception that can be thrown like any other exception. That's not necessarily bad; I just don't see how it's a compromise. (A compromise needs to make BOTH sides equally unhappy, not just one side!) -------------- next part -------------- A non-text attachment was scrubbed... Name: david.butenhof.vcf Type: text/x-vcard Size: 476 bytes Desc: not available URL: From david.butenhof at hp.com Wed Mar 8 13:31:51 2006 From: david.butenhof at hp.com (Dave Butenhof) Date: Wed, 08 Mar 2006 08:31:51 -0500 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> <440CC9B6.4010502@hp.com> <440E3FE8.4040902@hp.com> Message-ID: <440EDCC7.9010902@hp.com> David Abrahams wrote: > OK, it's a study group. Slightly more than a mailing list, but hardly > a committee. I guess I'm just alarmist. > I shouldn't belabor the point, but it really is just a mailing list at this point. That is, membership and participation in the mailing list does not imply any formal (or even semi-formal) association with a "study group"; just willingness to sign up and maybe read, possibly even reply, with no obligation. >> I guess I'd have to agree that the danger of injecting another exception >> type is low. And mostly due to the fact that C++ has no "root exception >> type" onto which could be grafted some minimal universal state >> > It has a de-facto root type: std::exception. > And if it was used universally that would be almost as good as a de-jure root type. ;-) >> (an architected status code space, like VMS condition codes, a >> descriptive string, etc.) so that nobody would need an anonymous and >> semantic-free catch(...) just to be sure nothing slipped past. >> > When you have a root type, catching that is practically anonymous and > semantic-free. It doesn't make much difference in practice. > A root type with properties can be processed and explained, unlike a truly anonymous 'catch(...)'. For example, I've been doing a lot of programming lately with the WBEM distributed management system. It has a C++ layer over the real XML and transport mechanism, making a fairly decent RPC. (With some archaic annoyances like non-STL standard strings and arrays because it was standardized before the real STL.) But only CIM exceptions are carried back "over the wire" from server to client; anything else allowed to propagate outside the server-side object comes through just as "unknown error". That's the consequence of 'catch(...)'. If there was a language requirement for example that all exceptions be subclasses of std::exception, you could catch(const exception &e) and always depend on being able to re-throw CIMOperationFailedException(String(e.what())). In terms of code flow, the difference is almost irrelevant (though I know of WBEM providers that include distinctive text in their exception descriptions and clients that parse the text); in terms of human interaction and even error logging, the difference is significant. DCE exceptions carried a standardized error code, which could be decyphered into facility and cause fields, and looked up in a message catalog. That has even greater advantages for code as well as humans, although registering unique facility codes is always a headache. But, OK, this is entirely off-topic basic C++ stuff, not "C++ pthreads", so let's move on... ;-) > Additional? I'm lost again. There is no workable cross-thread throw > without deferral. Anything else is an asynchronous exception. > Hmm. So your thread_throw(), like pthread_cancel(), would simply stash the exception object away somewhere for the target (victim?) thread to throw synchronously at a later time? At the same defined cancellation points? At a different set of points? Subject to cancelability state, or at the next cancellation point no matter what? Do we need to worry about "cancel disabled but other exceptions enabled", or vice versa... and will people expect to be able to enable or disable individual exception types? >> And if you're generalizing the unstoppable exception, >> > Generalizing? > >> I don't quite see how it makes sense not to generalize the deferral, >> and now cancel really is just a specific predefined exception that >> can be thrown like any other exception. That's not necessarily bad; >> I just don't see how it's a compromise. (A compromise needs to make >> BOTH sides equally unhappy, not just one side!) >> > The compromise I'm proposing makes it possible to generate an > unstoppable cancellation (bad for us) while making it ugly and > unnatural to do so (bad for "the other side"). > Ah; I think I misunderstood the semantics of your thread_throw(). From your introduction I took it as a mechanism for injecting any exception into another thread as "unstoppable". Apparently what you intended was that it simply injects ANY exception, and if that happens to be a weird "unstoppable" exception it works the same as it would from a normal throw within a single call stack. OK, I get it. So fine, perhaps that is a viable compromise. I'm not "morally opposed" to a generalized cross-thread exception. I'm not thrilled about anyone injecting unstoppable exceptions into some "innocent" call stack; but like cancellation it can only be done when you at least know the thread ID of the call stack (meaning either you created the thread or the facility that did made the ID available to you in one way or another, though possibly just by making a call into your facility). And if someone does it to some arbitrary and unprepared thread it'll may behave just as badly as they deserve. ;-) -------------- 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 Mar 8 15:28:23 2006 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 08 Mar 2006 07:28:23 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <440EDCC7.9010902@hp.com> (Dave Butenhof's message of "Wed, 08 Mar 2006 08:31:51 -0500") References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> <440CC9B6.4010502@hp.com> <440E3FE8.4040902@hp.com> <440EDCC7.9010902@hp.com> Message-ID: Dave Butenhof writes: >> Additional? I'm lost again. There is no workable cross-thread throw >> without deferral. Anything else is an asynchronous exception. >> > Hmm. So your thread_throw(), like pthread_cancel(), would simply > stash the exception object away somewhere for the target (victim?) > thread to throw synchronously at a later time? At the same defined > cancellation points? At a different set of points? Same points. > Subject to cancelability state, or at the next cancellation point no > matter what? Subject to cancelability. In C++ "cancelability" would indicate whether cancellation points can throw (these asynchronously-initiated exceptions). I actually think the parenthesized part could be removed, for all practical purposes. There's usually little point in preventing a function from throwing cancellation if it can throw something else. > Do we need to worry about "cancel disabled but other exceptions > enabled", or vice versa... and will people expect to be able to > enable or disable individual exception types? Naw, I don't think so. Nobody has mentioned a use case. If we find it is suddenly in demand because of some unanticipated use case, that sort of selective cancelability is pretty easy to add. >>> And if you're generalizing the unstoppable exception, >> Generalizing? >> >>> I don't quite see how it makes sense not to generalize the deferral, >>> and now cancel really is just a specific predefined exception that >>> can be thrown like any other exception. That's not necessarily bad; >>> I just don't see how it's a compromise. (A compromise needs to make >>> BOTH sides equally unhappy, not just one side!) >>> >> The compromise I'm proposing makes it possible to generate an >> unstoppable cancellation (bad for us) while making it ugly and >> unnatural to do so (bad for "the other side"). >> > Ah; I think I misunderstood the semantics of your thread_throw(). From > your introduction I took it as a mechanism for injecting any exception > into another thread as "unstoppable". Apparently what you intended was > that it simply injects ANY exception, and if that happens to be a weird > "unstoppable" exception it works the same as it would from a normal > throw within a single call stack. Correct. > OK, I get it. > > So fine, perhaps that is a viable compromise. I'm not "morally > opposed" to a generalized cross-thread exception. I'm not thrilled > about anyone injecting unstoppable exceptions into some "innocent" > call stack; but like cancellation it can only be done when you at > least know the thread ID of the call stack (meaning either you > created the thread or the facility that did made the ID available to > you in one way or another, though possibly just by making a call > into your facility). And if someone does it to some arbitrary and > unprepared thread it'll may behave just as badly as they > deserve. ;-) Yes. I do have sympathy, incidentally, for the other side's desire to "try really hard" to shut a thread down cleanly. I just don't happen to think unstoppable exceptions are a particularly effective tool for that job. -- Dave Abrahams Boost Consulting www.boost-consulting.com From dave at boost-consulting.com Wed Mar 8 12:40:59 2006 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 08 Mar 2006 04:40:59 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <440E3FE8.4040902@hp.com> (Dave Butenhof's message of "Tue, 07 Mar 2006 21:22:32 -0500") References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> <440CC9B6.4010502@hp.com> <440E3FE8.4040902@hp.com> Message-ID: Dave Butenhof writes: > Perhaps I'm worried about thought models and implementation while you're > concerned with appearance. Both views are certainly valid within certain > domains. I don't know what you meant by "appearance," but I'm concerned exactly with thought models. From the point of view of all the things one has to think about to decide how cancellation exceptions will act, whether it's possible to handle them correctly, etc., the fact that they are ultimately initiated by asynchronous events is totally irrelevant. They could just as easily be triggered by reading from stdin at each cancellation point to decide whether to throw. So I'd prefer to keep the conversation simple. If you'd rather be precise and talk about asynchronous cancellation while always mentioning synchronous exceptions as a response in the same breath, that's fine with me. in this context, though, it's more confusing than necessary, especially If you don't mention synchronous exceptions in the same breath (note that you confused me). > "Asynchronous cancelability type" is (at least potentially) an > asynchronous EXCEPTION in response to an asynchronous event, while > "deferred cancelability type" is a synchronous (deferred) exception in > response to the same asynchronous event. If you insist. > Does that help? I don't think it helps in this conversation, but suit yourself; we now understand each other. >>> However, when cancellation is enabled, any blocking call (or any >>> method/operator that makes or might make a blocking call, like >>> "cout<<", might raise an exception. Not all code will be prepared to >>> handle that, and much shouldn't be; it's important to be able to >>> disable cancelability dynamically over critical scopes. It's not >>> like most exceptions where the conditions for an exception are >>> generally static; it could happen at any time for reasons the >>> current thread cannot possibly anticipate. >>> >> That's exactly like most exceptions (c.f. out-of-memory). Usually >> conditions whose reasons can be anticipated can be effectively tested >> and become preconditions or simply should be reported by other means. >> > Sometimes. Exceptions are great for "out of band" notifications that may > not be intended for the direct caller; they can be picked up with full > state, and without additional mechanism, by anyone along the call path > who cares. I know that. I did say "most," didn't I? To get things back on track, your assertion was that the reasons for most exceptions can be anticipated. I'm not _precisely_ sure what you meant by "reasons ... anticipated," but I think I have a pretty good idea, and my assertion was that most exceptions are in fact just like that, making this particular aspect of asynchrony uninteresting as a distinction. >>> and I'm much less ignorant than I was 2 years ago when I started >>> working with C++ and STL on a regular basis. Still, I am not steeped >>> in the history and tradition of C++ as I am in threads, and probably >>> never will be. More than that, while I have an authoritative voice >>> on the POSIX working group and in the community, I'm not involved >>> with the C++ committee and have no time or management support to get >>> involved; and I won't put myself in the position of being an outside >>> expert in some other area pretending to tell the C++ committee what >>> it must (or even should) do. >>> >> I don't think you should. There are other areas where you could make >> a big difference, though, like the ISO committee for C++/POSIX binding >> Mr. Drepper is now running. >> > "ISO committee" is rather a strong description; it's a simple mailing > list that's hoping to gain some preliminary consensus towards > constructing a formal proposal to request permission to develop a > charter and start a working group with the intent of building a proposal > for a binding. That wasn't my impression, but maybe I misinterpreted the announcement I saw. The IEEE, Portable Applications Standard Committee, has just approved the formation of a "C++ Bindings Study Group" to investigate providing C++ bindings to the current POSIX Standard, IEEE Std 1003.1. If the group concludes that C++ bindings should be done, they will generate a request to IEEE PASC for project approval to develop a POSIX C++ bindings specification. The group is to report its findings to to PASC either by March 31, 2007, or within 12 months of it's first meeting, whichever comes first. The group will be chaired by Ulrich Drepper of Red Hat (drepper at redhat.com). OK, it's a study group. Slightly more than a mailing list, but hardly a committee. I guess I'm just alarmist. > But, yeah, OK, fine. ;-) OK, thanks. >>>> No, I wasn't suggesting anything that couldn't be caught. I was just >>>> suggesting an exception that couldn't be stopped. It could throw >>>> itself in its dtor (not that I'm advocating it, but it might satisfy >>>> the "other side"), for example. >>>> >>> The POSIX model where cancel propagates inexorably to thread >>> termination is an inherently flawed compromise; but simply the best >>> we could do within the context of ISO C and POSIX APIs. OUR >>> implementation always allowed finalization, via C++ catch(...), our >>> ISO C "CATCH_ALL" extensions, or whatever other language syntax >>> might fit. >>> >>> I really wouldn't want to propagate this restriction to C++. >>> >> Be clear, I'm not talking about a restriction. If you ask it to throw >> something normal, it's finalizable in the normal way. This is a way >> for the _cancelling_ thread to say, "I know what I'm doing; the author >> of the thread I'm cancelling doesn't. Force it to be killed at the >> next cancellation point." >> > The whole concept of cancellation is exactly that the TARGET thread, not > the cancelling thread, knows what it's doing and should control the > cleanup and termination entirely. Believe me, I agree. You said we had to look for compromises, so that's what I was doing. > Without explicit synchronization, the cancelling thread can't know > what it's doing and whether a forced abort is appropriate or > safe. And if it has enough synchronization to know that, there are > far better ways to gain a cooperative termination than cancellation. Sure. >>> One advantage, though, of the single cancel exception, is that it's >>> universal. When you asynchronously issue a cancel request for a >>> thread, you can't really know what code is executing: your's, STL, >>> some other shared library, etc. Cancel means the same to all of >>> them, and either is supported with commonly agreed semantics or >>> will be ignored (by disabling cancellation in critical >>> scopes). Once you start firing off your own arbitrary exceptions, >>> though, anything might happen because half the time the exceptions >>> won't belong anywhere in the call tree that's active at the time >>> they arrive. >>> >> That's not the way most exception-safe code works. It goes to the >> reason that exception-specifications are a failure: the particular >> type of exception that propagates out of a throwing function makes >> almost no difference to anyone. The type only becomes important where >> errors are reported, or where exceptions are translated -- either to >> other exception types or, for example, to error return codes that can >> propagate through other languages. So the danger of injecting an >> arbitrary exception type into existing code (especially libraries, >> which are very often exception-neutral) is very very low. >> > That's an intriguing statement. I'll need to think about that some. > > I've certainly always thought that exception specifications were little > more than a trap into which people could mire themselves as deeply as > they like. So maybe that means I agree. I'm not sure. ;-) > > I guess I'd have to agree that the danger of injecting another exception > type is low. And mostly due to the fact that C++ has no "root exception > type" onto which could be grafted some minimal universal state It has a de-facto root type: std::exception. > (an architected status code space, like VMS condition codes, a > descriptive string, etc.) so that nobody would need an anonymous and > semantic-free catch(...) just to be sure nothing slipped past. When you have a root type, catching that is practically anonymous and semantic-free. It doesn't make much difference in practice. >>> Which brings us back to the "academic" resolution: if an exception >>> means distinct things in different call trees, those call trees >>> should be distinct threads and only one universal exception is >>> necessary. ;-) >>> >> I think you might be missing the point. I am proposing the >> generalized >> >> thread_throw( thread_id, exception_object ) >> >> function so that those who wish to hang themselves with homegrown >> unstoppable exception types can do so without forcing the standard to >> sanction the use of unstoppable exceptions by providing any kind of >> "forced cancellation." If "the other side" has A WAY to force >> cancellation, maybe they won't insist it has to be THE WAY. I know, >> wishful thinking :) >> > I'm not sure how sanctioning generalized unstoppable exceptions I said I'm not sanctioning such a thing. You can build one today in standard C++ (it throws a copy of itself from its destructor), so there's no need. And of course we can't stop people from building them. > is going to mollify anyone opposed to an unstoppable variety of a > specific exception. Huh? Did you really mean "UNstoppable?" IIUC, you and I are both opposed to unstoppable thread cancellation. Are you saying you would need to be mollified in order to accept it, even if it's only available by hand-writing a very strange exception type? > At best, cancel becomes a subset of cross-thread throw with > specialized additional deferral semantics. Additional? I'm lost again. There is no workable cross-thread throw without deferral. Anything else is an asynchronous exception. > And if you're generalizing the unstoppable exception, Generalizing? > I don't quite see how it makes sense not to generalize the deferral, > and now cancel really is just a specific predefined exception that > can be thrown like any other exception. That's not necessarily bad; > I just don't see how it's a compromise. (A compromise needs to make > BOTH sides equally unhappy, not just one side!) The compromise I'm proposing makes it possible to generate an unstoppable cancellation (bad for us) while making it ugly and unnatural to do so (bad for "the other side"). -- Dave Abrahams Boost Consulting www.boost-consulting.com From david.butenhof at hp.com Wed Mar 8 16:29:01 2006 From: david.butenhof at hp.com (Dave Butenhof) Date: Wed, 08 Mar 2006 11:29:01 -0500 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> <440CC9B6.4010502@hp.com> <440E3FE8.4040902@hp.com> <440EDCC7.9010902@hp.com> Message-ID: <440F064D.2000501@hp.com> David Abrahams wrote: > Dave Butenhof writes: > >> So fine, perhaps that is a viable compromise. I'm not "morally >> opposed" to a generalized cross-thread exception. I'm not thrilled >> about anyone injecting unstoppable exceptions into some "innocent" >> call stack; but like cancellation it can only be done when you at >> least know the thread ID of the call stack (meaning either you >> created the thread or the facility that did made the ID available to >> you in one way or another, though possibly just by making a call >> into your facility). And if someone does it to some arbitrary and >> unprepared thread it'll may behave just as badly as they >> deserve. ;-) >> > Yes. > > I do have sympathy, incidentally, for the other side's desire to "try > really hard" to shut a thread down cleanly. I just don't happen to > think unstoppable exceptions are a particularly effective tool for > that job. > Indeed. We went through this with pthread_abort() in POSIX. For the embedded realtime environment, it's both possible and often essential to forcibly and immediately shut down a nonresponsive thread. In any modular programming environment, where you don't control all of the code in the process, it's impossible... and you'll get yourself into worse trouble by trying. It all goes back to the fact that threads are just asynchronous procedure calls within the same application; they have no real independence. Trash one set of invariants, and you can trash the entire co-dependent environment with no way to analyze or clean up because of all this annoying encapsulation and data hiding stuff. ;-) An embedded application can know precisely what data any thread might have touched, analyze and repair it all; though even there it's not easy (or 100% reliable) in any complicated application. When some of the data a thread might have touched is in STL, libc, or other libraries, you can just forget it. The only way to forcibly trash a thread is to crash the entire process and start over. We didn't accept pthread_abort() because we were too concerned about others trying to use it and getting themselves deep in trouble. And this is probably well over the line where that was a reasonable decision. It's fine for any embedded realtime environment to add its own pthread_abort(); it's just not portable. But the application wouldn't port anyway to any environment with a different set of state that needed to be cleaned (much less any hidden state that can't be cleaned). If you're just trying to get enough control to exit cleanly, there are usually better ways. If you really intend to recover and continue -- you're probably already in way over your head. ;-) A "forced unwind" is both better and worse... it is a cleaner mechanism, but if the call stack context is really trashed somehow, you're less likely to get the thread to actually terminate that way. -------------- next part -------------- A non-text attachment was scrubbed... Name: david.butenhof.vcf Type: text/x-vcard Size: 476 bytes Desc: not available URL: From Alisdair.Meredith at uk.renaultf1.com Wed Mar 8 16:34:58 2006 From: Alisdair.Meredith at uk.renaultf1.com (Meredith, Alisdair) Date: Wed, 8 Mar 2006 16:34:58 -0000 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost Message-ID: <79E021DD17C2E241ACA0C8AD79C88A178682CB@EN-EX-01.uk.rf1.dir> > -----Original Message----- > From: David Abrahams [mailto:dave at boost-consulting.com] > Sent: 08 March 2006 15:28 > To: Dave Butenhof > Cc: c++-pthreads at codesourcery.com > Subject: Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost > Subject to cancelability. In C++ "cancelability" would indicate > whether cancellation points can throw (these asynchronously-initiated > exceptions). Sorry to jump into the middle of a good dialog with what might seem an irrelevance, but how will these asynchronous exceptions (now being re-thrown 'as sychronous') interact with exception specifications? Badly is my only guess. Not that this should interfere with finding a good model for asynchronous exceptions or cancellations - far more useful to your general user! But it might mean we put some more thought into cleaning up exception specifications in C++0x, so that no problems arise. Unless, of course, I am imagining a problem that does not exist - would not be the first time. AlisdairM --------------------------------------------------------------------- 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 --------------------------------------------------------------------- From mark at codesourcery.com Wed Mar 8 16:51:56 2006 From: mark at codesourcery.com (Mark Mitchell) Date: Wed, 08 Mar 2006 08:51:56 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> <440CC9B6.4010502@hp.com> <440E3FE8.4040902@hp.com> <440EDCC7.9010902@hp.com> Message-ID: <440F0BAC.1070402@codesourcery.com> David Abrahams wrote: > I do have sympathy, incidentally, for the other side's desire to "try > really hard" to shut a thread down cleanly. I just don't happen to > think unstoppable exceptions are a particularly effective tool for > that job. Exactly. We have SIGKILL for processes so that we can be sure to get rid of them. (Well, modulo the situations where that doesn't work...) But, pthread_cancel is not analogous: for example a thread can run with cancellation disabled, while a process cannot block SIGKILL. The reason that people object to a pthread_kill is that there is no obvious way to clean up memory resources, etc., allocated by the thread, in the same way that the OS can reclaim resources used by a process. So, a cooperative model makes sense. I don't think we should support unstoppable exceptions at all. Silently rethrowing at the end of a catch handler breaks too many important invariants. -- Mark Mitchell CodeSourcery mark at codesourcery.com (650) 331-3385 x713 From dave at boost-consulting.com Wed Mar 8 16:50:17 2006 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 08 Mar 2006 08:50:17 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <79E021DD17C2E241ACA0C8AD79C88A178682CB@EN-EX-01.uk.rf1.dir> (Alisdair Meredith's message of "Wed, 8 Mar 2006 16:34:58 -0000") References: <79E021DD17C2E241ACA0C8AD79C88A178682CB@EN-EX-01.uk.rf1.dir> Message-ID: "Meredith, Alisdair" writes: "Meredith, Alisdair" writes: > David Abrahams [mailto:dave at boost-consulting.com] wrote: >> Subject to cancelability. In C++ "cancelability" would indicate >> whether cancellation points can throw (these asynchronously-initiated >> exceptions). > > Sorry to jump into the middle of a good dialog with what might seem an > irrelevance, but how will these asynchronous exceptions (now being > re-thrown 'as sychronous') Dave B: This is why I didn't want the term asynchronous in the discussion. It's just a confusing distraction. Alisdair M: there are absolutely no asynchronous exceptions here, period. > interact with exception specifications? > > Badly is my only guess. Answer 1: who cares? Answer 2: just the same as they interact with any other exception (i.e. no worse). > Not that this should interfere with finding a good model for > asynchronous exceptions or cancellations - far more useful to your > general user! But it might mean we put some more thought into > cleaning up exception specifications in C++0x, so that no problems > arise. > > Unless, of course, I am imagining a problem that does not exist - would > not be the first time. I think this is one of those imaginary problems. It doesn't introduce any new problems; we're just talking about more ordinary exceptions, and inasmuch as you know where other kinds of exceptions can be thrown, the same would be true of these. -- Dave Abrahams Boost Consulting www.boost-consulting.com From gshiman at commvault.com Wed Mar 8 17:08:33 2006 From: gshiman at commvault.com (George Shimanovich) Date: Wed, 8 Mar 2006 12:08:33 -0500 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost Message-ID: <52CA6BC0D0E9EE4E93208DB39A3218FE01698F4B@EXCHANGE.gp.cv.commvault.com> >I don't think we should support unstoppable exceptions at all. Silently >rethrowing at the end of a catch handler breaks too many important >invariants. For example, it is not compatible with thread pool implementations that try to reuse its threads regardless of how thread callback completes, normally or via thread cancellation. Note that since cancellation exception can only be caught via catch(...) there is no way to distinguish it from any system, non-C++ exception and thus decide to rethrow. George Shimanovich From pdimov at mmltd.net Wed Mar 8 17:16:47 2006 From: pdimov at mmltd.net (Peter Dimov) Date: Wed, 8 Mar 2006 19:16:47 +0200 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost References: <79E021DD17C2E241ACA0C8AD79C88A178682CB@EN-EX-01.uk.rf1.dir> Message-ID: <001e01c642d4$16644d90$6501a8c0@pdimov> Meredith, Alisdair wrote: >> Subject to cancelability. In C++ "cancelability" would indicate >> whether cancellation points can throw (these asynchronously-initiated >> exceptions). > > Sorry to jump into the middle of a good dialog with what might seem an > irrelevance, but how will these asynchronous exceptions (now being > re-thrown 'as sychronous') interact with exception specifications? > > Badly is my only guess. The exceptions are not asynchronous. You have a function void f(); that can throw (i.e. it doesn't give the nothrow guarantee). This function can throw a cancellation exception, but this is no different from throwing some other exception. From the point of view of the caller, nothing changes. The function just fails. If, on the other hand, you have void f() throw(); or void f() throw( X ); where X is not a base of the cancellation exception, this function won't throw a cancellation exception (although it might invoke unexpected() or terminate() if it invokes other throwing functions, which now includes cancellation points.) Alexander Terekhov has been proposing a model where cancellation points automatically detect that a throw-spec somewhere up the call stack would not let a cancellation exception through, and if so, refrain from throwing. But this requires a language change. From dave at boost-consulting.com Wed Mar 8 17:09:18 2006 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 08 Mar 2006 09:09:18 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <440F0BAC.1070402@codesourcery.com> (Mark Mitchell's message of "Wed, 08 Mar 2006 08:51:56 -0800") References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> <440CC9B6.4010502@hp.com> <440E3FE8.4040902@hp.com> <440EDCC7.9010902@hp.com> <440F0BAC.1070402@codesourcery.com> Message-ID: Mark Mitchell writes: > I don't think we should support unstoppable exceptions at all. > Silently rethrowing at the end of a catch handler breaks too many > important invariants. Usually, yes. Unfortunately that position is not much of a compromise: it doesn't give an inch to the other side. If we allow a generalized thread_throw then there's nothing we can do to stop people from building unstoppable exceptions and throwing them across the thread boundary, but to do so they'll have to write some tricky and non-obvious code. I'm hoping that's enough for people like us to say "don't do that: you get what you deserve when you write code like that" and for other people to say "I'm satisfied that I _can_ get the thread to stop once we hit a cancellation point with cancel enabled." -- Dave Abrahams Boost Consulting www.boost-consulting.com From david.butenhof at hp.com Wed Mar 8 20:59:48 2006 From: david.butenhof at hp.com (Dave Butenhof) Date: Wed, 08 Mar 2006 15:59:48 -0500 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: References: <79E021DD17C2E241ACA0C8AD79C88A178682CB@EN-EX-01.uk.rf1.dir> Message-ID: <440F45C4.9050204@hp.com> David Abrahams wrote: > "Meredith, Alisdair" writes: > >> David Abrahams [mailto:dave at boost-consulting.com] wrote: >> >>> Subject to cancelability. In C++ "cancelability" would indicate >>> whether cancellation points can throw (these asynchronously-initiated >>> exceptions). >>> >> Sorry to jump into the middle of a good dialog with what might seem an >> irrelevance, but how will these asynchronous exceptions (now being >> re-thrown 'as sychronous') >> > Dave B: This is why I didn't want the term asynchronous in the > discussion. It's just a confusing distraction. > Well, I guess it's a C++ viewpoint vs a threads viewpoint. When I see "synchronous" cross-thread exceptions, cancel or otherwise, my first thought has to be, so who is responsible for the synchronization, and how does it work? The point is, though, that there IS no synchronization. That is, by definition, the communication protocol is asynchronous. (Actually, in pure POSIX cancellation is IS possible to "post" a cancel request without synchronization, unless you need to blast through a blocking operation. With a general cross-thread exception that's unlikely to be possible, but the synchronization is far below the application level, and provides no useful synchronous behavior for the application developer; which amounts to the same thing as "asynchronous".) I can't possibly say "C++ does cross-thread exceptions synchronously", because it isn't a practical or useful definition, and wouldn't be a good operational model. The communication has to be asynchronous. Only the final step, entirely within the target thread, is fully synchronous with that thread at a level that's of any use to the application model. The target detects at a cancellation/exception point that the request currently exists (registered asynchronously at some previous time ;-) ), and SYNCHRONOUSLY throws the exception into its own call stack. So, yeah; the exception is synchronous. Fine. But that's only the final, and least interesting, step in the protocol. Or perhaps that's just "least interesting" to ME, because "I'm a thread guy". ;-) -------------- next part -------------- A non-text attachment was scrubbed... Name: david.butenhof.vcf Type: text/x-vcard Size: 476 bytes Desc: not available URL: From wil at bogo.xs4all.nl Wed Mar 8 21:41:54 2006 From: wil at bogo.xs4all.nl (Wil Evers) Date: Wed, 08 Mar 2006 22:41:54 +0100 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> <440CC9B6.4010502@hp.com> <440E3FE8.4040902@hp.com> <440EDCC7.9010902@hp.com> <440F0BAC.1070402@codesourcery.com> Message-ID: <440F4FA2.5050608@bogo.xs4all.nl> David Abrahams wrote: > Mark Mitchell writes: > >>I don't think we should support unstoppable exceptions at all. >>Silently rethrowing at the end of a catch handler breaks too many >>important invariants. > > Usually, yes. Unfortunately that position is not much of a > compromise: it doesn't give an inch to the other side. If we allow a > generalized thread_throw then there's nothing we can do to stop people > from building unstoppable exceptions and throwing them across the > thread boundary, but to do so they'll have to write some tricky and > non-obvious code. I'm hoping that's enough for people like us to say > "don't do that: you get what you deserve when you write code like > that" and for other people to say "I'm satisfied that I _can_ get the > thread to stop once we hit a cancellation point with cancel enabled." So who/where is this alledged "other side"? IMHO, one of the inspiring things in the discussion we've been witnessing here in the last couple of days is that no one, not even David B., is actually arguing in favor of unstoppable cancellation exceptions. (Mark mentioned Ulrich Drepper's glibc implementation; we all know what he did, but so far, I haven't found any explanation *why* he did that). It seems to me that, before phantasising about any sort of compromise with the "other side", we would need to know what the other side is after, and why. - Wil From pdimov at mmltd.net Wed Mar 8 21:44:45 2006 From: pdimov at mmltd.net (Peter Dimov) Date: Wed, 8 Mar 2006 23:44:45 +0200 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost References: <79E021DD17C2E241ACA0C8AD79C88A178682CB@EN-EX-01.uk.rf1.dir> <440F45C4.9050204@hp.com> Message-ID: <00b401c642f9$858ae4c0$6407a8c0@pdimov2> Dave Butenhof wrote: > So, yeah; the exception is synchronous. Fine. But that's only the > final, and least interesting, step in the protocol. Or perhaps that's > just "least interesting" to ME, because "I'm a thread guy". ;-) It is a very interesting step because that's what the thread sees, an ordinary exception, emanating from a function in the usual way; meaning that if the thread is already equipped to handle exceptions, as is the case with C++ code nowadays, it "just works". Which is nice. :-) From mark at codesourcery.com Wed Mar 8 22:02:52 2006 From: mark at codesourcery.com (Mark Mitchell) Date: Wed, 08 Mar 2006 14:02:52 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <440F4FA2.5050608@bogo.xs4all.nl> References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> <440CC9B6.4010502@hp.com> <440E3FE8.4040902@hp.com> <440EDCC7.9010902@hp.com> <440F0BAC.1070402@codesourcery.com> <440F4FA2.5050608@bogo.xs4all.nl> Message-ID: <440F548C.9000303@codesourcery.com> Wil Evers wrote: > So who/where is this alledged "other side"? IIRC, Jason Merill has also historically been sympathetic to the forced exception mechanism, because (if I paraphrase correctly!) he feels that it might help some code move into a threaded environment without change. In particular, by ignoring "catch" handlers, some subset of real programs might behave well enough, in that destructors would run to clean things up, and the code wouldn't have to be modified to know about thread-cancellation exceptions. However, again, if I recall correctly, Jason was also OK with the idea that a thread could catch a cancellation exception, but that future calls to cancellation points would cause it to be re-canceled. I might have just stuck an entire giant paragraph of words into Jason's mouth, though, in which case I very humbly apologize. As far as I remember, Ulrich is the only person who has really argued that it is unambiguously wrong to consider the situation in which a thread catches a cancellation exception. -- Mark Mitchell CodeSourcery mark at codesourcery.com (650) 331-3385 x713 From dave at boost-consulting.com Wed Mar 8 22:23:21 2006 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 08 Mar 2006 14:23:21 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <440F45C4.9050204@hp.com> (Dave Butenhof's message of "Wed, 08 Mar 2006 15:59:48 -0500") References: <79E021DD17C2E241ACA0C8AD79C88A178682CB@EN-EX-01.uk.rf1.dir> <440F45C4.9050204@hp.com> Message-ID: Dave Butenhof writes: > David Abrahams wrote: >> "Meredith, Alisdair" writes: >> >>> David Abrahams [mailto:dave at boost-consulting.com] wrote: >>> >>>> Subject to cancelability. In C++ "cancelability" would indicate >>>> whether cancellation points can throw (these asynchronously-initiated >>>> exceptions). >>> Sorry to jump into the middle of a good dialog with what might seem an >>> irrelevance, but how will these asynchronous exceptions (now being >>> re-thrown 'as sychronous') >> Dave B: This is why I didn't want the term asynchronous in the >> discussion. It's just a confusing distraction. >> > Well, I guess it's a C++ viewpoint vs a threads viewpoint. When I see > "synchronous" cross-thread exceptions, cancel or otherwise, my first > thought has to be, so who is responsible for the synchronization, and > how does it work? > > The point is, though, that there IS no synchronization. Aww, c'mon. You're seriously telling me that one thread can set the "there's now an active cancellation flag" for another thread, and the other thread can read it with _NO_ synchronization? That isn't how I learned things work by reading your book! > That is, by definition, the communication protocol is > asynchronous. (Actually, in pure POSIX cancellation is IS possible > to "post" a cancel request without synchronization, unless you need > to blast through a blocking operation. With a general cross-thread > exception that's unlikely to be possible, but the synchronization is > far below the application level, and provides no useful synchronous > behavior for the application developer; which amounts to the same > thing as "asynchronous".) So now you're telling me that my mental model for what's required to write this state in one thread and read it in another is all wrong, and I should be thinking of it in some way that makes it "asynchronous" despite the fact that it really is synchronous under the covers? This sound like you're just making it worse for "thought models," not better. > Only the final step, entirely within the target thread, is fully > synchronous with that thread at a level that's of any use to the > application model. The target detects at a cancellation/exception point > that the request currently exists (registered asynchronously at some > previous time ;-) ), and SYNCHRONOUSLY throws the exception into its own > call stack. > > So, yeah; the exception is synchronous. Fine. But that's only the final, > and least interesting, step in the protocol. Or perhaps that's just > "least interesting" to ME, because "I'm a thread guy". ;-) Yes, to you. For the purposes of the big argument over how these exceptions work, it's a completely irrelevant fact (if you can even call it that, because the real facts of the matter have only become blurrier as I read more of what you write). -- Dave Abrahams Boost Consulting www.boost-consulting.com From jason at redhat.com Wed Mar 8 23:08:48 2006 From: jason at redhat.com (Jason Merrill) Date: Wed, 08 Mar 2006 18:08:48 -0500 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <440F548C.9000303@codesourcery.com> References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> <440CC9B6.4010502@hp.com> <440E3FE8.4040902@hp.com> <440EDCC7.9010902@hp.com> <440F0BAC.1070402@codesourcery.com> <440F4FA2.5050608@bogo.xs4all.nl> <440F548C.9000303@codesourcery.com> Message-ID: <440F6400.1080801@redhat.com> Mark Mitchell wrote: > Wil Evers wrote: > >> So who/where is this alledged "other side"? > > IIRC, Jason Merill has also historically been sympathetic to the forced > exception mechanism, because (if I paraphrase correctly!) he feels that > it might help some code move into a threaded environment without change. > In particular, by ignoring "catch" handlers, some subset of real > programs might behave well enough, in that destructors would run to > clean things up, and the code wouldn't have to be modified to know about > thread-cancellation exceptions. Yes. This is the choice that Ada made for handling task cancellation; it functions like an exception except that it cannot be caught, at least not by user code. > However, again, if I recall correctly, > Jason was also OK with the idea that a thread could catch a cancellation > exception, but that future calls to cancellation points would cause it > to be re-canceled. Yes. Cancellation is not just an indication of a problem like most exceptions, it's specifically an attempt to unwind everything. There is a lot of code out there that does catch (...), tries to do generic recovery, and continue. iostreams does catch (...) and sets a flag instead of propagating an exception. Neither of these situations should cause the cancel to be discarded. Both the Ada approach and the re-cancellation approach avoid this problem of accidentally losing the cancellation request. If you can interrupt cancellation, re-cancellation is implemented trivially simply by just having the cancellation exception destructor call 'pthread_cancel (pthread_self ())'. The sticking point is being able to abort the cancellation in the first place, which is what Uli has been opposed to. > As far as I remember, Ulrich is the only person who has really argued > that it is unambiguously wrong to consider the situation in which a > thread catches a cancellation exception. I don't think he's opposed to catching it, just to doing anything that would involve backing out of the cancellation once it's started. Jason From mark at codesourcery.com Wed Mar 8 23:15:37 2006 From: mark at codesourcery.com (Mark Mitchell) Date: Wed, 08 Mar 2006 15:15:37 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <440F6400.1080801@redhat.com> References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> <440CC9B6.4010502@hp.com> <440E3FE8.4040902@hp.com> <440EDCC7.9010902@hp.com> <440F0BAC.1070402@codesourcery.com> <440F4FA2.5050608@bogo.xs4all.nl> <440F548C.9000303@codesourcery.com> <440F6400.1080801@redhat.com> Message-ID: <440F6599.8060102@codesourcery.com> Jason Merrill wrote: > If you can interrupt cancellation, re-cancellation is implemented > trivially simply by just having the cancellation exception destructor > call 'pthread_cancel (pthread_self ())'. The sticking point is being > able to abort the cancellation in the first place, which is what Uli has > been opposed to. It sounds like we really are close to a solution then; I think everyone here would be happy with the re-cancellation thing, and the destructor trick means that there's really no way the thread can permanently discard the cancellation request, short of things like longjmp -- and, of course, if the thread is really determined not to go away it can just hang around anyhow. So, it seems like this ought to satisfy everyone from the user-level perspective. > I don't think he's opposed to catching it, just to doing anything that > would involve backing out of the cancellation once it's started. Would the above satisfy him? -- Mark Mitchell CodeSourcery mark at codesourcery.com (650) 331-3385 x713 From Alisdair.Meredith at uk.renaultf1.com Wed Mar 8 23:26:18 2006 From: Alisdair.Meredith at uk.renaultf1.com (Meredith, Alisdair) Date: Wed, 8 Mar 2006 23:26:18 -0000 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost Message-ID: <79E021DD17C2E241ACA0C8AD79C88A172055C4@EN-EX-01.uk.rf1.dir> Sorry to be dense, or if I am covering old ground - just confirming I understand correctly: Also sorry for HTML format - it is all I can get remotely from our Exchange server :?( i/ cancellation will propogate as an (uncatchable?) exception, implying stack unwinding. ii/ if cancellation passes through an exception specification, we call unexpected and abort which pretty much achieves the same thing iii/ if cancellation interupts a dtor during regular stack unwinding, we call terminate which pretty much has the same effect, so everyone is still happy. I am still not sure about: iv/ if an exception is thrown but not caught in main, it is implementation defined whether stack unwinding occurs, so it will really be implementation defined whether the stack is unwound for thread cancellation in this scheme. I am also not clear whether unexpected / terminate will kill just the thread, or the whole process. I am currently expecting the latter as the status quo, although not with a strong opinion to fight for AlisdairM ________________________________ From: Mark Mitchell [mailto:mark at codesourcery.com] Sent: Wed 08/03/2006 23:15 To: Jason Merrill Cc: Wil Evers; David Abrahams; c++-pthreads at codesourcery.com Subject: Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost Jason Merrill wrote: > If you can interrupt cancellation, re-cancellation is implemented > trivially simply by just having the cancellation exception destructor > call 'pthread_cancel (pthread_self ())'. The sticking point is being > able to abort the cancellation in the first place, which is what Uli has > been opposed to. It sounds like we really are close to a solution then; I think everyone here would be happy with the re-cancellation thing, and the destructor trick means that there's really no way the thread can permanently discard the cancellation request, short of things like longjmp -- and, of course, if the thread is really determined not to go away it can just hang around anyhow. So, it seems like this ought to satisfy everyone from the user-level perspective. > I don't think he's opposed to catching it, just to doing anything that > would involve backing out of the cancellation once it's started. Would the above satisfy him? -- Mark Mitchell CodeSourcery mark at codesourcery.com (650) 331-3385 x713 --------------------------------------------------------------------- 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 --------------------------------------------------------------------- -------------- next part -------------- An HTML attachment was scrubbed... URL: From baker at cs.fsu.edu Thu Mar 9 00:22:15 2006 From: baker at cs.fsu.edu (Ted Baker) Date: Wed, 8 Mar 2006 19:22:15 -0500 Subject: [SPAM] - Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost - Email found in subject In-Reply-To: <440F548C.9000303@codesourcery.com> References: <440CC9B6.4010502@hp.com> <440E3FE8.4040902@hp.com> <440EDCC7.9010902@hp.com> <440F0BAC.1070402@codesourcery.com> <440F4FA2.5050608@bogo.xs4all.nl> <440F548C.9000303@codesourcery.com> Message-ID: <20060309002215.GB17294@cs.fsu.edu> > As far as I remember, Ulrich is the only person who has really argued > that it is unambiguously wrong to consider the situation in which a > thread catches a cancellation exception. -- Mark Mitchell This is one of the points where (*IF* this "study group" recommends to PASC that a project be started, and once the actual standard working group gets down to business) the POSIX C++ API group will need to make a choice between compatibility with the POSIX C API and "doing the right thing" from their own point of view. A core issue will be the canonical implementation model. I see two approaches: (A) Limit required semantics to what can be implemented using the POSIX C API, in C++-specific libraries, possibly with some help from the C++ compiler. (B) Create new semantics, which go beyond what can be done using the POSIX C API. When it comes to thread cancellation, there is an existing C library mechanism. You either build on it and limit your choices to what that permits (A), or you build something new (B). If (B) it will not be suitable for mixed C/C++ programs unless you can think of a unified mutually compatible underlying implementation mechanism and persuade the maintainer of the C library to do the work needed to make them interoperable. As this pertains to the question of whether thread cancellation can be handled, option (A) must be implementable using a library that supports the POSIX C API (and does no know about C++). The POSIX C API presumes that once cancellation of a thread begins it will progress through to termination of the thread. For example, the description of "acting on" thread cancellation says that "The cancelability state shall remain set to PTHREAD_CANCEL_DISABLE until the thread has terminated." In particular, it seems to me that the code of cancellation handlers is permitted to assume that it will run to completion, all the way out to the point of termination. It seems to me that if you try to layer a C++ API on top of the C API, this limitation will catch you. That is, if the C++ layer allows thread cancellation to be handled (and resume execution of the thread) there is no way that you could use the C API directly to later cancel the thread (again), since from that point on the C API sees that cancellation is disabled. This seems to be a special case of a more general problem, which will come up with every C library function that is a potential cancellation point. If a C++ application or library calls such a C library function, the C function will not know about C++ exceptions, and so will invoke some C-specific mechanism to implement the thread cancellation. In particular, it will probably call a C runtime library routine that starts walking the stack, finding cancelation handlers, and executing them. How does this get transferred into a C++ exception. I see a few options e.g., (1) You put a wrapper around every cancellation-point function, which installs its own cleanup handler, and the cleanup handler raises the C++ exception instead of returning in the normal way. A problem: this poentially violates invariants of the C cleanup handler model, since in C handlers must always return and then the thread must terminate. To make sure nothing breaks you need to get the C library implementor on board with the new feature. He/she will want to know how much rewriting of C library code will this take? Will there be a perforamance hit for C applications? (2) You roll your own C++ version of the entire library function, which calls a C++ runtime routine to implement thread cancellation. The C thread cancellation and the C++ thread cancellation are unrelated and do not interoperate. You don't need any cooperation from the C library implementor, but if you have a program that tries to use the two API's at once (maybe in different libraries) you sometimes get the C handlers and sometimes the C++, and maybe everthing crashes as one kind of exception tries to propagate into the scope of the other. Maybe other readers will suggest more stragies. In any case, I dare say you need to first decide the degree to which interoperability of C and C++ code is important enough to sacrifice other functional and aesthetic considerations. You then need to come up with an implementation model that provides that supports that level of interoperability without excessive costs in modification to working C and C++ standard language libraries and the standard POSIX API libraries. --Ted From baker at cs.fsu.edu Thu Mar 9 00:26:30 2006 From: baker at cs.fsu.edu (Ted Baker) Date: Wed, 8 Mar 2006 19:26:30 -0500 Subject: [SPAM] - Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost - Email found in subject In-Reply-To: <440F6400.1080801@redhat.com> References: <440E3FE8.4040902@hp.com> <440EDCC7.9010902@hp.com> <440F0BAC.1070402@codesourcery.com> <440F4FA2.5050608@bogo.xs4all.nl> <440F548C.9000303@codesourcery.com> <440F6400.1080801@redhat.com> Message-ID: <20060309002630.GC17294@cs.fsu.edu> > Yes. This is the choice that Ada made for handling task cancellation; > it functions like an exception except that it cannot be caught, at least > not by user code. Yes, and the POSIX Ada binding chose to ignore the C thread cancellation API. It was both freed and forced to do so because the Ada language standard provides equivalent (but not interoperable) functionality, based on a unified view of a task abort as a special kind of exception. > Both the Ada approach and the re-cancellation approach avoid this > problem of accidentally losing the cancellation request. Right. --Ted From baker at cs.fsu.edu Thu Mar 9 00:30:29 2006 From: baker at cs.fsu.edu (Ted Baker) Date: Wed, 8 Mar 2006 19:30:29 -0500 Subject: [SPAM] - Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost - Email found in subject In-Reply-To: <440F6599.8060102@codesourcery.com> References: <440E3FE8.4040902@hp.com> <440EDCC7.9010902@hp.com> <440F0BAC.1070402@codesourcery.com> <440F4FA2.5050608@bogo.xs4all.nl> <440F548C.9000303@codesourcery.com> <440F6400.1080801@redhat.com> <440F6599.8060102@codesourcery.com> Message-ID: <20060309003029.GD17294@cs.fsu.edu> On Wed, Mar 08, 2006 at 03:15:37PM -0800, Mark Mitchell wrote: > Jason Merrill wrote: > > > If you can interrupt cancellation, re-cancellation is implemented > > trivially simply by just having the cancellation exception destructor > > call 'pthread_cancel (pthread_self ())'. The sticking point is being > > able to abort the cancellation in the first place, which is what Uli has > > been opposed to. This would be illegal according to the C API, since once a thread begins executing cancellation handlers it becomes (irrevocably) not cancellable. That means a subsequent call to tthread_cancel is required to have no effect on the thread. So, if you want to do this you need a new function that is like pthread_cancel but has special semantics. That is, the developer of the C++ binding would need to coordinate with the implementor of pthread_cancel to provide this function not in the POSIX C API. > ... So, it seems like this ought to satisfy everyone > from the user-level perspective. I've been talking about the implementor-perspective. A standard will not be much good unless you can also persuade the implementors to buy in . --Ted From david.butenhof at hp.com Thu Mar 9 00:35:10 2006 From: david.butenhof at hp.com (Dave Butenhof) Date: Wed, 08 Mar 2006 19:35:10 -0500 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: References: <79E021DD17C2E241ACA0C8AD79C88A178682CB@EN-EX-01.uk.rf1.dir> <440F45C4.9050204@hp.com> Message-ID: <440F783E.9020501@hp.com> David Abrahams wrote: > Dave Butenhof writes: > > >> David Abrahams wrote: >> >>> "Meredith, Alisdair" writes: >>> >>> >>>> David Abrahams [mailto:dave at boost-consulting.com] wrote: >>>> >>>> >>>>> Subject to cancelability. In C++ "cancelability" would indicate >>>>> whether cancellation points can throw (these asynchronously-initiated >>>>> exceptions). >>>>> >>>> Sorry to jump into the middle of a good dialog with what might seem an >>>> irrelevance, but how will these asynchronous exceptions (now being >>>> re-thrown 'as sychronous') >>>> >>> Dave B: This is why I didn't want the term asynchronous in the >>> discussion. It's just a confusing distraction. >>> >>> >> Well, I guess it's a C++ viewpoint vs a threads viewpoint. When I see >> "synchronous" cross-thread exceptions, cancel or otherwise, my first >> thought has to be, so who is responsible for the synchronization, and >> how does it work? >> >> The point is, though, that there IS no synchronization. >> > Aww, c'mon. You're seriously telling me that one thread can set the > "there's now an active cancellation flag" for another thread, and the > other thread can read it with _NO_ synchronization? That isn't how I > learned things work by reading your book! > Cancellation state is a "stash and go" transaction; all that's necessary is visibility guarantees and a confidence that the storage can't go away in the midst. There are lots of lock free techniques. As far as my book advice goes, the point here is that there's no standard or portable API allowing application code to do this. It's "cake" for an implementation. >> That is, by definition, the communication protocol is >> asynchronous. (Actually, in pure POSIX cancellation is IS possible >> to "post" a cancel request without synchronization, unless you need >> to blast through a blocking operation. With a general cross-thread >> exception that's unlikely to be possible, but the synchronization is >> far below the application level, and provides no useful synchronous >> behavior for the application developer; which amounts to the same >> thing as "asynchronous".) >> > So now you're telling me that my mental model for what's required to > write this state in one thread and read it in another is all wrong, > and I should be thinking of it in some way that makes it > "asynchronous" despite the fact that it really is synchronous under > the covers? > > This sound like you're just making it worse for "thought models," not > better. > No, never mind. I'll surrender. I'm clearly thinking at a level of abstraction and/or detail that doesn't matter to most people. Maybe it is just pointless confusion. I've had a really busy couple of weeks and maybe I'm just blowing off a little steam in a nice technical argument. But if I'm arguing about something that doesn't matter to anyone but me, that's stupid. >> Only the final step, entirely within the target thread, is fully >> synchronous with that thread at a level that's of any use to the >> application model. The target detects at a cancellation/exception point >> that the request currently exists (registered asynchronously at some >> previous time ;-) ), and SYNCHRONOUSLY throws the exception into its own >> call stack. >> >> So, yeah; the exception is synchronous. Fine. But that's only the final, >> and least interesting, step in the protocol. Or perhaps that's just >> "least interesting" to ME, because "I'm a thread guy". ;-) >> > Yes, to you. For the purposes of the big argument over how these > exceptions work, it's a completely irrelevant fact (if you can even > call it that, because the real facts of the matter have only become > blurrier as I read more of what you write) OK, "least interesting" was mostly a joke, and the part that wasn't a joke was unnecessarily provocative. Sorry. I got carried away. -------------- next part -------------- A non-text attachment was scrubbed... Name: david.butenhof.vcf Type: text/x-vcard Size: 476 bytes Desc: not available URL: From mark at codesourcery.com Thu Mar 9 00:36:01 2006 From: mark at codesourcery.com (Mark Mitchell) Date: Wed, 08 Mar 2006 16:36:01 -0800 Subject: [SPAM] - Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost - Email found in subject In-Reply-To: <20060309002215.GB17294@cs.fsu.edu> References: <440CC9B6.4010502@hp.com> <440E3FE8.4040902@hp.com> <440EDCC7.9010902@hp.com> <440F0BAC.1070402@codesourcery.com> <440F4FA2.5050608@bogo.xs4all.nl> <440F548C.9000303@codesourcery.com> <20060309002215.GB17294@cs.fsu.edu> Message-ID: <440F7871.3050707@codesourcery.com> Ted Baker wrote: > A core issue will be the canonical implementation model. I see two > approaches: > > (A) Limit required semantics to what can be implemented using the POSIX C API, > in C++-specific libraries, possibly with some help from the C++ compiler. > > (B) Create new semantics, which go beyond what can be done using the > POSIX C API. Yes, this is an excellent point to clarify. I believe the assumption here is that we must be in choice (B). As you say, even the "forced unwinding" exception approach presently implemented on GNU/Linux requires help from the C library; it's not something that be done atop a "generic" POSIX C library, at least without dynamic linker magic. Any mechanism for running C++ destructors with reasonable performance is going to require help from the C library. In the case of GNU/Linux, the C library is already providing functionality for C++ beyond what's required for POSIX: just not the functionality that is emerging as the consensus here. :-) But, your point is well-taken; it's important that we're on the same page. -- Mark Mitchell CodeSourcery mark at codesourcery.com (650) 331-3385 x713 From david.butenhof at hp.com Thu Mar 9 01:26:29 2006 From: david.butenhof at hp.com (Dave Butenhof) Date: Wed, 08 Mar 2006 20:26:29 -0500 Subject: [c++-pthreads] Re: [SPAM] - Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost - Email found in subject In-Reply-To: <20060309003029.GD17294@cs.fsu.edu> References: <440E3FE8.4040902@hp.com> <440EDCC7.9010902@hp.com> <440F0BAC.1070402@codesourcery.com> <440F4FA2.5050608@bogo.xs4all.nl> <440F548C.9000303@codesourcery.com> <440F6400.1080801@redhat.com> <440F6599.8060102@codesourcery.com> <20060309003029.GD17294@cs.fsu.edu> Message-ID: <440F8445.8030608@hp.com> Ted Baker wrote: > On Wed, Mar 08, 2006 at 03:15:37PM -0800, Mark Mitchell wrote: > >> Jason Merrill wrote: >> >>> If you can interrupt cancellation, re-cancellation is implemented >>> trivially simply by just having the cancellation exception destructor >>> call 'pthread_cancel (pthread_self ())'. The sticking point is being >>> able to abort the cancellation in the first place, which is what Uli has >>> been opposed to. >>> > This would be illegal according to the C API, since once a thread > begins executing cancellation handlers it becomes (irrevocably) > not cancellable. That means a subsequent call to pthread_cancel > is required to have no effect on the thread. > The C binding is necessarily constrained; but we were careful (as much as possible within the restrictions of POSIX scope) to be clear that those constraints should not restrict more advanced language implementation. In particular, that cancel was always intended to be an exception and that in a language with the capability it SHOULD be. That of course, can't be stated as a requirement, but it was our intent. > So, if you want to do this you need a new function that is like > pthread_cancel but has special semantics. That is, the developer > of the C++ binding would need to coordinate with the implementor > of pthread_cancel to provide this function not in the POSIX C API. > Yes; unfortunately most UNIX systems still lack a cross-language exception infrastructure, so C++ and pthread cancel/exit, Ada, Java, and so forth have each "rolled their own" largely incompatible interfaces. Makes me miss OpenVMS and Tru64 UNIX, which did have common exceptions. The original implementation of the POSIX C API, going back way before there even WAS a POSIX C API, was based on VMS condition handling (OS exceptions) and Tru64 UNIX libexc. Interoperable exception support for cancel across C, C++, Ada, etc. was almost free since pretty much everyone ran destructors, finally clauses and such even on foreign exception unwinds. (Even if they didn't have named exception support to catch them.) Several other mainstream UNIX vendors nearly had a common exception API as well as a result of the Itanium UNIX ABI effort, but apparently everyone backed off when the group disbanded. (That was a major disappointment.) >> ... So, it seems like this ought to satisfy everyone from the user-level perspective. >> > I've been talking about the implementor-perspective. A standard will not > be much good unless you can also persuade the implementors to buy in. Nor will getting implementors on board if the final form isn't something compellingly useful to developers. I have trouble believing that a C++ POSIX binding that doesn't use exceptions will be accepted easily, widely, or quickly. -------------- 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 de.ibm.com Thu Mar 9 08:21:24 2006 From: TEREKHOV at de.ibm.com (Alexander Terekhov) Date: Thu, 9 Mar 2006 09:21:24 +0100 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <440F6599.8060102@codesourcery.com> Message-ID: Mark Mitchell wrote: [...] > It sounds like we really are close to a solution then; I think everyone > here would be happy with the re-cancellation thing, and the destructor > trick It would not satisfy me. For one. Cancel unaware code should be made cancel aware with "pthread_cancel (pthread_self ())" added only if/when it is really needed. I mean stuff like void oper() throw(int) { /**/ fclose(/*..*/); // doesn't throw; cancel is unexpected -- language // change with mandatory 2-phase EH and intelligent // cancel delivery is required } transformed to void oper() throw(int) { /**/ try { fclose(/*..*/); // can throw; cancel IS expected -- catch below } catch (std::thread_cancel_request const &) { /**/ std::enable_thread_cancel(); // re-enable cancel state std::thread_self().cancel(); // re-inject cancel request /**/ } } Well, I guess I could live with catch (std::thread_cancel_request & tcr) { tcr.stop_stupid_stickyness(); } but that's somewhat unsatisfying, so to speak. regards, alexander. Mark Mitchell on 09.03.2006 00:15:37 To: Jason Merrill cc: Wil Evers , David Abrahams , c++-pthreads at codesourcery.com Subject: Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost Jason Merrill wrote: > If you can interrupt cancellation, re-cancellation is implemented > trivially simply by just having the cancellation exception destructor > call 'pthread_cancel (pthread_self ())'. The sticking point is being > able to abort the cancellation in the first place, which is what Uli has > been opposed to. It sounds like we really are close to a solution then; I think everyone here would be happy with the re-cancellation thing, and the destructor trick means that there's really no way the thread can permanently discard the cancellation request, short of things like longjmp -- and, of course, if the thread is really determined not to go away it can just hang around anyhow. So, it seems like this ought to satisfy everyone from the user-level perspective. > I don't think he's opposed to catching it, just to doing anything that > would involve backing out of the cancellation once it's started. Would the above satisfy him? -- Mark Mitchell CodeSourcery mark at codesourcery.com (650) 331-3385 x713 From TEREKHOV at de.ibm.com Thu Mar 9 08:27:29 2006 From: TEREKHOV at de.ibm.com (Alexander Terekhov) Date: Thu, 9 Mar 2006 09:27:29 +0100 Subject: [c++-pthreads] Re: [SPAM] - Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost - Email found in subject In-Reply-To: <20060309002215.GB17294@cs.fsu.edu> Message-ID: Ted Baker wrote: [...] > It seems to me that if you try to layer a C++ API on top of the C > API, this limitation will catch you. That's just wrong way to layer. C API should be layered on top of the C++ stuff. http://www.codesourcery.com/archives/c++-pthreads/msg00465.html regards, alexander. From TEREKHOV at de.ibm.com Thu Mar 9 08:56:13 2006 From: TEREKHOV at de.ibm.com (Alexander Terekhov) Date: Thu, 9 Mar 2006 09:56:13 +0100 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <00b401c642f9$858ae4c0$6407a8c0@pdimov2> Message-ID: The C++ language can be extended to cope with the concept of async- cancel safety. I can even imagine that async cancel can be made the default with compiler automatically inserting sync_cancel { } wrappers (resulting in extra map tables entries with no runtime penalty until attempting async cancel delivery and finding out that it wasn't expected) for any async-cancel unsafe expressions. I see no reason why tons of std lib stuff like strlen() can't be declared to be size_t strlen(const char *s) async_cancel_safe; regards, alexander. "Peter Dimov" on 08.03.2006 22:44:45 To: "Dave Butenhof" , "David Abrahams" cc: "Meredith, Alisdair" , Subject: Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost Dave Butenhof wrote: > So, yeah; the exception is synchronous. Fine. But that's only the > final, and least interesting, step in the protocol. Or perhaps that's > just "least interesting" to ME, because "I'm a thread guy". ;-) It is a very interesting step because that's what the thread sees, an ordinary exception, emanating from a function in the usual way; meaning that if the thread is already equipped to handle exceptions, as is the case with C++ code nowadays, it "just works". Which is nice. :-) From baker at cs.fsu.edu Thu Mar 9 12:10:14 2006 From: baker at cs.fsu.edu (Ted Baker) Date: Thu, 9 Mar 2006 07:10:14 -0500 Subject: [SPAM] - Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost - Email found in subject In-Reply-To: <440F783E.9020501@hp.com> References: <79E021DD17C2E241ACA0C8AD79C88A178682CB@EN-EX-01.uk.rf1.dir> <440F45C4.9050204@hp.com> <440F783E.9020501@hp.com> Message-ID: <20060309121014.GA23715@cs.fsu.edu> > >Aww, c'mon. You're seriously telling me that one thread can set the > >"there's now an active cancellation flag" for another thread, and the > >other thread can read it with _NO_ synchronization? That isn't how I > >learned things work by reading your book! > > > Cancellation state is a "stash and go" transaction; all that's necessary > is visibility guarantees and a confidence that the storage can't go away > in the midst. There are lots of lock free techniques. By the way, this is one (the main?) reason why the transition from normal to cancelled is one-way, and the effect of cancellation is not necessarily immediate. That way you can maintain consistency without a lock on the bit that says whether a thread is cancelled. Another thread can set the cancellation bit and the target thread some time later notices that the bit is set. Since the bit is never reset, there is no race condition. --Ted From baker at cs.fsu.edu Thu Mar 9 12:14:28 2006 From: baker at cs.fsu.edu (Ted Baker) Date: Thu, 9 Mar 2006 07:14:28 -0500 Subject: [c++-pthreads] Re: [SPAM] - Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost - Email found in subject In-Reply-To: References: <20060309002215.GB17294@cs.fsu.edu> Message-ID: <20060309121428.GB23715@cs.fsu.edu> You may feel that way, Alexander, but I assume you are just enjoying being playfully provocative. You know well that insistence on a POSIX C++ API (or, say, an API for any other language) that implicitly imposes implementation requirements on implementations of the POSIX C API is a sure way to kill this project politically. --Ted On Thu, Mar 09, 2006 at 09:27:29AM +0100, Alexander Terekhov wrote: > > Ted Baker wrote: > [...] > > It seems to me that if you try to layer a C++ API on top of the C > > API, this limitation will catch you. > > That's just wrong way to layer. C API should be layered on top of > the C++ stuff. > > http://www.codesourcery.com/archives/c++-pthreads/msg00465.html > > regards, > alexander. From baker at cs.fsu.edu Thu Mar 9 12:43:55 2006 From: baker at cs.fsu.edu (Ted Baker) Date: Thu, 9 Mar 2006 07:43:55 -0500 Subject: [c++-pthreads] Re: [SPAM] - Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost - Email found in subject In-Reply-To: <440F8445.8030608@hp.com> References: <440EDCC7.9010902@hp.com> <440F0BAC.1070402@codesourcery.com> <440F4FA2.5050608@bogo.xs4all.nl> <440F548C.9000303@codesourcery.com> <440F6400.1080801@redhat.com> <440F6599.8060102@codesourcery.com> <20060309003029.GD17294@cs.fsu.edu> <440F8445.8030608@hp.com> Message-ID: <20060309124355.GA23872@cs.fsu.edu> > >I've been talking about the implementor-perspective. A standard will not > >be much good unless you can also persuade the implementors to buy in. > Nor will getting implementors on board if the final form isn't something > compellingly useful to developers. I have trouble believing that a C++ > POSIX binding that doesn't use exceptions will be accepted easily, > widely, or quickly. Right. So, the POSIX C++ API must include exceptions, but the way in which exceptions and thread cancellation interact needs to put most (maybe all?) of the special burden of supporting C++ onto the implementors of the C++ compiler and the C++ binding, not maintainers of the C binding and the C compiler. Of course, if the C and C++ bindings happen to be done by the same person/group, this matters less. That may be the case with Gnu/gcc, but it seems unwise to assume it will be the case on all platforms. --Ted From dave at boost-consulting.com Thu Mar 9 16:20:08 2006 From: dave at boost-consulting.com (David Abrahams) Date: Thu, 09 Mar 2006 08:20:08 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <79E021DD17C2E241ACA0C8AD79C88A172055C4@EN-EX-01.uk.rf1.dir> (Alisdair Meredith's message of "Wed, 8 Mar 2006 23:26:18 -0000") References: <79E021DD17C2E241ACA0C8AD79C88A172055C4@EN-EX-01.uk.rf1.dir> Message-ID: "Meredith, Alisdair" writes: > Sorry to be dense, or if I am covering old ground - just confirming > I understand correctly: > Also sorry for HTML format - it is all I can get remotely from our > Exchange server :?( > > i/ cancellation will propogate as an (uncatchable?) exception, > implying stack unwinding. In the model I'm proposing, cancellation will be expressed by telling the cancelled thread to throw a specific exception object at the next (or current) cancellation point reached with cancellation enabled. All exceptions are catchable. Exceptions can be unstoppable, if you write them in a particular way. > ii/ if cancellation passes through an exception specification, we > call unexpected and abort which pretty much achieves the same thing No, it doesn't complete stack unwinding, and it might kill the whole process (I'm not sure about that). > iii/ if cancellation interupts a dtor during regular stack > unwinding, we call terminate which pretty much has the same effect, > so everyone is still happy. Likewise. > I am still not sure about: > iv/ if an exception is thrown but not caught in main, it is > implementation defined whether stack unwinding occurs, so it will > really be implementation defined whether the stack is unwound for > thread cancellation in this scheme. 1. This thread may not contain a main(). We are not going to propagate exceptions across threads. 2. It's "just an exception." If you want to force unwinding in the main() thread, in principle you have to do a catch+rethrow pair. 3. The standard says nothing today about how other threads may behave when an exception propagates out uncaught. Fortunately, the threading library binding can force unwinding if the thread is initiated from C++ at least. > I am also not clear whether unexpected / terminate will kill just > the thread, or the whole process. I don't think anyone has been trying to decide that here. -- Dave Abrahams Boost Consulting www.boost-consulting.com From dave at boost-consulting.com Thu Mar 9 16:24:40 2006 From: dave at boost-consulting.com (David Abrahams) Date: Thu, 09 Mar 2006 08:24:40 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <440F6400.1080801@redhat.com> (Jason Merrill's message of "Wed, 08 Mar 2006 18:08:48 -0500") References: <87219549@web.de> <42E8BFC0.9080106@hp.com> <440C843D.8060503@hp.com> <440CA19E.5030809@hp.com> <440CC9B6.4010502@hp.com> <440E3FE8.4040902@hp.com> <440EDCC7.9010902@hp.com> <440F0BAC.1070402@codesourcery.com> <440F4FA2.5050608@bogo.xs4all.nl> <440F548C.9000303@codesourcery.com> <440F6400.1080801@redhat.com> Message-ID: Jason Merrill writes: >> As far as I remember, Ulrich is the only person who has really argued >> that it is unambiguously wrong to consider the situation in which a >> thread catches a cancellation exception. > > I don't think he's opposed to catching it, just to doing anything that > would involve backing out of the cancellation once it's started. The inability to do that would prevent several systems that Dave B. and I have cited from working properly. These systems, if allowed to "back out" from a language/library point-of-view, will unwind completely and terminate the thread as though there was no logical "backing out," but otherwise will exhibit undefined behavior. So I don't think preventing "backing out" at any level that can be enforced by the language or library is tenable if you actually want cancellation to be able to cancel threads. -- Dave Abrahams Boost Consulting www.boost-consulting.com From dave at boost-consulting.com Thu Mar 9 16:34:13 2006 From: dave at boost-consulting.com (David Abrahams) Date: Thu, 09 Mar 2006 08:34:13 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: (Alexander Terekhov's message of "Thu, 9 Mar 2006 09:56:13 +0100") References: Message-ID: Alexander Terekhov writes: > The C++ language can be extended to cope with the concept of async- > cancel safety. I can even imagine that async cancel can be made the > default with compiler automatically inserting sync_cancel { } > wrappers (resulting in extra map tables entries with no runtime > penalty until attempting async cancel delivery and finding out that > it wasn't expected) for any async-cancel unsafe expressions. I see > no reason why tons of std lib stuff like strlen() can't be declared > to be > > size_t strlen(const char *s) async_cancel_safe; In principle, yes. In practice, it's a much bigger problem, still requires lots of attention from the programmer to use correctly, would place new restrictions on implementation technique that may be extremely difficult politically to pass, and could be added atop the answer for "synchronous" cancellation. Let's solve the "easy" problem first. Nobody will forget about async-cancel safety and 2-phase EH as long as you're around, Alexander. -- Dave Abrahams Boost Consulting www.boost-consulting.com From baker at cs.fsu.edu Mon Mar 13 20:35:09 2006 From: baker at cs.fsu.edu (Ted Baker) Date: Mon, 13 Mar 2006 15:35:09 -0500 Subject: [SPAM] - Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost - Email found in subject In-Reply-To: References: <87219549@web.de> <440F6400.1080801@redhat.com> Message-ID: <20060313203508.GB29747@cs.fsu.edu> Maybe two different meanings of "back out"? a) back out = work your way out of the nest of active subprogram calls, doing appropriate cleanups b) back out = stop the cancellation, i.e., stop processing the cancellation, and let the thread resume normal execution Doing (b) would mean not completing (a). I think Ulrich and some others expect (a) will always complete, and so would not like to allow (b). --Ted On Thu, Mar 09, 2006 at 08:24:40AM -0800, David Abrahams wrote: > Jason Merrill writes: > > >> As far as I remember, Ulrich is the only person who has really argued > >> that it is unambiguously wrong to consider the situation in which a > >> thread catches a cancellation exception. > > > > I don't think he's opposed to catching it, just to doing anything that > > would involve backing out of the cancellation once it's started. > > The inability to do that would prevent several systems that Dave > B. and I have cited from working properly. These systems, if allowed > to "back out" from a language/library point-of-view, will unwind > completely and terminate the thread as though there was no logical > "backing out," but otherwise will exhibit undefined behavior. So I > don't think preventing "backing out" at any level that can be enforced > by the language or library is tenable if you actually want > cancellation to be able to cancel threads. > > -- > Dave Abrahams > Boost Consulting > www.boost-consulting.com From dave at boost-consulting.com Tue Mar 14 06:37:18 2006 From: dave at boost-consulting.com (David Abrahams) Date: Mon, 13 Mar 2006 22:37:18 -0800 Subject: [SPAM] - Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost - Email found in subject In-Reply-To: <20060313203508.GB29747@cs.fsu.edu> (Ted Baker's message of "Mon, 13 Mar 2006 15:35:09 -0500") References: <87219549@web.de> <440F6400.1080801@redhat.com> <20060313203508.GB29747@cs.fsu.edu> Message-ID: Ted Baker writes: > Maybe two different meanings of "back out"? > > a) back out = work your way out of the nest of active subprogram > calls, doing appropriate cleanups > > b) back out = stop the cancellation, i.e., > stop processing the cancellation, and let the thread resume > normal execution > > Doing (b) would mean not completing (a). Exactly wrong. Sometimes doing (b) is /required/ in order to do (a) successfully. Please read the foregoing thread where this is explained. > I think Ulrich and some others expect (a) will always complete, > and so would not like to allow (b). Yes, but they are not aware that (b) is sometimes necessary in order to achieve (a) -- Dave Abrahams Boost Consulting www.boost-consulting.com From jason at redhat.com Tue Mar 14 21:53:45 2006 From: jason at redhat.com (Jason Merrill) Date: Tue, 14 Mar 2006 16:53:45 -0500 Subject: [c++-pthreads] Re: [SPAM] - Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost - Email found in subject In-Reply-To: <20060309121014.GA23715@cs.fsu.edu> References: <79E021DD17C2E241ACA0C8AD79C88A178682CB@EN-EX-01.uk.rf1.dir> <440F45C4.9050204@hp.com> <440F783E.9020501@hp.com> <20060309121014.GA23715@cs.fsu.edu> Message-ID: <44173B69.80005@redhat.com> Ted Baker wrote: > By the way, this is one (the main?) reason why the transition from normal > to cancelled is one-way, and the effect of cancellation is not necessarily > immediate. That way you can maintain consistency without a lock on the bit that > says whether a thread is cancelled. Another thread can set the cancellation > bit and the target thread some time later notices that the bit is set. Since > the bit is never reset, there is no race condition. This is the first justification I've seen for Ulrich's position. Can you elaborate on how allowing us to reset the cancelled bit could lead to a race condition? Jason From jason at redhat.com Tue Mar 14 21:37:45 2006 From: jason at redhat.com (Jason Merrill) Date: Tue, 14 Mar 2006 16:37:45 -0500 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: References: <79E021DD17C2E241ACA0C8AD79C88A172055C4@EN-EX-01.uk.rf1.dir> Message-ID: <441737A9.8060807@redhat.com> David Abrahams wrote: > "Meredith, Alisdair" writes: > > In the model I'm proposing, cancellation will be expressed by telling > the cancelled thread to throw a specific exception object at the next > (or current) cancellation point reached with cancellation enabled. > All exceptions are catchable. Exceptions can be unstoppable, if you > write them in a particular way. Hmm.... extern "C" int printf (const char *, ...); struct E { bool undead; E(): undead (true) { } ~E() { if (undead) throw E(); } }; int main() { try { try { throw E(); } catch (...) { printf ("caught once\n"); } } catch (E& e) { printf ("caught twice\n"); e.undead = false; } } This works in g++, but EDG calls terminate() when the destructor throws. I think g++ is correct; 15.5.1 doesn't mention throwing during destruction of the exception object due to flowing off the end of the handler as one of the situations that causes terminate() to be called, and I don't see any reason why it would need to be. We would still call terminate() if the catch(...) block exits by throwing another exception, since then the exception object is destroyed during stack unwinding. >> ii/ if cancellation passes through an exception specification, we >> call unexpected and abort which pretty much achieves the same thing > > No, it doesn't complete stack unwinding, and it might kill the whole > process (I'm not sure about that). > >> iii/ if cancellation interupts a dtor during regular stack >> unwinding, we call terminate which pretty much has the same effect, >> so everyone is still happy. > > Likewise. In previous discussions everyone has agreed that cancellation should be disabled during stack unwinding, to avoid this situation. This could be implemented either by the EH runtime calling pthread_setcancelstate or by the cancellation runtime checking to see if it's safe to throw a la Alexander. Jason From dave at boost-consulting.com Tue Mar 14 21:45:27 2006 From: dave at boost-consulting.com (David Abrahams) Date: Tue, 14 Mar 2006 13:45:27 -0800 Subject: [c++-pthreads] Re: FW: RE: Re: I'm Lost In-Reply-To: <441737A9.8060807@redhat.com> (Jason Merrill's message of "Tue, 14 Mar 2006 16:37:45 -0500") References: <79E021DD17C2E241ACA0C8AD79C88A172055C4@EN-EX-01.uk.rf1.dir> <441737A9.8060807@redhat.com> Message-ID: Jason Merrill writes: > David Abrahams wrote: >> "Meredith, Alisdair" writes: >> In the model I'm proposing, cancellation will be expressed by >> telling >> the cancelled thread to throw a specific exception object at the next >> (or current) cancellation point reached with cancellation enabled. >> All exceptions are catchable. Exceptions can be unstoppable, if you >> write them in a particular way. > > Hmm.... > > extern "C" int printf (const char *, ...); > > struct E > { > bool undead; > E(): undead (true) { } > ~E() { if (undead) throw E(); } You need to check uncaught_exception before throwing here. Remember, it's unspecified how many copies of the exception are made and if a destructor of an original is executed due to the throwing of a copy, you'll terminate. I think that may account for EDG's behavior. >>> ii/ if cancellation passes through an exception specification, we >>> call unexpected and abort which pretty much achieves the same >>> thing >> >> No, it doesn't complete stack unwinding, and it might kill the whole >> process (I'm not sure about that). >> >>> iii/ if cancellation interupts a dtor during regular stack >>> unwinding, we call terminate which pretty much has the same effect, >>> so everyone is still happy. >> >> Likewise. > > In previous discussions everyone has agreed that cancellation should be > disabled during stack unwinding, to avoid this situation. This could be > implemented either by the EH runtime calling pthread_setcancelstate or > by the cancellation runtime checking to see if it's safe to throw a la > Alexander. I'm still happy with that. -- Dave Abrahams Boost Consulting www.boost-consulting.com From jason at redhat.com Tue Mar 14 22:51:43 2006 From: jason at redhat.com (Jason Merrill) Date: Tue, 14 Mar 2006 17:51:43 -0500 Subject: [c++-pthreads] Re: [SPAM] - Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost - Email found in subject In-Reply-To: <44173B69.80005@redhat.com> References: <79E021DD17C2E241ACA0C8AD79C88A178682CB@EN-EX-01.uk.rf1.dir> <440F45C4.9050204@hp.com> <440F783E.9020501@hp.com> <20060309121014.GA23715@cs.fsu.edu> <44173B69.80005@redhat.com> Message-ID: <441748FF.3050200@redhat.com> Jason Merrill wrote: > Ted Baker wrote: >> Since the bit is never reset, there is no race condition. > > This is the first justification I've seen for Ulrich's position. Can > you elaborate on how allowing us to reset the cancelled bit could lead > to a race condition? Actually, I suppose there's no need to reset the cancelled bit and call pthread_cancel again to get the sticky cancel behavior. At least with glibc we just want to clear EXITING_BIT so that the next test will cause us to throw again. Jason From baker at cs.fsu.edu Fri Mar 17 16:12:00 2006 From: baker at cs.fsu.edu (Ted Baker) Date: Fri, 17 Mar 2006 11:12:00 -0500 Subject: [c++-pthreads] Re: [SPAM] - Re: [c++-pthreads] Re: FW: RE: Re: I'm Lost - Email found in subject In-Reply-To: <44173B69.80005@redhat.com> References: <79E021DD17C2E241ACA0C8AD79C88A178682CB@EN-EX-01.uk.rf1.dir> <440F45C4.9050204@hp.com> <440F783E.9020501@hp.com> <20060309121014.GA23715@cs.fsu.edu> <44173B69.80005@redhat.com> Message-ID: <20060317161200.GC23620@cs.fsu.edu> > This is the first justification I've seen for Ulrich's position. Can > you elaborate on how allowing us to reset the cancelled bit could lead > to a race condition? -- Jason The potential race is between resetting the bit and a new cancellation request, potentially missing a new cancellation request. From an implementors point of view, depending on how your thread implementation does other things internally, if protecting this bit requires adding a second per-thread lock, you have a problem with potential deadlock. I seem to recall running into this problem, years ago, when I was working on such things. From an applications point of view, allowing threads once-cancelled to again become "virgin" is also semantically bad, because of indeterminacy: 1. Some therad B tries to cancel a thread A. It locks the cancellation state of A, and sets a bit to indicate that A should cancel. I'm assuming this is because of some condition detected by another thread (or process), maybe a timeout because the thread A has not responded for a while. 2. Some concurrent thread C, who also noticed that the thread is not responding, also tries to cancel A. It locks the cancellation state of A, and sets the cancellation pending bit. We now have three possible scenarios, in a race: 3a. (2) takes effect before A starts recovery, and so (1) and (2) are merged into a single exception from A's point of view. 3b. (2) takes effect while A is executing exception handler code. Depending on implementation details, the second cancellation may be merged with the first, or it may appear as a new pending cancellation event, to be detected as soon as A becomes cancellable again. 3c. (2) takes effect after A finished executing the handler code, and has resumed normal execution. A new cancellation process begins for A at the next point it is cancellable. The standard C thread cancellation semantics, by not allowing a thread to return to normal after cancellation, eliminate possibilities (3b) and (3c), so the outcome of multiiple cancellation attempts is deterministic. --Ted