Callback functions

The CALLBACK mechanism provides the facility to wrap Forth definitions in code which is callable by OS X.

Simple CALLBACK functions

variable ip-default     \ -- addr
Holds the default value of IP-HANDLE that is set for each CALLBACK entry.

variable op-default     \ -- addr
Holds the default value of OP-HANDLE that is set for each CALLBACK entry.

: set-callback  \ xt callback --
Make the xt be the action of the callback.

: callback,     \ #in #out -- address
Lay down a callback data structure. The first cell contains the address of the entry point. The address of the data structure is returned.

: CALLBACK:     \ #in #out "<name>" -- ; -- a-addr
Create a callback function. #IN and #OUT refer to the number of input and output parameters required for the callback. When the definition <name>is executed it will return the address of the callback function. For example

  2 1 CallBack: Foo

creates a callback named Foo with two inputs, and one output. Executing Foo returns the entry point used by OS X. To use it, pass Foo as the entry point required by OS X, e.g as the address of a task action. Foo is built to use the "C" calling convention.

  ' FooAction to-callback foo

Having defined an action for the callback, you can now use the callback as if it was a C or assembler function called by the operating system.

: CallProc:     \ #in #out "<name>" -- ; -- entry
Create a callback function and start compilation of its action. #IN and #OUT refer to the number of input and output parameters required for the callback. When the definition <name>is executed it will return the entry point address of the callback function.


4 1 CallProc: <name>  \ #in #out -- ; -- entry
\ Callback action ; x1 x2 x3 x4 -- op
  ...
;
<name>   \ returns entry point address

: CB:           \ xt #in "<name>" -- ; -- entry
Create a callback function that executes the action of xt. action. #IN refers to the number of input parameters. The number of output parameters is 1. When <name>is executed it will return the entry point address of the callback function. This word is provided to ease porting from other Forth systems.


:noname  ( a b c -- d )
...
; 3 CB: <name>

: to-callback   \ xt <"name"> --
Assign an XT as the action of a defined callback. This word is state smart.

An example. Creating a signal handler

An OS X signal handler has the prototype

  void sa_siginfo( int signum, siginfo_t * siginfo, ucontext_t * uc );

As far as Forth is concerned we need to execute a Forth word that receives three parameters and returns none.

 (SigTrap)   \ signum *siginfo *ucontext --

The code fragment below achives this.


3 0 callback: SigTrap  \ -- addr
\ executing SigTrap in Forth returns the C entry point.

: (SigTrap)  \ signum *siginfo *ucontext --
\ Action of SigTrap.
  nip                                   \ discard siginfo
  cr
  cr ." Signal number " swap .sigName
  uc.mcontext                           \ point at CPU context
  cr ." at address " dup sc.EIP @ dup .dword
     ." , probably in " ip>nfa .name
  cr
  ['] SigThrow swap sc.EIP !            \ force return to SigThrow
;
assign (SigTrap) to-callback SigTrap

The callback entry code provides you with a default I/O device and sets BASE to decimal. It does not set up a default THROW handler. If your callbacks must cope with exceptions, you must provide a top-level CATCH yourself.

Implementation notes

Callbacks are (usually) C functions. In the case of VFX Forth these functions create a Forth environment with two or more stacks, a USER area and so on. In a GUI environment, callbacks are very common, and so must be established and discarded quickly. The easiest place to do this is to use the calling C stack and build the Forth stacks and data areas on the C stack. This has several consequences: