c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen#ifndef MODULE_CONTEXT_H
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen#define MODULE_CONTEXT_H
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
807138876ab6d04b4369e33cf92cb6fd40744c61Timo Sirainen#include "array.h"
807138876ab6d04b4369e33cf92cb6fd40744c61Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen/*
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen This is a bit complex to use, but it prevents using wrong module IDs
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen in module_contexts arrays.
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen ---------
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen The main structure is implemented like this:
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct STRUCT_NAME_module_register {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen unsigned int id;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen };
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen union STRUCT_NAME_module_context {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct STRUCT_NAME_module_register *reg;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen // it's allowed to have some structure here so it won't waste space.
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen // for example: struct STRUCT_NAME_vfuncs super;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen };
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct STRUCT_NAME {
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(union STRUCT_NAME_module_context *) module_contexts;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen };
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen extern struct STRUCT_NAME_module_register STRUCT_NAME_module_register;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen ---------
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen The usage in modules goes like:
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen static MODULE_CONTEXT_DEFINE(mymodule_STRUCT_NAME_module,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen &STRUCT_NAME_module_register);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct mymodule_STRUCT_NAME {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen union STRUCT_NAME_module_context module_ctx;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen // module-specific data
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen };
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct mymodule_STRUCT_NAME *ctx = i_new(...);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT_SET(obj, mymodule_STRUCT_NAME_module, ctx);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct mymodule_STRUCT_NAME *ctx =
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT(obj, mymodule_STRUCT_NAME_module);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen*/
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define OBJ_REGISTER(obj) \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen ((**(obj)->module_contexts.v)->reg)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define OBJ_REGISTER_COMPATIBLE(obj, id_ctx) \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(OBJ_REGISTER(obj), (id_ctx).reg)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define MODULE_CONTEXT(obj, id_ctx) \
139143f1b798472438b813343a48601f1c564060Sergey Kitov (module_get_context_id(&(id_ctx).id) < array_count(&(obj)->module_contexts) ? \
139143f1b798472438b813343a48601f1c564060Sergey Kitov (*((void **)array_idx_modifiable(&(obj)->module_contexts, \
139143f1b798472438b813343a48601f1c564060Sergey Kitov module_get_context_id(&(id_ctx).id)) + \
139143f1b798472438b813343a48601f1c564060Sergey Kitov OBJ_REGISTER_COMPATIBLE(obj, id_ctx))) : NULL)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
a813184174d2ef1692e93ac13db99608b010f811Aki Tuomi/* Will crash if context is missing. This is mainly used to simplify code and
a813184174d2ef1692e93ac13db99608b010f811Aki Tuomi keep static analyzers happy. This syntax discards result of i_panic and
a813184174d2ef1692e93ac13db99608b010f811Aki Tuomi returns NULL instead to keep compilers happy. */
a813184174d2ef1692e93ac13db99608b010f811Aki Tuomi#define MODULE_CONTEXT_REQUIRE(obj, id_ctx) \
a813184174d2ef1692e93ac13db99608b010f811Aki Tuomi (module_get_context_id(&(id_ctx).id) < array_count(&(obj)->module_contexts) ? \
a813184174d2ef1692e93ac13db99608b010f811Aki Tuomi (*((void **)array_idx_modifiable(&(obj)->module_contexts, \
a813184174d2ef1692e93ac13db99608b010f811Aki Tuomi module_get_context_id(&(id_ctx).id)) + \
a813184174d2ef1692e93ac13db99608b010f811Aki Tuomi OBJ_REGISTER_COMPATIBLE(obj, id_ctx))) : (i_panic("Module context " #id_ctx " missing"), NULL))
a813184174d2ef1692e93ac13db99608b010f811Aki Tuomi
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#ifdef HAVE_TYPEOF
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen# define MODULE_CONTEXT_DEFINE(_name, _reg) \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct _name { \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct module_context_id id; \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen typeof(_reg) reg; \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen } _name
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen# define MODULE_CONTEXT_INIT(_reg) \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen { { &(_reg)->id, 0, FALSE }, NULL }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#else
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen# define MODULE_CONTEXT_DEFINE(_name, _reg) \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct _name { \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct module_context_id id; \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen } _name
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen# define MODULE_CONTEXT_INIT(_reg) \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen { { &(_reg)->id, 0, FALSE } }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#endif
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define MODULE_CONTEXT_DEFINE_INIT(_name, _reg) \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT_DEFINE(_name, _reg) = MODULE_CONTEXT_INIT(_reg)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstruct module_context_id {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen unsigned int *module_id_register;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen unsigned int module_id;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen bool module_id_set;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen};
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic inline unsigned int module_get_context_id(struct module_context_id *id)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (!id->module_id_set) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen id->module_id = *id->module_id_register;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen id->module_id_set = TRUE;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen *id->module_id_register += 1;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return id->module_id;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define MODULE_CONTEXT_SET_FULL(obj, id_ctx, ctx, module_ctx) STMT_START { \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen void *_module_tmp = ctx + \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(module_ctx, \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen (**(obj)->module_contexts.v)) + \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen OBJ_REGISTER_COMPATIBLE(obj, id_ctx); \
684844265f01abd1da5864647a6dd69cc1bbbc71Timo Sirainen array_idx_set_i(&(obj)->module_contexts.arr, \
793f2c5e5bf9b4fcdfbedff89e6d1f26aebfd604Timo Sirainen module_get_context_id(&(id_ctx).id), &_module_tmp); \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen } STMT_END
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define MODULE_CONTEXT_SET(obj, id_ctx, context) \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT_SET_FULL(obj, id_ctx, context, &(context)->module_ctx)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define MODULE_CONTEXT_SET_SELF(obj, id_ctx, context) \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen MODULE_CONTEXT_SET_FULL(obj, id_ctx, context, context)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define MODULE_CONTEXT_UNSET(obj, id_ctx) \
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen array_idx_clear(&(obj)->module_contexts, (id_ctx).id.module_id)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#endif