This is the mail archive of the gcc-patches@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: [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


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