> 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
signature.asc
Description: Message signed with OpenPGP using GPGMail