This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [basic-improvements] try/finally support for c/c++ - more tests

On Wed, Nov 06, 2002 at 04:44:49PM -0800, Mark Mitchell wrote:
> >See elsewhere about resistance compiling libc with a c++ compiler.
> I know there's resistance, but frankly I think that's just predjudice.
> Compile the bits you need C++ features for in C++.  Avoid stuff that
> seems fragile, like virtual bases/virtual functions etc; just use
> try/catch and/or destructors if that's all you want.  The functionality
> you need has been stable for ages and ages.
> I feel strongly that we should not try to bring C++ features into C,
> just to avoid having to compile some stuff in libc with G++.  Especially
> as similar features may eventually go into ISO C with subtly different
> semantics.

To clarify, this is about pthread_cleanup_push/pop, right?  Which are
used in code that _uses_ libc, not just inside libc itself.  I got the
impression that the idea here was to be able to do

#define pthread_cleanup_push(routine_, arg_) {	 \
  __pthread_cleanup_t __cleanup_info;		 \
  __cleanup_info.routine = routine_;		 \
  __cleanup_info.arg = arg_;			 \
  __cleanup_info.doit = 1;			 \
  __try {

#define pthread_cleanup_pop(doit_)		 \
 __cleanup_info.doit = doit_;			 \
 } __finally {					 \
   if (__cleanup_info.doit)			 \
     __cleanup_info.routine(__cleanup_info.arg); \
 } }

And the point of doing this is to get pthread_cancel handlers to be
run when a C++ exception is thrown, and vice versa to get destructors
to be run when pthread_cancel() happens.  (pthread_cancel itself will
presumably call _Unwind_RaiseException directly, in this scheme.)

This is actually an important correctness issue for threading in C++.
Currently, you can be reliable in the face of pthread_cancel, or you can
be reliable in the face of exceptions being thrown, but not both at the
same time.  It is also, obviously, desirable not to have to maintain
separate versions of these macros for C and C++.  And I sympathize
somewhat with the desire to create a generic extension rather than one
specific to this precise situation.

However.  The code I sketched above has a number of correctness issues --
mostly due to the unhygenic nature of C preprocessor macros rather than
to the try/finally construct itself.  It is difficult to make them go
away while still using the present proposal, but it would be very easy
to get rid of them using a narrowly tailored one:

#define pthread_cleanup_push(routine_, arg_) \
  __builtin_cleanup_block(routine_, arg_) {

#define pthread_cleanup_pop(doit_) \
  __builtin_toggle_do_cleanup(doit_); }

These are equivalent to this C++:

struct cleanup {
  void (*routine)(void *); 
  void *arg;
  int doit;
  cleanup(void (*R)(void *), void *A) : routine(R), arg(A), doit(1) { };
  ~cleanup() { if(doit) routine(arg); }

#define pthread_cleanup_push(R, A) { cleanup C(R, A);
#define pthread_cleanup_pop(DOIT)  C.doit = DOIT; }

except that (a) the local variable is anonymous, (b) they work in C
as well as C++, and (d) no declaration of struct cleanup is visible.

Are there other uses of __try/__finally which y'all have in mind that
wouldn't be covered by this?


p.s. It would be nifty if setjmp/longjmp could be defined in terms of
exception handling.  Anyone put thought into that?

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]