> On 07 Sep 2016, at 5:38 , Ben Coman <b...@openinworld.com> wrote:
> 
> On Wed, Sep 7, 2016 at 10:42 PM, Ben Coman <b...@openinworld.com 
> <mailto: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 ??

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

Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail

Reply via email to