On Mon, Sep 12, 2016 at 6:08 PM, Henrik Johansen <
henrik.s.johan...@veloxit.no> wrote:

>
> On 07 Sep 2016, at 5:38 , Ben Coman <b...@openinworld.com
> <b...@openinworld.com>> wrote:
>
> On Wed, Sep 7, 2016 at 10:42 PM, Ben Coman <b...@openinworld.com> wrote:
>
> On Wed, Sep 7, 2016 at 9:09 PM, Esteban Lorenzano <esteba...@gmail.com>
> wrote:
>
>
> On 07 Sep 2016, at 14:56, Ben Coman <b...@openinworld.com
> <b...@openinworld.com>> wrote:
>
> 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).
>
>
>
> At the bottom of FFIExternalResourceExecutor class comment I read...
>   "Note that in #finalizeResourceData: you cannot
>    access any other properties of your instance,
>    since it is already garbage collected."
>
> But in my experiments it seems okay to access instance variables in
> #finalize.
> For example...
>
> CXString >> autoRelease
>  self class finalizationRegistry add: self
>
> CXString >> finalize
>   Transcript crShow: 'Finalizing CXString ' ; show: self private_flags.
>   self dispose.
>   Transcript show: ', done!'.
>
> CXString >>private_flags
>   "This method was automatically generated"
>   ^handle unsignedLongAt: 5
>
> Libclang getClangVersion autoRelease.
> Smalltalk garbageCollect.
> "==> Finalizing CXString 1, done! "
>
>
> Is this an unlucky coincidence?   Or maybe something changed from NB
> to UFFI?  (There is a reference to NB there)
>
>
> yes, is a coincidence.
> the idea of using #finalizeResourceData: is that you keep minimal
> information (in general, just the handle)… this way we ensure instances
> will
> be collected because we will not have circular references (preventing the
> weakregistry to work).
>
> In general, you can always implement as you did it, but I would prefer the
> #finalizeResourceData: approach, even for structures.
> The only reason it is not implemented is because I didn’t reach the
> necessity, then I just skipped it (not in purpose, it was not in my head
> :P), but now is a good moment to implement it… if you want it :)
>
>
> Thanks for the offer, but hold off for the moment.  I think I actually
> need more than just finalization session management.  To get a real
> displayable string requires calling the clang_getCString() library
> function.  I imagine I'd like to call this from  CXString>>printOn: --
> but this of course this would break after restarting the image.
>
> extern "C" {
> const char *clang_getCString(CXString string) {
>   ....
>   return static_cast<const char *>(string.data);
> }}
>
> typedef struct {
>  const void *data;
>  unsigned private_flags;
> } CXString;
>
> So I think I need to register CXString with SessionManager to set *data
> <-- 0
> on startup.
>
> An alternative might be adding a session variable to CXString,
>    FFIExternalStructure subclass: #CXString
>        instanceVariableNames: 'session'
>        classVariableNames: ''
>        poolDictionaries: 'CXStringFlag'
>        package: 'Libclang'
>
> except doing so crashes when calling....
> getClangVersion
>   ^ self ffiCall: #( CXString clang_getClangVersion () ) module: Libclang
>
>
> So this worked...
>
>  CXString >> resetData
>      handle unsignedLongAt: 1 put: 0.
>
>  CXString class >> startUp: resuming
>      resuming
>          ifTrue: [ self allInstances do: [ :cxs | cxs resetData ] ].
>
>  CXString class >> initialize
>      "self initialize"
>      SessionManager default registerSystemClassNamed: self name
>
>
> Now immediate after a save/restart, doing...
>    CXString allInstances first getString   "==> UndefinedObject(nil)"
> instead of crashing the VM.
>
> Can you see/guess any traps hidden from me? Now I wonder early it is
> practical to prioritise such a reset.  My first thought is at least
> before #printString starts getting called ??
>
>
> For traps, there's the assumption in resetData that pointer stored in
> handle is unsignedLong-sized.
> Shouldn't there be auto-generated accessors for #data you can use instead
> to change the value to Pointer void?
>
> Cheers,
> Henry
>

Good point.  This is the auto-generated accessor...

   data: anObject
handle pointerAt: 1 put: anObject getHandle.

However getHandle is only understood by ExternalObject and
FFIExternalArray, and it seems a bit awkward to create a null on of those
just to zero the handle.

Actually your comment lead me to dicover ExternalAddress>>beNull, which
looked promising.  However the /handle/ of a FFIExternalStructure is a
ByteArray rather than an ExternalAddress (which I guess makes sense). So...

1. maybe push beNull up to ByteArray, and maybe also isNull

2. #beNull implementation is  'self atAllPut: 0'  which is understood by
ByteArray.  In my case I don't care if private_flags is also cleared, so
maybe...
    CXString >> beNull
         handle atAllPut: 0.

cheers -ben

Reply via email to