module-context.h revision c25356d5978632df6203437e1953bcb29e0c736f
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen#ifndef MODULE_CONTEXT_H
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen#define MODULE_CONTEXT_H
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
cc77c1cfe8d072765f793474f49fecd897525466Stephan Bosch/*
cc77c1cfe8d072765f793474f49fecd897525466Stephan Bosch This is a bit complex to use, but it prevents using wrong module IDs
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen in module_contexts arrays.
a24665de9d5c773115a5918e60ed587aafe67d5cTimo Sirainen
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen ---------
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen The main structure is implemented like this:
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct STRUCT_NAME_module_register {
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen unsigned int id;
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen };
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen union STRUCT_NAME_module_context {
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen struct STRUCT_NAME_module_register *reg;
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen // it's allowed to have some structure here so it won't waste space.
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen // for example: struct STRUCT_NAME_vfuncs super;
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen };
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen struct STRUCT_NAME {
88b8c5db9f66bdbb70d274d8592947716f364c36Timo Sirainen ARRAY_DEFINE(module_contexts, union STRUCT_NAME_module_context *);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen };
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen extern struct STRUCT_NAME_module_register STRUCT_NAME_module_register;
f40e6ef5190f68c2fd0e94c0b001bdf7d160236aTimo Sirainen
f40e6ef5190f68c2fd0e94c0b001bdf7d160236aTimo Sirainen ---------
f86c599ead3602dc2d63a473cc13c1119978f538Timo Sirainen The usage in modules goes like:
f86c599ead3602dc2d63a473cc13c1119978f538Timo Sirainen
f86c599ead3602dc2d63a473cc13c1119978f538Timo Sirainen static MODULE_CONTEXT_DEFINE(mymodule_STRUCT_NAME_module,
f86c599ead3602dc2d63a473cc13c1119978f538Timo Sirainen &STRUCT_NAME_module_register);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct mymodule_STRUCT_NAME {
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen union STRUCT_NAME_module_context module_ctx;
f40e6ef5190f68c2fd0e94c0b001bdf7d160236aTimo Sirainen // module-specific data
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen };
15581297511b658a29c707c6031a258bab7bf1a5Stephan Bosch
15581297511b658a29c707c6031a258bab7bf1a5Stephan Bosch struct mymodule_STRUCT_NAME *ctx = i_new(...);
15581297511b658a29c707c6031a258bab7bf1a5Stephan Bosch MODULE_CONTEXT_SET(obj, mymodule_STRUCT_NAME_module, ctx);
15581297511b658a29c707c6031a258bab7bf1a5Stephan Bosch
15581297511b658a29c707c6031a258bab7bf1a5Stephan Bosch struct mymodule_STRUCT_NAME *ctx =
15581297511b658a29c707c6031a258bab7bf1a5Stephan Bosch MODULE_CONTEXT(obj, mymodule_STRUCT_NAME_module);
cc77c1cfe8d072765f793474f49fecd897525466Stephan Bosch*/
cc77c1cfe8d072765f793474f49fecd897525466Stephan Bosch
cc77c1cfe8d072765f793474f49fecd897525466Stephan Bosch#define OBJ_REGISTER(obj) \
cc77c1cfe8d072765f793474f49fecd897525466Stephan Bosch ((**(obj)->module_contexts.v)->reg)
cc77c1cfe8d072765f793474f49fecd897525466Stephan Bosch#define OBJ_REGISTER_COMPATIBLE(obj, id_ctx) \
cc77c1cfe8d072765f793474f49fecd897525466Stephan Bosch COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(OBJ_REGISTER(obj), (id_ctx).reg)
cc77c1cfe8d072765f793474f49fecd897525466Stephan Bosch
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#define MODULE_CONTEXT(obj, id_ctx) \
fbad2d10747ac76a29b3a9dcfb4e7e67236ab872Stephan Bosch (*((void **)array_idx_modifiable(&(obj)->module_contexts, \
fbad2d10747ac76a29b3a9dcfb4e7e67236ab872Stephan Bosch (id_ctx).id.module_id) + \
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen OBJ_REGISTER_COMPATIBLE(obj, id_ctx)))
c10706d231f0690e934affdf18daa9b9a41814c6Timo Sirainen
c10706d231f0690e934affdf18daa9b9a41814c6Timo Sirainen#ifdef HAVE_TYPEOF
c10706d231f0690e934affdf18daa9b9a41814c6Timo Sirainen# define MODULE_CONTEXT_DEFINE(_name, _reg) \
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct _name { \
struct module_context_id id; \
typeof(_reg) reg; \
} _name
# define MODULE_CONTEXT_INIT(_reg) \
{ { &(_reg)->id, 0, FALSE }, NULL }
#else
# define MODULE_CONTEXT_DEFINE(_name, _reg) \
struct _name { \
struct module_context_id id; \
} _name
# define MODULE_CONTEXT_INIT(_reg) \
{ { &(_reg)->id, 0, FALSE } }
#endif
#define MODULE_CONTEXT_DEFINE_INIT(_name, _reg) \
MODULE_CONTEXT_DEFINE(_name, _reg) = MODULE_CONTEXT_INIT(_reg)
struct module_context_id {
unsigned int *module_id_register;
unsigned int module_id;
bool module_id_set;
};
static inline unsigned int module_get_context_id(struct module_context_id *id)
{
if (!id->module_id_set) {
id->module_id = *id->module_id_register;
id->module_id_set = TRUE;
*id->module_id_register += 1;
}
return id->module_id;
}
#define MODULE_CONTEXT_SET_FULL(obj, id_ctx, ctx, module_ctx) STMT_START { \
void *_module_tmp = ctx + \
COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(module_ctx, \
(**(obj)->module_contexts.v)) + \
OBJ_REGISTER_COMPATIBLE(obj, id_ctx); \
_array_idx_set(&(obj)->module_contexts.arr, \
module_get_context_id(&(id_ctx).id), &_module_tmp); \
} STMT_END
#define MODULE_CONTEXT_SET(obj, id_ctx, context) \
MODULE_CONTEXT_SET_FULL(obj, id_ctx, context, &(context)->module_ctx)
#define MODULE_CONTEXT_SET_SELF(obj, id_ctx, context) \
MODULE_CONTEXT_SET_FULL(obj, id_ctx, context, context)
#define MODULE_CONTEXT_UNSET(obj, id_ctx) \
array_idx_clear(&(obj)->module_contexts, (id_ctx).id.module_id)
#endif