diff --git a/doc/ext_ffi_api.html b/doc/ext_ffi_api.html index e865a5f7..222c580e 100644 --- a/doc/ext_ffi_api.html +++ b/doc/ext_ffi_api.html @@ -78,6 +78,9 @@ corresponding ctype.
  • ct — A C type specification which can be used for most of the API functions. Either a cdecl, a ctype or a cdata serving as a template type.
  • +
  • cb — A callback object. This is a C data object +holding a special function pointer. Calling this function from +C code runs an associated Lua function.
  • VLA — A variable-length array is declared with a ? instead of the number of elements, e.g. "int[?]". The number of elements (nelem) must be given when it's @@ -473,6 +476,31 @@ Contains the target architecture name. Same contents as jit.arch.

    +

    Methods for Callbacks

    +

    +The C types for callbacks +have some extra methods: +

    + +

    cb:free()

    +

    +Free the resources associated with a callback. The associated Lua +function is unanchored and may be garbage collected. The callback +function pointer is no longer valid and must not be called anymore +(it may be reused by a subsequently created callback). +

    + +

    cb:set(func)

    +

    +Associate a new Lua function with a callback. The C type of the +callback and the callback function pointer are unchanged. +

    +

    +This method is useful to dynamically switch the receiver of callbacks +without creating a new callback each time and registering it again (e.g. +with a GUI library). +

    +

    Extended Standard Library Functions

    The following standard library functions have been extended to work diff --git a/doc/ext_ffi_semantics.html b/doc/ext_ffi_semantics.html index 79f25510..7e140e27 100644 --- a/doc/ext_ffi_semantics.html +++ b/doc/ext_ffi_semantics.html @@ -297,10 +297,12 @@ arguments to C calls: stringstring data →const char[] +functioncreate callback →C function type + tabletable initializerArray - + tabletable initializerstruct/union - + cdatacdata payload →C type

    @@ -821,6 +823,127 @@ cdata objects are indistinguishable from pointers returned by C functions (which is one of the reasons why the GC cannot follow them).

    +

    Callbacks

    +

    +The LuaJIT FFI automatically generates special callback functions +whenever a Lua function is converted to a C function pointer. This +associates the generated callback function pointer with the C type +of the function pointer and the Lua function object (closure). +

    +

    +This can happen implicitly due to the usual conversions, e.g. when +passing a Lua function to a function pointer argument. Or you can use +ffi.cast() to explicitly cast a Lua function to a +C function pointer. +

    +

    +Currently only certain C function types can be used as callback +functions. Neither C vararg functions nor functions with +pass-by-value aggregate argument or result types are supported. There +are no restrictions for the kind of Lua functions that can be called +from the callback — no checks for the proper number of arguments +are made. The return value of the Lua function will be converted to the +result type and an error will be thrown for invalid conversions. +

    +

    +It's allowed to throw errors across a callback invocation, but it's not +advisable in general. Do this only if you know the C function, that +called the callback, copes with the forced stack unwinding and doesn't +leak resources. +

    + +

    Callback resource handling

    +

    +Callbacks take up resources — you can only have a limited number +of them at the same time (500 - 1000, depending on the +architecture). The associated Lua functions are anchored to prevent +garbage collection, too. +

    +

    +Callbacks due to implicit conversions are permanent! There is no +way to guess their lifetime, since the C side might store the +function pointer for later use (typical for GUI toolkits). The associated +resources cannot be reclaimed until termination: +

    +
    +ffi.cdef[[
    +typedef int (__stdcall *WNDENUMPROC)(void *hwnd, intptr_t l);
    +int EnumWindows(WNDENUMPROC func, intptr_t l);
    +]]
    +
    +-- Implicit conversion to a callback via function pointer argument.
    +local count = 0
    +ffi.C.EnumWindows(function(hwnd, l)
    +  count = count + 1
    +end, 0)
    +-- The callback is permanent and its resources cannot be reclaimed!
    +-- Ok, so this may not be a problem, if you do this only once.
    +
    +

    +Note: this example shows that you must properly declare +__stdcall callbacks on Windows/x86 systems. The calling +convention cannot be automatically detected, unlike for +__stdcall calls to Windows functions. +

    +

    +For some use cases it's necessary to free up the resources or to +dynamically redirect callbacks. Use an explicit cast to a +C function pointer and keep the resulting cdata object. Then use +the cb:free() +or cb:set() methods +on the cdata object: +

    +
    +-- Explicitly convert to a callback via cast.
    +local count = 0
    +local cb = ffi.cast("WNDENUMPROC", function(hwnd, l)
    +  count = count + 1
    +end)
    +
    +-- Pass it to a C function.
    +ffi.C.EnumWindows(cb, 0)
    +-- EnumWindows doesn't need the callback after it returns, so free it.
    +
    +cb:free()
    +-- The callback function pointer is no longer valid and its resources
    +-- will be reclaimed. The created Lua closure will be garbage collected.
    +
    + +

    Callback performance

    +

    +Callbacks are slow! First, the C to Lua transition itself +has an unavoidable cost, similar to a lua_call() or +lua_pcall(). Argument and result marshalling add to that cost. +And finally, neither the C compiler nor LuaJIT can inline or +optimize across the language barrier and hoist repeated computations out +of a callback function. +

    +

    +Do not use callbacks for performance-sensitive work: e.g. consider a +numerical integration routine which takes a user-defined function to +integrate over. It's a bad idea to call a user-defined Lua function from +C code millions of times. The callback overhead will be absolutely +detrimental for performance. +

    +

    +It's considerably faster to write the numerical integration routine +itself in Lua — the JIT compiler will be able to inline the +user-defined function and optimize it together with its calling context, +with very competitive performance. +

    +

    +As a general guideline: use callbacks only when you must, because +of existing C APIs. E.g. callback performance is irrelevant for a +GUI application, which waits for user input most of the time, anyway. +

    +

    +For new designs avoid push-style APIs (C function repeatedly +calling a callback for each result). Instead use pull-style APIs +(call a C function repeatedly to get a new result). Calls from Lua +to C via the FFI are much faster than the other way round. Most well +designed libraries already use pull-style APIs (read/write, get/put). +

    +

    C Library Namespaces

    A C library namespace is a special kind of object which allows @@ -1002,7 +1125,6 @@ Other missing features: