This is the mail archive of the gcc@gcc.gnu.org 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: Interleaving pthread_cleanups in C and C++


On Sat, May 03, 2003 at 07:57:25PM -0700, Zack Weinberg wrote:
> Making it a real C++ exception allows one to do things like use it
> in throw specs; catch it specifically; catch everything but it; etc.
> Basically it allows a bunch more flexibility on the C++ side of the
> fence.

Eh.  Maybe.  I think it would be short-sighted to write code
that was completely C++ specific, i.e. actually write 

	throw pthead_cancel_exception;

in some C++ file.  But I doubt anyone is going to volunteer
to solve the real inter-language exception problem.

Certainly I am not going to do either of the above.

> Mark's proposal IMHO goes way too far down the "anything but a
> language extension!" road; however, I am a little leery of generic
> try/finally in C, given the objections raised way back when ...

Perhaps I've blocked it all, but I don't recall any specific
objections that went beyond "please no language extensions".

> ... and besides which it isn't clear to me that try/finally are really
> what is wanted.  It seems to me that the appropriate extension is a
> subset of C++'s destructor functionality, allowing one to write something
> like this:
> 
> typedef void (*__pthread_cleanup_handler) (void *);
> 
> struct __pthread_cleanup {
>   __pthread_cleanup_handler handler;
>   void *arg;
>   bool execute;
> 
>   ~__pthread_cleanup() { if (execute) handler(arg); }
> };
> 
> #define pthread_cleanup_push(H, A) \
>  { struct __pthread_cleanup __pc = { (H), (A), true };
> 
> #define pthread_cleanup_pop(E) \
>   __pc.execute = E; }

Um, ok, but isn't that worse than try/finally?  I can't even
imagine what sort of grammer changes might be required to be
able to add destructors to structures.

Blah.  Ok, I give up.  What about 

	void __builtin_cleanup (void (*fn)(void *), void *arg);

which calls "fn(arg)" when leaving the current lexical scope,
as you'd expect.  We then write

	struct __phread_cleanup {
	  void (*fn) (void *);
	  void *arg;
	  bool execute;
	};

	static inline void
	__do_pthread_cleanup(void *ptr)
	{
	  struct __phread_cleanup *data = ptr;
	  if (data->execute)
	    data->fn (data->arg);
	}

	#define pthread_cleanup_push(H, A)			\
	  { struct __phread_cleanup __pc = { (H), (A), true };	\
	    __builtin_cleanup (__do_pthread_cleanup, &__pc);	\
	    {

	#define pthread_cleanup_pop(E)				\
	    }							\
	    __pc.execute = (E);					\
	  }

I don't know if this can be made to work reliably, since we
don't have a new lexical scope being created at the point of
the __builtin_cleanup call, unlike with the declaration of a
new object and associated destructor.

I also don't know if it's possible to detect jumps into the
middle of the cleanup block, as we do noticing jumps past an
object with a constructor.

I guess I'll look at this next week.


r~


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