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> 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 ??

cheers -ben

Reply via email to