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 <[hidden email]> wrote:
_,,,^..^,,,_ best, Eliot |
Free forum by Nabble | Edit this page |