-----Original Message-----
From: Brendon Costa [mailto:[EMAIL PROTECTED]
Sent: Friday, October 10, 2008 2:33 AM
To: Dave Korn
Cc: 'Taras Glek'; 'Grigori Fursin'; 'Hugh Leather'; 'Basile
STARYNKEVITCH'; gcc@gcc.gnu.org;
'Sean Callanan'; 'Cupertino Miranda'; [EMAIL PROTECTED];
[EMAIL PROTECTED]; 'Taras Glek';
'Diego Novillo'; 'Mike O'Boyle'
Subject: Re: Defining a common plugin machinery
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");
}