简体   繁体   中英

Infinite recursive loop with QPluginLoader::instance()

I have a conceptual problem I would like to discuss. First I made an automatic system for plugin loading that works like this:

1) It is given the plugin file names or path(s) where to look.

2) It then can be queried with an interface pointer and it will cast in it an appropriate plugin when found (optionally with further conditions).

The templated function for finding the implementation looks like this:

template<tInterface> tInterface *implementation(const Requirements &req = Requierements())
{
    tInterface *interface = nullptr;

    for(QPluginLoader *loader : loaders(req)) //returns list of plugins that meet requirements in req
    {
        interface = qobject_cast<tInterface*>(loader.instance())

        if(interface)
            break;
    }

    return interface;
}

According to Qt documentation the plugin instance() (returning the root component) should be "shared" between all QPluginLoader objects operating on that same file. Well I found out it is not the case. The above code will loop infinitely when there is a call to it from within the plugin constructor (or in any constructor that is called by the root one). Because such a call will instantiate that same plugin (among others) to test for a requested implementation that will trigger yet another call and so forth. It works fine only when called outside of plugin constructors...

I am trying to figure out a solution that would allow me to use it even in constructors of plugins. So far I cannot think of a way or mechanism that would stop the loop hence my question here. Thanks for any ideas!

Ok so the answer is rather simple. The QPluginLoader object on which is currently called instance() must be "locked" prior to that call of instance() so that subsequent calls of instance on it are prohibited until the first call is finished - sort of a mutex behaviour. This prevents the described problem of calling instance() inside the call to instance() on the same QPluginLoader (happens because of the search through all plugins looking for possible implementations of the interface, see OP for function that does that).

I accomplished it with tracking the QPluginLoader objects that are "in use" releasing them after the instance() finished. This allows me to request plugins in constructors of other plugins with the only restriction that I cannot request the same plugin or any "parent" plugin in the loading hierarchy:

If constructor(s) of plugin X requests plugin Y that (in its constructor(s)) requests plugin Z then Z cannot request Y nor X (and Y cannot request X) in its own constructor(s). Such attempts would fail returning nullptr interface.

For completeness sake here is the modified function:

template<tInterface> tInterface *implementation(const Requirements &req = Requierements())
{
    tInterface *interface = nullptr;

    for(QPluginLoader *loader : loaders(req)) 
    //loaders() returns list of plugins that meet requirements in req
    //AND ARE NOT PRESENT IN m_Locked
    {
        m_Locked << loader;
        interface = qobject_cast<tInterface*>(loader.instance())
        m_Locked.removeOne(loader);

        if(interface)
            break;
    }

    return interface;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM