DemoFFI - Type Mapping

17 March 2016

I've pushed another update to libffidemo, adding the class DemoFFITypeMappedThing and tests. With Pharo v50647 image's UFFI enhancements, all DemoFFI tests pass.

DemoFFITypeMappedThing allows using the C typedef demo_thing in #ffiCall: function signatures:

DemoFFILibrary>>apiAllocByMappedPointerPointer: handle
    "int alloc_by_pointer_pointer(demo_thing**)"
    ^ self ffiCall: #(int alloc_by_pointer_pointer (demo_thing **handle))

The C and Smalltalk signatures match. The ability to specify #ffiCall: function signatures very much like the actual C function signatures should make it easier to create bindings for UFFI.

The magic of DemoFFITypeMappedThing lies in FFIOpaqueObject, and,

DemoFFILibrary class>>initializeTypeMap
    TypeMap := Dictionary newFromPairs: #(
        demo_thing    FFIOpaqueObject

With the above, UFFI maps (a pointer to) demo_thing in #ffiCall: signature to FFIOpaqueObject.

Compare and contrast with the earlier versions of DemoFFI:

DemoFFILibrary>>apiAllocByPointerPointer: handle
    "int alloc_by_pointer_pointer(demo_thing**)"
    ^ self ffiCall: #(int alloc_by_pointer_pointer (DemoFFIExternalObject *handle))

Notice "demo_thing**" in the C signature, and "DemoFFIExternalObject*" in the Smalltalk signature. Conceptually, DemoFFIExternalObject represents a pointer to demo_thing, hence "demo_thing**" == "DemoFFIExternalObject*". Still, the difference in number of asterisks can cause confusion or result in subtle typo's.

Sometimes, it may be worth creating subclasses of FFIOpaqueObject to represent pointers to different C structure types. One may think of FFIOpaqueObject as a generic "void*", and, say, DemoFFIExternalObject as "demo_thing*", or, NBSQLite3DatabaseExternalObject as "sqlite3*" and NBSQLite3StatementExternalObject as "sqlite3_stmt*".

DemoFFI - Garbage Collection

12 March 2016

I've pushed an update to libffidemo, adding the class DemoFFIAutoThing and tests.

DemoFFIAutoThing sends #autoRelease to its handle when said handle is filled by libffidemo with a proper pointer. To support auto-release, DemoFFIExternalObject implements the following class-side method:

finalizeResourceData: resourceData
    DemoFFILibrary uniqueInstance
        ffiCall: #(int free_thing (ExternalAddress resourceData))

Note the C function signature, which is different from DemoFFILibrary>>apiFree:'s:

apiFree: handle
    "int free_thing(demo_thing*)"
    ^ self ffiCall: #(int free_thing (DemoFFIExternalObject handle))

DemoFFIAutoThing>>letGo becomes a no-op. Making it send "super letGo", which effectively calls DemoFFILibrary>>apiFree:, crashes the VM.

DemoFFI - Using Pharo's Unified FFI

9 March 2016

I've published libffidemo, a simple C source file meant to be built as a shared library, and DemoFFI, a Smalltalk package that calls libffidemo to, well, demonstrate Pharo's new Unified FFI. DemoFFI was originally published on Smalltalkhub; Damien Pollet kindly repackaged the Smalltalk code, wrote a Makefile for the C source, etc and now libffidemo is a single self-contained repository with all necessary source files. The unit tests serve as the examples. Known working on Linux and OS X.

FreeBSD FFI Oddity

8 September 2013

Periodically, I build the CogVM from source on FreeBSD. I've prevously mentioned that I had encountered some oddity with FFI on that platform. Still there today.

The following code crashes the VM/image:

| db |
db := SQLiteConnection fileNamed: '/tmp/x.db'.
db withResultForQuery: 'select * from a;'
  do: [ :result |
    result do: [ :row |
      Transcript show: row asString; cr ]].
db close.

The oddity is that one particular version of the SqueakFFIPrims plugin works. Several other versions that I've built all fail. Overwriting the failed versions of the plugin with the known-working one allows that particular crashing VM's FFI to work.

-rwxr-xr-x  1 root  wheel  77035 Oct 21  2012 ./4.0-2562/SqueakFFIPrims
-rwxr-xr-x  1 root  wheel  77035 Oct 21  2012 ./4.0-2586/SqueakFFIPrims
-rwxr-xr-x  1 root  wheel  74637 Nov 11  2012 ./4.0-2586/SqueakFFIPrims.broken
-rwxr-xr-x  1 root  wheel  77035 Oct 21  2012 ./4.0-2779/SqueakFFIPrims

The working one appears here three times. I'm running FreeBSD 8.3.