[cpp-threads] pthread_cancel and EH: let's try this again

Jason Merrill jason at redhat.com
Mon Jul 11 16:18:06 BST 2005


Previous discussion on this topic ended in something of a stalemate.
Unfortunately, the practical result of this on linux has been very
unfortunate for users: code that uses both pthread_cancel and catch(...)
blocks aborts at runtime, where it worked on previous releases, and
continues to work on other platforms.  This is the worst of both worlds for
users, and needs to change.

In previous discussions, my favored solution was:
1a) Cancellation is disabled during stack unwinding, to avoid trying to
throw out of a destructor.
1b) Make cancellation a normal exception that can be caught and discarded,
but have the destructor for the exception re-assert cancellation so that
the process will begin again at the next cancellation point.
Apparently this is also the Boost.Threads design.

Then there's the Ada-equivalent model:
2a) Cancellation is disabled during destructors and empty exception specs.
2b) Cancellation exceptions are not caught by (...).

And the current status quo in GCC:
3) #1, except that the destructor for the exception calls abort().
Additional inelegant possibilities for the destructor would be killing just
the thread, throwing a new exception, or doing nothing (leaving the thread
in a sort of zombie state).

The main difference here is handling of (...).  I can think of four uses
of catch (...):

Cleanup without using a destructor (catch and rethrow).  This works under
  #1 and #3, and doesn't work under #2.  OTOH, this is already considered
  inelegant, and a #2 system could simply say that for a program to be
  pthread_cancel-safe it needs to put all cleanups in destructors.

Destructor exception safety (catch and discard).  This works fine under all
  models because cancellation is disabled during cleanup, so no
  cancellation exception is thrown.

Thread robustness (catch and retry).  A thread could have a catch (...)
  at the top level to try to recover from errors, on the principle that
  limping along is better than total failure.  Previous discussion seemed
  to assume that the users would want this to catch cancellation as well,
  but I think that's wrong; if someone specifically told the thread to go
  away, they don't want it to recover, they want it to go away.  Having
  implemented #3, Red Hat has gotten a couple of bug reports from users
  with this sort of code; before we implemented the cancellation exception
  the thread went away like it was supposed to, but now we end up calling
  terminate() because they don't rethrow the exception.  This isn't very
  helpful.

  #2 has the desired semantics for this situation, backward compatible with
  existing pthread_cleanup_push/pop code; under a #1 system users would
  need to add code to specifically look for cancellation exceptions in
  order to let them through.  #3 modified to only kill the current thread
  would probably work with most cases.

Inter-language glue (catch and throw something else).  #1 handles this by
  waiting and throwing another cancellation exception at the next
  cancellation point encountered, or doing whatever the other language does
  to handle cancellation.  #2 handles this by ignoring it and just
  propagating the cancellation (which should be handled properly by all
  languages sharing the EH runtime).  #3 blows up.

Ulrich Drepper insists that #1 is impossible, because pthread cancellation
is an irreversible state change.  But I'm not sure why you can't just flip
various flags back to where they were before.

My current inclination is to go with model #2; backwards compatibility
with code written to work with pthread_cleanup_push/pop seems like a
powerful argument in its favor.  People who want model #1 can use a
different threading library, such as Boost.Threads.

Archives:
http://www.codesourcery.com/archives/c++-pthreads/threads.html
http://gcc.gnu.org/ml/gcc-patches/2003-04/msg02246.html
http://gcc.gnu.org/ml/gcc-patches/2003-05/msg00000.html

Jason




More information about the cpp-threads mailing list