lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Am 22.03.2016 um 07:39 schröbte Daurnimator:
On 22 March 2016 at 08:34, Tim Hill <drtimhill@gmail.com> wrote:

[A] Design the C function to not use state, or not call any Lua APIs while it holds resources/state. This results in very strange contorted code even when it is possible.

[B] Compile Lua for C++ so that it uses exceptions and not longjmp, and then use try() clauses to inject “finally” handling to clean up resources. This of course is only viable when C++ is available, and assumes that Lua uses exceptions in a manner that allows that to work (I’ve not studied this in detail).

[C] Allocate the stateful structure as a Lua full userdata, and then use __gc() to perform cleanup when Lua collects the abandoned structure (essentially a dispose() model).

[D] Have a dummy “outer” C function that then does a lua_pcall() into the (inner) real C function, so that Lua errors are caught and the state can be cleaned up before the outer C function either returns or re-throws the Lua error.


I'm usually okay with A, C or D.
However there is one exception: APIs that allocate an object for you.
e.g. imagine an API that returns a freshly allocated string for you,
e.g. it does (in C) `return strdup(buffer_on_stack)`

==> How do you bind this to lua?
   - Using lua_pushstring directly would throw on OOM, and not free the string.
   - There is no way to reliably pre-allocate space for a string
(ALTERNATIVE FIX POSSIBLE HERE)
   - Allocating an object to use __gc on it isn't fast or flexible.
     It also changes your coding style as it's hard to share a
metatable between functions.

Use a lightuserdata to an internal static variable as a key in the registry?! If you store the cleanup function as a function pointer in the userdata, you only need one metatable for all your temporary resources.

   - Having a helper function and using lua_pcall is really the only
way I can see.

For pure memory resources approach C works well (with some helper functions).

    void** p = moon_resource( L, free );
    *p = strdup( somestring );
    lua_pushstring( L, *p ); /* may throw, don't care */
    moon_release( L, p ); /* don't wait for the GC if not necessary */

I described `moon_resource` and `moon_release` in an earlier post[1].

It becomes more problematic if you really can't wait for cleanup via GC even in the (unlikely) error path. I've only had this situation once, and I used nested C functions, `lua_pcall`, and a preprocessor macro. Maybe we can make it less awkward using some helper functions as well. We should try that before we add to the Lua API.


Philipp

  [1]:  http://lua-users.org/lists/lua-l/2016-03/msg00002.html