Hi igor

but this is also important that if the user is a nice guy and the
library is acting well we do not have to write a plugin for each
callback, no?
To me forcing people to write a plugin is not nice.
Having solution that would work on normal use case is really nice to have.

Stef


On Thu, Mar 16, 2017 at 12:04 PM, Igor Stasenko <siguc...@gmail.com> wrote:
>
>
> On 16 March 2017 at 01:44, Eliot Miranda <eliot.mira...@gmail.com> wrote:
>>
>>
>> Hi Igor,
>>
>> On Wed, Mar 15, 2017 at 2:53 AM, Igor Stasenko <siguc...@gmail.com> wrote:
>>>
>>>
>>> Here's my d)
>>> implement callback functions in C, or in native form => no need for
>>> entering the smalltalk execution => no risk of GC => nothing to worry about.
>>>
>>> I guess nobody will like it (and will be right, of course ;) , but it is
>>> how it was originally done. I used NativeBoost to implement those callback
>>> functions and they're won't cause any GC problems.
>>
>>
>> yes, I like this.  I was wondering why the callbacks solution was used at
>> all yesterday.  All they do is redirect to the cairo library.  What are the
>> reasons?  Tedious to write and maintain the necessary simple plugin?
>>
>> Clément pointed out a really ugly problem with the current implementation.
>> If one calls back into Pharo from the BitBlt primitives and then reinvokes
>> BitBlt, say by innocently putting a halt in those callbacks, then the
>> original BitBlt's state will get overwritten by the BitBlt invocations in
>> the callback's dynamic exert.  At least with my changes the BitBlt primitive
>> will abort, rather than continue with the invalid state.
>>
>>>
>>> That, of course, gave me solution in this concrete case, but not in
>>> general.. i.e. : if you have another callback that cannot be implemented
>>> na(t)ively, then
>>> you facing similar problems, mainly: how to work around the problem, that
>>> primitive(s) that using callbacks may capture state, that are subject of GC
>>> activity.
>>>
>>> In general , then, i think such primitive should be (re)written in such
>>> way , that it won't get puzzled by GC.. and addGCRoot(s), IMO then best way,
>>> from general interfacing/implementation standpoint.
>>> I would just add extra interface for using it especially in primitives,
>>> so that it
>>> 1) won't punish primitive writer with too much coding
>>> 2) automatically handle primitive/callback nesting e.g.
>>> primitive1 -> adds roots1 -> calls fn -> callback -> st code ->
>>> primitive2 -> adds roots2 -> calls fn2 -> callback2 ...
>>>
>>>
>>> something like this:
>>>
>>> static initialized once myprimooptable = [ a,b,c].
>>> vm pushPrimRoots: myooptable.
>>> self do things primitive does.
>>> vm popPrimRoots
>>>
>>> or, since we have green threading, then maybe better will be in this
>>> form:
>>>
>>> rootsId := static initialized once myprimooptable = [ a,b,c].
>>> vm pushPrimRoots: myooptable.
>>> self do things primitive does.
>>> vm popPrimRoots: rootsId.
>>
>>
>> We kind of have this with the addGCRoot: interface.  But I think it's much
>> better to design the system so that the primitive fails and can be retried.
>> The problem there is having to have the primitive failure code check and
>> roll back.  For example in the copyBits primitive one sees
>>
>> ((sourceForm isForm) and: [sourceForm unhibernate])
>> ifTrue: [^ self copyBits].
>> ((destForm isForm) and: [destForm unhibernate])
>> ifTrue: [^ self copyBits].
>> ((halftoneForm isForm) and: [halftoneForm unhibernate])
>> ifTrue: [^ self copyBits].
>>
>> This is really scruffy because...GrafPort implements copyBits, so this
>> ends up not just retrying the primitive but running a lot more besides.  One
>> way to write it is
>>
>>
>> ((sourceForm isForm) and: [sourceForm unhibernate])
>> ifTrue: [^ self perform: #copyBits withArguments: #() inSuperclass:
>> BitBlt].
>> ((destForm isForm) and: [destForm unhibernate])
>> ifTrue: [^ self perform: #copyBits withArguments: #() inSuperclass:
>> thisContext method methodClass].
>> ((halftoneForm isForm) and: [halftoneForm unhibernate])
>> ifTrue: [^ self perform: #copyBits withArguments: #() inSuperclass:
>> thisContext methodClass].
>>
>> but that's ugly.
>>
>> A mechanism that was in the VM would be nice.  The state for the
>> invocation is saved on the stack.  So there could be a special failure path
>> for this kind of recursive invocation problem; another send-back such as
>> doesNotUnderstand: attemptToReturn:through:.  Note (I'm sure you know this
>> Igor)  that there are primitives such as the ThreadedFFIPlugin's call-out
>> primitive that very much expect to be invoked recursively and have no
>> problem with it.
>>
>
> Yes, i know it. But keep in mind, that reentrant FFI callout mechanism means
> *just* reentrant FFI callout code, it doesn't means that things, it will be
> calling, automagically become reentrant as well.
> And the above note about "Clément pointed out a really ugly problem" is good
> example of it :)
> And since you cannot predict/prevent/pretend/protect every single piece of
> code, that FFI users are going to call, there's no solution to that, unless
> users understand what they do and be aware of pitfalls and consequences.
>
> It is quite easy to say "meh.. your FFI don't works.. go away, come year
> later.. i will use other (put other language/software system there)"..
> mostly because of ignorance, that there's a limits on what FFI can do and
> what can't.
>
> --
> Best regards,
> Igor Stasenko.

Reply via email to