Skip to content
This repository has been archived by the owner on Jan 5, 2023. It is now read-only.

Using with UFFI

Pablo Tesone edited this page Jul 20, 2020 · 2 revisions

Pharo Threaded FFI (TFFI) plugin can be correctly used with UFFI (Unified FFI). TFFI implements a backend for UFFI. All the required configuration is done through the FFILibraries.

Configuring the FFILibrary

The FFILibrary instances represent the configuration of a given library that is accessed from Pharo. So, before we can use UFFI we have to describe the library that we are pointing to. Each library can have different configurations, and as a result, each one can use different backends.

Each class implementing FFI methods has to implement #ffiLibrary returning the library description to use. This is the usual configuration used in UFFI.

Ex:

ffiLibrary

	^ TFTestLibraryUsingWorker uniqueInstance

Setting the Library to use TFFI

To select the backend to use in UFFI is just needed to set-up the callout class to use, in the case of TFFI we need to redefine the method #calloutAPIClass in our FFILibrary. We need to use TFCalloutAPI. Doing so, automatically all the FFI calls in the class will be using the TFFI backend.

Attention: If you have already done calls with the class using this library with an old configuration it requires to restart the image to clean up the caches of UFFI.

How to change the TFCalloutAPI of a particular FFILibrary

calloutAPIClass

	^ TFCalloutAPI 

Selecting the Runner to use

In the current state, TFFI supports three running strategies:

  • TFSameThreadRunner: this strategy runs the callouts in the same system thread than the VM is running. This strategy implements the same behavior that SqueakFFI has. Performing calls with this strategy blocks the execution of the VM until the callout is ended.

  • TFWorker: This strategy runs the callouts using a separate thread of the VM, allowing the VM to continue executing other Smalltalk processes. This strategy can use a common thread or a different thread per library.

  • TFMainThreadRunner: this strategy runs the callouts in the main thread of the application. This runner is only working when the VM is launched in a thread different than the main one (for example, to use alternative UI libraries).

For more details of the differences and the reasons behind doing one or the other, please refer to:

The selection of the Runner is done through the redefinition of the method runner in our FFILibrary

runner 
	
	^ TFWorker default

You can check examples of a library implemented that uses TFFI in the classes TFTestLibraryUsingSameThreadRunner and TFTestLibraryUsingSameThreadRunner from the TFFI tests.

Using Callbacks with TFFI

For creating callbacks that uses the TFFI backend is as easy as with the callouts. We have two options:

  1. Creating anonymous callbacks.
  2. Creating callbacks through a class.

Please pay attention, that it does not matter the way the callback it is created; it should be referenced correctly during all its life-time in the external library. If the callback is collected during a Garbage Collection, a memory access error will occur.

Anonymous Callbacks

Callbacks can be created from a function signature and a block, to do so it is required to use the message newCallbackWithSignature:block: in a class that has a correctly configured FFILibrary; depending the FFILibrary used it will select the backend to use.

Ex:

	callback := self
		newCallbackWithSignature: #(float (int a, float b))
		block: [ :a :b | a + b ].

Callbacks through a Class

To reuse behavior in the callbacks it is normal in UFFI to make classes extending FFICallback to implement them. Selecting the backend to use is the same than with the FFILibraries, we need to override the calloutAPIClass method

calloutAPIClass

	^ TFCalloutAPI