> Sounds like you're almost in need of a generic data marshalling interface > here. > Why do we need the complication of data marshaling?
I don't see why we need to define that all plugin hooks have the same function interface as currently proposed. I.e. a single void*. This makes a lot of work marshaling data both as parameters and from return values. This is already done for us by the language (Though i may have mis-understood the train of thought here). I will propose the start of a new idea. This needs to be fleshed out a lot but it would be good to get some feedback. I will use the following terminology borrowed from QT: signal: Is a uniquely identified "hook" to which zero or more slots are added. (I.e. Caller) slot: Is a function implementation say in a plugin. This is added to a linked list for the specified signal. (I.e. Callee) The main concepts in this plugin hook definition are: * Signals can define any type of function pointer so can return values and accept any parameters without special data marshaling * Each signal is uniquely identified as a member variable in a struct called Hooks * A signal is implemented as a linked list where each node has a reference to a slot that has been connected to the signal * A slot is a function pointer and a unique string identifier This differs a bit from the QT definition but i find it helpful to describe the entities. Important things to note: Multiple plugins are "chained" one after the other. I.e. It is the responsibility of the plugin author to call any plugins that follow it in the list. This gives the plugin authors a bit more control over how their plugins inter-operate with other plugins, however it would be STRONGLY recommended that they follow a standard procedure and just call the next plugin after they have done their work. Basically, the idea is to provide the following structure and then most of the work will involve manipulation of the linked lists. I.e. Querying existing items in the LL, inserting new items before/after existing items, removing items from the LL. This is not a proposed end product. It is just to propose an idea. There are a few disadvantages with the way it is implemented right now: * Too much boilerplate code for each signal definition * The idea of chaining calls means the responsibility of calling the next plugin ends up with the plugin developer which could be bad if a plugin developer does not take due care, however it also provides them with more flexibility (not sure if that is necessary). Now, i have NO experience with the current pass manager in GCC, but would the passes be able to be managed using this same framework assuming that each pass is given a unique identifier? Thanks, Brendon. #include <stdio.h> #include <stdlib.h> /* GCC : Code */ struct Hooks { /* Define the blah signal. */ struct BlahFPWrap { const char* name; int (*fp)(struct BlahFPWrap* self, int i, char c, float f); void* data; struct BlahFPWrap* next; struct BlahFPWrap* prev; }* blah; struct FooFPWrap { const char* name; void (*fp)(struct FooFPWrap* self); void* data; struct FooFPWrap* next; struct FooFPWrap* prev; }* foo; }; /* Initialised by main */ struct Hooks hooks; void SomeFunc1(void) { /* Call plugin hook: blah */ int result = (!hooks.blah ? 0 : hooks.blah->fp(hooks.blah, 3, 'c', 2.0f)); /* ... do stuff with result ... */ (void)result; } void SomeFunc2(void) { /* Call plugin hook: foo */ if (hooks.foo) hooks.foo->fp(hooks.foo); } void PlgInit(struct Hooks* h); int main() { hooks.blah = NULL; hooks.foo = NULL; PlgInit(&hooks); return 0; } /* Writeme... */ #define PLUGIN_INSERT_BEFORE(Hooks, Struct, Hook, FuncPtr, Before, SlotName) /* In plugin */ #define PLUGIN_NAME "myplg" static void MyFoo(struct FooFPWrap* self) { printf("MyFoo\n"); if (self->next) self->next->fp(self->next); } static void MyBlah(struct BlahFPWrap* self, int i, char c, float f) { printf("MyBlah\n"); if (self->next) self->next->fp(self->next, i, c, f); } void PlgInit(struct Hooks* h) { PLUGIN_INSERT_BEFORE(h, struct BlahFPWrap, blah, &MyBlah, NULL, PLUGIN_NAME "_MyBlah"); PLUGIN_INSERT_BEFORE(h, struct FooFPWrap, foo, &MyFoo, NULL, PLUGIN_NAME "_MyFoo"); } void PlgShut(struct Hooks* h) { PLUGIN_REMOVE(h, PLUGIN_NAME "_MyBlah"); PLUGIN_REMOVE(h, PLUGIN_NAME "_MyFoo"); }