This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
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~