Mercurial > prosody-hg
comparison util-src/managed_pointer.h @ 12692:b001b0f42512
util-src: Add new utility header managed_pointer.h
The macros in this header allow creation of GC-managed objects from manually-
managed C alloc/free APIs.
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Fri, 01 Jul 2022 15:11:08 +0100 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 12691:90d90b540b6b | 12692:b001b0f42512 |
|---|---|
| 1 /* managed_pointer.h | |
| 2 | |
| 3 These macros allow wrapping an allocator/deallocator into an object that is | |
| 4 owned and managed by the Lua garbage collector. | |
| 5 | |
| 6 Why? It is too easy to leak objects that need to be manually released, especially | |
| 7 when dealing with the Lua API which can throw errors from many operations. | |
| 8 | |
| 9 USAGE | |
| 10 ----- | |
| 11 | |
| 12 For example, given an object that can be created or released with the following | |
| 13 functions: | |
| 14 | |
| 15 fancy_buffer* new_buffer(); | |
| 16 void free_buffer(fancy_buffer* p_buffer) | |
| 17 | |
| 18 You could declare a managed version like so: | |
| 19 | |
| 20 MANAGED_POINTER_ALLOCATOR(new_managed_buffer, fancy_buffer*, new_buffer, free_buffer) | |
| 21 | |
| 22 And then, when you need to create a new fancy_buffer in your code: | |
| 23 | |
| 24 fancy_buffer *my_buffer = new_managed_buffer(L); | |
| 25 | |
| 26 NOTES | |
| 27 ----- | |
| 28 | |
| 29 Managed objects MUST NOT be freed manually. They will automatically be | |
| 30 freed during the next GC sweep after your function exits (even if via an error). | |
| 31 | |
| 32 The managed object is pushed onto the stack, but should generally be ignored, | |
| 33 but you'll need to bear this in mind when creating managed pointers in the | |
| 34 middle of a sequence of stack operations. | |
| 35 */ | |
| 36 | |
| 37 #define MANAGED_POINTER_MT(wrapped_type) #wrapped_type "_managedptr_mt" | |
| 38 | |
| 39 #define MANAGED_POINTER_ALLOCATOR(name, wrapped_type, wrapped_alloc, wrapped_free) \ | |
| 40 static int _release_ ## name(lua_State *L) { \ | |
| 41 wrapped_type *p = (wrapped_type*)lua_topointer(L, 1); \ | |
| 42 if(*p != NULL) { \ | |
| 43 wrapped_free(*p); \ | |
| 44 } \ | |
| 45 return 0; \ | |
| 46 } \ | |
| 47 static wrapped_type name(lua_State *L) { \ | |
| 48 wrapped_type *p = (wrapped_type*)lua_newuserdata(L, sizeof(wrapped_type)); \ | |
| 49 if(luaL_newmetatable(L, MANAGED_POINTER_MT(wrapped_type)) != 0) { \ | |
| 50 lua_pushcfunction(L, _release_ ## name); \ | |
| 51 lua_setfield(L, -2, "__gc"); \ | |
| 52 } \ | |
| 53 lua_setmetatable(L, -2); \ | |
| 54 *p = wrapped_alloc(); \ | |
| 55 if(*p == NULL) { \ | |
| 56 lua_pushliteral(L, "not enough memory"); \ | |
| 57 lua_error(L); \ | |
| 58 } \ | |
| 59 return *p; \ | |
| 60 } | |
| 61 |
