enumerated return values from FFI callback

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

enumerated return values from FFI callback

Ben Coman
Following on from my "Parting words" at [1] I'd like to add the following...
  FFIExternalEnumerationType >> callbackReturnOn: callbackContext for: anObject
      ^ super callbackReturnOn: callbackContext for: anObject value

but I'm seeking some expert feedback before logging an issue.
For discussion background, here is a reference C program that sets up the framework for a callback that returns an enumeration...

----------example.c
  #include <stdio.h>
  typedef enum {
    A = 1,
    B = 2,
    C = 3
  } CallBackReturnValue;

  CallBackReturnValue callbackFn() {
    return B;
  }

  CallBackReturnValue callout( CallBackReturnValue (*callback)() )
  {
    return callback();
  }

  int main()
  {
    printf("%d\n", callout(callbackFn) );
    return 0;
  }
----------

And validation...
$ gcc  -Wall -Werror  example.c
$ ./a.out 
2
----------

Now after deleting main() and callback(), then compiling to a shared library per [2]...
$ gcc  -c  -Wall  -Werror  -fpic  example.c
$ gcc  -shared  -o passthru.so  example.o
$ cp  example.so   /tmp

the Pharo equivalent is....

FFIExternalEnumeration subclass: #CallBackReturnValue
instanceVariableNames: ''
classVariableNames: ''
package: 'AAAExample'

CallBackReturnValue class >> enumDecl
    ^ #( A 1
      B 2
     C 3 )

CallBackReturnValue class >> initialize
self initializeEnumeration

And evaluate "CallBackReturnValue initialize."


FFILibrary subclass: #Example
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: 'CallBackReturnValue'
package: 'AAAExample'

Example >> unixModuleName
^ '/tmp/example.so'

Example class >> callout: callbackBlock
^ self ffiCall: #( int callout ( FFICallback callbackBlock ) ) module: Example

Example class >> doCallback
| callbackFn |
callbackFn := 
  FFICallback
signature:  #( CallBackReturnValue ( void ) )
block: [ B ].
^ Example callout: callbackFn.

-----
But "Example doCallback"
produces error in VMCallbackContext32>>wordResult: anInteger
where anInteger is aCallBackReturnValue(#B)
rather than 2

I can resolve this using... 
callbackFn := 
   FFICallback
signature:  #( CallBackReturnValue ( void ) )
block: [ B value ]. "<==="

but the original direct use of the enumeration "B" directly is nicer. 
This can be facilitated by moving #value as follows...
  FFIExternalEnumerationType >> callbackReturnOn: callbackContext for: anObject
      ^ super callbackReturnOn: callbackContext for: anObject value "<=="
 
where the existing method for super is...
  FFIExternalType >> callbackReturnOn: callbackContext for: anObject
^ callbackContext wordResult: anObject


Anyone see a problem with that addition?

btw, Would that example be useful for the book?

cheers -ben