[c++-pthreads] Re: pthread_cancel and EH: let's try this again

Dave Butenhof david.butenhof at hp.com
Wed Jul 13 17:15:00 UTC 2005


Jason Merrill wrote:

>On Wed, 13 Jul 2005 17:28:50 +0200, Alexander Terekhov <terekhov at web.de> wrote:
>  
>
>>Jason Merrill wrote:
>>[...]
>>    
>>
>>>while (true)
>>> try
>>>  {
>>>   body();
>>>  }
>>> catch (...)
>>>  {
>>>   recover();
>>>  }
>>>
>>>Under the old non-EH implementation this thread cancelled properly.  
>>>      
>>>
>>You mean with omitted recovery? That's hardly "properly".
>>
>>Cancel-unaware code is not meant to be canceled. 
>>
>>It's as simply as that.
>>    
>>
>A customer of ours has code along those lines in a package that uses
>pthread_cleanup_push/pop to handle cleanups on cancellation.  It works fine
>under Solaris, tru64, and older linux systems.
>  
>
If we're talking C++ code using pthread_cleanup_push/pop, which I infer 
to be the case, then it did NOT work on Tru64 UNIX -- though the 
customer may have failed to notice that it didn't work. While the C 
language macros would COMPILE under C++ they didn't work usefully. We'd 
always told people NOT to use the macros in C++.

Cancellation was always intended to be an exception, even in C. It's 
just that ISO C and POSIX don't possess the semantics or syntax. Tru64 
UNIX however has real exception support, and The Digital/Compaq/HP C 
("GEM C") compiler has extensions to interact with that exception 
support. If compiling under the "ideal" C compiler, the POSIX macros 
used real exceptions -- but otherwise they use the crufty old 
setjmp/longjmp portable "exception" package, which does not interoperate 
with the native Tru64 exception support (and thus with frames built by 
Ada, C++, or GEM C). Unwinding through a frame using 
pthread_cleanup_push/pop that wasn't compiled with GEM C will break 
interleaved frames with any real exception handling -- including C++ 
object destructors.

pthread_cleanup_push/pop is an artifact of the limitations of the POSIX 
C binding, not intended (nor portably supported) for use in any other 
language, including C++. C++ code that uses POSIX cleanup is straddling 
the line between two contradictory standards. While it's true that any 
use of threads in C++ is beyond the help of either standard, there are 
reasonable and widely implemented mechanisms on which developers can 
rely with reasonable safety -- a mutex WILL work when called from C++, 
the C++ compiler will not implicitly generate code that defies 
multithread coherency requirements. Cancel is NOT in that category. The 
problems are on the same scope as combining threads and UNIX signals; 
two radically different specifications and implementations intended to 
do much the same (but one substantially limited by environmental 
constraints). They don't mix easily or conveniently.

The best way to make signals and threads cooperate might have been to 
recast signals as a special type of thread, but that wasn't practical. 
What we have instead is a mess, with a lot of rough edges and a lot of 
restrictions; but with care it can be made to work, and the combination 
provides significant advantages.

>It IS cancel-aware.  The problem is that allowing catch(...) to catch
>cancellation changes what it MEANS to be cancel-aware in an incompatible
>way.
>  
>
Where? Again on Tru64 UNIX and with any C++ using the native Tru64 
exception support in a compatible and conforming way, catch(...) WILL 
catch cancel, and always has. Some code depends on this; so REMOVING the 
capability "changes what it means to be cancel-aware in an incompatible 
way".

C++ is not C, despite trivial and unfortunately common misconceptions. 
POSIX threads is a C language binding, but serves only as an abstract 
representation (not a concrete implementation) of the capabilities that 
ought to be provided for a different language binding.

Cancellation IS an exception, and was always designed to BE an 
exception, nothing else. It was only the representational limitations of 
ISO C and POSIX that lead to the current ambiguous specification. POSIX 
contains an explicit statement of intent that languages with exceptions 
should use them rather than implementing cleanup push/pop; however even 
if a binding chose to ignore that advice, the C++ implementation of 
cleanup push/pop must interoperate with C++ exceptions and object 
destructors in a way that a C implementation cannot.

There are many complicated compatibility issues in modelling something 
like POSIX cancellation in C++ without breaking some usage patterns of 
C++ exceptions. There's no way around that. In particular, arguments of 
"it has to be this way because" or "it can't be this way because" miss 
the point. Or rather, if you're going to insist that IS the point then 
it just can't be done and we should face that any C++ code using cancel 
is inherently broken. Otherwise, existing usage patterns are going to 
change, and a lot of code will be adversely impacted by the changes; 
either to traditional C++ exception usage patterns or to traditional 
POSIX cancellation usage patterns.

One of the biggest issues is reconciling the global nature of 
cancellation state with C++ "no throw zones". Many years ago I had 
thought of making our CMA "alert" state dynamic by grabbing reserved 
bits off the VAX stack frame masks, so that each call could 
automatically set the desired local cancel state without any additional 
overhead, and we'd work it all out when a cancel exception was actually 
thrown. The problem is that at each frame that doesn't declare its own 
intent, its state is dependent on the last outer frame that did, which 
means traversing further down the stack before initiating the real 
unwind. (This is beyond even a normal 2-phase EH, because the search 
phase often needs to continue beyond the frame that expresses unwind 
intent unless the call sequence propagates the state.)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: david.butenhof.vcf
Type: text/x-vcard
Size: 476 bytes
Desc: not available
URL: <http://sourcerytools.com/pipermail/c++-pthreads/attachments/20050713/2a860276/attachment.vcf>


More information about the c++-pthreads mailing list