From anguiano at codesourcery.com Thu Dec 18 22:12:51 2003 From: anguiano at codesourcery.com (Ricardo Anguiano) Date: Thu, 18 Dec 2003 14:12:51 -0800 Subject: Welcome to the c++-pthreads mailing list Message-ID: Greetings, You have been subscribed to the c++-pthreads mailing list. To post messages to the list, send mail to c++-pthreads at codesourcery.com. To unsubscribe, send mail to: c++-pthreads-unsubscribe at codesourcery.com The mailing list is archived and available on the web at: http://www.codesourcery.com/archives/c++-pthreads/threads.html If you have any questions please feel free to contact me. Thanks, -- Ricardo Anguiano http://www.codesourcery.com From mark at codesourcery.com Thu Dec 18 22:34:03 2003 From: mark at codesourcery.com (Mark Mitchell) Date: Thu, 18 Dec 2003 14:34:03 -0800 Subject: C++ and POSIX Threads Mailing List Message-ID: <1071786842.21686.192.camel@doubledemon.codesourcery.com> There has been a fair amount of discussion on the GCC mailing list about possibe ways of integrating POSIX threads with ISO C++. The key question to date has been how to deal with thread cancellation. People have asked questions like: * Should cancellation throw an exception? * What happens if the exception is caught, and not rethrown? * What happens if the exception violates an exception-specification? * What should be done about the fact that ISO C++ says that C library functions like "printf" never throw exceptions? Much of the GCC discussion can be found here: http://gcc.gnu.org/ml/gcc/2003-12/msg00743.html However, this issue is not specific to any compiler; it's a general question about the interaction between C++ and POSIX threads, and perhaps even other threading systems. Therefore, we've started a new mailing list for discussing these issues. To post messages to the list, send mail to c++-pthreads at codesourcery.com. To unsubscribe, send mail to: c++-pthreads-unsubscribe at codesourcery.com The mailing list is archived and available on the web at: http://www.codesourcery.com/archives/c++-pthreads/threads.html Yours, -- Mark Mitchell CodeSourcery, LLC From baker at cs.fsu.edu Thu Dec 18 23:47:18 2003 From: baker at cs.fsu.edu (Ted Baker) Date: Thu, 18 Dec 2003 18:47:18 -0500 Subject: C++ and POSIX Threads Mailing List In-Reply-To: <1071786842.21686.192.camel@doubledemon.codesourcery.com> References: <1071786842.21686.192.camel@doubledemon.codesourcery.com> Message-ID: <20031218234718.GC3023@diablo.name> I hope the C++ folks can learn something from the work done by the POSIX Ada binding group, and the Ada language implementation folks, about ten years ago. The semantic ramifications of exceptions and thread cancelation came up during the original P1003.4a ballot, and were the source of strong objections from the Ada community, including a negative coordination ballot from the POSIX Ada bindings 1003.5 working group. The standard was passed, over these negative ballots. The net effect is that with Ada one cannot safely use thread cancelation. Instead, Ada programmers should use the language-defined task abort operation, which is integrated with the handling of exceptions and has well defined semantics. The implementations of task abort are rather complicated, because they cannot rely on much support from the POSIX threads library. Abort is essentially an asynchronously delivered exception, but it can only be handled by a special kind of handler, called an asynchronous select statement. The latter is called an asynchronous transfer of control, and works sort of like the C-language setjmp() and longjmp() from a signal handler; the differences are that cleanup is done along the way, and the effect is semantically well defined.. If there is no active async. select statement, the entire task must be terminated. Ada requires that propagation of exceptions perform finalization of all controlled objects, as one "unwinds" the nest of activation records back to the appropriate handler. For GNAT we implement abort using a signal. The signal tells the task to abort. The signal handler checks a per-task attribute to see whether it is currently OK to raise an async. exception. If not, the exception will be raised synchronously on exit from the protected region. If we are not in a protected region, the signal handler transfers to control to the nearest handler. There are implicitly provided handlers for every scope that requires finalization. If there is no explicit (user) handler, the exception is just re-raised to propagate out to the next handler. I could say more, since we spent at least three years hashing this stuff out, first in the ANSI/ISO language standarization area, then in the POSIX area, and then in the Gnat implemenation. However, I've learned the hard way that some people don't believe programming language wisdom transfers between languages. If you think my input is of any value, plese add me to your e-mail list. --Ted On Thu, Dec 18, 2003 at 02:34:03PM -0800, Mark Mitchell wrote: > There has been a fair amount of discussion on the GCC mailing list about > possibe ways of integrating POSIX threads with ISO C++. > > The key question to date has been how to deal with thread cancellation. > > People have asked questions like: > > * Should cancellation throw an exception? > > * What happens if the exception is caught, and not rethrown? > > * What happens if the exception violates an exception-specification? > > * What should be done about the fact that ISO C++ says that C library > functions like "printf" never throw exceptions? > > Much of the GCC discussion can be found here: > > http://gcc.gnu.org/ml/gcc/2003-12/msg00743.html > > However, this issue is not specific to any compiler; it's a general > question about the interaction between C++ and POSIX threads, and > perhaps even other threading systems. > > Therefore, we've started a new mailing list for discussing these issues. > > To post messages to the list, send mail to > c++-pthreads at codesourcery.com. > > To unsubscribe, send mail to: > c++-pthreads-unsubscribe at codesourcery.com > > The mailing list is archived and available on the web at: > http://www.codesourcery.com/archives/c++-pthreads/threads.html > > Yours, > > -- > Mark Mitchell > CodeSourcery, LLC From TEREKHOV at de.ibm.com Fri Dec 19 10:39:33 2003 From: TEREKHOV at de.ibm.com (Alexander Terekhov) Date: Fri, 19 Dec 2003 11:39:33 +0100 Subject: C++ and POSIX Threads Mailing List In-Reply-To: <1071786842.21686.192.camel@doubledemon.codesourcery.com> Message-ID: Mark Mitchell wrote: [...] > * Should cancellation throw an exception? Of course. > * What happens if the exception is caught, and not rethrown? Nothing special. Pls see "example" in the message referenced below. > * What happens if the exception violates an exception-specification? That's my favorite. ;-) http://lists.boost.org/MailArchives/boost/msg27199.php http://lists.boost.org/MailArchives/boost/msg27206.php (Subject: [boost] Re: std::expected_exception) > * What should be done about the fact that ISO C++ says that C library > functions like "printf" never throw exceptions? ISO C++ is broken in this respect. Some patching is needed. regards, alexander. From baker at cs.fsu.edu Fri Dec 19 12:45:02 2003 From: baker at cs.fsu.edu (Ted Baker) Date: Fri, 19 Dec 2003 07:45:02 -0500 Subject: [c++-pthreads] Re: C++ and POSIX Threads Mailing List In-Reply-To: References: <1071786842.21686.192.camel@doubledemon.codesourcery.com> Message-ID: <20031219124502.GA6775@diablo.name> >> * Should cancellation throw an exception? > Of course. Not clear. First, you are stuck with the POSIX thread implmentations. They do not provide any way of catching thread cancellation. All they do is guarantee that somehow the cleanup routines will be executed and then the thread will terminate. Furthermore, the POSIX/UNIX standards do not define the semantics for continuation of a thread after cancellation. If you are building on an existing C-language thread implementation, or want to be compatible with one, once a thread is cancelled, you can't count on doing much/anything in that thread other than excecuting cleanup handlers. Back when the POSIX threads standard was being balloted, one of the things the Ada folks asked for was that is should be possible to do a longjmp() from a cancellation cleanup routine, and that longjmp() would execute the stack of cleanup handlers out to the point of the corresponding setjmp(). The balloting group was immovable on this. As a result, we had to accept that Ada asynchronous transfers of control (including task abort) are not fully interoperable with C thread cancellation, but had been ported to all POSIX and UNIX thread implementations, and allows mixing C and Ada code in a single program so long as one does not try to cancel a C thread using an Ada abort, cancel an Ada task (implemented as a C thread) using pthread_cancel, or mix handlers of the two different languages in the same nest of calls. I guess that for C++ you do want to preserve interoperability with C, up to some point. However, if you want good integration with exception handling, you may have to make some compromise like we did with Ada. If you do make exceptions part of your POSIX C++ API, you should think hard about the software engineering issues also. From my 20 years or so experience using and implementing Ada exceptions, I have found that they are mixed blessing. Exceptions are already pretty nasty from the point of view of info. hiding, proofs of correctness using pre/postconditions, structured testing, etc. -- because they introduce a huge potential number of alternate flows of control -- a huge new potential for spaghetti code. In general, you cannot tell for certain that a given piece of code will *not* throw some kind of exception, especially as the code is "maintined", and *especially* if you have asynchronous forms of exception like cancellation. Exceptions are useful in very limited ways, because when one gets to the handler one generally can assume very little about the system state (since the exception may have come from virtually anywhere). A good use is for general error recovery, at a coarse-grained level, where one does not need to assume much about system state. Recovery consists of logging the failure, and then either terminating the process or restarting by setting all state that might have been affected to known valid values. The latter still is often a problem, especially as a system evolves and operations hidden several layers down in abstractions develop side-effects on persistent state that were not anticipated when the recovery code was written. I've also seen exceptions used for two good local uses: (1) exiting deep recursions, as in a depth-first search. (2) catching "expected" exceptions, such as reaching the end of an input stream Outside of these just about every example I've seen of "cute" uses of exception handling ends up having some flaw. Whe we did the POSIX Ada bindings (IEEE 1003.5*) the working group was enamored of exceptions, and made the choice to map all system call failures to exceptions. This has made the API awkward to use for local recovery, and added code to the binding. The implementor has to code something like (excuse the Ada code): if c_system_call(...) = -1 then raise POSIX_Error; end if; And then the user has to code something like (excuse the Ada): begin ada_system_call(...); exception when POSIX_Error => ...recover... end; The latter is not only cumbersome to read and write, but it also imposes runtime overhead. To keep recovery possible, one needs to keep the scope of the handler very local. The larger the scope of the handler, the more things might have gone wrong, and the less hope one has of writing correct recovery code. (I guess you know that error recovery code is generically the least tested and most error-prone code in a system. Just try exhaustive testing of exception handling code in any reasonably large system.) However, even putting the handler right around a single system call does not make recovery easy; POSIX/UNIX standards allow system calls to fail for nonstandard and undocumented reasons, so when one gets to the handler one is stuck with a mess trying to figure out what actually failed. Many a time I've wished for the old C-language interface, with just the if-statement, for system calls. On the other hand, if you expect all your system calls to succeed, and only want to do global recovery, raising exceptions is the way to go. The programmer does the thing most C programmers do in real life (i.e., ignore the function return value), and if anything goes wrong it raises an exception. >> * What happens if the exception is caught, and not rethrown? > Nothing special. Pls see "example" in the message referenced below. This violates basic principles of abstraction and information hiding. 1) The expected effect of cancellation is to terminate a thread. Anything that does not result in termination of the thread breaks the abstraction. 2) If you allow local handling of cancellation, without rethrowing, a hidden operation, many levels deep, may nullify the intended effect of cancelation. This becomes a serious maintenance problem, as some newbie programmer decides to protect his favorite critical section against cancelation and forgets to rethrow it. Suddenly, you have an intermittent bug that will be *very* hard to track down. How often will a thread be cancelled, and how often will it be cancelled at that point? Imagine trying to reproduce this kind of failure. --Ted Baker From TEREKHOV at de.ibm.com Fri Dec 19 13:44:56 2003 From: TEREKHOV at de.ibm.com (Alexander Terekhov) Date: Fri, 19 Dec 2003 14:44:56 +0100 Subject: [c++-pthreads] Re: C++ and POSIX Threads Mailing List In-Reply-To: <20031219124502.GA6775@diablo.name> Message-ID: Ted Baker wrote: [...] > I guess that for C++ you do want to preserve interoperability > with C, up to some point. However, if you want good integration > with exception handling, you may have to make some compromise > like we did with Ada. C++ should simply adopt as and introduce "better" . To me, threaded-C is nothing but "a little bit castrated" threaded-C++, I mean... (just an illustration, nothing real) typedef std::thread * pthread_t; // e.g. #define PTHREAD_CANCELED std::thread_canceled() struct thread_canceled { operator void * () { return &unique; } static thread_canceled unique; }; class thread_termination_request : public std::exception ... class thread_cancel_request : public std::thread_termination_request ... class thread_exit_request : public std::thread_termination_request ... template class thread_exit_value : public std::thread_exit_request ... extern "C" pthread_t pthread_self() throw() { return std::thread_self().raw_ptr(); } extern "C" void pthread_exit(void * ptr) throw(std::thread_termination_request) { ptr == PTHREAD_CANCELED ? std::thread_cancel() : std::thread_exit(ptr); } template void thread_exit(T value) { assert(std::thread_self().can_exit_with()); throw thread_exit_value(value); } template<> void thread_exit(std::thread_canceled) { thread_cancel(); } void thread_cancel() { throw std::thread_cancel_request(); } struct no_cleanup { void operator()(void *) { // NOOP } }; template bool no_TSD_cleanup(const cleanup &) throw() { return false; } template<> bool no_TSD_cleanup(const no_cleanup &) throw() { return true; } template class thread_specific_ptr : cleanup /* noncopyable */ { _TSD_key_t _key; static void dtor(void * data, void * THIS) { static_cast(THIS)-> operator()(static_cast(data)); } public: thread_specific_ptr() throw(std::bad_alloc, std::try_again); thread_specific_ptr(const cleanup&) throw(std::bad_alloc, std::try_again); ~thread_specific_ptr() throw(); T * get() throw(); void set(T *) throw(std::bad_alloc); T * operator->() throw(); T * release() throw(); void dispose() throw(); void reset(T *) throw(std::bad_alloc); }; template thread_specific_ptr::thread_specific_ptr() throw(std::bad_alloc, std::try_again) { _tsd_key_create(&_key, no_TSD_cleanup( *static_cast (this)) ? 0 : &dtor, this); } template thread_specific_ptr::thread_specific_ptr( const cleanup& _cleanup) throw(std::bad_alloc, std::try_again) : cleanup(_cleanup) { _tsd_key_create(&_key, no_TSD_cleanup( __cleanup) ? 0 : &dtor, this); } /* ... */ extern "C" typedef void (* _c_TSD_dtor_t)(void *); extern "C++" typedef void (* _cpp_TSD_dtor_t)(void *); struct _cthread_TSD_cleanup { _cthread_TSD_cleanup(_c_TSD_dtor_t _c_TSD_dtor_) : _func(_c_TSD_dtor_ ? c : null), _c_TSD_dtor(_c_TSD_dtor_) { } _cthread_TSD_cleanup(_cpp_TSD_dtor_t _cpp_TSD_dtor_) : _func(_cpp_TSD_dtor_ ? cpp : null), _cpp_TSD_dtor(_cpp_TSD_dtor_) { } void operator()(void * _data) { if (_data) switch(_func) { case c: _c_TSD_dtor(_data); break; case cpp: _cpp_TSD_dtor(_data); break; } } enum { null, c, cpp } _func; union { _c_TSD_dtor_t _c_TSD_dtor; _cpp_TSD_dtor_t _cpp_TSD_dtor; }; }; template<> bool no_TSD_cleanup(const _cthread_TSD_cleanup & _cleanup) throw() { return _cleanup._func == _cthread_TSD_cleanup::null; } typedef std::thread_specific_ptr * pthread_key_t; // try { throw; } catch... "idiom" int _translate_exception_to_error_code() throw(); extern "C" int pthread_key_create(pthread_key_t * key, void ( * dtor)(void *)) throw() { try { *key = new std::thread_specific_ptr(_cthread_TSD_cleanup(dtor)); } catch(...) { return _translate_exception_to_error_code(); } return 0; } extern "C++" int pthread_key_create(pthread_key_t * key, void ( * dtor)(void *)) throw() { try { *key = new std::thread_specific_ptr(_cthread_TSD_cleanup(dtor)); } catch(...) { return _translate_exception_to_error_code(); } return 0; } extern "C" int pthread_key_delete(pthread_key_t key) throw() { delete key; return 0; } extern "C" void * pthread_getspecific(pthread_key_t key) throw() { return key->get(); } extern "C" int pthread_setspecific(pthread_key_t key, const void * p) throw() { try { key->set(const_cast(p)); } catch(...) { return _translate_exception_to_error_code(); } return 0; } extern "C" int pthread_resetspecific(pthread_key_t key, const void * p) throw() { try { key->reset(const_cast(p)); } catch(...) { return _translate_exception_to_error_code(); } return 0; } extern "C" void * pthread_releasespecific(pthread_key_t key) throw() { return key->release(); } extern "C" void pthread_disposespecific(pthread_key_t key) throw() { return key->dispose(); } // PODs typedef std::aligned_storage pthread_mutex_t; typedef std::aligned_storage pthread_mutexattr_t; #define PTHREAD_MUTEX_INITIALIZER { /* magic */ } pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; extern "C" int pthread_mutex_init(pthread_mutex_t * mutex_storage, const pthread_mutexattr_t * attr_storage) throw() { try { attr_storage ? new (mutex_storage->place()) std::mutex(attr_storage->object()) : new (mutex_storage->place()) std::mutex(); } catch(...) { // see ES of mutex::mutex(/*...*/) return _translate_exception_to_error_code(); } return 0; } extern "C" int pthread_mutex_lock(pthread_mutex_t * m) throw() { try { m->object().acquire(); } catch(...) { // see ES of mutex::acquire() return _translate_exception_to_error_code(); } return 0; } extern "C" int pthread_mutex_destroy(pthread_mutex_t * m) throw() { m->object().~mutex(); return 0; } typedef aligned_storage< once_call< void > > pthread_once_t; #define PTHREAD_ONCE_INIT { /* magic */ } extern "C" int pthread_once(pthread_once_t * once_control, void (* init_routine)()) { once_control->object()(init_routine); return 0; } extern "C++" int pthread_once(pthread_once_t * once_control, void (* init_routine)()) { once_control->object()(init_routine); return 0; } and so forth (or something like that ;-) ). See also http://groups.google.com/groups?selm=3ECB8F71.689E551C%40web.de regards, alexander. From konrad.schwarz at siemens.com Fri Dec 19 07:58:53 2003 From: konrad.schwarz at siemens.com (Schwarz Konrad) Date: Fri, 19 Dec 2003 08:58:53 +0100 Subject: C++ and POSIX Threads Mailing List Message-ID: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> Mark Mitchell posted the existance of this mailing list to austin-group. Although not a C++ programmer, I want to present my views on the subject: Pthreads cancelation and C++ exceptions have arisen in different contexts. Although Tru64 apparently unites the two, I believe this is not necessary. Pthread code that is aysnc-cancelation safe needs to take extra precautions (pushing and popping cancelation handlers). Why can't this restriction be extended to C++? I.e., C++ code that wishes to be async-cancelation safe can do the exact same thing as C code. This avoids all the thorny issues that, juding from the (few) mails I read from your archive, are nearly impossible to solve. Regards, Konrad From austern at apple.com Fri Dec 19 18:28:46 2003 From: austern at apple.com (Matt Austern) Date: Fri, 19 Dec 2003 10:28:46 -0800 Subject: [c++-pthreads] Re: C++ and POSIX Threads Mailing List In-Reply-To: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> Message-ID: <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> On Dec 18, 2003, at 11:58 PM, Schwarz Konrad wrote: > Mark Mitchell posted the existance of this mailing list to > austin-group. > > Although not a C++ programmer, I want to present my views on the > subject: > > Pthreads cancelation and C++ exceptions have arisen in different > contexts. > Although Tru64 apparently unites the two, I believe this is not > necessary. > > Pthread code that is aysnc-cancelation safe needs to take extra > precautions > (pushing and popping cancelation handlers). Why can't this > restriction be > extended to C++? I.e., C++ code that wishes to be async-cancelation > safe > can do the exact same thing as C code. This avoids all the thorny > issues > that, juding from the (few) mails I read from your archive, are nearly > impossible to solve. The annoying issues include synchronous cancellation, not just asynchronous. At the simplest level: the POSIX standard says that read is a cancellation point and that fread might be one too. The C++ standard says that fread does not throw exceptions, and, while the C++ standard doesn't mention read, most C++ programmers would think it's reasonable to assume that read doesn't throw exceptions either. If we decide that thread cancellation results in something like an exception getting thrown in the canceled thread, then we've got a problem. One possible solution (perhaps overly drastic): in C++, eliminate all cancelation points except for pthread_testcancel. --Matt From ncm at cantrip.org Fri Dec 19 19:45:03 2003 From: ncm at cantrip.org (Nathan Myers) Date: Fri, 19 Dec 2003 11:45:03 -0800 Subject: cancellation points report failure In-Reply-To: <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> Message-ID: <20031219194503.GA31795@tofu.dreamhost.com> On Fri, Dec 19, 2003 at 10:28:46AM -0800, Matt Austern wrote: > > One possible solution (perhaps overly drastic): in C++, eliminate > all cancelation points except for pthread_testcancel. Another would be for those functions identified as cancellation points to report failure. In particular, a read() call should return immediately. Existing (good) code has to handle normal failures already. Well-designed library code will propagate the failure up to the point where a check for cancellation, and throw, may occur. To me, the whole problem is how to salvage libraries, both C and C++. I don't know how to write C library code to maintain invariants against stack unwinding. By contrast, a main program that the author knows will be running threaded can reasonably be expected to perform heroics to accommodate cancellations. Our task is to get those cancellations propagated, reasonably quickly, to a context that expects them, without demanding that the libraries do anything unusual. Any place where an exception is allowed, though (such as operator new() and filebuf:: overflow()) seems like a reasonable place to turn the cancellation into an exception. I expect that no matter what we do, some libraries will fail to respond properly to a cancellation. Code that fails to check for write() failure is common, and for printf() even moreso. That's too bad, but we needn't agonize over it. The set of libraries available to threaded programs has always been restricted. A requirement of correct response to failures seems not to great an additional restriction. I don't like the idea of ever entirely discarding a cancellation. If a cancellation exception is thrown, caught, and discarded, I would like to see it surface again at the next opportunity. I think that means that, e.g., I/O operations might be allowed in exception-handling code being run during the cancellation unwind, but if one of those handlers were to swallow the exception, the next I/O operation would fail or throw another cancellation. The idea is not to let the thread get much further without finding cause to bubble up toward the top-level caller that knows it's in a thread, and can die gracefully. Nathan Myers ncm at cantrip.org From mark at codesourcery.com Fri Dec 19 19:49:23 2003 From: mark at codesourcery.com (Mark Mitchell) Date: Fri, 19 Dec 2003 11:49:23 -0800 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: <20031219194503.GA31795@tofu.dreamhost.com> References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> Message-ID: <1071863363.25325.55.camel@doubledemon.codesourcery.com> > I don't like the idea of ever entirely discarding a cancellation. If > a cancellation exception is thrown, caught, and discarded, I would like > to see it surface again at the next opportunity. I think that means > that, e.g., I/O operations might be allowed in exception-handling code > being run during the cancellation unwind, but if one of those handlers > were to swallow the exception, the next I/O operation would fail or > throw another cancellation. The idea is not to let the thread get > much further without finding cause to bubble up toward the top-level > caller that knows it's in a thread, and can die gracefully. I think that is a reasonable idea. I would much prefer that to (say) implicitly rethrowing cancellation exceptions. -- Mark Mitchell CodeSourcery, LLC From austern at apple.com Fri Dec 19 19:52:18 2003 From: austern at apple.com (Matt Austern) Date: Fri, 19 Dec 2003 11:52:18 -0800 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: <1071863363.25325.55.camel@doubledemon.codesourcery.com> References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> <1071863363.25325.55.camel@doubledemon.codesourcery.com> Message-ID: On Dec 19, 2003, at 11:49 AM, Mark Mitchell wrote: > >> I don't like the idea of ever entirely discarding a cancellation. If >> a cancellation exception is thrown, caught, and discarded, I would >> like >> to see it surface again at the next opportunity. I think that means >> that, e.g., I/O operations might be allowed in exception-handling code >> being run during the cancellation unwind, but if one of those handlers >> were to swallow the exception, the next I/O operation would fail or >> throw another cancellation. The idea is not to let the thread get >> much further without finding cause to bubble up toward the top-level >> caller that knows it's in a thread, and can die gracefully. > > I think that is a reasonable idea. > > I would much prefer that to (say) implicitly rethrowing cancellation > exceptions. My understanding is that if a particular cancellation point is disabled, this does *not* mean that the cancellation is discarded. It means that it will be kept around until the next cancellation point. (The thread will never see the cancellation if it never calls a function that is a cancellation points, but that's an inevitable consequence of any synchronous cancellation scheme.) --Matt From dave at boost-consulting.com Fri Dec 19 20:44:19 2003 From: dave at boost-consulting.com (David Abrahams) Date: Fri, 19 Dec 2003 15:44:19 -0500 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: <20031219194503.GA31795@tofu.dreamhost.com> (Nathan Myers's message of "Fri, 19 Dec 2003 11:45:03 -0800") References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> Message-ID: Nathan Myers writes: > On Fri, Dec 19, 2003 at 10:28:46AM -0800, Matt Austern wrote: >> >> One possible solution (perhaps overly drastic): in C++, eliminate >> all cancelation points except for pthread_testcancel. > > Another would be for those functions identified as cancellation > points to report failure. In particular, a read() call should return > immediately. Existing (good) code has to handle normal failures > already. Well-designed library code will propagate the failure up > to the point where a check for cancellation, and throw, may occur. Ingenious! I'm not sure about all the implications, but I think we should explore this idea further. In hindsight, it's almost obvious: a function should only report failure in one way. Requiring programmers to deal with exceptions *and* failure status makes the whole thing unwieldy and error-prone. Nice one, Nathan. -- Dave Abrahams Boost Consulting www.boost-consulting.com From austern at apple.com Fri Dec 19 20:55:26 2003 From: austern at apple.com (Matt Austern) Date: Fri, 19 Dec 2003 12:55:26 -0800 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> Message-ID: On Dec 19, 2003, at 12:44 PM, David Abrahams wrote: > Nathan Myers writes: > >> On Fri, Dec 19, 2003 at 10:28:46AM -0800, Matt Austern wrote: >>> >>> One possible solution (perhaps overly drastic): in C++, eliminate >>> all cancelation points except for pthread_testcancel. >> >> Another would be for those functions identified as cancellation >> points to report failure. In particular, a read() call should return >> immediately. Existing (good) code has to handle normal failures >> already. Well-designed library code will propagate the failure up >> to the point where a check for cancellation, and throw, may occur. > > Ingenious! I'm not sure about all the implications, but I think we > should explore this idea further. In hindsight, it's almost obvious: > a function should only report failure in one way. Requiring > programmers to deal with exceptions *and* failure status makes the > whole thing unwieldy and error-prone. I'm not sure it really solves the problem, though. Yes, it's good for read() to report failure if the thread is cancelled. But we should also make sure that the thread really does get cancelled! *If* we are using a special exception type to represent thread cancellation, then we had better make sure that we get a cancellation exception somewhere within the thread---if not from read, then at least later. We can defer the exception to a later point where the program knows how to deal with it, but we shouldn't eliminate it. (Maybe we should take a step back and ask why we're thinking of representing thread cancellation as an exception. Rationale: we want to make sure that the cancellation isn't ignored, but we also want to give the thread a chance to do some cleanup before it dies. In C we might have cleanup callbacks. In C++ exceptions seem like the natural choice. I think everyone who has done a C++ binding for POSIX has made that choice, but it would be interesting to hear of counterexamples.) --Matt From baker at cs.fsu.edu Fri Dec 19 20:57:46 2003 From: baker at cs.fsu.edu (Ted Baker) Date: Fri, 19 Dec 2003 15:57:46 -0500 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> Message-ID: <20031219205746.GA12322@diablo.name> How do you propose to prevent cancelation occurring (i.e., the thread starts executing the cleanup routines and then exits) if a C++ library function uses an underlying C library call that is a thread cancelation point? Are you figuring on redoing all the libraries to avoid calls to such C functions? --Ted > >> One possible solution (perhaps overly drastic): in C++, eliminate > >> all cancelation points except for pthread_testcancel. > > > > Another would be for those functions identified as cancellation > > points to report failure. In particular, a read() call should return > > immediately. Existing (good) code has to handle normal failures > > already. Well-designed library code will propagate the failure up > > to the point where a check for cancellation, and throw, may occur. > > Ingenious! I'm not sure about all the implications, but I think we > should explore this idea further. In hindsight, it's almost obvious: > a function should only report failure in one way. Requiring > programmers to deal with exceptions *and* failure status makes the > whole thing unwieldy and error-prone. From dave at boost-consulting.com Fri Dec 19 21:18:31 2003 From: dave at boost-consulting.com (David Abrahams) Date: Fri, 19 Dec 2003 16:18:31 -0500 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: (Matt Austern's message of "Fri, 19 Dec 2003 12:55:26 -0800") References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> Message-ID: Matt Austern writes: > On Dec 19, 2003, at 12:44 PM, David Abrahams wrote: > >> Nathan Myers writes: >> >>> On Fri, Dec 19, 2003 at 10:28:46AM -0800, Matt Austern wrote: >>>> >>>> One possible solution (perhaps overly drastic): in C++, eliminate >>>> all cancelation points except for pthread_testcancel. >>> >>> Another would be for those functions identified as cancellation >>> points to report failure. In particular, a read() call should return >>> immediately. Existing (good) code has to handle normal failures >>> already. Well-designed library code will propagate the failure up >>> to the point where a check for cancellation, and throw, may occur. >> >> Ingenious! I'm not sure about all the implications, but I think we >> should explore this idea further. In hindsight, it's almost obvious: >> a function should only report failure in one way. Requiring >> programmers to deal with exceptions *and* failure status makes the >> whole thing unwieldy and error-prone. > > I'm not sure it really solves the problem, though. Yes, it's good for > read() to report failure if the thread is cancelled. But we should also > make sure that the thread really does get cancelled! There really is absolutely no way to *make sure* of that other than by using async cancellation, though. Even if you throw an exception, the thread can catch it and resume normal work inside the catch handler if it wants to -- in that case, the compiler has no way to detect that we're not responding to it. I admit that's a somewhat perverse case, but my point is that the best we can hope to do is come up with a model which works out most of the time and is likely to be compatible with existing coding patterns. > *If* we are using a special exception type to represent thread > cancellation, then we had better make sure that we get a cancellation > exception somewhere within the thread---if not from read, then at > least later. We can defer the exception to a later point where the > program knows how to deal with it, but we shouldn't eliminate it. Of course pthread_testcancel would still throw (once?) if a cancellation request had been issued but the thread was still running. > (Maybe we should take a step back and ask why we're thinking of > representing thread cancellation as an exception. Rationale: we > want to make sure that the cancellation isn't ignored I've never bought the idea that exceptions "make sure errors aren't ignored". There's plenty of code that ignores the possibility of exceptions; it's just as broken as code that ignores error return codes. If you really mean "make sure the cancellation really unwinds the whole thread", well, we can't do that either because the exception may not be able to traverse language boundaries safely. > but we also want to give the thread a chance to do some cleanup > before it dies. In C we might have cleanup callbacks. In C++ > exceptions seem like the natural choice. I think everyone who has > done a C++ binding for POSIX has made that choice, but it would be > interesting to hear of counterexamples.) I'm not sure if this is relevant: In a recent conversation I had with David Butenhof about "2-phase exception handling" we discussed the possibility that there's a special subset of all the cleanups "on the stack" which needs to be run even when termination is forced (e.g. for things like assertion failures, and possibly thread cancellations(?)) in order to release global resources like file locks. 2-phase EH provides a language mechanism for addressing that need, though IIRC there are some cases it doesn't actually handle. In any case, I don't think mandating 2-phase EH in the C++ standard would be appropriate. You can, however, build a fairly elegant library solution using set_terminate_handler() which handles all the cases. -- Dave Abrahams Boost Consulting www.boost-consulting.com From dave at boost-consulting.com Fri Dec 19 21:34:21 2003 From: dave at boost-consulting.com (David Abrahams) Date: Fri, 19 Dec 2003 16:34:21 -0500 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: <20031219205746.GA12322@diablo.name> (Ted Baker's message of "Fri, 19 Dec 2003 15:57:46 -0500") References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> <20031219205746.GA12322@diablo.name> Message-ID: Ted Baker writes: > How do you propose to prevent cancelation occurring (i.e., the > thread starts executing the cleanup routines and then exits) if a > C++ library function uses an underlying C library call that is a > thread cancelation point? > > Are you figuring on redoing all the libraries to avoid calls > to such C functions? One of us is very confused. What you're talking about is the problem we have today. IIUC, Nathan was suggesting that read() should report cancellation using the same means it uses to report failures to 'C' programs, IOW, not by throwing an exception. Maybe I've misunderstood something? >> >> One possible solution (perhaps overly drastic): in C++, eliminate >> >> all cancelation points except for pthread_testcancel. >> > >> > Another would be for those functions identified as cancellation >> > points to report failure. In particular, a read() call should return >> > immediately. Existing (good) code has to handle normal failures >> > already. Well-designed library code will propagate the failure up >> > to the point where a check for cancellation, and throw, may occur. >> >> Ingenious! I'm not sure about all the implications, but I think we >> should explore this idea further. In hindsight, it's almost obvious: >> a function should only report failure in one way. Requiring >> programmers to deal with exceptions *and* failure status makes the >> whole thing unwieldy and error-prone. > -- Dave Abrahams Boost Consulting www.boost-consulting.com From TEREKHOV at de.ibm.com Fri Dec 19 18:51:09 2003 From: TEREKHOV at de.ibm.com (Alexander Terekhov) Date: Fri, 19 Dec 2003 19:51:09 +0100 Subject: [c++-pthreads] Re: C++ and POSIX Threads Mailing List In-Reply-To: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> Message-ID: Schwarz Konrad wrote: [...] > Pthread code that is aysnc-cancelation safe needs to take extra > precautions (pushing and popping cancelation handlers). .... Async-cancel-safety enforced by the language will surely help to dispose all those myths about "terrible async-cancel". But nobody was really talking about ASYNC cancel (unless I've just missed something). Thus far, the topic is/was synchronous ("deferred") cancel. Forced unwinding is brain-damaged. And it's absolutely not needed (neither for "foreign exceptions" nor jumps). http://google.com/groups?selm=3F78478A.F0CCBD0%40web.de What's really needed is standard mandated (mandatory) 2-phase EH and some patching of exception specifications (get rid of silly unwinding on ES violations) plus, perhaps, some extras like weak "ATTACHED"[1] cleanup handlers ala "action_on_propagation_of" http://google.com/groups?threadm=3EBA6888.D4DF2AB1%40web.de and a few other goodies. ;-) regards, alexander. [1] http://google.com/groups?selm=3eb91018%40usenet01.boi.hp.com From baker at cs.fsu.edu Fri Dec 19 22:56:50 2003 From: baker at cs.fsu.edu (Ted Baker) Date: Fri, 19 Dec 2003 17:56:50 -0500 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> <20031219205746.GA12322@diablo.name> Message-ID: <20031219225650.GA13735@diablo.name> If I'm confused, enlighten me. How are you going to implement this version of read() that raises the exeption? The only way I know is to create a wrapper for the C-language read() function (or the corresponding system call trap), check the return value and if it is negative, throw the exception. If you are lucky in how the thread-safe version of the C-language read() works it will already be a wrapper for the system-call trap, that checks for pending cancelation before returning. If you are willing to go directly to the trap, you can replace this code by code to throw your exception. It means you will need to implement your binding in a non-portable way, using the appropriate traps, rather than writing wrappers for the already-standardized C-language functions. If you are unlucky, the implementation of thread cancellation will be done at the kernel level, and the check for pending cancellation will be done beore return from the system call trap. In that case you will not get a chance to catch it and turn it into an exception unless you are friendly with the kernel maintainer. --Ted On Fri, Dec 19, 2003 at 04:34:21PM -0500, David Abrahams wrote: > Ted Baker writes: > > > How do you propose to prevent cancelation occurring (i.e., the > > thread starts executing the cleanup routines and then exits) if a > > C++ library function uses an underlying C library call that is a > > thread cancelation point? > > > > Are you figuring on redoing all the libraries to avoid calls > > to such C functions? > > One of us is very confused. What you're talking about is the problem > we have today. IIUC, Nathan was suggesting that read() should report > cancellation using the same means it uses to report failures to 'C' > programs, IOW, not by throwing an exception. Maybe I've > misunderstood something? From rth at redhat.com Fri Dec 19 23:15:22 2003 From: rth at redhat.com (Richard Henderson) Date: Fri, 19 Dec 2003 15:15:22 -0800 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: <20031219225650.GA13735@diablo.name>; from baker@cs.fsu.edu on Fri, Dec 19, 2003 at 05:56:50PM -0500 References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> <20031219205746.GA12322@diablo.name> <20031219225650.GA13735@diablo.name> Message-ID: <20031219151522.A3398@redhat.com> On Fri, Dec 19, 2003 at 05:56:50PM -0500, Ted Baker wrote: > If you are unlucky, the implementation of thread cancellation > will be done at the kernel level, and the check for pending > cancellation will be done beore return from the system > call trap. In that case you will not get a chance to catch it > and turn it into an exception unless you are friendly with > the kernel maintainer. I'd be very surprised if this were ever true. Don't forget that POSIX added its own pseudo-exceptions to pthreads in the form of pthread_cleanup_push/pop. r~ From dave at boost-consulting.com Sat Dec 20 01:15:03 2003 From: dave at boost-consulting.com (David Abrahams) Date: Fri, 19 Dec 2003 20:15:03 -0500 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: <20031219225650.GA13735@diablo.name> (Ted Baker's message of "Fri, 19 Dec 2003 17:56:50 -0500") References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> <20031219205746.GA12322@diablo.name> <20031219225650.GA13735@diablo.name> Message-ID: Ted Baker writes: > If I'm confused, enlighten me. > > How are you going to implement this version of > read() that raises the exeption? > > The only way I know is to create a wrapper for the C-language > read() function (or the corresponding system call trap), check the > return value and if it is negative, throw the exception. IIUC, you're still being confused in the same way... but I'll let Nathan explain himself because, who knows, maybe it's me that's confused after all? -- Dave Abrahams Boost Consulting www.boost-consulting.com From jason at redhat.com Sat Dec 20 03:03:23 2003 From: jason at redhat.com (Jason Merrill) Date: Fri, 19 Dec 2003 22:03:23 -0500 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: <20031219225650.GA13735@diablo.name> (Ted Baker's message of "Fri, 19 Dec 2003 17:56:50 -0500") References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> <20031219205746.GA12322@diablo.name> <20031219225650.GA13735@diablo.name> Message-ID: On Fri, 19 Dec 2003 17:56:50 -0500, Ted Baker wrote: > How are you going to implement this version of read() that raises the > exeption? The glibc/NPTL pthread library throws an exception. read() is compiled with the necessary unwind information so that the exception will propagate out of it. Jason From ncm at cantrip.org Sat Dec 20 04:56:18 2003 From: ncm at cantrip.org (Nathan Myers) Date: Fri, 19 Dec 2003 20:56:18 -0800 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> <20031219205746.GA12322@diablo.name> <20031219225650.GA13735@diablo.name> Message-ID: <20031220045618.GA27836@tofu.dreamhost.com> On Fri, Dec 19, 2003 at 08:15:03PM -0500, David Abrahams wrote: > Ted Baker writes: > > How are you going to implement this version of > > read() that raises the exeption? > > > > The only way I know is to create a wrapper for the C-language > > read() function (or the corresponding system call trap), check the > > return value and if it is negative, throw the exception. > > IIUC, you're still being confused in the same way... but I'll let > Nathan explain himself because, who knows, maybe it's me that's > confused after all? As I had described the goal, ::read() would never throw an exception. Library code would never expect, or be prepared to handle, an exception from it. Instead, it would return -1. It would set errno to EIO or ECANCELED or ESOMEDAMNTHINGELSE defined by POSIX. The simplest way to make this happen would be for the C library to do it. I'm most interested now in discovering and defining semantics for synchronous cancellation that make it usable with C++ libraries. If we fail, then we are back to the status quo, which is that thread cancellation is incompatible with C++ libraries. Since it apparently isn't yet clear to everybody what I had suggested, I'll outline it again: C library and system calls never throw. In the event of cancellation, cancellation point functions report failure via their normal means (e.g. return -1, or NULL), and set errno if appropriate. Blocked calls fail immediately. C++ library functions that are normally allowed to throw may throw a cancellation exception. (E.g. std::filebuf::overflow().) A thread, once cancelled, stays cancelled, regardless of any C++ catch blocks entered or left. C++ catch blocks work normally; a cancellation exception may be rethrown, or swallowed like any other. In a catch block handling a cancellation exception, functions identified as cancellation points work normally. When a cancellation exception is swallowed by a catch block, subsequently-called cancellation point functions report failure, as before, until another cancellation exception is thrown. Eventually the inability of the thread to achieve anything leads it to top-level code equipped to recognize the cancelled condition as such, and to clean up and die in a controlled way. I am certain that with enough control over the execution environment, the above is more or less trivially implementable. A simpler model would have calling cancellation-point functions from within a catch block also fail or throw, and the caller be expected to tolerate the failure or catch (and discard or rethrow) any resulting exception. Nathan Myers ncm at cantrip.org From TEREKHOV at de.ibm.com Sat Dec 20 17:00:49 2003 From: TEREKHOV at de.ibm.com (Alexander Terekhov) Date: Sat, 20 Dec 2003 18:00:49 +0100 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: <20031220045618.GA27836@tofu.dreamhost.com> Message-ID: Nathan Myers wrote: [...] > C library and system calls never throw. > In the event of cancellation, cancellation point functions report > failure via their normal means (e.g. return -1, or NULL), and set > errno if appropriate. Blocked calls fail immediately. This will essentially break a lot of existing C/C++ code that is cancel-safe and doesn't known how to handle ECANCELED "error" (instead of expected behavior -- exception/unwinding). > In a catch block handling a cancellation exception, functions > identified as cancellation points work normally. They work normally because "When a cancellation request is acted upon, or when a thread calls pthread_exit(), the thread first disables cancellation by setting its cancelability state to PTHREAD_CANCEL_DISABLE and its cancelability type to PTHREAD_CANCEL_DEFERRED. " And, in plain-C POSIX, "The behavior is undefined if a cancellation cleanup handler or thread- specific data destructor routine changes the cancelability state to PTHREAD_CANCEL_ENABLE" (source: TC2). > When a cancellation exception is swallowed by a catch block, > subsequently-called cancellation point functions report failure, > as before, until another cancellation exception is thrown. That's sticky cancel. Not fun if you're using cancel for canceling *jobs* and really want to reuse worker threads (your simply catch and finalize cancel exception, enable cancel again, and continue with next job). regards, alexander. From mark at codesourcery.com Sat Dec 20 18:54:44 2003 From: mark at codesourcery.com (Mark Mitchell) Date: Sat, 20 Dec 2003 10:54:44 -0800 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: <20031220045618.GA27836@tofu.dreamhost.com> References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> <20031219205746.GA12322@diablo.name> <20031219225650.GA13735@diablo.name> <20031220045618.GA27836@tofu.dreamhost.com> Message-ID: <1071946483.25325.69.camel@doubledemon.codesourcery.com> > Since it apparently isn't yet clear to everybody what I had suggested, > I'll outline it again: I think it's a great to see a tidy description of your idea. It's good to get concrete proposals on the table. Jason (Merill), would you care to post a similar description of your preferred scenario? Thanks, -- Mark Mitchell CodeSourcery, LLC From ncm at cantrip.org Sat Dec 20 20:05:18 2003 From: ncm at cantrip.org (Nathan Myers) Date: Sat, 20 Dec 2003 12:05:18 -0800 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: References: <20031220045618.GA27836@tofu.dreamhost.com> Message-ID: <20031220200518.GB27836@tofu.dreamhost.com> On Sat, Dec 20, 2003 at 06:00:49PM +0100, Alexander Terekhov wrote: > Nathan Myers wrote: > [...] > > C library and system calls never throw. > > In the event of cancellation, cancellation point functions report > > failure via their normal means (e.g. return -1, or NULL), and set > > errno if appropriate. Blocked calls fail immediately. > > This will essentially break a lot of existing C/C++ code that is > cancel-safe and doesn't known how to handle ECANCELED "error" > (instead of expected behavior -- exception/unwinding). I don't know of any "existing C/C++ code that is cancel-safe and doesn't known how to handle ECANCELED" errno values. I don't know of any C++ code that expects to field exceptions from C functions. Uncountably many libraries, though, would reasonably be expected to fail (e.g. corrupt memory, leak resources) if such an unexpected exception ripped through. Well-written code handles errors, and well-written portable code handles unknown 'errno' values sanely. That is the code that I am trying to preserve. The far tinier fraction of code (0.1%? 0.01%?) of library code written to know about asynchronous cancellation exceptions will, necessarily, be relatively easy to adapt. > > In a catch block handling a cancellation exception, functions > > identified as cancellation points work normally. > > They work normally because "When a cancellation request is acted > upon, or when a thread calls pthread_exit(), the thread first > disables cancellation by setting its cancelability state to > PTHREAD_CANCEL_DISABLE and its cancelability type to > PTHREAD_CANCEL_DEFERRED. " And, in plain-C POSIX, "The behavior > is undefined if a cancellation cleanup handler or thread- > specific data destructor routine changes the cancelability > state to PTHREAD_CANCEL_ENABLE" (source: TC2). Details do matter. The point is to know what you want, first, and then arrange to make it happen. It's nice to see that POSIX has developed vocabulary to describe what we want. > > When a cancellation exception is swallowed by a catch block, > > subsequently-called cancellation point functions report failure, > > as before, until another cancellation exception is thrown. > > That's sticky cancel. Not fun if you're using cancel for canceling > *jobs* and really want to reuse worker threads (your simply catch > and finalize cancel exception, enable cancel again, and continue > with next job). Any top-level code that fields a cancellation exception is equipped to unstick it, or do something else appropriate. But that's none of our business. Our problem is how to propagate the cancellation out of the libraries (which don't know what it is) to that top-level code (which must), without corrupting memory along the way. Nathan Myers ncm at cantrip.org From TEREKHOV at de.ibm.com Sat Dec 20 21:01:55 2003 From: TEREKHOV at de.ibm.com (Alexander Terekhov) Date: Sat, 20 Dec 2003 22:01:55 +0100 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: <20031220200518.GB27836@tofu.dreamhost.com> Message-ID: Nathan Myers wrote: [...] > Uncountably many libraries, though, would reasonably be expected > to fail (e.g. corrupt memory, leak resources) if such an > unexpected exception ripped through. All those libraries are simply NOT thread-cancel-safe (and I mean synchronous, not asynchronous cancelation). Well, you might want to take a look at http://tinyurl.com/33kjj and, uhmm, yeah, http://tinyurl.com/2zcq6 (I guess that you have a sort of similar problem... except that you're dealing with code that was never meant to be thread-cancel-safe, to begin with). regards, alexander. From ncm at cantrip.org Sun Dec 21 00:41:38 2003 From: ncm at cantrip.org (Nathan Myers) Date: Sat, 20 Dec 2003 16:41:38 -0800 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: References: <20031220200518.GB27836@tofu.dreamhost.com> Message-ID: <20031221004138.GC27836@tofu.dreamhost.com> On Sat, Dec 20, 2003 at 10:01:55PM +0100, Alexander Terekhov wrote: > Nathan Myers wrote: > [...] > > Uncountably many libraries, though, would reasonably be expected > > to fail (e.g. corrupt memory, leak resources) if such an > > unexpected exception ripped through. > > All those libraries are simply NOT thread-cancel-safe (and I mean > synchronous, not asynchronous cancelation). Well, you might want > to take a look at http://tinyurl.com/33kjj and, uhmm, yeah, > http://tinyurl.com/2zcq6 (I guess that you have a sort of similar > problem... except that you're dealing with code that was never > meant to be thread-cancel-safe, to begin with). OK, I have read those. Unlike you, I have no interest in maintaining compatibility for the sake of existing thread-cancel-safe libraries. I don't know of any, and doubt more than a few exist. I do know, however, of thousands upon thousands of ordinary thread-safe libraries. I don't believe that the goal of a "thread-cancel-safe" library (that must take special pains to achieve it) is desirable, nor, in the case of a C library, possible in general. Therefore, I'm interested in defining semantics for a C++ binding that allows use of existing (well-written) libraries, that are only normally thread-safe, in threads that might suffer cancellation . I'm interested in comments on whether the semantics I posted would work, and in any suggested improvements. If the model works, and "we" implement it, it should be easy enough to get some standards body to ratify it. Nathan Myers ncm at cantrip.org From TEREKHOV at de.ibm.com Mon Dec 22 07:13:20 2003 From: TEREKHOV at de.ibm.com (Alexander Terekhov) Date: Mon, 22 Dec 2003 08:13:20 +0100 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: <20031221004138.GC27836@tofu.dreamhost.com> Message-ID: Nathan Myers wrote: [...] > If the model works, ... int peekc(FILE * f) { return ungetc(getc_unlocked(f), f); /* "The ungetc() */ /* function is infrequently called relative to the other */ /* functions/macros so no unlocked variation is needed." */ /* */ /* How fascinating. Well, __fsetlocking() is my friend. */ } Both getc_unlocked() and ungetc() are cancelation points. This function offers basic exception safety and basic thread safety (and it is thread-cancel-safe, of course). Do you really want me to change it to something like int peekc(FILE * f) { int c = ungetc(getc_unlocked(f), f); if (c == EOF && !feof(f) && errno == ECANCELED) { /*... ?re-inject cancel request? ... */ /*... ?re-enable cancel state? ... */ pthread_testcancel(); /* hurrah! */ } return c; } What if someone[1] has it written as int peekc(FILE * f) { int c = getc(f); if (c != EOF) ungetc(c, f); return c; } and cancelation hits at "unchecked" ungetc(), in your model? regards, alexander. [1] google.com/groups?selm=slrn8cvkde.mf3.kaz at ashi.FootPrints.net From TEREKHOV at de.ibm.com Mon Dec 22 13:15:07 2003 From: TEREKHOV at de.ibm.com (Alexander Terekhov) Date: Mon, 22 Dec 2003 14:15:07 +0100 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: <20031219194503.GA31795@tofu.dreamhost.com> Message-ID: Nathan Myers wrote: [...] > I don't know how to write C library code to maintain invariants > against stack unwinding. You simply use pthread_cleanup_push/pop. http://terekhov.de/DESIGN-futex-CV-with-async.cancelable-wait.txt http://groups.google.com/groups?selm=3EDE1AE2.3A8D0929%40web.de regards, alexander. From jm at bourguet.org Mon Dec 22 14:52:50 2003 From: jm at bourguet.org (Jean-Marc Bourguet) Date: Mon, 22 Dec 2003 15:52:50 +0100 Subject: C++ and posix threads Message-ID: <3FE70542.5060104@bourguet.org> I feel confused. I wonder what is the context of the discussion and especially the constraints or the liberties we assume from an implementation. Shoult it - need the collaboration of the pthread library or be implementable as wrapper around an existing pthread library? - allow modifications to the C interface visible from C or not? - allow modifications to the C interface visible from C++ or not? Answering those questions will more or less strongly constraints the rest of the discussion. I didn't saw these issues discussed in the archive (if I missed them please point me to the discussion) and it seems to me that people are assuming different positions on them (Ted Baker seems to assume that it will be a wrapper around an existing pthread library without modifications seen to C code while Nathan Myers's proposition to return an ECANCELED error imply afaik the collaboration of the pthread library and modification to the C interface and Alexander Terekhov is apparently somewhere in between them along this space). Yours, -- Jean-Marc From fjh at cs.mu.oz.au Mon Dec 22 15:07:47 2003 From: fjh at cs.mu.oz.au (Fergus Henderson) Date: Tue, 23 Dec 2003 02:07:47 +1100 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <3FE70542.5060104@bourguet.org> References: <3FE70542.5060104@bourguet.org> Message-ID: <20031222150747.GA13194@jupiter.cs.mu.oz.au> On 22-Dec-2003, Jean-Marc Bourguet wrote: > I feel confused. I wonder what is the context of the discussion > and especially the constraints or the liberties we assume from > an implementation. Shoult it > - need the collaboration of the pthread library or be implementable > as wrapper around an existing pthread library? > - allow modifications to the C interface visible from C or not? > - allow modifications to the C interface visible from C++ or not? I think part of the difficulty is that the problem may be over-constrained. Ideally, the solution would - not require changes to the C pthread library - not modify the C interface visible from C - not modify the C interface visible from C++ - never result in a thread cancellation request being ignored - allow threads to execute arbitrary cleanup code in response to a thread cancellation request - make exception-safe C++ code also safe for (synchronous) cancellation - make cancellation-safe C code also exception-safe, and allow propagation of C++ exceptions through cancellation-safe C code - not introduce any new C++ language constructs or semantics - not introduce any new C language constructs or semantics - not reduce performance of any existing code - be simple, easy to use/understand/teach/specifiy/implement, etc. - probably some other goals that I've accidentally omitted/forgotten However, it is almost certainly not possible to achieve all of these simultaneously. -- Fergus Henderson | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: | -- the last words of T. S. Garp. From jm at bourguet.org Mon Dec 22 15:34:52 2003 From: jm at bourguet.org (Jean-Marc Bourguet) Date: Mon, 22 Dec 2003 16:34:52 +0100 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <20031222150747.GA13194@jupiter.cs.mu.oz.au> References: <3FE70542.5060104@bourguet.org> <20031222150747.GA13194@jupiter.cs.mu.oz.au> Message-ID: <3FE70F1C.7030707@bourguet.org> Fergus Henderson wrote: > On 22-Dec-2003, Jean-Marc Bourguet wrote: > >>I feel confused. I wonder what is the context of the discussion >>and especially the constraints or the liberties we assume from >>an implementation. Shoult it >> - need the collaboration of the pthread library or be implementable >> as wrapper around an existing pthread library? >> - allow modifications to the C interface visible from C or not? >> - allow modifications to the C interface visible from C++ or not? > > and interoperatibility with > I think part of the difficulty is that the problem may be over-constrained. > Ideally, the solution would > > - not require changes to the C pthread library > - not modify the C interface visible from C > - not modify the C interface visible from C++ > - never result in a thread cancellation request being ignored > - allow threads to execute arbitrary cleanup code in > response to a thread cancellation request > - make exception-safe C++ code also safe for (synchronous) > cancellation > - make cancellation-safe C code also exception-safe, > and allow propagation of C++ exceptions through cancellation-safe > C code > - not introduce any new C++ language constructs or semantics > - not introduce any new C language constructs or semantics > - not reduce performance of any existing code > - be simple, easy to use/understand/teach/specifiy/implement, etc. > - probably some other goals that I've accidentally omitted/forgotten > > However, it is almost certainly not possible to achieve all of these > simultaneously. I know, but allowing to redesigning Posix, C and C++ is probably a under-constrained problem. Agreeing on constraints and goals and prioritize them is probably important to get a usefull solution. -- Jean-Marc From mark at codesourcery.com Mon Dec 22 16:48:26 2003 From: mark at codesourcery.com (Mark Mitchell) Date: 22 Dec 2003 08:48:26 -0800 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <3FE70542.5060104@bourguet.org> References: <3FE70542.5060104@bourguet.org> Message-ID: <1072111706.3474.17.camel@minax.codesourcery.com> On Mon, 2003-12-22 at 06:52, Jean-Marc Bourguet wrote: > I feel confused. I wonder what is the context of the discussion > and especially the constraints or the liberties we assume from > an implementation. Shoult it > - need the collaboration of the pthread library or be implementable > as wrapper around an existing pthread library? > - allow modifications to the C interface visible from C or not? > - allow modifications to the C interface visible from C++ or not? These are excellent questions. I believe that the right answers are that: (a) it is OK to have to make modifications to the pthread and/or C libraries on the system, (b) the modifications must be backwards-compatible in C (i.e., no functions should be removed from the pthreads library, although it would be OK to add new ones), and (c) it is OK to consider slightly broader modifications to the existing C interfaces for C++ (such as modifying "read()" to throw an exception), but it should still be possible to recompile C programs as C++ programs and get reasonable behavior. -- Mark Mitchell CodeSourcery, LLC From fjh at cs.mu.OZ.AU Mon Dec 22 17:44:22 2003 From: fjh at cs.mu.OZ.AU (Fergus Henderson) Date: Tue, 23 Dec 2003 04:44:22 +1100 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> <20031219205746.GA12322@diablo.name> Message-ID: <20031222174422.GA14704@ceres.cs.mu.oz.au> On 19-Dec-2003, David Abrahams wrote: > Ted Baker writes: > > > How do you propose to prevent cancelation occurring (i.e., the > > thread starts executing the cleanup routines and then exits) if a > > C++ library function uses an underlying C library call that is a > > thread cancelation point? > > > > Are you figuring on redoing all the libraries to avoid calls > > to such C functions? > > One of us is very confused. What you're talking about is the problem > we have today. IIUC, Nathan was suggesting that read() should report > cancellation using the same means it uses to report failures to 'C' > programs, IOW, not by throwing an exception. Maybe I've > misunderstood something? I understood Ted Baker's comment to be a reply to Matt Austern's "perhaps overly drastic" suggestion that in C++, pthread_testcancel() should be the only cancellation point, not to Nathan's alternative proposal. I don't think Matt Austern's suggestion is workable, because defining the semantics of system calls to be different in C++ than in C would be much too confusing. Ted Baker's comment above is elaborating on one of the consequences of this. > >> >[Matt Austern:] > >> >> One possible solution (perhaps overly drastic): in C++, eliminate > >> >> all cancelation points except for pthread_testcancel. > >> > > >> [Nathan:] > >> > Another would be for those functions identified as cancellation > >> > points to report failure. In particular, a read() call should return > >> > immediately. Existing (good) code has to handle normal failures > >> > already. Well-designed library code will propagate the failure up > >> > to the point where a check for cancellation, and throw, may occur. > >> > >[David Abrahams:] > >> Ingenious! I'm not sure about all the implications, but I think we > >> should explore this idea further. In hindsight, it's almost obvious: > >> a function should only report failure in one way. Requiring > >> programmers to deal with exceptions *and* failure status makes the > >> whole thing unwieldy and error-prone. If we were to toss out concerns about backwards compatibility, I'm sure we could come up with better solutions. But backwards compatibility is important. And Posix already specifies the semantics of system calls to be such that they report different kinds of failure in different ways. -- Fergus Henderson | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: | -- the last words of T. S. Garp. From TEREKHOV at de.ibm.com Mon Dec 22 18:01:54 2003 From: TEREKHOV at de.ibm.com (Alexander Terekhov) Date: Mon, 22 Dec 2003 19:01:54 +0100 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <3FE70542.5060104@bourguet.org> Message-ID: Jean-Marc Bourguet wrote: [...] > - need the collaboration of the pthread library or be implementable > as wrapper around an existing pthread library? Pthread library shall use/throw C++ exceptions for thread cancel and thread exit (without , we can exit with only void*). "Collaboration" (see below) would be really nice and is probably the best way to provide both / and interfaces. > - allow modifications to the C interface visible from C or not? No changes except just a few extensions -- see (3) below. > - allow modifications to the C interface visible from C++ or not? Nothing but extensions to C interface and changes (3) to C++: 1. "Visible" C++ exceptions for thread cancel and thread exit (ability to "intercept" thread cancel/exit); 2. Ability to re-enable cancelation after thread termination has been initiated (thread cancelation state was set to disabled by the implementation). 3. Mandatory 2-phase EH and sort of "intelligent" cancelation points -- they shall NOT throw thread_cancel_request exception if no matching handler is found in the dynamic context... such as invocation of C cleanup handler via pthread_cleanup_pop(1). And all C++ dtors should have an implicit throw()-nothing ES, of course. For C++, that would also mean "some" changes in ES semantics which are currently pretty much totally busted, BTW. [...] > Terekhov is apparently somewhere in between Well, I'm not really in between. would simply provide much better C++ interface... in addition to the "classic" one (/). It's just like () and (): http://std.dkuug.dk/JTC1/SC22/WG14/www/docs/n972.pdf http://std.dkuug.dk/JTC1/SC22/WG21/docs/papers/2003/n1457.pdf Obviously, interface definitions written in the common subset of C and C++ would have the widest potential audience, since they would be readable by compilers for both languages. But the additional abstraction mechanisms of C++, such as classes and templates, are useful in writing code [...]. They allow the encapsulation of features into classes, providing type safety along with maximum efficiency through the use of templates. Nevertheless, it is an important goal to provide an interface that allows [...] to write code that compiles equally under C and C++ compilers. Therefore, [...] specifies two interfaces: one using the common subset of C and C++ and a second using modern C++ constructs. Implementers of the commonsubset style interface might use functions or inline functions, or might decide that function-like macros or intrinsic functions better serve their objectives. [...] The implementation of the [... C ...] interface on top of the interface is mainly straightforward. This section provides an example of how such an implementation can be achieved. regards, alexander. From dave at boost-consulting.com Mon Dec 22 20:48:41 2003 From: dave at boost-consulting.com (David Abrahams) Date: Mon, 22 Dec 2003 15:48:41 -0500 Subject: GMane reflector Message-ID: This mailing list should now be reflected as a newsgroup at news.gmane.org Cheers! -------------- next part -------------- An embedded message was scrubbed... From: Lars Magne Ingebrigtsen Subject: Re: subscribe c++-pthreads at codesourcery.com Date: Mon, 22 Dec 2003 21:35:26 +0100 Size: 2223 URL: -------------- next part -------------- -- Dave Abrahams Boost Consulting www.boost-consulting.com From baker at cs.fsu.edu Mon Dec 22 21:57:12 2003 From: baker at cs.fsu.edu (Ted Baker) Date: Mon, 22 Dec 2003 16:57:12 -0500 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <1072111706.3474.17.camel@minax.codesourcery.com> References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> Message-ID: <20031222215712.GB1528@diablo.name> > (c) it is OK to consider slightly broader modifications to the existing > C interfaces for C++ (such as modifying "read()" to throw an exception), > but it should still be possible to recompile C programs as C++ programs > and get reasonable behavior. I don't think you will be able to get buy-in from vendors or users of C if you require changes to the POSIX C libraries that would change the behavior of any existing C application that conforms to the current Open Group Unix or the IEEE POSIX standards. --Ted From mark at codesourcery.com Mon Dec 22 22:18:18 2003 From: mark at codesourcery.com (Mark Mitchell) Date: Mon, 22 Dec 2003 14:18:18 -0800 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <20031222215712.GB1528@diablo.name> References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> Message-ID: <1072131497.7562.22.camel@doubledemon.codesourcery.com> On Mon, 2003-12-22 at 13:57, Ted Baker wrote: > > (c) it is OK to consider slightly broader modifications to the existing > > C interfaces for C++ (such as modifying "read()" to throw an exception), > > but it should still be possible to recompile C programs as C++ programs > > and get reasonable behavior. > > I don't think you will be able to get buy-in from vendors or > users of C if you require changes to the POSIX C libraries that > would change the behavior of any existing C application that > conforms to the current Open Group Unix or the IEEE POSIX > standards. I agree -- but I did not say that. I said: it is OK to consider slightly broader modifications to the existing C interfaces for C++ There's no inherent reason why a vendor would refuse to make a change to the interfaces in some new mode -- so long as the backwards-compatibility requirement you mention were preserved. -- Mark Mitchell CodeSourcery, LLC From austern at apple.com Mon Dec 22 22:23:32 2003 From: austern at apple.com (Matt Austern) Date: Mon, 22 Dec 2003 14:23:32 -0800 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <1072131497.7562.22.camel@doubledemon.codesourcery.com> References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> Message-ID: <7A091423-34CD-11D8-9070-00039390D9E0@apple.com> On Dec 22, 2003, at 2:18 PM, Mark Mitchell wrote: > On Mon, 2003-12-22 at 13:57, Ted Baker wrote: >>> (c) it is OK to consider slightly broader modifications to the >>> existing >>> C interfaces for C++ (such as modifying "read()" to throw an >>> exception), >>> but it should still be possible to recompile C programs as C++ >>> programs >>> and get reasonable behavior. >> >> I don't think you will be able to get buy-in from vendors or >> users of C if you require changes to the POSIX C libraries that >> would change the behavior of any existing C application that >> conforms to the current Open Group Unix or the IEEE POSIX >> standards. > > I agree -- but I did not say that. I said: > > it is OK to consider slightly broader modifications to the > existing C interfaces for C++ > > There's no inherent reason why a vendor would refuse to make a change > to > the interfaces in some new mode -- so long as the > backwards-compatibility requirement you mention were preserved. And I think such modifications are almost inevitable. POSIX defined a binding for C. It takes some thought to apply that binding to a different language that has different mechanisms for abstraction, encapsulation, and error reporting. --Matt From ncm at cantrip.org Mon Dec 22 17:51:54 2003 From: ncm at cantrip.org (Nathan Myers) Date: Mon, 22 Dec 2003 09:51:54 -0800 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <3FE70542.5060104@bourguet.org> References: <3FE70542.5060104@bourguet.org> Message-ID: <20031222175154.GB30780@tofu.dreamhost.com> On Mon, Dec 22, 2003 at 03:52:50PM +0100, Jean-Marc Bourguet wrote: > I feel confused. I wonder what is the context of the discussion > and especially the constraints or the liberties we assume from > an implementation. This list was started in hope getting guidance for the implementers of gcc/glibc in creating a synchronous thread-cancellation binding that is sensible for C++. > Shoult it > - need the collaboration of the pthread library or be implementable > as wrapper around an existing pthread library? > - allow modifications to the C interface visible from C or not? > - allow modifications to the C interface visible from C++ or not? > > Answering those questions will more or less strongly constraints the rest > of the discussion. We assume implementers have full control of the compiler and support libraries, including any underlying C and related (e.g. "pthread") libraries. [Someday the notion of an "underlying" C library will be seen as quaint and primitive, but evidently not yet.] The binding doesn't have to match POSIX's binding for C, although it shouldn't demand heroics from the C library. The goal, as I understand it, is to elucidate a model that is simple to describe and document, and to code to, and that may be implemented quickly and cheaply without ambiguities or troublesome choices. Nathan Myers ncm at cantrip.org From ncm at cantrip.org Mon Dec 22 18:16:11 2003 From: ncm at cantrip.org (Nathan Myers) Date: Mon, 22 Dec 2003 10:16:11 -0800 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <20031222150747.GA13194@jupiter.cs.mu.oz.au> References: <3FE70542.5060104@bourguet.org> <20031222150747.GA13194@jupiter.cs.mu.oz.au> Message-ID: <20031222181611.GC30780@tofu.dreamhost.com> Our goal is to define a binding that is possible, practical, and simple. Therefore... On Tue, Dec 23, 2003 at 02:07:47AM +1100, Fergus Henderson wrote: > On 22-Dec-2003, Jean-Marc Bourguet wrote: > > I feel confused. I wonder what is the context of the discussion > > and especially the constraints or the liberties we assume from > > an implementation. Shoult it > > - need the collaboration of the pthread library or be implementable > > as wrapper around an existing pthread library? > > - allow modifications to the C interface visible from C or not? > > - allow modifications to the C interface visible from C++ or not? > > I think part of the difficulty is that the problem may be over-constrained. > Ideally, the solution would > > - not require changes to the C pthread library > - not modify the C interface visible from C > - not modify the C interface visible from C++ > - never result in a thread cancellation request being ignored > - allow threads to execute arbitrary cleanup code in > response to a thread cancellation request > - make exception-safe C++ code also safe for (synchronous) > cancellation > - make cancellation-safe C code also exception-safe, > and allow propagation of C++ exceptions through cancellation-safe > C code > - not introduce any new C++ language constructs or semantics > - not introduce any new C language constructs or semantics > - not reduce performance of any existing code > - be simple, easy to use/understand/teach/specifiy/implement, etc. > - probably some other goals that I've accidentally omitted/forgotten > > However, it is almost certainly not possible to achieve all of these > simultaneously. I believe that we can achieve our goal if we omit impossible requirements. Of the above, I see the following as showstoppers that must be jettisoned immediately: - not require changes to the C pthread library We assume we can adapt the libraries involved as needed, as long as our demands are simple to describe and implement. - never result in a thread cancellation request being ignored This is impossible on its face, as it ultimately depends on users' coding practices. A reasonable goal would be that simple good coding practices are unlikely to cause cancellation requests to be ignored indefinitely. - make cancellation-safe C code also exception-safe, and allow propagation of C++ exceptions through cancellation-safe C code While cancellation-safe C code might exist, in principle, we should not contort our solution to try to accommodate it. A correct C++ library does not let exceptions escape to C code, so this case is only of academic interest. We can presume that any C code that is cancellation-safe also handles normal error returns sensibly. - not [ever] reduce performance of any existing code Threads necessarily impose inefficiencies. We can have a goal to minimze those. - probably some other goals that I've accidentally omitted/forgotten We can burn those bridges when we get to them. Let's try not to get sidetracked. The consequence of failure or excessive delay is that C++, like Ada, will remain incompatible with any form of thread cancellation. Nathan Myers ncm at cantrip.org From ncm at cantrip.org Mon Dec 22 17:37:09 2003 From: ncm at cantrip.org (Nathan Myers) Date: Mon, 22 Dec 2003 09:37:09 -0800 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: References: <20031219194503.GA31795@tofu.dreamhost.com> Message-ID: <20031222173709.GA30780@tofu.dreamhost.com> On Mon, Dec 22, 2003 at 02:15:07PM +0100, Alexander Terekhov wrote: > Nathan Myers wrote: > [...] > > I don't know how to write C library code to maintain invariants > > against stack unwinding. > > You simply use pthread_cleanup_push/pop. > > http://terekhov.de/DESIGN-futex-CV-with-async.cancelable-wait.txt > http://groups.google.com/groups?selm=3EDE1AE2.3A8D0929%40web.de My point was just that C does not offer the language facilities needed to write exception-safe code. Anyhow, extensions involving pthread_thisandthat aren't exercised in any of the libraries might I want to use. Nathan Myers ncm at cantrip.org From gdr at integrable-solutions.net Mon Dec 22 23:51:10 2003 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 23 Dec 2003 00:51:10 +0100 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <20031222181611.GC30780@tofu.dreamhost.com> References: <3FE70542.5060104@bourguet.org> <20031222150747.GA13194@jupiter.cs.mu.oz.au> <20031222181611.GC30780@tofu.dreamhost.com> Message-ID: Nathan Myers writes: | not contort our solution to try to accommodate it. A correct C++ | library does not let exceptions escape to C code, so this case is | only of academic interest. We can presume that any C code that is | cancellation-safe also handles normal error returns sensibly. only when "academic interest" is the code that are not your production :-) And if I apply that same definition to my of view, then your codes immediately become of academic interest. >From a C++ program, how do you indentify a C code? (The 'extern "C"' is meant to let exception propagate correctly through C codes and return back to C++ handlers (if nay). That has always been part of the linkage specification facility). | Let's try not to get sidetracked. Yup. The above assumption would be a distraction. -- Gaby From gdr at integrable-solutions.net Mon Dec 22 23:56:42 2003 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 23 Dec 2003 00:56:42 +0100 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <20031222175154.GB30780@tofu.dreamhost.com> References: <3FE70542.5060104@bourguet.org> <20031222175154.GB30780@tofu.dreamhost.com> Message-ID: Nathan Myers writes: | On Mon, Dec 22, 2003 at 03:52:50PM +0100, Jean-Marc Bourguet wrote: | > I feel confused. I wonder what is the context of the discussion | > and especially the constraints or the liberties we assume from | > an implementation. | | This list was started in hope getting guidance for the implementers of | gcc/glibc in creating a synchronous thread-cancellation binding that is | sensible for C++. I hope this list was not setup in order to come up with GCC- or GLIBC-centric solutions. I think that was precisely the opposite, if I understand Matt's original suggestion correctly. I wonder if this is the right forum for this discussion? I agree with you and Jason that the C++ and POSIX standards are incompatible. I also agree that it's very important to reconcile them, and that it's an embarrassment that it's taken so long to do it. Essentially, you're proposing a C++ binding to (a part of) POSIX. The reason I wonder whether this is the right forum: this is the gcc mailing list. But we don't want a gcc C++ POSIX binding, we want to have the same C++ POSIX binding for all relevant compilers and operating systems. --Matt -- Gaby From rth at redhat.com Tue Dec 23 01:02:15 2003 From: rth at redhat.com (Richard Henderson) Date: Mon, 22 Dec 2003 17:02:15 -0800 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <20031222150747.GA13194@jupiter.cs.mu.oz.au> References: <3FE70542.5060104@bourguet.org> <20031222150747.GA13194@jupiter.cs.mu.oz.au> Message-ID: <20031223010215.GA6897@redhat.com> On Tue, Dec 23, 2003 at 02:07:47AM +1100, Fergus Henderson wrote: > - never result in a thread cancellation request being ignored Along similar lines, it might be worth considering if longjmp_unwind (a function mentioned, for instance, in the ia64 eh abi), is even implementable. My guess is that it isn't, simply because it's too easy for a handler to abort the unwinding. [ Rant about C++ programmers failing to distinguish between catch-all and cleanups elided. ] r~ From ncm at cantrip.org Tue Dec 23 02:08:38 2003 From: ncm at cantrip.org (Nathan Myers) Date: Mon, 22 Dec 2003 18:08:38 -0800 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: References: <3FE70542.5060104@bourguet.org> <20031222175154.GB30780@tofu.dreamhost.com> Message-ID: <20031223020838.GF27836@tofu.dreamhost.com> On Tue, Dec 23, 2003 at 12:56:42AM +0100, Gabriel Dos Reis wrote: > Nathan Myers writes: > > | On Mon, Dec 22, 2003 at 03:52:50PM +0100, Jean-Marc Bourguet wrote: > | > I feel confused. I wonder what is the context of the discussion > | > and especially the constraints or the liberties we assume from > | > an implementation. > | > | This list was started in hope getting guidance for the implementers of > | gcc/glibc in creating a synchronous thread-cancellation binding that is > | sensible for C++. > > I hope this list was not setup in order to come up with GCC- or > GLIBC-centric solutions. I think that was precisely the opposite, if > I understand Matt's original suggestion correctly. Of course. This list is meant to bring in people from outside the gcc list, but it's not POSIX. If we invent a design, and implement and demonstrate it, it's a valuable example for all C++ implementers. But if we tie ourselves in knots trying to accommodate every historical mistake and every overconstrained implementation, we we will make no progress and no contribution, and will waste everybody's time besides. It is essential that we stick to the basics: what is essential, and what can we really implement? It has already been observed that the standards as conceived are incompatible. We are have no choice but to do something different, and work to standardize that. (Actually, we do have a choice: we can fail. Ada has no POSIX cancellation binding.) Do you have anything to say about the model that was proposed, or can you propose an alternative? Nathan Myers ncm at cantrip.org From gdr at integrable-solutions.net Tue Dec 23 03:47:49 2003 From: gdr at integrable-solutions.net (Gabriel Dos Reis) Date: 23 Dec 2003 04:47:49 +0100 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <20031223020838.GF27836@tofu.dreamhost.com> References: <3FE70542.5060104@bourguet.org> <20031222175154.GB30780@tofu.dreamhost.com> <20031223020838.GF27836@tofu.dreamhost.com> Message-ID: Nathan Myers writes: | On Tue, Dec 23, 2003 at 12:56:42AM +0100, Gabriel Dos Reis wrote: | > Nathan Myers writes: | > | > | On Mon, Dec 22, 2003 at 03:52:50PM +0100, Jean-Marc Bourguet wrote: | > | > I feel confused. I wonder what is the context of the discussion | > | > and especially the constraints or the liberties we assume from | > | > an implementation. | > | | > | This list was started in hope getting guidance for the implementers of | > | gcc/glibc in creating a synchronous thread-cancellation binding that is | > | sensible for C++. | > | > I hope this list was not setup in order to come up with GCC- or | > GLIBC-centric solutions. I think that was precisely the opposite, if | > I understand Matt's original suggestion correctly. | | Of course. This list is meant to bring in people from outside the gcc | list, but it's not POSIX. Right. | If we invent a design, and implement and | demonstrate it, it's a valuable example for all C++ implementers. But If the purpose was just to come up with an implementation for a particular compiler/system as a proof of concept, that could have been done in GCC/GLIBC inner circles without creating this list and alerting the world about it. | if we tie ourselves in knots trying to accommodate every historical | mistake and every overconstrained implementation, we we will make no | progress and no contribution, and will waste everybody's time besides. | | It is essential that we stick to the basics: what is essential, and | what can we really implement? It has already been observed that the | standards as conceived are incompatible. We are have no choice but | to do something different, and work to standardize that. (Actually, | we do have a choice: we can fail. Ada has no POSIX cancellation | binding.) | | Do you have anything to say about the model that was proposed, or can | you propose an alternative? I'm carefully listening to what other people (and inputs from non-GCC tied ones are most welcome) to say/propose before legislating about what is relevant or not, historical mistake or not, essential or not. -- Gaby From kaih at khms.westfalen.de Mon Dec 22 21:13:00 2003 From: kaih at khms.westfalen.de (Kai Henningsen) Date: 22 Dec 2003 23:13:00 +0200 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <3FE70542.5060104@bourguet.org> References: <3FE70542.5060104@bourguet.org> Message-ID: <8-NBCKFHw-B@khms.westfalen.de> jm at bourguet.org (Jean-Marc Bourguet) wrote on 22.12.03 in <3FE70542.5060104 at bourguet.org>: > I feel confused. I wonder what is the context of the discussion > and especially the constraints or the liberties we assume from > an implementation. Shoult it > - need the collaboration of the pthread library or be implementable > as wrapper around an existing pthread library? If it is strictly a wrapper, that means it can be made to work everywhere there is a correct and sufficiently complete pthreads implementation. If it needs pthreads-level changes, I see grave problems getting it implemented on non-glibc platforms. (Which would pretty much mean portability becomes an uninteresting question.) > - allow modifications to the C interface visible from C or not? If it needs C-C changes, it is pretty much certain that POSIX will reject it, I believe. See the Ada experience. > - allow modifications to the C interface visible from C++ or not? That could probably be done with wrappers. And giving the at least partly conflicting ideas between C and C++ on this, this may be necessary. MfG Kai From fjh at cs.mu.oz.au Tue Dec 23 09:26:31 2003 From: fjh at cs.mu.oz.au (Fergus Henderson) Date: Tue, 23 Dec 2003 20:26:31 +1100 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <20031222181611.GC30780@tofu.dreamhost.com> References: <3FE70542.5060104@bourguet.org> <20031222150747.GA13194@jupiter.cs.mu.oz.au> <20031222181611.GC30780@tofu.dreamhost.com> Message-ID: <20031223092631.GD20663@jupiter.cs.mu.oz.au> On 22-Dec-2003, Nathan Myers wrote: > On Tue, Dec 23, 2003 at 02:07:47AM +1100, Fergus Henderson wrote: > > I think part of the difficulty is that the problem may be over-constrained. > > Ideally, the solution would > > > > - not require changes to the C pthread library > > - not modify the C interface visible from C > > - not modify the C interface visible from C++ > > - never result in a thread cancellation request being ignored > > - allow threads to execute arbitrary cleanup code in > > response to a thread cancellation request > > - make exception-safe C++ code also safe for (synchronous) > > cancellation > > - make cancellation-safe C code also exception-safe, > > and allow propagation of C++ exceptions through cancellation-safe > > C code > > - not introduce any new C++ language constructs or semantics > > - not introduce any new C language constructs or semantics > > - not reduce performance of any existing code > > - be simple, easy to use/understand/teach/specifiy/implement, etc. > > - probably some other goals that I've accidentally omitted/forgotten > > > > However, it is almost certainly not possible to achieve all of these > > simultaneously. > > I believe that we can achieve our goal if we omit impossible > requirements. Of the above, I see the following as showstoppers > that must be jettisoned immediately: > > - not require changes to the C pthread library > > We assume we can adapt the libraries involved as needed, as long as > our demands are simple to describe and implement. That seems fair to me. > - never result in a thread cancellation request being ignored > > This is impossible on its face, as it ultimately depends on users' > coding practices. A reasonable goal would be that simple good coding > practices are unlikely to cause cancellation requests to be ignored > indefinitely. That seems fair too. > - make cancellation-safe C code also exception-safe, and > allow propagation of C++ exceptions through cancellation-safe > C code > > While cancellation-safe C code might exist, in principle, we should > not contort our solution to try to accommodate it. A correct C++ > library does not let exceptions escape to C code, so this case is > only of academic interest. Here I don't agree. Firstly, you should say "a portable C++ library", not "a correct C++ library", since some C/C++ implementations do support throwing C++ exceptions across C code, and I'm sure some correct but not portable C++ code takes advantage of this. Secondly, and more importantly, I think that allowing this case is important for language interoperability, not just for C/C++, but also for interoperability between C++ and other languages (many of which are implemented via compilation to C). Posix thread cancellation is, in effect, a mechanism that provides a limited form of exception handling for C. It is natural for C implementations to extend C with more general support for exception handling, both for its own inherent usefulness and for ease of interoperability with other languages. For example, both GNU C and Microsoft C have provided C language extensions for exception handling, and there have been numerous C libraries that provide support for exception handling -- see for example - Costello and Truta's "cexcept" - Doug Gwyn's "ex" package, available from the cexpect site. - Ian Zimmerman's "exc" package, also available via the cexcept site. - David Hanson's "except.h", in his book "C Interfaces and Implementations" - Bruce W. Bigby's "GEF" - Schotland and Petersen's (unnamed?) exception handling library , - Kaz Kylheku's "KazLib" - Symbian EPOC - MLib - my own "CXCPT" There are probably lots more examples. Given the likelihood of C being extended in this way with some form of exception handling, it is desirable to make this exception handling interoperate well with both Posix thread cancellation and C++ exceptions. This in turn essentially requires that Posix thread cancellation and C++ exceptions interoperate well with each other. To my mind that includes being able to propagate C++ exceptions through cancellation-safe C code. When talking about cancellation-safe C code, we should consider that this may also include exception-safe C code that has been (or will be) written using a C exception facility that is compatible with and/or interoperates with Posix thread cancellation. Currently pthread_cleanup_push() and pthread_cleanup_pop() are the only _standardized_ facility for enabling C code to clean up during stack unwinding. C exception handling extensions will need to provide their own facilities for that. But it seems like a bad idea to have more than one underlying mechanism for such clean up code; even if we may be stuck with several interfaces, having them all be implemented using a single underlying mechanisms seems like the only reasonable way to get the desired level of interoperability. -- Fergus Henderson | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: | -- the last words of T. S. Garp. From dave at boost-consulting.com Tue Dec 23 12:18:37 2003 From: dave at boost-consulting.com (David Abrahams) Date: Tue, 23 Dec 2003 07:18:37 -0500 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <20031223092631.GD20663@jupiter.cs.mu.oz.au> (Fergus Henderson's message of "Tue, 23 Dec 2003 20:26:31 +1100") References: <3FE70542.5060104@bourguet.org> <20031222150747.GA13194@jupiter.cs.mu.oz.au> <20031222181611.GC30780@tofu.dreamhost.com> <20031223092631.GD20663@jupiter.cs.mu.oz.au> Message-ID: Fergus Henderson writes: > On 22-Dec-2003, Nathan Myers wrote: >> On Tue, Dec 23, 2003 at 02:07:47AM +1100, Fergus Henderson wrote: > >> - make cancellation-safe C code also exception-safe, and >> allow propagation of C++ exceptions through cancellation-safe >> C code >> >> While cancellation-safe C code might exist, in principle, we should >> not contort our solution to try to accommodate it. A correct C++ >> library does not let exceptions escape to C code, so this case is >> only of academic interest. > > Here I don't agree. Though all the points you make in opposition are well-made, I wonder if you really disagree with what I consider to be Nathan's most important point: "While cancellation-safe C code might exist, in principle, we should not contort our solution to try to accommodate it" Fortunately, the question may be moot: is there really much we *can* do with a C++ binding in order to "accomodate" cancellation-safe C code? Surely throwing an exception into C++ code which *probably* doesn't expect it doesn't do anything to help C code which might be cancellation-safe? -- Dave Abrahams Boost Consulting www.boost-consulting.com From TEREKHOV at de.ibm.com Tue Dec 23 14:21:16 2003 From: TEREKHOV at de.ibm.com (Alexander Terekhov) Date: Tue, 23 Dec 2003 15:21:16 +0100 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: Message-ID: David Abrahams wrote: [...] > Fortunately, the question may be moot: is there really much we *can* > do with a C++ binding in order to "accomodate" cancellation-safe C > code? ... Well, http://google.com/groups?threadm=3ecb86f7%40usenet01.boi.hp.com (Subject: Re: __attribute__((cleanup(function)) versus try/finally) >> > "William E. Kempf" wrote: >> The motivations are backwards here, though. If the C++ language >> adopts a threading library, POSIX systems will have a lot of >> motivation for defining a POSIX C++ binding, or at the very least, >> making a particular implementation's POSIX binding compatible with > the C++ threading. Right now, the C++ language has, by default and convention, a POSIX binding; 1003.1-2001. The C and C++ languages are sufficiently interoperable that this presents only a few restrictions on the use by C++ code, around exceptions and member functions. OK, so the thread start routine needs to be 'extern "C"' -- a minor inconvenience. OK, so there's no portable standard on interoperability between POSIX cleanup and C++ exceptions, and I'll resist suggesting that only an idiot would fail to make them completely compatible and interoperable; but at least most people can be educated to realize that they ought to be. The big hurdle for a true C++ binding is that the current state of affairs is "good enough" for most people, and the political process of developing a full native C++ binding would be painful. (Remember, it's not just saying that the thread::create method takes a class member at which the thread will start... it means reviewing every method and template in the STL to determine which have thread safety requirements, and deciding precisely what those requirements are and how to meet them. Then there's the matter of cancellation points... and so forth.) When and if the C++ standard adds true thread support, that will be, by default and in practice, the thread binding for C++; whether the underlying thread environment is POSIX, Win32, or something else. This is great, as long as it doesn't do or say anything stupid, but it still leaves a few loopholes because inevitably people will continue to write applications that mix languages. Mixing C and C++ has never been a problem; but if the thread model in C++ is radically different, it could become a problem. Furthermore, there's a missing piece that neither POSIX 1003.1-2001 plus ISO C++ 2005 (or whatever), or even 1003.1-2001 plus a hypothetical "1003.C++" will necessarily (or even likely) supply -- and that's how the two interoperate. If C++ or 1003.C++ says that thread::cancel raises an exception, and 1003.1 says that pthread_cancel() invokes cleanup handlers, does that mean that cancelling a thread with pthread_cancel() will trigger catch(...), or even destructors? Well, maybe not. This could more easily be solved with a 1003.C++, perhaps, since at least the two standards are in a family. Since the C++ standard is unlikely to mention POSIX any more than now, it's unlikely to provide any guarantees. Perhaps that would provide an opportunity for a smaller POSIX project, though; a PROFILE that would chink the holes where the two walls meet. In effect, specifying a "POSIX platform" supporting both threads and C++ that simply says "C++ cancellation is the same as POSIX cancellation", "POSIX cleanup handlers are logically and semantically the same as C++ object destructors", and "POSIX cancellation is visible as a C++ exception". regards, alexander. From baker at cs.fsu.edu Tue Dec 23 16:03:14 2003 From: baker at cs.fsu.edu (Ted Baker) Date: Tue, 23 Dec 2003 11:03:14 -0500 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <1072131497.7562.22.camel@doubledemon.codesourcery.com> References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> Message-ID: <20031223160314.GA9780@diablo.name> Am I missing something here? How do you propose to modify read() to throw an exception and still have backwards compatability with applications that expect read() to always return (more specifically, to return -1 if it fails)? It seems to me that the only way you could do this is to define a function with a new name, e.g., read_with_exception() in your binding. Otherwise, the linker will not be able to tell the difference between your exception-throwing read() and the normal C one. (OK, you might try playing macro games with renaming read() subject to a conditional compilation flag for C++ programs, but: (1) that is very error prone; (2) it would break existing C++ programs that are using calls to C-library functions like read(). --Ted On Mon, Dec 22, 2003 at 02:18:18PM -0800, Mark Mitchell wrote: > On Mon, 2003-12-22 at 13:57, Ted Baker wrote: > > > (c) it is OK to consider slightly broader modifications to the existing > > > C interfaces for C++ (such as modifying "read()" to throw an exception), > > > but it should still be possible to recompile C programs as C++ programs > > > and get reasonable behavior. > > > > I don't think you will be able to get buy-in from vendors or > > users of C if you require changes to the POSIX C libraries that > > would change the behavior of any existing C application that > > conforms to the current Open Group Unix or the IEEE POSIX > > standards. > > I agree -- but I did not say that. I said: > > it is OK to consider slightly broader modifications to the > existing C interfaces for C++ > > There's no inherent reason why a vendor would refuse to make a change to > the interfaces in some new mode -- so long as the > backwards-compatibility requirement you mention were preserved. > > -- > Mark Mitchell > CodeSourcery, LLC From mark at codesourcery.com Tue Dec 23 16:29:38 2003 From: mark at codesourcery.com (Mark Mitchell) Date: Tue, 23 Dec 2003 08:29:38 -0800 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <20031223160314.GA9780@diablo.name> References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> Message-ID: <1072196977.7974.34.camel@doubledemon.codesourcery.com> On Tue, 2003-12-23 at 08:03, Ted Baker wrote: > Am I missing something here? > > How do you propose to modify read() to throw an exception and > still have backwards compatability with applications that expect > read() to always return (more specifically, to return -1 if it > fails)? There are various ways of changing the behavior of a function based on an "application mode", including environment variables, calls at start-up time to profile-selection routines, linking with different versions of libraries, etc. All of these methods are used on various systems and while you can certainly pick nits about each one, they work well for most programs most of the time. But, all that is beside the point, in that it is implementation detail. The key question is what behavior we would like to see. The most constructive posting on this list so far has been Nathan's proposal here: http://www.codesourcery.com/archives/c++-pthreads/msg00021.html in that it is a concrete proposal that makes a certain set of tradeoffs. What I would like to see is not criticism of Nathan's proposal, not discussion of implementation issues, not discussion of thread support in ISO C++, but rather alternative proposals for making POSIX threads interoperate successfully with C++. Once there are several such proposals on the table, we might be able to discuss the various strengths and weaknesses between them. -- Mark Mitchell CodeSourcery, LLC From dave at boost-consulting.com Tue Dec 23 21:12:52 2003 From: dave at boost-consulting.com (David Abrahams) Date: Tue, 23 Dec 2003 16:12:52 -0500 Subject: C++ and posix threads References: Message-ID: "Alexander Terekhov" writes: > David Abrahams wrote: > [...] >> Fortunately, the question may be moot: is there really much we *can* >> do with a C++ binding in order to "accomodate" cancellation-safe C >> code? ... > > Well, > > http://google.com/groups?threadm=3ecb86f7%40usenet01.boi.hp.com > (Subject: Re: __attribute__((cleanup(function)) versus try/finally) > > > >>> > "William E. Kempf" wrote: >>> The motivations are backwards here, though. If the C++ language >>> adopts a threading library, POSIX systems will have a lot of >>> motivation for defining a POSIX C++ binding, or at the very least, >>> making a particular implementation's POSIX binding compatible with >> the C++ threading. > > Right now, the C++ language has, by default and convention, a POSIX > binding; 1003.1-2001. The C and C++ languages are sufficiently > interoperable that this presents only a few restrictions on the use > by C++ code, around exceptions and member functions. OK, so the ... blah, blah, blah. Is some part of the long quote which follows relevant to accomodating cancellation-safe 'C' code, or shall I resort to `S-l a p t' as is my wont? -- Dave Abrahams Boost Consulting www.boost-consulting.com From jason at redhat.com Wed Dec 24 01:03:57 2003 From: jason at redhat.com (Jason Merrill) Date: Tue, 23 Dec 2003 20:03:57 -0500 Subject: [c++-pthreads] The Ada example In-Reply-To: <20031219124502.GA6775@diablo.name> (Ted Baker's message of "Fri, 19 Dec 2003 07:45:02 -0500") References: <1071786842.21686.192.camel@doubledemon.codesourcery.com> <20031219124502.GA6775@diablo.name> Message-ID: On Fri, 19 Dec 2003 07:45:02 -0500, Ted Baker wrote: > First, you are stuck with the POSIX thread implmentations. > They do not provide any way of catching thread cancellation. > All they do is guarantee that somehow the cleanup routines > will be executed and then the thread will terminate. > > Furthermore, the POSIX/UNIX standards do not define the > semantics for continuation of a thread after cancellation. Right, but we can define those semantics. This discussion assumes control over the thread implementation. > Back when the POSIX threads standard was being balloted, one of > the things the Ada folks asked for was that is should be possible > to do a longjmp() from a cancellation cleanup routine, and that > longjmp() would execute the stack of cleanup handlers out to the > point of the corresponding setjmp(). The balloting group was > immovable on this. That's what we in the ia64 C++ ABI group called longjmp_unwind. I note that the POSIX spec explicitly leaves the semantics of longjmp out of a cancellation cleanup undefined, so an implementation is free to give it the semantics you suggest. But what would you expect the effect of such a longjmp to be on the cancellation request? And what happens if one of the cleanups run by this longjmp also calls longjmp? More generally, how does Ada deal with this situation? From looking over http://www.adaic.org/standards/95lrm/html/RM-9-8.html it seems that task abort runs finalizers for objects, but doesn't interact with exception handling. In C++, the only way to run object destructors is via exception handling, unless we want to define a whole new parallel concept, which I doubt. >>> * What happens if the exception is caught, and not rethrown? >> Nothing special. Pls see "example" in the message referenced below. > > This violates basic principles of abstraction and information > hiding. > > 1) The expected effect of cancellation is to terminate a thread. > Anything that does not result in termination of the thread breaks > the abstraction. Yes. > 2) If you allow local handling of cancellation, without > rethrowing, a hidden operation, many levels deep, may nullify the > intended effect of cancelation. This becomes a serious > maintenance problem, as some newbie programmer decides to protect > his favorite critical section against cancelation and forgets to > rethrow it. Suddenly, you have an intermittent bug that will be > *very* hard to track down. How often will a thread be cancelled, > and how often will it be cancelled at that point? Imagine trying > to reproduce this kind of failure. It's worse than that--the programmer just has to decide that his code shouldn't throw any exceptions, and wrap it with a catch-all handler. This happens in some of the C++ I/O code, which if left unchanged would mean that a thread which does a lot of I/O may cancel when you ask it to, or it may decide to discard the request. And a long sequence of I/O seems to me like something that we might often want to cancel. There's no way for the thread which sends the cancellation request to determine that the cancellation has beens swallowed, and it needs to send another. I suppose this is the sort of thing that leads to users madly clicking on cancel buttons until the program finally responds. Jason From ncm at cantrip.org Wed Dec 24 04:46:22 2003 From: ncm at cantrip.org (Nathan Myers) Date: Tue, 23 Dec 2003 20:46:22 -0800 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <20031223160314.GA9780@diablo.name> References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> Message-ID: <20031224044622.GG27836@tofu.dreamhost.com> On Tue, Dec 23, 2003 at 11:03:14AM -0500, Ted Baker wrote: > > How do you propose to modify read() to throw an exception and > still have backwards compatability with applications that expect > read() to always return (more specifically, to return -1 if it > fails)? This is the second time you have asked this. I haven't noticed anybody on this list suggesting read() should throw an exception. The only detailed proposal thus far has read() returning -1 in the event of cancellation. It might be tricky getting a read() call that is already waiting on input to return immediately. That might seem to require cooperation from the kernel, but clever use of a signal might suffice. As Mark notes, implementation details are for implementers. Our task here is to decide what to implement. If what we decide we want turns out to be too hard to implement, we will have to adjust our expectations. Nathan Myers ncm at cantrip.org From ncm at cantrip.org Wed Dec 24 06:07:33 2003 From: ncm at cantrip.org (Nathan Myers) Date: Tue, 23 Dec 2003 22:07:33 -0800 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: References: <20031221004138.GC27836@tofu.dreamhost.com> Message-ID: <20031224060733.GH27836@tofu.dreamhost.com> I apologize for the delay in replying to this. It took a while to see what you are getting at. On Mon, Dec 22, 2003 at 08:13:20AM +0100, Alexander Terekhov wrote: > > int peekc(FILE * f) { > return ungetc(getc_unlocked(f), f); /* "The ungetc() */ > /* function is infrequently called relative to the other */ > /* functions/macros so no unlocked variation is needed." */ > /* */ > /* How fascinating. Well, __fsetlocking() is my friend. */ > } > > Both getc_unlocked() and ungetc() are cancelation points. This > function offers basic exception safety and basic thread safety > (and it is thread-cancel-safe, of course). Do you really want > me to change it to something like > > int peekc(FILE * f) { > int c = ungetc(getc_unlocked(f), f); > if (c == EOF && !feof(f) && errno == ECANCELED) { > /*... ?re-inject cancel request? ... */ > /*... ?re-enable cancel state? ... */ > pthread_testcancel(); /* hurrah! */ > } > return c; > } I don't understand where you get that. I thought I had made clear that I didn't expect any ordinary (correct!) C library code to need changes. Since getc_unlocked(f) may always return EOF, so you had better be prepared for it. I.e. your original function is of questionable correctness. However, it would correctly return EOF in the event of a cancellation (under my proposed model), so that's OK. (The read position would be left indeterminate, but that's how you wrote it.) > What if someone[1] has it written as > > int peekc(FILE * f) { > int c = getc(f); > if (c != EOF) > ungetc(c, f); > return c; > } > > and cancelation hits at "unchecked" ungetc(), in your model? > > [1] google.com/groups?selm=slrn8cvkde.mf3.kaz at ashi.FootPrints.net Buggy code is buggy. That code looks better than your original version, though. This int peekc(FILE * f) { int c = getc(f); return (c == EOF) ? EOF : ungetc(c, f); } would be more strictly correct. However, the version in [1] would not introduce any corruption. Any subsequent attempt to read the (not-really) put-back character would (also) fail, and control would, eventually, bubble out to a top-level context. Nathan Myers ncm at cantrip.org From boo at terekhov.de Wed Dec 24 10:56:44 2003 From: boo at terekhov.de (Alexander Terekhov) Date: Wed, 24 Dec 2003 11:56:44 +0100 Subject: [c++-pthreads] C++ and posix threads References: <1072259709.2322.ezmlm@codesourcery.com> Message-ID: <3FE970EC.6FAF08BA@terekhov.de> Nathan Myers wrote: [...] > This is the second time you have asked this. I haven't noticed > anybody on this list suggesting read() should throw an exception. read(), fread(), printf() and etc. all should throw an exception. http://www.opengroup.org/onlinepubs/007904975/functions/xsh_chap02_09.html#tag_02_09_05_02 "The side effects of acting upon a cancellation request while suspended during a call of a function are the same as the side effects that may be seen in a single-threaded program when a call to a function is interrupted by a signal and the given function returns [EINTR]. Any such side effects occur before any cancellation cleanup handlers are called. Whenever a thread has cancelability enabled and a cancellation request has been made with that thread as the target, and the thread then calls any function that is a cancellation point (such as pthread_testcancel() or read()), the cancellation request shall be acted upon before the function returns. If a thread has cancelability enabled and a cancellation request is made with the thread as a target while the thread is suspended at a cancellation point, the thread shall be awakened and the cancellation request shall be acted upon. However, if the thread is suspended at a cancellation point and the event for which it is waiting occurs before the cancellation request is acted upon, it is unspecified whether the cancellation request is acted upon or whether the cancellation request remains pending and the thread resumes normal execution." http://google.com/groups?selm=hUFm8.1374%24fL6.26921%40news.cpqcorp.net "The second list is of OPTIONAL cancellation points. The distinction is, roughly, between what are conventionally syscalls into the kernel (required) vs what are conventionally user-space C runtime functions that MIGHT use those syscalls. The intent was that library calls which might use the syscalls be allowed to check for cancellation only when they actually make the kernel calls; e.g., when printf() flushes its buffer by calling write(). In practice, the optional list is more often used as an excuse to avoid recoding the library to deal with cancellation, instead disabling it around the syscall. This is all quite convenient for implementations, of course, but bad for applications. All applications that use any of these functions must be prepared to react correctly should cancellation occur at any such call... but at the same time may not portably DEPEND on cancellation occurring. [...] Nevertheless, the standard should specify mechanism, not policy. To say "thou shalt not catch cancel because I don't think you should" is mandating the committee's collective consensus of "proper behavior", and that's at best inappropriate. There are always "exceptions". If some standard application really does need to catch and finalize "all exceptions", there's absolutely no justification for making cancel or thread exit any different from all the others. They SHOULD be in the std::exception hierarchy, though perhaps in a separate "thread" subclass hierarchy." regards, alexander. From boo at terekhov.de Wed Dec 24 10:57:35 2003 From: boo at terekhov.de (Alexander Terekhov) Date: Wed, 24 Dec 2003 11:57:35 +0100 Subject: [c++-pthreads] cancellation points report failure References: <1072260334.3100.ezmlm@codesourcery.com> Message-ID: <3FE9711F.748925A7@terekhov.de> Nathan Myers wrote: [...] > > int peekc(FILE * f) { > > int c = ungetc(getc_unlocked(f), f); /* > > if (c == EOF && !feof(f) && errno == ECANCELED) { > > /*... ?re-inject cancel request? ... */ > > /*... ?re-enable cancel state? ... */ > > pthread_testcancel(); /* hurrah! */ > > } */ if (c == EOF && !feof(f) && errno == ECANCELED) pthread_exit(PTHREAD_CANCELED); > > return c; > > } > > I don't understand where you get that. I thought I had made clear > that I didn't expect any ordinary (correct!) C library code to need > changes. Since getc_unlocked(f) may always return EOF, so you had > better be prepared for it. I.e. your original function is of > questionable correctness. Huh? http://www.opengroup.org/onlinepubs/007904975/functions/ungetc.html "If the value of c equals that of the macro EOF, the operation shall fail and the input stream shall be left unchanged. [...] Upon successful completion, ungetc() shall return the byte pushed back after conversion. Otherwise, it shall return EOF." > > > What if someone[1] has it written as > > > > int peekc(FILE * f) { > > int c = getc(f); > > if (c != EOF) > > ungetc(c, f); > > return c; > > } > > > > and cancelation hits at "unchecked" ungetc(), in your model? > > > > [1] google.com/groups?selm=slrn8cvkde.mf3.kaz at ashi.FootPrints.net > > Buggy code is buggy. Except that it isn't buggy under the POSIX model where ungetc() does throw thread cancel exception. regards, alexander. From jason at redhat.com Wed Dec 24 12:51:37 2003 From: jason at redhat.com (Jason Merrill) Date: Wed, 24 Dec 2003 07:51:37 -0500 Subject: [c++-pthreads] cancellation points report failure In-Reply-To: <1071946483.25325.69.camel@doubledemon.codesourcery.com> (Mark Mitchell's message of "Sat, 20 Dec 2003 10:54:44 -0800") References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> <20031219205746.GA12322@diablo.name> <20031219225650.GA13735@diablo.name> <20031220045618.GA27836@tofu.dreamhost.com> <1071946483.25325.69.camel@doubledemon.codesourcery.com> Message-ID: On Sat, 20 Dec 2003 10:54:44 -0800, Mark Mitchell wrote: >> Since it apparently isn't yet clear to everybody what I had suggested, >> I'll outline it again: > > I think it's a great to see a tidy description of your idea. It's good > to get concrete proposals on the table. > > Jason (Merill), would you care to post a similar description of your > preferred scenario? The scenario I've been thinking of is: * The POSIX cancellation points can throw a cancellation exception. * C++ I/O functions can throw a cancellation exception. * C++ catch blocks work normally. * If a cancellation exception is destroyed, the cancellation request is re-entered, and acted on again at the next cancellation point. This model doesn't work as well for pthread_exit or longjmp_unwind, since they don't have predefined deferral semantics. I'm somewhat inclined to stay with calling terminate if we swallow an exit exception. I just did some testing on Tru64: Evidently in their structured exception handling model, finalizing a cancellation exception discards the cancellation request, as Mark was suggesting; ditto for pthread_exit. And, interestingly, abort(). Testcase attached below. The main problem with extending these semantics to C++ is the iostream code which traps all exceptions. I think this is a mistake in the design of iostreams, but it seems likely to be a common mistake, and I feel strongly that it shouldn't silently discard the cancellation request. That would almost certainly be an unintended side-effect. Jason -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: text/x-c Size: 712 bytes Desc: not available URL: From jason at redhat.com Wed Dec 24 13:09:57 2003 From: jason at redhat.com (Jason Merrill) Date: Wed, 24 Dec 2003 08:09:57 -0500 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <20031223160314.GA9780@diablo.name> (Ted Baker's message of "Tue, 23 Dec 2003 11:03:14 -0500") References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> Message-ID: On Tue, 23 Dec 2003 11:03:14 -0500, Ted Baker wrote: > How do you propose to modify read() to throw an exception and > still have backwards compatability with applications that expect > read() to always return (more specifically, to return -1 if it > fails)? read() already doesn't return if it's acting on a cancellation request. Throwing an exception is just a different way of not returning. Jason From ncm at cantrip.org Wed Dec 24 15:22:38 2003 From: ncm at cantrip.org (Nathan Myers) Date: Wed, 24 Dec 2003 07:22:38 -0800 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> Message-ID: <20031224152238.GD2774@tofu.dreamhost.com> On Wed, Dec 24, 2003 at 08:09:57AM -0500, Jason Merrill wrote: > On Tue, 23 Dec 2003 11:03:14 -0500, Ted Baker wrote: > > > How do you propose to modify read() to throw an exception and > > still have backwards compatability with applications that expect > > read() to always return (more specifically, to return -1 if it > > fails)? > > read() already doesn't return if it's acting on a cancellation request. > Throwing an exception is just a different way of not returning. Jason, whether read() is to return is one of the points at issue. Nathan Myers ncm at cantrip.org From ncm at cantrip.org Wed Dec 24 17:05:17 2003 From: ncm at cantrip.org (Nathan Myers) Date: Wed, 24 Dec 2003 09:05:17 -0800 Subject: concrete library-code example (was: C++ and posix threads) In-Reply-To: References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> Message-ID: <20031224170517.GG30780@tofu.dreamhost.com> On Wed, Dec 24, 2003 at 08:09:57AM -0500, Jason Merrill wrote: > On Tue, 23 Dec 2003 11:03:14 -0500, Ted Baker wrote: > > > How do you propose to modify read() to throw an exception and > > still have backwards compatability with applications that expect > > read() to always return (more specifically, to return -1 if it > > fails)? > > read() already doesn't return if it's acting on a cancellation request. > Throwing an exception is just a different way of not returning. Enlarging on this question... Here is a more-or-less concrete example, for discussion purposes. It's meant as a generic example of code written according to the existing contract offered by C libraries. int affect_world(struct state* s) { int result; violate_invariants_or_claim_resources(s); result = c_function_or_system_call(s->member); if (result < 0) { clean_up(s, result); return result; } act_on_result(s, result); restore_invariants_and_release_resources(s); return 0; } This pattern is extremely common in both C and C++ libraries. If read() were to throw (or to "just ... not return"), the program state would be corrupted. A redefinition of c_function_or_system_call semantics that breaks this code breaks many thousands of existing thread-safe C and C++ libraries. (The cancellation model described in http://www.codesourcery.com/archives/c++-pthreads/msg00021.html is designed to preserve libraries that contain code that follows this pattern.) Jason, do you not consider those libraries worth preserving? Nathan Myers ncm at cantrip.org From dave at boost-consulting.com Wed Dec 24 17:38:46 2003 From: dave at boost-consulting.com (David Abrahams) Date: Wed, 24 Dec 2003 12:38:46 -0500 Subject: cancellation points report failure References: <2A8DB02E3018D411901B009027FD3A3F01CAAF6A@mchp905a.mch.sbs.de> <2E98D8A4-3251-11D8-B7E5-00039390D9E0@apple.com> <20031219194503.GA31795@tofu.dreamhost.com> <20031219205746.GA12322@diablo.name> <20031219225650.GA13735@diablo.name> <20031220045618.GA27836@tofu.dreamhost.com> <1071946483.25325.69.camel@doubledemon.codesourcery.com> Message-ID: Jason Merrill writes: > On Sat, 20 Dec 2003 10:54:44 -0800, Mark Mitchell wrote: > >>> Since it apparently isn't yet clear to everybody what I had suggested, >>> I'll outline it again: >> >> I think it's a great to see a tidy description of your idea. It's good >> to get concrete proposals on the table. >> >> Jason (Merill), would you care to post a similar description of your >> preferred scenario? > > The scenario I've been thinking of is: > > * The POSIX cancellation points can throw a cancellation exception. I'm unhappy with this one for the same reasons as Nathan has outlined... but there's more to your proposal. > * C++ I/O functions can throw a cancellation exception. > * C++ catch blocks work normally. > * If a cancellation exception is destroyed, the cancellation request > is re-entered, and acted on again at the next cancellation point. I appreciate that your motivation is to ensure that synchronous cancellation requests aren't ignored, but that doesn't really seem to accomplish the goal. After all, a thread never has to reach a cancellation point, and even if it does, it can keep catching and discarding the exceptions indefinitely. It seems to me that it should be up to the cancelling thread to decide whether it wants to take drastic measures to ensure that cancellation happens. The only effective way I can think of to do that is to do allow synchronous cancellation requests with a timeout that forces thread termination if it fails to respond... but I'm sure there are other approaches. -- Dave Abrahams Boost Consulting www.boost-consulting.com From rth at redhat.com Thu Dec 25 00:11:17 2003 From: rth at redhat.com (Richard Henderson) Date: Wed, 24 Dec 2003 16:11:17 -0800 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <20031224044622.GG27836@tofu.dreamhost.com> References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224044622.GG27836@tofu.dreamhost.com> Message-ID: <20031225001117.GA13447@redhat.com> On Tue, Dec 23, 2003 at 08:46:22PM -0800, Nathan Myers wrote: > The only detailed proposal thus far has read() returning -1 in the > event of cancellation. And the proposal is a complete non-starter, because the POSIX C binding ALREADY says that synchronous thread cancelation runs the handlers set up by pthread_cleanup_push, and then terminates the thread. You'll get zero uptake from library implementors or POSIX if you try to change that semantic. r~ From rth at redhat.com Thu Dec 25 00:21:40 2003 From: rth at redhat.com (Richard Henderson) Date: Wed, 24 Dec 2003 16:21:40 -0800 Subject: [c++-pthreads] The Ada example In-Reply-To: References: <1071786842.21686.192.camel@doubledemon.codesourcery.com> <20031219124502.GA6775@diablo.name> Message-ID: <20031225002140.GB13447@redhat.com> On Tue, Dec 23, 2003 at 08:03:57PM -0500, Jason Merrill wrote: > More generally, how does Ada deal with this situation? From looking over > > http://www.adaic.org/standards/95lrm/html/RM-9-8.html > > it seems that task abort runs finalizers for objects, but doesn't interact > with exception handling. In C++, the only way to run object destructors is > via exception handling, unless we want to define a whole new parallel > concept, which I doubt. Well, yes and no. You'd do this the way I originally proposed -- non-exceptions such as longjmp_unwind and thread cancelation would run cleanups, but not catch-all. We can tell the difference in the encoding of the regions in the lsda. r~ From jason at redhat.com Thu Dec 25 04:55:59 2003 From: jason at redhat.com (Jason Merrill) Date: Wed, 24 Dec 2003 23:55:59 -0500 Subject: [c++-pthreads] concrete library-code example In-Reply-To: <20031224170517.GG30780@tofu.dreamhost.com> (Nathan Myers's message of "Wed, 24 Dec 2003 09:05:17 -0800") References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224170517.GG30780@tofu.dreamhost.com> Message-ID: On Wed, 24 Dec 2003 09:05:17 -0800, Nathan Myers wrote: > On Wed, Dec 24, 2003 at 08:09:57AM -0500, Jason Merrill wrote: >> On Tue, 23 Dec 2003 11:03:14 -0500, Ted Baker wrote: >> >> > How do you propose to modify read() to throw an exception and >> > still have backwards compatability with applications that expect >> > read() to always return (more specifically, to return -1 if it >> > fails)? >> >> read() already doesn't return if it's acting on a cancellation request. >> Throwing an exception is just a different way of not returning. > > Enlarging on this question... > > Here is a more-or-less concrete example, for discussion purposes. > It's meant as a generic example of code written according to the > existing contract offered by C libraries. > > int affect_world(struct state* s) > { > int result; > violate_invariants_or_claim_resources(s); > result = c_function_or_system_call(s->member); > if (result < 0) { > clean_up(s, result); > return result; > } > act_on_result(s, result); > restore_invariants_and_release_resources(s); > return 0; > } > > This pattern is extremely common in both C and C++ libraries. If > read() were to throw (or to "just ... not return"), the program state > would be corrupted. A redefinition of c_function_or_system_call > semantics that breaks this code breaks many thousands of existing > thread-safe C and C++ libraries. This is not cancellation-safe C under the current POSIX standard, if c_function_or_system_call is a cancellation point. If it is, cleanups are run and the thread is terminated. To be truly thread-safe, the user must use pthread_cleanup_push/pop so that the resources are released on cancellation. Implementing cancellation by throwing an exception has no effect on the thread-safety of this code. > Jason, do you not consider those libraries worth preserving? No, they're already broken. Jason From ncm at cantrip.org Thu Dec 25 06:42:19 2003 From: ncm at cantrip.org (Nathan Myers) Date: Wed, 24 Dec 2003 22:42:19 -0800 Subject: [c++-pthreads] concrete library-code example In-Reply-To: References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224170517.GG30780@tofu.dreamhost.com> Message-ID: <20031225064219.GF2774@tofu.dreamhost.com> On Wed, Dec 24, 2003 at 11:55:59PM -0500, Jason Merrill wrote: > > > > int affect_world(struct state* s) > > { > > int result; > > violate_invariants_or_claim_resources(s); > > result = c_function_or_system_call(s->member); > > if (result < 0) { > > clean_up(s, result); > > return result; > > } > > act_on_result(s, result); > > restore_invariants_and_release_resources(s); > > return 0; > > } > > > > This pattern is extremely common in both C and C++ libraries. > > If read() were to throw (or to "just ... not return"), the > > program state would be corrupted. A redefinition of > > c_function_or_system_call semantics that breaks this code breaks > > many thousands of existing thread-safe C and C++ libraries. > > This is not cancellation-safe C under the current POSIX standard, if > c_function_or_system_call is a cancellation point. If it is, cleanups > are run and the thread is terminated. To be truly thread-safe, the > user must use pthread_cleanup_push/pop so that the resources are > released on cancellation. I think that is what I said. It was thread-safe code until the semantics of calls it uses changed without changing the names. What was good code is now broken, in a POSIX C thread-cancellation environment. > Implementing cancellation by throwing an exception has no effect on > the thread-safety of this code. In other words, because (under the C binding) this code has already been broken, throwing exceptions through it won't break it any further. However, we're not talking about the C binding here. This list is for discussion of a C++ binding, which need not be so procrustean as the C binding. > > Jason, do you not consider those libraries worth preserving? > > No, they're already broken. You answered the question with reference to the C binding. Defining a C++ binding is the purpose of this list. With an appropriately-defined C++ binding, those libraries need not be broken *when linked as part of a C++ program*. In other words, you, as a C++ implementer, have the power to choose whether to preserve or to break those C and C++ libraries, regardless of what has been decided for the C binding. (C++ coders would certainly choose to preserve them, but it seems that no C++ coders are in a position to do more than try to persuade you.) So, I ask the question again, but in reference to the C++ binding that we are working on here. What would breaking all those thousands of existing libraries buy us? Nathan Myers ncm at cantrip.org From baker at cs.fsu.edu Thu Dec 25 14:59:12 2003 From: baker at cs.fsu.edu (Ted Baker) Date: Thu, 25 Dec 2003 09:59:12 -0500 Subject: [c++-pthreads] C++ and posix threads In-Reply-To: <20031223160314.GA9780@diablo.name> References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> Message-ID: <20031225145912.GA10080@diablo.name> Please forgive my last posting, which was done in haste. I just read it, and realized it is nonsense, so I'll answer my own question. In the event of thread cancellation the POSIX read() function does *not* return, but instead enters a control path that causes it to execute the stack of cancellation cleanup handlers, and then exit the thread. The only way you could have incompatibility would be if the cleanup handlers were not executed, or the thread did not exit. As others have pointed out here, there are few existing C applications or libraries that make correct use of thread cancellation and cleanup handlers, and fewer (none?) C++ ones that rely on this. On Tue, Dec 23, 2003 at 11:03:14AM -0500, Ted Baker wrote: > Am I missing something here? > > How do you propose to modify read() to throw an exception and > still have backwards compatability with applications that expect > read() to always return (more specifically, to return -1 if it > fails)? > > It seems to me that the only way you could do this is to > define a function with a new name, e.g., read_with_exception() > in your binding. Otherwise, the linker will not be able to > tell the difference between your exception-throwing read() > and the normal C one. (OK, you might try playing macro games > with renaming read() subject to a conditional compilation flag > for C++ programs, but: (1) that is very error prone; (2) > it would break existing C++ programs that are using calls > to C-library functions like read(). > > --Ted From baker at cs.fsu.edu Thu Dec 25 15:34:37 2003 From: baker at cs.fsu.edu (Ted Baker) Date: Thu, 25 Dec 2003 10:34:37 -0500 Subject: [c++-pthreads] The Ada example In-Reply-To: References: <1071786842.21686.192.camel@doubledemon.codesourcery.com> <20031219124502.GA6775@diablo.name> Message-ID: <20031225153437.GA10124@diablo.name> > But what would you expect the effect of such a longjmp to be on the > cancellation request? I would expect cancellation to be implemented as a longjmp() to a setjmp() in the standard thread wrapper provided by pthread_create(). If the user does a longjmp() while a synchronous cancellation request is pending, I would expect the user longjmp() to act as a cancellation point, and simply initiate the processing of the pending cancellation (rather than going to the user's intended setjmp() target). > And what happens if one of the cleanups run by this > longjmp also calls longjmp? If done by a user, that would be an ill-behaved cleanup handler, comparable to a cleanup handler that does some other erroneous thing (e.g., try to derefence a junk pointer) tha can cause chaotic behavior (e.g., random changes to code and data, SIGSEGV, SIGBUS). If done by a compiler abd/or language-support runtime system, written by disciplined programmers, chaining longjmps might be the way longjmp with cleanup is actually implemented. This would only be done with full knowledge of, and reliance on, the internals of the particular setjmp() and longjmp() implementation. > More generally, how does Ada deal with this situation? From looking over > > http://www.adaic.org/standards/95lrm/html/RM-9-8.html > > it seems that task abort runs finalizers for objects, but doesn't interact > with exception handling. In C++, the only way to run object destructors is > via exception handling, unless we want to define a whole new parallel > concept, which I doubt. You are right. The Ada language defines task abort processing as distinct from exception processing. There is no way in the language to handle a task abort. The finalizers are run, as the stack of the task is unwound, and then the task terminates. What can be done inside a finalizer is limited, in an effort to make sure the task terminates in a bounded time, but one cannot eliminate all possibilities (e.g., a finalizer with an infinite loop). The theory is that if you find a need to "handle" task abort you do this by entering a frame with a finalizer, and let the finalizer do the handling. That is, the theory is that there should not be any abort-specific processing that needs to be done. It should all be "cleanup" that should be done on exit from the frame, regardless of the cause. It works pretty well. On the other hand, the GNAT (gcc) *implementation* of task abort is to treat it as an exception. This is a "special exception", for which the compiler can generate handlers (and does so, to implement the execution of finalizers) but the compiler does not allow user code to contain such a handler or raise this exception other than by task abort. We did put in a compiler flag that allows the Ada runtime system code to contain handlers for this exception, and to raise it, in order to implement task abort and the associated language features. We use this in a very disciplined way, always eventually re-raising the abort exception, so that abort is not "swallowed". There is another GNAT-specific extension that we found handy. That is the "at end" handler. That is a syntactic block of code that is *always* executed on exit from the corresponding frame (both normal exit and exceptional exit, including task abort). That is the building block on which finalizers are implemented. Since we needed it any to implement finalization, we found it nice to have around for situations where we had some cleanup to do but did not want to pay the runtime overhead of creating and destroying a local controlled object just for the finalization effect. From jason at redhat.com Thu Dec 25 18:23:13 2003 From: jason at redhat.com (Jason Merrill) Date: Thu, 25 Dec 2003 13:23:13 -0500 Subject: [c++-pthreads] concrete library-code example In-Reply-To: <20031225064219.GF2774@tofu.dreamhost.com> (Nathan Myers's message of "Wed, 24 Dec 2003 22:42:19 -0800") References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224170517.GG30780@tofu.dreamhost.com> <20031225064219.GF2774@tofu.dreamhost.com> Message-ID: On Wed, 24 Dec 2003 22:42:19 -0800, Nathan Myers wrote: > On Wed, Dec 24, 2003 at 11:55:59PM -0500, Jason Merrill wrote: >> This is not cancellation-safe C under the current POSIX standard, if >> c_function_or_system_call is a cancellation point. If it is, cleanups >> are run and the thread is terminated. To be truly thread-safe, the >> user must use pthread_cleanup_push/pop so that the resources are >> released on cancellation. > > I think that is what I said. It was thread-safe code until the > semantics of calls it uses changed without changing the names. > What was good code is now broken, in a POSIX C thread-cancellation > environment. In what sense was it ever thread-safe? It was fine for non-threaded code, but has always been broken in a POSIX threads environment. >> Implementing cancellation by throwing an exception has no effect on >> the thread-safety of this code. > > In other words, because (under the C binding) this code has already > been broken, throwing exceptions through it won't break it any further. Yes. > However, we're not talking about the C binding here. This list is for > discussion of a C++ binding, which need not be so procrustean as the > C binding. Currently, the C++ binding is the C binding, so your example is broken under C++ as well. And it would seem rather odd for the C++ binding to go to great lengths to accommodate code which is broken under C, when C++ already provides a simple way to express cleanups. C++ code doesn't need to mess with pthread_cleanup_push; it can just use destructors. >> > Jason, do you not consider those libraries worth preserving? >> >> No, they're already broken. > > You answered the question with reference to the C binding. > > Defining a C++ binding is the purpose of this list. With an > appropriately-defined C++ binding, those libraries need not be broken > *when linked as part of a C++ program*. In other words, you, as a C++ > implementer, have the power to choose whether to preserve or to break > those C and C++ libraries, regardless of what has been decided for > the C binding. On the contrary, these libraries are broken. You are proposing to un-break them. Jason From jason at redhat.com Thu Dec 25 18:31:46 2003 From: jason at redhat.com (Jason Merrill) Date: Thu, 25 Dec 2003 13:31:46 -0500 Subject: [c++-pthreads] The Ada example In-Reply-To: <20031225153437.GA10124@diablo.name> (Ted Baker's message of "Thu, 25 Dec 2003 10:34:37 -0500") References: <1071786842.21686.192.camel@doubledemon.codesourcery.com> <20031219124502.GA6775@diablo.name> <20031225153437.GA10124@diablo.name> Message-ID: On Thu, 25 Dec 2003 10:34:37 -0500, Ted Baker wrote: >> More generally, how does Ada deal with this situation? From looking over >> >> http://www.adaic.org/standards/95lrm/html/RM-9-8.html >> >> it seems that task abort runs finalizers for objects, but doesn't interact >> with exception handling. In C++, the only way to run object destructors is >> via exception handling, unless we want to define a whole new parallel >> concept, which I doubt. > > You are right. The Ada language defines task abort processing as > distinct from exception processing. There is no way in the > language to handle a task abort. The finalizers are run, as the > stack of the task is unwound, and then the task terminates. What > can be done inside a finalizer is limited, in an effort to make > sure the task terminates in a bounded time, but one cannot > eliminate all possibilities (e.g., a finalizer with an infinite > loop). This sounds like the pthread_cleanup_push/pop model in C, or just running C++ destructors. > On the other hand, the GNAT (gcc) *implementation* of task abort > is to treat it as an exception. This is a "special exception", > for which the compiler can generate handlers (and does so, to > implement the execution of finalizers) but the compiler does not > allow user code to contain such a handler or raise this exception > other than by task abort. So similar to a C++ scheme in which catch(...) doesn't catch the cancellation exception. > There is another GNAT-specific extension that we found handy. > That is the "at end" handler. This sounds like try/finally. Thanks for the reference point. Jason From dave at boost-consulting.com Thu Dec 25 19:35:31 2003 From: dave at boost-consulting.com (David Abrahams) Date: Thu, 25 Dec 2003 14:35:31 -0500 Subject: C++ and posix threads References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224044622.GG27836@tofu.dreamhost.com> <20031225001117.GA13447@redhat.com> Message-ID: Richard Henderson writes: > On Tue, Dec 23, 2003 at 08:46:22PM -0800, Nathan Myers wrote: >> The only detailed proposal thus far has read() returning -1 in the >> event of cancellation. > > And the proposal is a complete non-starter, because the POSIX C > binding ALREADY says that synchronous thread cancelation runs the > handlers set up by pthread_cleanup_push, and then terminates the > thread. > > You'll get zero uptake from library implementors or POSIX if you > try to change that semantic. I'm not sure I understand what you're saying. The POSIX C binding standard is in direct conflict with the ISO C++ standard, so _some_ standard will be violated. Are you suggesting that anything that violates the POSIX standard is automatically a non-starter, or is it more subtle than that? If that's what you're saying, why is it better to violate the POSIX standard than the ISO C++ standard? -- Dave Abrahams Boost Consulting www.boost-consulting.com From dave at boost-consulting.com Thu Dec 25 19:52:16 2003 From: dave at boost-consulting.com (David Abrahams) Date: Thu, 25 Dec 2003 14:52:16 -0500 Subject: concrete library-code example References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224170517.GG30780@tofu.dreamhost.com> <20031225064219.GF2774@tofu.dreamhost.com> Message-ID: Jason Merrill writes: > On Wed, 24 Dec 2003 22:42:19 -0800, Nathan Myers wrote: > >> On Wed, Dec 24, 2003 at 11:55:59PM -0500, Jason Merrill wrote: > >>> This is not cancellation-safe C under the current POSIX standard, if >>> c_function_or_system_call is a cancellation point. If it is, cleanups >>> are run and the thread is terminated. To be truly thread-safe, the >>> user must use pthread_cleanup_push/pop so that the resources are >>> released on cancellation. >> >> I think that is what I said. It was thread-safe code until the >> semantics of calls it uses changed without changing the names. >> What was good code is now broken, in a POSIX C thread-cancellation >> environment. > > In what sense was it ever thread-safe? It was fine for non-threaded code, > but has always been broken in a POSIX threads environment. Are any threading environments other than POSIX worthy of consideration here? If not, anything that's not thread-safe under POSIX is, as you say, not thread-safe period. Otherwise, POSIX is breaking thread-safe code by introducing the possibility of control flow (unwinding) that can't be anticipated without knowledge of POSIX itself. The real-world problems that breakage introduces for plain C are somewhat minimized by the fact that C code has to know something about how to register cleanups in order to get any unanticipated control flow other than termination. Still, unanticipated termination can leak important system resources and cause other difficult-to-diagnose problems. For C++, it's a much more serious problem because the binding wants to run destructors, and you don't need special knowledge of POSIX in order to write a destructor. >>> Implementing cancellation by throwing an exception has no effect on >>> the thread-safety of this code. Obviously that depends on how you define "thread safe". Don't you think defining it in terms of the POSIX standard is, in this case at least, a bit circular? It's a great way to close off certain parts of the discussion, but it doesn't seem to provide us with any power to think about the problems. > Currently, the C++ binding is the C binding, so your example is broken > under C++ as well. And it would seem rather odd for the C++ binding to go > to great lengths to accommodate code which is broken under C, when C++ > already provides a simple way to express cleanups. C++ code doesn't need > to mess with pthread_cleanup_push; it can just use destructors. You say that like it's a *good* thing ;-) I'm being slightly facetious here, but having destructors run automatically under thread-cancellation is a double-edged sword if the code's author was unable to anticipate the possibility of an exception. -- Dave Abrahams Boost Consulting www.boost-consulting.com From boo at terekhov.de Sat Dec 27 18:40:09 2003 From: boo at terekhov.de (Alexander Terekhov) Date: Sat, 27 Dec 2003 19:40:09 +0100 Subject: [c++-pthreads] Re: concrete library-code example References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224170517.GG30780@tofu.dreamhost.com> <20031225064219.GF2774@tofu.dreamhost.com> Message-ID: <3FEDD209.9AF9BAEF@terekhov.de> David Abrahams wrote: [...] > Are any threading environments other than POSIX worthy of > consideration here? Well, let's have some fun. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemThreadingThreadClassAbortTopic1.asp regards, alexander. P.S. And System.StackOverflow is even more fun, oder? ;-) From boo at terekhov.de Sat Dec 27 19:26:07 2003 From: boo at terekhov.de (Alexander Terekhov) Date: Sat, 27 Dec 2003 20:26:07 +0100 Subject: [c++-pthreads] C++ and posix threads References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031225145912.GA10080@diablo.name> Message-ID: <3FEDDCCF.1AA78C7C@terekhov.de> Ted Baker wrote: [...] > As others have pointed > out here, there are few existing C applications or libraries > that make correct use of thread cancellation and cleanup handlers, > and fewer (none?) C++ ones that rely on this. http://google.com/groups?threadm=vYOa9.21%24Wx6.741391%40news.cpqcorp.net (Subject: Re: pthread : nifty source code package) regards, alexander. From rth at redhat.com Sat Dec 27 23:24:44 2003 From: rth at redhat.com (Richard Henderson) Date: Sat, 27 Dec 2003 15:24:44 -0800 Subject: [c++-pthreads] Re: C++ and posix threads In-Reply-To: References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224044622.GG27836@tofu.dreamhost.com> <20031225001117.GA13447@redhat.com> Message-ID: <20031227232444.GA14692@redhat.com> On Thu, Dec 25, 2003 at 02:35:31PM -0500, David Abrahams wrote: > I'm not sure I understand what you're saying. The POSIX C binding > standard is in direct conflict with the ISO C++ standard, so _some_ > standard will be violated. [...] If that's what you're saying, why > is it better to violate the POSIX standard than the ISO C++ standard? I think there are degrees here. The conflict with ISO C++ is that it says that ISO C functions can't throw. Reverting that clause seems to me to be a minor change. The proposed change to POSIX such that it does not use abnormal return semantics is a *major* change. r~ From dave at boost-consulting.com Sun Dec 28 01:46:46 2003 From: dave at boost-consulting.com (David Abrahams) Date: Sat, 27 Dec 2003 20:46:46 -0500 Subject: C++ and posix threads References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224044622.GG27836@tofu.dreamhost.com> <20031225001117.GA13447@redhat.com> <20031227232444.GA14692@redhat.com> Message-ID: Richard Henderson writes: > On Thu, Dec 25, 2003 at 02:35:31PM -0500, David Abrahams wrote: >> I'm not sure I understand what you're saying. The POSIX C binding >> standard is in direct conflict with the ISO C++ standard, so _some_ >> standard will be violated. [...] If that's what you're saying, why >> is it better to violate the POSIX standard than the ISO C++ standard? > > I think there are degrees here. > > The conflict with ISO C++ is that it says that ISO C functions can't > throw. Reverting that clause seems to me to be a minor change. > > The proposed change to POSIX such that it does not use abnormal return > semantics is a *major* change. I don't get it. Changing the C++ standard to allow certain functions to throw is minor but changing POSIX to forbid those functions from throwing is major? -- Dave Abrahams Boost Consulting www.boost-consulting.com From ncm at cantrip.org Sun Dec 28 04:54:06 2003 From: ncm at cantrip.org (Nathan Myers) Date: Sat, 27 Dec 2003 20:54:06 -0800 Subject: [c++-pthreads] Re: C++ and posix threads In-Reply-To: <20031227232444.GA14692@redhat.com> References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224044622.GG27836@tofu.dreamhost.com> <20031225001117.GA13447@redhat.com> <20031227232444.GA14692@redhat.com> Message-ID: <20031228045406.GI2774@tofu.dreamhost.com> On Sat, Dec 27, 2003 at 03:24:44PM -0800, Richard Henderson wrote: > On Thu, Dec 25, 2003 at 02:35:31PM -0500, David Abrahams wrote: > > I'm not sure I understand what you're saying. The POSIX C binding > > standard is in direct conflict with the ISO C++ standard, so _some_ > > standard will be violated. [...] If that's what you're saying, why > > is it better to violate the POSIX standard than the ISO C++ standard? > > I think there are degrees here. > > The conflict with ISO C++ is that it says that ISO C functions can't > throw. Reverting that clause seems to me to be a minor change. Do you _really_ see breaking just about every existing thread-safe library as a minor change? (It would be disingenuous to remark that those libraries are "already broken". Thousands of them have been working fine on millions of systems, year after year.) Exception-safe code distinguishes points that may throw from those that can't. Those functions have not reasonably been expected ever to throw. Code that calls them frequently and reasonably depends, for correctness, on them returning normally. It is manifestly clear that, for C++, requiring all those thousands of libraries to be rewritten is unnecessary. > The proposed change to POSIX such that it does not use abnormal return > semantics is a *major* change. Nobody proposed changing POSIX. The proposed semantics is for the C++ _binding_ to POSIX, which (I understand) doesn't exist yet. This implementation would be a demonstration of a simple C++ binding, to present to POSIX, which might later be elaborated with a C++-like interface to matching semantics. The only risk I see in this first effort is if some of the required cancellation points do not have any means to report failure; there would be some work in identifying those, if indeed there are any. (There would certainly be plenty of C programmers who would welcome a mode in which cancellation means syscalls return failure, so they can use those thousands of libraries that have been rendered inoperative by late implemention activity -- but that's none of our business here.) I have been reading archives of discussion of the POSIX C binding: Whenever a C++ compatibility concern was raised, in the messages I read, someone was quick to retort that it was the C, not the C++ binding, that was under discussion. Such rejections implied a promise that for C++ the semantics could reasonably differ as needed to be compatible with C++ language semantics. To assert now that the C++ binding cannot depart from the C binding in any detail would be a deep betrayal of that implied promise. Nathan Myers ncm at cantrip.org From boo at terekhov.de Mon Dec 29 10:41:47 2003 From: boo at terekhov.de (Alexander Terekhov) Date: Mon, 29 Dec 2003 11:41:47 +0100 Subject: [c++-pthreads] Re: C++ and posix threads References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224044622.GG27836@tofu.dreamhost.com> <20031225001117.GA13447@redhat.com> <20031227232444.GA14692@redhat.com> <20031228045406.GI2774@tofu.dreamhost.com> Message-ID: <3FF004EB.137A34B6@terekhov.de> Nathan Myers wrote: [...] > Do you _really_ see breaking just about every existing thread-safe > library as a minor change? (It would be disingenuous to remark that > those libraries are "already broken". Thousands of them have been > working fine on millions of systems, year after year.) But they will continue working "just fine". They will simply remain thread-cancel-UNsafe. Too bad we don't have throw(...) and throw() wan't made the default (I presume 2-phase EH and kinda "intelligent" cancelation points [and also async-cancel "delivery" inside async- cancel-safe regions, of course]). regards, alexander. From ben.hutchings at businesswebsoftware.com Mon Dec 29 16:08:02 2003 From: ben.hutchings at businesswebsoftware.com (Ben Hutchings) Date: Mon, 29 Dec 2003 16:08:02 -0000 Subject: [c++-pthreads] cancellation points report failure Message-ID: David Abrahams wrote: > It seems to me that it should be up to the cancelling thread to decide > whether it wants to take drastic measures to ensure that cancellation > happens. The only effective way I can think of to do that is to do > allow synchronous cancellation requests with a timeout that forces > thread termination if it fails to respond... but I'm sure there are > other approaches. What you seem to be suggesting is to convert a synchronous cancellation into an asynchronous cancellation. I don't see how this can be safe. If a calling thread is to be allowed to set a time limit on cancellation then I think the time-out action should to be to terminate the process. However, I'm not convinced that programmers are generally very good at setting time limits. From rth at redhat.com Mon Dec 29 23:28:17 2003 From: rth at redhat.com (Richard Henderson) Date: Mon, 29 Dec 2003 15:28:17 -0800 Subject: [c++-pthreads] Re: C++ and posix threads In-Reply-To: <20031228045406.GI2774@tofu.dreamhost.com> References: <3FE70542.5060104@bourguet.org> <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224044622.GG27836@tofu.dreamhost.com> <20031225001117.GA13447@redhat.com> <20031227232444.GA14692@redhat.com> <20031228045406.GI2774@tofu.dreamhost.com> Message-ID: <20031229232817.GA21305@redhat.com> On Sat, Dec 27, 2003 at 08:54:06PM -0800, Nathan Myers wrote: > Do you _really_ see breaking just about every existing thread-safe > library as a minor change? Yes. Primarily because I disagree that changing the throw status of printf will have this effect. > Nobody proposed changing POSIX. > > The proposed semantics is for the C++ _binding_ to POSIX, which > (I understand) doesn't exist yet. If you are seriously suggesting that printf work differently depending on whether the object file is linked into a C or a C++ program, then I give up. That is NOT an option. You will get absolutely ZERO uptake from library implementors. r~ From ncm at cantrip.org Tue Dec 30 01:58:08 2003 From: ncm at cantrip.org (Nathan Myers) Date: Mon, 29 Dec 2003 17:58:08 -0800 Subject: [c++-pthreads] Re: C++ and posix threads In-Reply-To: <20031229232817.GA21305@redhat.com> References: <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224044622.GG27836@tofu.dreamhost.com> <20031225001117.GA13447@redhat.com> <20031227232444.GA14692@redhat.com> <20031228045406.GI2774@tofu.dreamhost.com> <20031229232817.GA21305@redhat.com> Message-ID: <20031230015808.GM2774@tofu.dreamhost.com> On Mon, Dec 29, 2003 at 03:28:17PM -0800, Richard Henderson wrote: > On Sat, Dec 27, 2003 at 08:54:06PM -0800, Nathan Myers wrote: > > Do you _really_ see breaking just about every existing thread-safe > > library as a minor change? > > Yes. Primarily because I disagree that changing the throw status > of printf will have this effect. Have you ever coded C++? Exception-safe code depends on knowing where exceptions may occur. While it is very rare that code depends on returned results from ::printf, other calls have rather more complicated result semantics. > > Nobody proposed changing POSIX. > > > > The proposed semantics is for the C++ _binding_ to POSIX, which > > (I understand) doesn't exist yet. > > If you are seriously suggesting that printf work differently > depending on whether the object file is linked into a C or a > C++ program, then I give up. That is NOT an option. You will > get absolutely ZERO uptake from library implementors. Richard, all these "ZERO uptake" remarks make it very hard to discuss design decisions calmly. It sounds like you're saying that if the right thing for C++ is something Ulrich doesn't care for, we must shadow the C functions, in libstdc++, with wrapper code. That would be unfortunate. Nathan Myers ncm at cantirp.org From austern at apple.com Tue Dec 30 03:52:57 2003 From: austern at apple.com (Matt Austern) Date: Mon, 29 Dec 2003 19:52:57 -0800 Subject: [c++-pthreads] Re: C++ and posix threads In-Reply-To: <20031230015808.GM2774@tofu.dreamhost.com> References: <1072111706.3474.17.camel@minax.codesourcery.com> <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224044622.GG27836@tofu.dreamhost.com> <20031225001117.GA13447@redhat.com> <20031227232444.GA14692@redhat.com> <20031228045406.GI2774@tofu.dreamhost.com> <20031229232817.GA21305@redhat.com> <20031230015808.GM2774@tofu.dreamhost.com> Message-ID: On Dec 29, 2003, at 5:58 PM, Nathan Myers wrote: > On Mon, Dec 29, 2003 at 03:28:17PM -0800, Richard Henderson wrote: >> On Sat, Dec 27, 2003 at 08:54:06PM -0800, Nathan Myers wrote: >>> Do you _really_ see breaking just about every existing thread-safe >>> library as a minor change? >> >> Yes. Primarily because I disagree that changing the throw status >> of printf will have this effect. > > Have you ever coded C++? Exception-safe code depends on knowing > where exceptions may occur. While it is very rare that code depends > on returned results from ::printf, other calls have rather more > complicated result semantics. I agree that we shouldn't rule out the idea of changing POSIX functions' interfaces. As you say, the POSIX specification deliberately chose not to take C++ into account. We don't have that luxury. (Digression: one other question that POSIX doesn't answer, but that we do have to answer, is what namespace these functions go in. Most people have assumed that not saying anything means they go into the global namespace, but that's not logically right. Not saying anything means not saying anything.) I'm not so sure I agree with you that declaring them nothrow, and representing thread cancellation as a new kind of error code, is a good idea. Remember, the whole idea of thread cancellation is that the thread is supposed to *stop*. Synchronous cancellation means it doesn't stop just anywhere, and POSIX puts in some features to give programmers a bit more control (temporarily disabling cancellation, registering cleanup handlers, and so on), but the basic idea is still there that thread cancellation is an urgent request. You're right that C++ code that uses printf, and that doesn't take cancellation into account, won't function properly in the presence of thread cancellation. But I claim that the same is true under your scheme: a library that doesn't rigorously check return codes, and that doesn't introduce its own cancellation- handing framework using those return codes, also won't function properly in your scheme. If anything, I think it'll be easier to fix naive code under the exception-throwing scheme than under the error return scheme. Maybe we should start by tracing through the logic we originally used that led us to think that thread cancellation had something to do with exceptions. Our reasoning may have been wrong, but at least it should be taken into account. --Matt From rth at redhat.com Tue Dec 30 05:07:55 2003 From: rth at redhat.com (Richard Henderson) Date: Mon, 29 Dec 2003 21:07:55 -0800 Subject: [c++-pthreads] Re: C++ and posix threads In-Reply-To: <20031230015808.GM2774@tofu.dreamhost.com> References: <20031222215712.GB1528@diablo.name> <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224044622.GG27836@tofu.dreamhost.com> <20031225001117.GA13447@redhat.com> <20031227232444.GA14692@redhat.com> <20031228045406.GI2774@tofu.dreamhost.com> <20031229232817.GA21305@redhat.com> <20031230015808.GM2774@tofu.dreamhost.com> Message-ID: <20031230050755.GB21387@redhat.com> On Mon, Dec 29, 2003 at 05:58:08PM -0800, Nathan Myers wrote: > Have you ever coded C++? Yes. > > If you are seriously suggesting that printf work differently > > depending on whether the object file is linked into a C or a > > C++ program, then I give up. That is NOT an option. You will > > get absolutely ZERO uptake from library implementors. > > Richard, all these "ZERO uptake" remarks make it very hard to discuss > design decisions calmly. If you think I mean just Uli, then you're wrong. I mean any vendor. I also, personally, think that having different semantics for bleeding system calls between C and C++ is the worst idea ever. If you want to automatically disable cancelation while destructors are running, that would be fine. Small changes to the exception support code in libstdc++ could do that. Beyond that, I have no idea what you think the problem is with system calls throwing exceptions, nor what you hope to achieve with ETHREADCANCEL. r~ From dave at boost-consulting.com Tue Dec 30 13:03:44 2003 From: dave at boost-consulting.com (David Abrahams) Date: Tue, 30 Dec 2003 08:03:44 -0500 Subject: cancellation points report failure References: Message-ID: "Ben Hutchings" writes: > David Abrahams wrote: > >> It seems to me that it should be up to the cancelling thread to decide >> whether it wants to take drastic measures to ensure that cancellation >> happens. The only effective way I can think of to do that is to do >> allow synchronous cancellation requests with a timeout that forces >> thread termination if it fails to respond... but I'm sure there are >> other approaches. > > What you seem to be suggesting is to convert a synchronous cancellation > into an asynchronous cancellation. I don't see how this can be safe. > If a calling thread is to be allowed to set a time limit on cancellation > then I think the time-out action should to be to terminate the process. > However, I'm not convinced that programmers are generally very good at > setting time limits. Of course it's not safe. That's my point, sort of: if you use synchronous cancellation, you have to give up on any *guarantee* that the thread will be cancelled, so we shouldn't be considering measures that take heroic steps to try to ensure it. If you want to guarantee that cancellation happens, you have to do something unsafe. -- Dave Abrahams Boost Consulting www.boost-consulting.com From boo at terekhov.de Tue Dec 30 13:58:29 2003 From: boo at terekhov.de (Alexander Terekhov) Date: Tue, 30 Dec 2003 14:58:29 +0100 Subject: [c++-pthreads] Re: cancellation points report failure References: Message-ID: <3FF18485.93F2D588@terekhov.de> David Abrahams wrote: [...] > Of course it's not safe. That's my point, sort of: if you use > synchronous cancellation, you have to give up on any *guarantee* that > the thread will be cancelled, so we shouldn't be considering measures > that take heroic steps to try to ensure it. If you want to guarantee > that cancellation happens, you have to do something unsafe. Note that the use of POSIX asynchronous cancellation (I mean the presence of async-cancel{-safe} regions on the execution path) does NOT guarantee thread termination (cancel request delivery) at all. Conforming implementations are free to ignore it completely, so to speak. I wish the standard would define pthread_testcancel() "in terms" of an empty async-cancel region (and it would also provide async-cancel-safety for pthread_testcancel() itself): void pthread_testcancel() { /* mandatory shall occur semantics */ int oldtype; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); pthread_setcanceltype(oldtype, &oldtype); } regards, alexander. From ncm at cantrip.org Wed Dec 31 22:06:12 2003 From: ncm at cantrip.org (Nathan Myers) Date: Wed, 31 Dec 2003 14:06:12 -0800 Subject: [c++-pthreads] Re: C++ and posix threads In-Reply-To: <20031230050755.GB21387@redhat.com> References: <1072131497.7562.22.camel@doubledemon.codesourcery.com> <20031223160314.GA9780@diablo.name> <20031224044622.GG27836@tofu.dreamhost.com> <20031225001117.GA13447@redhat.com> <20031227232444.GA14692@redhat.com> <20031228045406.GI2774@tofu.dreamhost.com> <20031229232817.GA21305@redhat.com> <20031230015808.GM2774@tofu.dreamhost.com> <20031230050755.GB21387@redhat.com> Message-ID: <20031231220611.GI30780@tofu.dreamhost.com> Richard, please suspend judgment and read carefully. On Mon, Dec 29, 2003 at 09:07:55PM -0800, Richard Henderson wrote: > On Mon, Dec 29, 2003 at 05:58:08PM -0800, Nathan Myers wrote: > > > > Richard, all these "ZERO uptake" remarks make it very hard to discuss > > design decisions calmly. [...] > > If you think I mean just Uli, then you're wrong. I mean any vendor. Have you actually asked all all these vendors? I suspect you'd find that most would have preferred the option to offer _only_ error-return semantics, and not be obliged to implement unwinding at all. The error-return semantics are certainly easy to provide. Imagine, for the sake of discussion only, a single new pthread call, e.g. pthread_c10n_points_fail(). After it is called, C cancellation points, when cancelled, do not unwind the stack, they just return EOF, or -1, or 0, as appropriate, and maybe set errno. Would ordinary well-written, thread-safe code break? No. Would (those few) libraries that have already been modified to be "cancellation-safe" fail? No. Would cancelled threads fail to die? No more so than they might with C-style unwind semantics. Might some cancelled threads take a little longer to die? Maybe, but no time limits are defined in any case. > I also, personally, think that having different semantics for > bleeding system calls between C and C++ is the worst idea ever. No C++ programmer would object to allowing C programs to run with error-return semantics. Furthermore, many of the people who maintain C programs would welcome the opportunity to exercise those semantics, and not be obliged to rewrite all their libraries. You write as if we are asking for something radical, when in fact we simply want well-established public interfaces to continue honoring the same semantics they have always documented. (Adding a new reason they might fail doesn't violate the documented semantics, because they are documented as perhaps failing for reasons beyond those listed.) What is radical is to change system calls' semantics without changing their names. Good code has to handle ordinary failures anyway. Ordinary failures exercise those handlers. Similarly, in C++, destructors have to be run anyway. Running them during exception handling doesn't add extra risk. Making cancellation exercise that same code, whether normal failure handling blocks or destructors and catch clauses, is likewise pretty safe. Coding a whole separate apparatus for cancellation that is otherwise never executed, though, is fundamentally risky. Unexercised code rots. > If you want to automatically disable cancelation while destructors > are running, that would be fine. Small changes to the exception > support code in libstdc++ could do that. I don't doubt that it would be easy to support such a change. It might be necessary, but it would not suffice. > Beyond that, I have no idea what you think the problem is with > system calls throwing exceptions, nor what you hope to achieve > with ETHREADCANCEL. I will explain again. I am certain that (under other circumstances) you, Richard, can easily recognize how changing the semantics defined at an interface breaks code written to the old definition. Earlier, I posted a code example to illustrate it. I am also certain that you can easily understand why people avoid changing library code unnecessarily, particularly in libraries they don't control. I am at a loss to understand why you seem unable or unwilling to apply that understanding in this case. Can you enlighten us? Many of us see it as neither necessary nor responsible to break the thousands of well-written libraries that have been deployed and running for years on millions of systems, in programs linked with "-lpthread". Nothing in the goal of supporting thread cancellation seems to require violating ISO-standard language semantics. Our goal is to continue to use the same libraries we have been using, unchanged, and to have them support reasonable cancellation semantics just as they are. As it happens, that is technically easy to achieve. As it is, cancellation is not compatible with g++. Changing language semantics in g++, or demanding changes in third-party libraries, is certain not to fix that. Just suspending cancellation in catch blocks isn't sufficient to fix it. Our needs are simple, and neither remarkable, radical, nor unreasoned. I don't understand the hostility they evoke. Nathan Myers ncm at cantrip.org