This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [basic-improvements] try/finally support for c/c++ - more tests
On Thu, Nov 07, 2002 at 10:29:21PM +1100, Fergus Henderson wrote:
> On 06-Nov-2002, Geoff Keating <geoffk@geoffk.org> wrote:
> > Richard Henderson <rth@redhat.com> writes:
> >
> > > On Wed, Nov 06, 2002 at 03:32:20PM -0800, Mark Mitchell wrote:
> > > > I do not think we should add exception support of any kind to GNU C; use
> > > > C++ if you want exceptions.
> > >
> > > See elsewhere about resistance compiling libc with a c++ compiler.
> >
> > It wouldn't work, anyway. User programs can also use
> > pthread_cleanup_push/pthread_cleanup_pop, in C, so whatever mechanism
> > is used for that must be accessible to C.
>
> How about the following?
> This uses the C++ compiler's exception support, and is accessible from C.
> It makes use of the GNU C nested function extension.
> The main drawback that I can see is that it is not as efficient as possible.
s/not efficient as possible/completely inefficient/.
Plus it is incorrect too as pthread_cleanup_p{ush,op} implementation - the
cleanup is to be run if cancellation happens no matter whether __call_cleanup
is zero or non-zero.
This would slow e.g. stdio a lot.
ATM if libpthread is not linked in, __libc_cleanup_region_start
and __libc_cleanup_region_end make no function calls at all, if it is
linked in, it makes functions calls but certainly the body is not forced to
be a separate function, forcing all parent's variables
to stack and accessing them through static chain pointers.
With __try/__finally, there would be no calls at all and no need
to duplicate the cleanup once in a separate function for the unwinder,
once when exiting the block (__libc_cleanup_region_end).
Furthemore, even when no exceptions are used, __try/__finally is a nice
way how to avoid very common goto gem:
x = malloc (somesize);
if (x == NULL)
{
ret = ENOMEM;
goto out_exit;
}
if (fstat (fd, &st) < 0)
{
ret = errno;
goto out_exit;
}
...
out_exit:
free (y);
free (x);
return ret;
One just writes:
__try
{
x = malloc (somesize);
if (x == NULL)
return ENOMEM;
if (fstat (fd, &st) < 0)
return errno;
...
return 0;
}
__finally
{
free (y);
free (x);
}
and magically the code is pthread cancellation aware.
>
> /* pthread.h */
>
> void __pthread_try_finally(void (*)(void), void (*)(void *), void *, int);
>
> #define pthread_cleanup_push(__routine,__arg) \
> { \
> void (*__cleanup_routine)(void *) = __routine; \
> void *__cleanup_arg = __arg; \
> void __body(void) {
>
> #define pthread_cleanup_pop(__call_cleanup) \
> } \
> __pthread_try_finally(__body, __cleanup_routine, __cleanup_arg, \
> __call_cleanup); \
> }
>
> /* pthread_try_finally.cpp */
>
> extern "C" {
>
> void
> __pthread_try_finally(
> void (*body)(void),
> void (*cleanup_routine)(void *),
> void (*cleanup_arg)(void),
> int call_cleanup)
> {
> class S {
> void (*cleanup_routine)(void *);
> void (*cleanup_arg)(void);
> int call_cleanup;
> public:
> S(void (*cleanup_routine)(void *),
> void (*cleanup_arg)(void),
> int call_cleanup)
> {
> this->cleanup_routine = cleanup_routine;
> this->cleanup_arg = cleanup_arg;
> this->call_cleanup = call_cleanup;
> }
> ~S()
> {
> if (call_cleanup)
> (*cleanup_routine)(cleanup_arg);
> }
> } s(cleanup_routine, cleanup_arg, call_cleanup);
>
> (*body)();
> }
>
> }
Jakub