[squeak-dev] Plugin Repository Needed [was FFI callbacks]

Chris Cunnington brasspen at gmail.com
Fri Sep 4 01:05:07 UTC 2015


This community needs a repository for plugins. A directory at 
http://ftp.squeak.org ought to do it.

If I want to try Alien I need the plugin. Where am I going to get that? 
I could get VMMaker, read NewSqueakIA32ABIPlugin three times to see it 
is not saying Newspeak and realize it compiles a plugin called IA32ABI, 
which - coincidentally - is the name of the plugin the error Alien 
exampleCqsort will gives me. (NewSqueakIA32ABIPlugin class>> moduleName 
returns IA32ABI).

Does anybody know what the Genie plugin does? Does Paul DeBrucker need 
to store a BerkeleyDB plugin dll he got by emailing somebody on GitHub?

If I understand this correctly, if such a directory existed, then all a 
person would need to do to try the above Alien code would be to download 
a pre-compiled plugin from - say - 
http://ftp.squeak/plugins/Alien/fooVersion, put it in their VM directory 
and start the image. Then check with SmalltalkImage current 
listLoadedModules to see if you're ready to go.

I nominate Fabio Niephaus to be the person the community can send 
pre-compiled plugins for inclusion in such a directory. Eliot's been 
banging away about Alien for some time [1]. If a person could go, get 
the plugin and give the code shot, he could have more productive 
conversations about Alien.

So, if, Eliot, you have a pre-compiled plugin for Alien, perhaps in an 
idle moment, you could email it to Fabio? And when, Fabio, you've 
created the directory in http://ftp.squeak.org you could announce it 
here on Squeak-dev?

FWIW,

Chris

[1] http://wiki.squeak.org/squeak/uploads/6100/

On 2015-09-03 7:07 PM, Eliot Miranda wrote:
> Hi Craig,
>
>     you need Alien-eem.24
>
> Here's Alien class>>exampleCqsort
> "Call the libc qsort function (which requires a callback)."
> "Alien exampleCqsort"
> "(Time millisecondsToRun: [100 timesRepeat: [Alien exampleCqsort]]) / 
> 100.0"
> | cb rand nElements sizeofDouble values orig sort |
> rand := Random new.
> values := Alien newC: (nElements := 100) * (sizeofDouble := 8).
> 1 to: values dataSize by: sizeofDouble do:
> [:i| values doubleAt: i put: rand next].
> orig := (1 to: values dataSize by: sizeofDouble) collect: [:i| values 
> doubleAt: i].
> cb := Callback
> signature:  #(int (*)(const void *, const void *))
> block: [ :arg1 :arg2 | ((arg1 doubleAt: 1) - (arg2 doubleAt: 1)) sign].
> (Alien lookup: 'qsort' inLibrary: Alien libcName)
> primFFICallResult: nil
> with: values pointer
> with: nElements
> with: sizeofDouble
> with: cb thunk.
> sort := (1 to: values dataSize by: sizeofDouble) collect: [:i| values 
> doubleAt: i].
> values free.
> ^orig -> sort
>
> The above example uses Alien to make the callout.  To use it with the 
> FFI simply pass cb pointer as the argument as is done above.
>
>
> Implementation:
>
> The way that it works is in two parts
> - the VM passes up a pointer to a structure from which all arguments, 
> stacked and in registers (because the VM has copied the register args 
> into the struct) can be accessed, and through which the result can be 
> returned.
> - the image level provides marshalling methods that match the 
> signature in the callback
>
> So e.g. with a callback of
> Callback
> signature:  #(int (*)(const void *, const void *))
> block: [ :arg1 :arg2 | ((arg1 doubleAt: 1) - (arg2 doubleAt: 1)) sign]
> the marshalling methods are in Callback's signature protocol:
>
> Callback>>voidstarvoidstarRetint: callbackContext sp: spAlien
> <signature: #(int (*)(const void *, const void *)) abi: 'IA32'>
> ^callbackContext wordResult:
> (block
> value: (Alien forPointer: (spAlien unsignedLongAt: 1))
> value: (Alien forPointer: (spAlien unsignedLongAt: 5)))
>
> where spAlien is an Alien pointing to a VMCallbackContext32.
>
> For ARM support we would add
>
> Callback>>voidstarvoidstarRetint: callbackContext sp: spAlien 
> intRegArgs: regsAlien
> <signature: #(int (*)(const void *, const void *)) abi: 'ARMV5'>
> ^callbackContext wordResult:
> (block
> value: (Alien forPointer: (regsAlien unsignedLongAt: 1))
> value: (Alien forPointer: (regsAlien unsignedLongAt: 5)))
>
> Basically the idea is that the selector of the method doesn't matter 
> except for the number of arguments.  What's important is the pragma 
> which defines the signature and the ABI for which this is a valid 
> marshalling method.
>
> When the callback is instantiated, Callback introspects to find the 
> marshalling method that matches the signature.  If one doesn't already 
> exist you can write one.  Hopefully we'll write an ABI compiler that 
> will automatically generate these marshalling methods according to the 
> platform's ABI, but for now its a manual process.  But at least it's 
> open and flexible.  When the callback is invoked the evaluator is 
> performed with the current callbackContext and pointer(s) to the 
> arguments. There is a 32-bit and a 64-bit callback context, and it can 
> have a stack pointer, integer register args and floating point 
> register args.  So it's general enough for any callback.
>
> To pass back the result, a value is assigned into the struct via the 
> accessor in the marshalling method and control returns to teh point 
> where teh callback comes in, and this uses a primitive to return.  
> Inside the callbackCOntext is a jmpbuf from a setjmp.  The primitive 
> longjmp's back to the entry point in the VM which extracts the result 
> and the code for the kind of result and returns:
>
> Callback class>>invokeCallbackContext: vmCallbackContextAddress 
> "<Integer>" "^<FFICallbackReturnValue>"
> "The low-level entry-point for callbacks sent from the VM/IA32ABI plugin.
> Return via primReturnFromContext:through:.  thisContext's sender is the
> call-out context."
> | callbackAlien type |
> callbackAlien := (Smalltalk wordSize = 4
> ifTrue: [VMCallbackContext32]
> ifFalse: [VMCallbackContext64])
> atAddress: vmCallbackContextAddress.
> [type := Callback evaluateCallbackForContext: callbackAlien]
> ifCurtailed: [self error: 'attempt to non-local return across a 
> callback'].
> type ifNil:
> [type := 1. callbackAlien wordResult: -1].
> callbackAlien primReturnAs: type fromContext: thisContext
>
> On Thu, Sep 3, 2015 at 5:22 AM, Craig Latta <craig at netjam.org 
> <mailto:craig at netjam.org>> wrote:
>
>
>     Hi all--
>
>          I'd like to use a C shared library via FFI from Squeak or Pharo.
>     Specifically, I want to call a C function which takes as one of its
>     parameters a pointer to an array of callback function addresses. Does
>     one of the FFI approaches floating around handle that, and provide a
>     relatively pleasant mapping between Smalltalk block closures and C
>     callback function addresses?
>
>          I was doing this so far in GemStone, but apparently its FFI only
>     supports passing callback function addresses one at a time as direct
>     parameters of C callouts. I suppose I could write a wrapper C library
>     around the one I really want to use, that provides the callback setup
>     interface that GemStone expects, but whenever I have to write actual C
>     code I start to think "Hm, why don't I just use a Smalltalk VM for
>     which
>     I have the source?" :)  All the fancy distributed object-database
>     stuff
>     that my project also wants can wait for a bit.
>
>
>          thanks!
>
>     -C
>
>     --
>     Craig Latta
>     netjam.org <http://netjam.org>
>     +31 6 2757 7177 <tel:%2B31%20%20%206%202757%207177> (SMS ok)
>     + 1 415 287 3547 <tel:%2B%201%20415%20%20287%203547> (no SMS)
>
>
>
>
>
> -- 
> _,,,^..^,,,_
> best, Eliot
>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20150903/15feca28/attachment.htm


More information about the Squeak-dev mailing list