From 71d00a56dbab6c29c0346093dbe530d7b7608be4 Mon Sep 17 00:00:00 2001
From: Mike Pall
+The C types for callbacks +have some extra methods: +
+ ++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). +
+ ++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). +
+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:
@@ -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).
++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. +
+ ++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.
+
+
++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). +
+A C library namespace is a special kind of object which allows @@ -1002,7 +1125,6 @@ Other missing features: