<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On 16 March 2017 at 01:44, Eliot Miranda <span dir="ltr"><<a href="mailto:eliot.miranda@gmail.com" target="_blank">eliot.miranda@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"> <br><div dir="ltr">Hi Igor,<br><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Mar 15, 2017 at 2:53 AM, Igor Stasenko <span dir="ltr"><<a href="mailto:siguctua@gmail.com" target="_blank">siguctua@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"> <br><div dir="ltr">Here's my d)<div>implement callback functions in C, or in native form => no need for entering the smalltalk execution => no risk of GC => nothing to worry about.<br><br>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.<br></div></div></blockquote><div><br></div><div>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?</div><div><br></div><div>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.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><br>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 </div><div>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.<br><br>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.<br>I would just add extra interface for using it especially in primitives, so that it <br>1) won't punish primitive writer with too much coding<br>2) automatically handle primitive/callback nesting e.g. <br>primitive1 -> adds roots1 -> calls fn -> callback -> st code -> primitive2 -> adds roots2 -> calls fn2 -> callback2 ... <br><br><br>something like this:<br><br>static initialized once myprimooptable = [ a,b,c].<br>vm pushPrimRoots: myooptable.<br>self do things primitive does.<br>vm popPrimRoots<br><br>or, since we have green threading, then maybe better will be in this form: </div><div><br>rootsId := static initialized once myprimooptable = [ a,b,c].<br>vm pushPrimRoots: myooptable.<br>self do things primitive does.<br>vm popPrimRoots: rootsId.<br></div></div></blockquote><div><br></div><div>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</div><div><br></div><div><span class="gmail-m_5208382041311001762gmail-Apple-tab-span" style="white-space:pre-wrap">   </span>((sourceForm isForm) and: [sourceForm unhibernate])</div><div><span class="gmail-m_5208382041311001762gmail-Apple-tab-span" style="white-space:pre-wrap">            </span>ifTrue: [^ self copyBits].</div><div><span class="gmail-m_5208382041311001762gmail-Apple-tab-span" style="white-space:pre-wrap">     </span>((destForm isForm) and: [destForm unhibernate])</div><div><span class="gmail-m_5208382041311001762gmail-Apple-tab-span" style="white-space:pre-wrap">                </span>ifTrue: [^ self copyBits].</div><div><span class="gmail-m_5208382041311001762gmail-Apple-tab-span" style="white-space:pre-wrap">     </span>((halftoneForm isForm) and: [halftoneForm unhibernate])</div><div><span class="gmail-m_5208382041311001762gmail-Apple-tab-span" style="white-space:pre-wrap">                </span>ifTrue: [^ self copyBits].</div><div><br></div><div>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</div><div><br></div><div><br></div><div><span class="gmail-m_5208382041311001762gmail-Apple-tab-span" style="white-space:pre-wrap">    </span>((sourceForm isForm) and: [sourceForm unhibernate])</div><div><span class="gmail-m_5208382041311001762gmail-Apple-tab-span" style="white-space:pre-wrap">            </span>ifTrue: [^ self perform: #copyBits withArguments: #() inSuperclass: BitBlt].</div><div><span class="gmail-m_5208382041311001762gmail-Apple-tab-span" style="white-space:pre-wrap">   </span>((destForm isForm) and: [destForm unhibernate])</div><div><span class="gmail-m_5208382041311001762gmail-Apple-tab-span" style="white-space:pre-wrap">                </span>ifTrue: [^ self perform: #copyBits withArguments: #() inSuperclass: thisContext method methodClass].</div><div><span class="gmail-m_5208382041311001762gmail-Apple-tab-span" style="white-space:pre-wrap">   </span>((halftoneForm isForm) and: [halftoneForm unhibernate])</div><div><span class="gmail-m_5208382041311001762gmail-Apple-tab-span" style="white-space:pre-wrap">                </span>ifTrue: [^ self perform: #copyBits withArguments: #() inSuperclass: thisContext methodClass].</div><div><br></div><div>but that's ugly.</div><div><br></div><div>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.</div><div><br></div></div></div></div></blockquote><div><br>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.<br>And the above note about "Clément pointed out a really ugly problem" is good example of it :)<br>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.</div></div><br clear="all"><div>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.<br><br></div>-- <br><div class="gmail_signature">Best regards,<br>Igor Stasenko.</div>
</div></div>