On Tue, Sep 6, 2016 at 8:08 PM, Esteban Lorenzano <esteba...@gmail.com> wrote: > Hi, > > sorry for arriving so late to this, but I was on holidays :) > this is how autoRelease works: > > 1) #autoRelease of an object registers object for finalisation with a > particular executor. Then behaviour is divided: > > 2.1.1) for ExternalAddresses, it just registers in regular way, who will call > #finalize on GC > 2.1.2) finalize will just call a free assuming ExternalAddress was allocated > (which is a malloc) > > 2.2.1) for all FFIExternalReference, it will register for finalisation what > #resourceData answers (normally, the handle of the object) > 2.2.2) finalisation process will call the object > class>>#finalizeResourceData: method, with the #resourceData result as > parameter > 2.2.3) each kind of external reference can decide how to free that data (by > default is also just freeing). > > An example of this is how CairoFontFace works (or AthensCairoSurface). > > In you case, you will have something like: > > FFIExternalObject subclass: #CXString
Thanks Esteban for the detailed description. However I've come to the conclusion that the C-library dynamically allocating memory for a field inside the struct of CXString doesn't exactly fit any of the pre-existing FFI types. When CXString subclasses FFIExternalObject the call to clang_getClangVersion () crashes the VM since its handle ==> ExternalAddress of 4 bytes but 8 bytes are required for a pointer + uint, https://github.com/llvm-mirror/clang/blob/google/stable/include/clang-c/CXString.h /* The CXString type is used to return strings from the interface when * the ownership of that string might differ from one call to the next. * Use clang_getCString() to retrieve the string data and, once finished * with the string data, call clang_disposeString() to free the string. */ typedef struct { const void *data; unsigned private_flags; } CXString; In my limited experience so far it seems FFIExternalStructure is most appropriate So what I've got working is... FFIExternalStructure subclass: #CXString instanceVariableNames: '' classVariableNames: '' poolDictionaries: 'CXStringFlag' package: 'Libclang' CXString class>>fieldsDesc ^ #( void *data; uint private_flags; ) Thus handle of CXString new ==> ByteArray of 8 bytes. However ByteArray and FFIExternalStructure doesn't have any of the smarts of ExternalAddress and FFIExternalReference. So... CXString>>autoRelease self class finalizationRegistry add: self CXString>>finalize self dispose. Transcript crShow: 'debug CXString disposed'. CXString>>dispose self private_flags = CXS_Malloc value "as set by C library" ifTrue: [ self private_flags: CXS_Disposed value. self unguardedDispose. ] ifFalse: [ Error signal: 'Guard prevents double-dispose' ]. CXString>>unguardedDispose self ffiCall: #( void clang_disposeString ( CXString self ) ) module: Libclang > > CXString class>>#finalizeResourceData: version > self ffiCall: #(void clang_disposeString(void *version)) This only seems applicable to FFIExternalReference subclasses. I guess I could copy FFIExternalReference>>autoRelease to CXString. Do you think there would be much advantage to doing this? I see FFIExternalResourceExecutor>>finalize has some session tracking, presumably to avoid freeing dangling references. but I'm not sure about the semantics of #addResource:'s call to #resourceData, and what CXString>>resourceData would return. cheers -ben