The CALLBACK mechanism provides the facility to wrap Forth definitions in code which is callable by OS X.
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 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.
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:
USER
variables are initialised:
S0
, R0
, BASE
, IP-HANDLE
, OP-HANDLE
,
ThreadExit?
, ThreadTCB
, and ThreadSync
.