File

util-src/managed_pointer.h @ 13665:30a91d819913 13.0

mod_account_activity: Record an account's last activity timestamp This is similar to mod_lastlog/mod_lastlog2. Some functionality was dropped, compared to mod_lastlog2. These features (recording the IP address, or tracking the timestamp of multiple events) are handled better by the mod_audit family of modules. For example, those correctly handle multiple logins, IP address truncation, and data retention policies. The "registered" timestamp from mod_lastlog2 was also dropped, as this has been stored in account_details by Prosody itself since at least 0.12 already.
author Matthew Wild <mwild1@gmail.com>
date Wed, 12 Feb 2025 12:33:45 +0000
parent 12692:b001b0f42512
line wrap: on
line source

/* managed_pointer.h

These macros allow wrapping an allocator/deallocator into an object that is
owned and managed by the Lua garbage collector.

Why? It is too easy to leak objects that need to be manually released, especially
when dealing with the Lua API which can throw errors from many operations.

USAGE
-----

For example, given an object that can be created or released with the following
functions:

  fancy_buffer* new_buffer();
  void free_buffer(fancy_buffer* p_buffer)

You could declare a managed version like so:

  MANAGED_POINTER_ALLOCATOR(new_managed_buffer, fancy_buffer*, new_buffer, free_buffer)

And then, when you need to create a new fancy_buffer in your code:

  fancy_buffer *my_buffer = new_managed_buffer(L);

NOTES
-----

Managed objects MUST NOT be freed manually. They will automatically be
freed during the next GC sweep after your function exits (even if via an error).

The managed object is pushed onto the stack, but should generally be ignored,
but you'll need to bear this in mind when creating managed pointers in the
middle of a sequence of stack operations.
*/

#define MANAGED_POINTER_MT(wrapped_type) #wrapped_type "_managedptr_mt"

#define MANAGED_POINTER_ALLOCATOR(name, wrapped_type, wrapped_alloc, wrapped_free) \
  static int _release_ ## name(lua_State *L) {                                \
  	wrapped_type *p = (wrapped_type*)lua_topointer(L, 1);                 \
  	if(*p != NULL) {                                                      \
	  	wrapped_free(*p);                                             \
	}                                                                     \
  	return 0;                                                             \
  }                                                                           \
  static wrapped_type name(lua_State *L) {                                    \
  	wrapped_type *p = (wrapped_type*)lua_newuserdata(L, sizeof(wrapped_type)); \
  	if(luaL_newmetatable(L, MANAGED_POINTER_MT(wrapped_type)) != 0) {     \
  		lua_pushcfunction(L, _release_ ## name);                      \
  		lua_setfield(L, -2, "__gc");                                  \
  	}                                                                     \
  	lua_setmetatable(L, -2);                                              \
  	*p = wrapped_alloc();                                                 \
  	if(*p == NULL) {                                                      \
  		lua_pushliteral(L, "not enough memory");                      \
  		lua_error(L);                                                 \
  	}                                                                     \
  	return *p;                                                            \
  }