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

Reply via email to