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
