On Wed, 6 Jan 2021 18:11:17 +0200 "Yordan Karadzhov (VMware)" <y.karadz@xxxxxxxxx> wrote: > When we implement a KernelShark plugins, we often need a way to define > a structure that can hold context data that is visible only inside the > plugin and that has specific values for each data stream. The tricky > part here is that the total number of data streams and the IDs of the > active streams are dynamic quantities that can change as the user adds > or removes data streams. The macro defines an interface of functions > that will be useful for the plugin developer, helping to directly use > context objects, without caring for the complications due to the dynamic > configuration of active data streams. > --- > src/libkshark-plugin.h | 43 +++++++++++++++++++++++++++++++++++++++ > tests/libkshark-tests.cpp | 32 +++++++++++++++++++++++++++++ > 2 files changed, 75 insertions(+) > > diff --git a/src/libkshark-plugin.h b/src/libkshark-plugin.h > index f3c724f..e58d658 100644 > --- a/src/libkshark-plugin.h > +++ b/src/libkshark-plugin.h > @@ -360,6 +360,49 @@ int kshark_handle_all_dpis(struct kshark_data_stream *stream, > } \ > } \ > > +/** General purpose macro defining methods for adding plugin context. */ > +#define KS_DEFINE_PLUGIN_CONTEXT(type) \ When macros like this are done in Linux, it is common to add a "prefix" argument, and name all the variables and functions created by it with that prefix. #define KS_DEFINE_PLUGIN_CONTEXT(prefix, type) \ static type **prefix##_context_handler; \ [..] static inline type *prefix##_init(int sd) \ [..] This would allow this macro to be used more than once in a file. It's up to you if you want to do it that way. -- Steve > +static type **__context_handler; \ > +static ssize_t __n_streams = -1; \ > +static bool ok; \ > +static inline type *__init(int sd) \ > +{ \ > + type *obj; \ > + if (__n_streams < 0 && sd < KS_DEFAULT_NUM_STREAMS) { \ > + __context_handler = \ > + (type **) calloc(KS_DEFAULT_NUM_STREAMS, \ > + sizeof(*__context_handler)); \ > + if (!__context_handler) \ > + return NULL; \ > + __n_streams = KS_DEFAULT_NUM_STREAMS; \ > + } else if (sd >= __n_streams) { \ > + KS_DOUBLE_SIZE(type *, __context_handler, \ > + &__n_streams, &ok) \ > + if (!ok) \ > + return NULL; \ > + } \ > + assert(__context_handler[sd] == NULL); \ > + obj = (type *) calloc(1, sizeof(*obj)); \ > + __context_handler[sd] = obj; \ > + return obj; \ > +} \ > +static inline void __close(int sd) \ > +{ \ > + if (sd < 0) { \ > + free(__context_handler); \ > + __n_streams = -1; \ > + return; \ > + } \ > + free(__context_handler[sd]); \ > + __context_handler[sd] = NULL; \ > +} \ > +static inline type *__get_context(int sd) \ > +{ \ > + if (sd < 0 || sd >= __n_streams) \ > + return NULL; \ > + return __context_handler[sd]; \ > +} \ > + > #ifdef __cplusplus > } > #endif // __cplusplus