From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21896 invoked by alias); 8 Nov 2002 13:47:06 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 21847 invoked from network); 8 Nov 2002 13:47:03 -0000 Received: from unknown (HELO devserv.devel.redhat.com) (66.187.233.200) by sources.redhat.com with SMTP; 8 Nov 2002 13:47:03 -0000 Received: (from jakub@localhost) by devserv.devel.redhat.com (8.11.6/8.11.0) id gA8Dkx231256; Fri, 8 Nov 2002 08:46:59 -0500 Date: Fri, 08 Nov 2002 05:47:00 -0000 From: Jakub Jelinek To: Nicola Pero Cc: Mark Mitchell , Zack Weinberg , "gcc-patches@gcc.gnu.org" Subject: Re: [basic-improvements] try/finally support for c/c++ - more tests Message-ID: <20021108084659.A10988@devserv.devel.redhat.com> Reply-To: Jakub Jelinek References: <147270000.1036722436@warlock.codesourcery.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.2.5.1i In-Reply-To: ; from nicola@brainstorm.co.uk on Fri, Nov 08, 2002 at 12:48:49PM +0000 X-SW-Source: 2002-11/txt/msg00564.txt.bz2 On Fri, Nov 08, 2002 at 12:48:49PM +0000, Nicola Pero wrote: > Well you're not a lone voice of insance conservatism, I actually think you > are quite well giving voices to the puzzled C users, like me. :-) > > In all this discussion, I didn't quite find discussed how it would work in > C/ObjC, from a pure C/ObjC perspective. Which IMO is essential to have > the C extension approved. > > The suggestion that this change is good because "it makes C look more like > C++ so that it's easier to integrate C and C++" might be good for C++ > hackers and lovers, but it's definitely unconvincing for C/ObjC users with > no interest in C++. If you look at a typical system nowadays, C and C++ has to easily integrate together, as C++ code often calls C routines (starting from libstdc++ using C library functions where C library is most often written in C) and a lot of C programs/libraries are using C++ libraries too. > Shall we "finally try" to talk a bit about this C language extension from > a C user perspective, without jumping into C++ every sentence ? > > I've got a lot of doubts that this extension is good for C, at least as it > is. > > In C there is no exception handling, so it's common for C libraries to > implement some sort of exception handling using setjmp/longjmp. > > As far as I understand, the proposed feature wouldn't be enough powerful > to replace the existing setjmp/longjmp based exception handling. It has no intent to replace it, it is about cleanups when exception is thrown, not the exception handling mechanism itself. > Actually, the proposed feature would actually not work with the existing > setjmp/longjmp based exception handling ... either you use the new feature > (which is not enough powerful to provide exception handling), or you use > setjmp/longjmp. But it plays nicely with setjmp/longjmp_unwind. Code using pure setjmp/longjmp nowadays cannot use any cleanups locally, all buffers you allocate or locks you acquire have to be global, so that when setjmp returns non-zero you can free them or release them. At least with current glibc pthread_cleanup_* implementation, it even cannot use pthread_cleanup_*, because libpthread will be seriously confused (usually segfault) after you try longjmp for the first time skipping some frame which did pthread_cleanup_push. > As a C/ObjC user, I don't find this solution very satisfactorily. We've > been long waiting for "real" exception handling in C/ObjC ... and this is > *not* it. See the above. If you do: jmp_buf b; void foo (void) { if (setjmp (b)) { exception was raised; } bar (); } void bar (void) { void *x = malloc (1024); __try { do_something_with_x baz (); do_something_else_with_x } __finally { free (x); } } void baz (void) { if (some_weird_condition) longjmp_unwind (b); } then you IMHO have all you need for satisfactory pure C exception handling with minimal overhead. With __thread variables you can put any data you want into them at longjmp_unwind time (ie. throw someobject in C) and check it at setjmp time. Without __try/__finally but with longjmp_unwind you can still do this, but see my other mail what needs to be done instead of that, making the code quite unreadable. > As far as I understand from the explanations on this thread, try/finally > in C would only be used to cleanup before returning from a function, such > as > > try > { > char *stringA = NULL; > char *stringB = NULL; > char *stringC = NULL; > > stringA = malloc (sizeof (char) * 20); > if (stringA == NULL) > return; > > ... > > stringB = malloc (sizeof (char) * 20); > if (stringB == NULL) > return; > > ... > > stringC = malloc (sizeof (char) * 20); > if (stringC == NULL) > return; > > ... > > return; > } > finally > { > if (stringA != NULL) > free (stringA); > > if (stringB != NULL) > free (stringB); > > if (stringC != NULL) > free (stringC); > } > > It's nice as an example, except I can trivially do it already without any > need for a C extension: > > char *stringA = NULL; > char *stringB = NULL; > char *stringC = NULL; > > stringA = malloc (sizeof (char) * 20); > if (stringA == NULL) > goto finally; > > ... > > stringB = malloc (sizeof (char) * 20); > goto finally; > > ... > > stringC = malloc (sizeof (char) * 20); > if (stringC == NULL) > goto finally; > > ... > > finally: > { > if (stringA != NULL) > free (stringA); > > if (stringB != NULL) > free (stringB); > > if (stringC != NULL) > free (stringC); > > return; > } Sure, but: a) typically in such functions they are not returning void, but some value, with __try/__finally you can leave the code as above, just add the return value to each return statement. With goto gem you need some function scope variable and set it first, then return, so if (stringC == NULL) return 134; becomes if (stringC == NULL) { ret = 134; goto finally; } which is less readable b) if not all variables are function scope, the code gets much uglier c) with __try/__finally, you get the cleanups with pthread cancellation or C++ exceptions thrown or longjmp_unwind for free. You don't have to worry about storing stringA, stringB, stringC not in separate variables, but into some local structure, doing pthread_cleanup_push at the beginning with address of that local structure and either having the finally block just do pthread_cleanup_pop(1) or pthread_cleanup_pop(0) with duplication of all the free calls into the code after finally label and in a separate function. Jakub