From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id p7CAvF8i002488 for ; Fri, 12 Aug 2011 12:57:15 +0200 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AiMBAHAGRU5RZ90xkWdsb2JhbABBp3UUAQEBAQkLCwcUAyKBQAEBAQECATo4DAsCAQgYChQQMiUCBAEaE4dUArwWhWhfBJMQkHE X-IronPort-AV: E=Sophos;i="4.67,361,1309730400"; d="scan'208";a="105311452" Received: from mtaout03-winn.ispmail.ntl.com ([81.103.221.49]) by mail4-smtp-sop.national.inria.fr with ESMTP; 12 Aug 2011 12:57:05 +0200 Received: from aamtaout01-winn.ispmail.ntl.com ([81.103.221.35]) by mtaout03-winn.ispmail.ntl.com (InterMail vM.7.08.04.00 201-2186-134-20080326) with ESMTP id <20110812105700.GLEE17535.mtaout03-winn.ispmail.ntl.com@aamtaout01-winn.ispmail.ntl.com>; Fri, 12 Aug 2011 11:57:00 +0100 Received: from romulus.metastack.com ([81.102.132.77]) by aamtaout01-winn.ispmail.ntl.com (InterMail vG.3.00.04.00 201-2196-133-20080908) with ESMTP id <20110812105700.TIEY20122.aamtaout01-winn.ispmail.ntl.com@romulus.metastack.com>; Fri, 12 Aug 2011 11:57:00 +0100 Received: from remus.metastack.local ([172.16.0.1]) by romulus.metastack.com (8.14.2/8.14.2) with ESMTP id p7CAuuDu002977 (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=FAIL); Fri, 12 Aug 2011 11:56:56 +0100 Received: from Remus.metastack.local ([fe80::547c:3c42:e1da:eda2]) by Remus.metastack.local ([fe80::547c:3c42:e1da:eda2%10]) with mapi id 14.01.0289.001; Fri, 12 Aug 2011 11:56:55 +0100 From: David Allsopp To: Thomas Braibant , "caml-list@inria.fr" Thread-Topic: [Caml-list] C bindings: memory managment Thread-Index: AQHMWNgfctF/dRzce0ab8pH5l83FRZUZBg1g Date: Fri, 12 Aug 2011 10:56:54 +0000 Message-ID: References: In-Reply-To: Accept-Language: en-GB, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [172.16.0.8] Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Organization: MetaStack Solutions Ltd. X-Scanned-By: MIMEDefang 2.65 on 81.102.132.77 X-Cloudmark-Analysis: v=1.1 cv=R50lirqlHffDPPkwUlkuVa99MrvKdVWo//yz83qex8g= c=1 sm=0 a=OnY-5VE14_gA:10 a=Hw9C8t-IKHgA:10 a=cTs9vV391PwA:10 a=kj9zAlcOel0A:10 a=xqWC_Br6kY4A:10 a=rlXSZG7xp-CNWBsNIfQA:9 a=mII_4q1gmud7ZhFQD8UA:7 a=CjuIK1q_8ugA:10 a=HpAAvcLHHh0Zw7uRqdWCyQ==:117 Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from quoted-printable to 8bit by walapai.inria.fr id p7CAvF8i002488 Subject: RE: [Caml-list] C bindings: memory managment Thomas Braibant wrote: > During my summer vacations, I decided to have fun trying to make an OCaml > binding for a C library (my first time). My requirements were to have an > "OCaml feeling" (i.e. to have an OCaml interface that looks like the > library was written in OCaml) This is obviously a good idea! However, it's often worth making the C stubs the simplest possible bindings to the underlying C functions and then creating the "OCaml feeling" in the OCaml code for your library. It's much easier debugging higher level OCaml wrapping around your stubs than it is debugging a faulty C stub (obviously, performance considerations sometimes override this). > and to have good memory management (no leaks). That's compulsory ;o) > Following the manual, it was easy to get a working binding for a subset of > the library (enough to follow the tutorial of the given library). However, > I ended up bitten by a nasty problem. > However, this is wrong, since with the following piece of code, the GC has > the right to remove the bodies once in the loop (there is no more > reference to them). I end up with a segmentation fault. > > let body1 = Body.make ... in > let body2 = Body.make ... in > let space = Space.make () in > let _ = Space.add_body space body1 in > let _ = Space.add_body space body2 in > for i = 0 to ... do > Space.step space > done;; > > This bodies are not global roots (as far as I understand the terminology), > so I do not see a way to tell the GC not to free the bodies while there is > still a reference to the space they have been added to. At least, I see no > such thing in the documentation. You need to link the values [space], [body1] and [body2] together so that the GC knows that [body1] and [body2] are still reachable. There's no way around that (if you make [body1] and [body2] part of a global root, they'll never be collected). > The solutions I can imagine are: > - either to define Space.t as a record/tuple that contains a space* and an > OCaml list of the bodies that have been added. This seems a bit of a > duplication of the underlying C library. Your problem, if I understand it correctly, is that there is relationship between the value [space] and values [body1] and [body2] which was set in place by (the C stub) [Space.add_body]? In which case, you have to make the GC aware of that relationship - and this is the best way of doing it. Presumably when your variable [space] is garbage collected, it would then be okay to collect [body1] and [body2] as they're not referenced elsewhere. This would then happen automatically as once [space] has been collected, there will be no more references to [body1] and [body2] and they'll be collected too. Your C library stores references to the C body* pointers in the space object as part of its own operation - your C stubs store a list of body values with a space value as part of automatic memory management (which your C library presumably does not provide). That's not duplication: they're doing different things with different values. > - either to use some reference counting and memory management as an > interface between the target C library, and the OCaml library. Yuck - definitely not. Your reference counters would be no better than the list of values. That's why OCaml has a GC - definitely use it! > - either to require the user to use a "free" OCaml function to do the > memory management (this does not meet my requirements, but this is how my > target C library is binded in other functional languages...). This is correct if your underlying C "things" aren't just memory - usually if a resource is "precious" (e.g. file descriptor, socket, etc.) then you should provide close functions on the OCaml side (because end-users' code *should* be worrying about releasing them). Bear in mind that OCaml does not call finalizers when a program terminates (Java and .NET, I *think*, do, for example - but that's a hazy memory!) so you should never have critical release code in a finalizer. HTH, David