Hi All,

I'm thinking of introducing two large changes to core which will
likely break the plugin API/ABI and just wanted to get some discussion
on this before I continue. The first change is to PluginClassHandler
and the second change is to WrapableInterface and various #defines.

1. Separate plugin class init/fini into two stages with the usual
constructor / destructor and an ::init and ::fini stage

I have noticed a lot of bugs recently where a crash is caused because
a constructor or destructor tries to access other bits of the plugin's
memory (such as other window structures), which might not be available
either directly or indirectly through wrapped function calls. This is
because of the way the the construction / tear down system works,
where we have something like:

Construct Screen (screen ctor) -> Construct Window #1 -> Construct
Window #2 -> Construct Window #3
Destroy Window #3 -> Destroy Window #2 -> Destroy Window #1 -> Destroy
Screen (screen dtor).

The problem in this situation is that the screen ctor could do
something during an initialization phase which could it to attempt to
try and access plugin structures which haven't been built yet (either
directly or indirectly through a wrapped function call). In the case
of "directly" trying to do this, most plugins have worked around this
by simple creating a one-shot timer to be called after the window
initialization phase is done (eg at the top of ::handleEvent () ).
Likewise, it is possible to loop the complete window list during a
window's dtor, when we can't guarantee that our plugin has a attached
structures on every single window (thus causing
PluginClassHandler::get ()) to fail.

My solution is this: we will add a virtual bool init () and virtual
void fini () to the template PluginClassHandler. On plugin
construction, the ctor the screen will be called first, and then all
the window ctors, and then screen ::init and window ::init. This means
that we can guaruntee that all plugin structures have at least been
created at this point. For tear-down (plugin unload) there will be
first a loop where ::fini () is called on all the windows and then
::fini () is called on the screen. Note that this doesn't actually
destroy any objects, nor should the plugins do so in this stage. It is
simply for tear-down cleanup, and it is guaranteed that it is safe to
access other plugin structures at this point. Then we will call
destructors, where there is no guarantee that other bits of plugin
memory is accessible.

This change won't require updates to too many of the plugins, but
basically anywhere where we are *reading* heap memory or calling
wrapped functions in the constructor or destructor should be moved
into ::init and ::fini respectively.

2. Add masks to WrapableInterface and related defines.

One of the larger performance issues that was targeted during the
0.9.0 release series was making wrapped function calls for plugins
dynamically enabled and disabled. As such, plugins can disable their
wrapped function from being called in the chain if they don't actually
need to be using that wrapped function, which saves a lot of CPU.

One of the outstanding problems with this is wrapped functions which
might be called for multiple purposes, such CompScreen::handleEvent,
where we handle a number of core X Events. Plugins might need to only
wrap ::handleEvent in the case where they need to know when a
ConfigureNotify has happened for example, but if they wrap
::handleEvent then that means that we get another useless function
call every single time there is a ButtonPress, or a ClientMessage or
PropertyNotify or MotionNotify (if the screen is grabbed). This is a
huge waste of CPU usage in itself and can easily be cut down.

What I propose to add is a virtual void setMask () and virtual bool
evaluateMask () to WrapableInterface. setMask () would be used to set
a bitmask (long int) of why this function is being called (eg
COMP_HANDLE_EVENT_BUTTON_PRESS) and evaluateMask () would be used to
evaluate another set int against this bitmask to see if the plugin's
function should be called.

We would have another define for WrapableInterface, something like
functionSetMask (long int mask); This sets a mask for the plugin's
implementation of the interface, which is evaluated before the
function is called. If the bitwise AND succeeds then the function gets
called. The default would be 0xffffffffffffffffffff which would mean
that the function gets called on every mask "reason" by default.

Let me know what you all think of this, and I will try and have a
sample implementation of these two changes after 0.9.2.1 has been
released (bugfix release)

Regards,

Sam

-- 
Sam Spilsbury
_______________________________________________
dev mailing list
[email protected]
http://lists.compiz.org/mailman/listinfo/dev

Reply via email to