From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on yquem.inria.fr X-Spam-Level: * X-Spam-Status: No, score=1.0 required=5.0 tests=AWL,SPF_NEUTRAL autolearn=disabled version=3.1.3 Received: from discorde.inria.fr (discorde.inria.fr [192.93.2.38]) by yquem.inria.fr (Postfix) with ESMTP id 7968CBC0B for ; Tue, 16 Jan 2007 05:18:53 +0100 (CET) Received: from wx-out-0506.google.com (wx-out-0506.google.com [66.249.82.239]) by discorde.inria.fr (8.13.6/8.13.6) with ESMTP id l0G4IqoU013378 for ; Tue, 16 Jan 2007 05:18:52 +0100 Received: by wx-out-0506.google.com with SMTP id i26so1976890wxd for ; Mon, 15 Jan 2007 20:18:52 -0800 (PST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=beta; h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; b=prjcc2t1s45KzCWWfH1IJ+7Ubi1vRFsujgfBpxvCfNtmtTE3MiSfdsFgITpIdkjK1Xz6G74zDqQJcEk7aIAN5IGU0+Xu3ZJb0iT9X3APxBNhuvVT0DMWddasVZ/v7J5hWHwNYjO4CqZp9brItqAk24vnvTFFCj0Y13uGK2r9iks= Received: by 10.90.103.2 with SMTP id a2mr3764614agc.1168921131344; Mon, 15 Jan 2007 20:18:51 -0800 (PST) Received: by 10.90.55.5 with HTTP; Mon, 15 Jan 2007 20:18:51 -0800 (PST) Message-ID: <875c7e070701152018s4eca17b1i72a10440e0c1edef@mail.gmail.com> Date: Mon, 15 Jan 2007 23:18:51 -0500 From: "Chris King" To: "Bob Matcuk" Subject: Re: [Caml-list] va_arg values Cc: caml-list@yquem.inria.fr In-Reply-To: <200701132310.l0DNArug026315@discorde.inria.fr> MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inline References: <200701132310.l0DNArug026315@discorde.inria.fr> X-j-chkmail-Score: MSGID : 45AC522C.000 on discorde : j-chkmail score : X : 0/20 1 0.000 -> 1 X-Miltered: at discorde with ID 45AC522C.000 by Joe's j-chkmail (http://j-chkmail . ensmp . fr)! X-Spam: no; 0.00; params:01 camlparam:01 camlparam:01 afaik:01 hash:01 hash:01 mlvalues:01 alloc:01 malloc:01 caml's:01 exn:01 re-raise:01 printexc:01 failwith:01 camlreturn:01 Short answer: your function is okay, but not for the reasons you state. Long answer: On 1/13/07, Bob Matcuk wrote: > I guess the real question is: is it even necessary to worry about this? > The function, as I said, will only ever be called from other C > functions (who have already designated these values as being > params/local to themselves, assuming they are written correctly). This doesn't matter. The purpose of CAMLparam/CAMLlocal is twofold: first, to declare that a particular value shouldn't be garbage collected (which, as you point out, the other C functions take care of). Secondly (and more importantly in this case), they inform the garbage collector of the all roots which it may need to update in the event that it relocates a block. If you don't use CAMLparam/CAMLlocal and a GC cycle occurs, there's a chance that a block which one of your values points to will be moved, and your value will become invalid. > I > seem to recall reading somewhere that if you write a function that > will only ever be called from other C functions that have already > registered the values (via CAMLparam/CAMLlocal), then it's > unnecessary to do it again. AFAIK this is incorrect (because blocks can be relocated). The only time it is safe not to register values is if your code does not assume that the contents of a value are valid after a call which could trip the GC. > The function doesn't allocate any new > values either, so it shouldn't trip the GC anyway, right? True, false. caml_callbackN executes arbitrary code, which may or may not trip the GC. hash_variant and caml_get_public_method are questionable also (since they return values), but looking at the Caml source code, it seems that they are safe (but I don't think the docs guarantee this). (BTW you should use caml_hash_variant rather than hash_variant; the comment for caml_get_public_method in caml/mlvalues.h should probably be updated to this effect also.) > Should probably check calloc for success and maybe throw an exception > if it failed... You could do this with caml_stat_alloc and caml_stat_free (in caml/memory.h). These are equivalent to malloc/free but throw Caml's out-of-memory exception if they fail. However in this case, I would simply declare args as an array. Otherwise, if the callback throws an exception, args will not be freed unless you explicitly catch exceptions via caml_callbackN_exn, free it, and then re-raise the exception. Note that if you have no control over the C functions higher up the call chain (say an external library which calls your function), they could exhibit similar problems if they are unaware of the possibility of your function raising an exception. The best thing to do in such a case would be to return an error condition if possible, or at the very least, print a warning and return or exit gracefully (the functions in caml/printexc.h help here). > Which actually brings me to another quick question: if > I throw an exception, say caml_failwith("..."), is it necessary to > still call CAMLreturn after it? Or will the exception cause the > function to exit? The exception causes the function to exit. You can see which functions act like this in the header files by looking for the "Noreturn" attribute at the end of their declaration. > Is it an invalid assumption that it is unnecessary to bother with the > CAMLparam/CAMLlocal stuff since there's nothing to trip the GC? If so, > what is the best way to handle all the CAMLparam/CAMLlocal stuff? Yes, it is an invalid assumption, because your code may in fact trip the GC. BUT Look over the function you wrote carefully. Notice that values obj and *args are used only before the call to caml_callbackN, and that the value r is used only after that call. Your function is indeed safe, only because you don't use after the "unsafe" call any value which was initialized before. Of course, for the sake of maintainability, I wouldn't in general endorse such eliding of CAMLparam/CAMLlocal. I'd recommend putting a big ol' warning in there :) > For > example, CAMLlocalN(args, n + 1) is invalid because C does not allow > you to declare dynamic arrays. K&R C doesn't, but GCC does. If you're using another compiler or some compatibility flag, then the alloca function (usually found in alloca.h) should do the trick. It allocates space on the stack exactly like an array declaration does, so the guts of CAMLlocalN should apply to it. > I know values are just pointers so it is syntactically correct, but > what I'm asking is: is it safe to do? Should I be using some function > instead to create a copy of the value? Copying values with assignment is perfectly legal, provided the locations to which they are copied are registered with the GC first (just like any other value). Hope this was able to clear things up, I've hit many of these bumps myself while learning to write extensions. The best thing to remember is that Caml's GC is not a reference counter but a generational collector and can move blocks from right under your nose. Then the reasons to use CAMLlocal/CAMLparam become clear. - Chris