Browse Source

Merge branch '127-fix-plugin-resolve-issues'

* 127-fix-plugin-resolve-issues:
  Fixed a enum warning and documentation typo.
  Added a plugin framework property for pre-loading libraries.
  During resolving a plug-in, set the state of resolved dependencies.
  Set the current plug-in operation before actually doing it.
Sascha Zelzer 13 years ago
parent
commit
f72b94d47c

+ 1 - 0
Libs/PluginFramework/ctkPluginConstants.cpp

@@ -30,6 +30,7 @@ const QString ctkPluginConstants::FRAMEWORK_STORAGE = "org.commontk.pluginfw.sto
 const QString ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN = "org.commontk.pluginfw.storage.clean";
 const QString ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT = "onFirstInit";
 const QString ctkPluginConstants::FRAMEWORK_PLUGIN_LOAD_HINTS = "org.commontk.pluginfw.loadhints";
+const QString ctkPluginConstants::FRAMEWORK_PRELOAD_LIBRARIES = "org.commontk.pluginfw.preloadlibs";
 
 const QString ctkPluginConstants::PLUGIN_SYMBOLICNAME = "Plugin-SymbolicName";
 const QString ctkPluginConstants::PLUGIN_COPYRIGHT = "Plugin-Copyright";

+ 16 - 0
Libs/PluginFramework/ctkPluginConstants.h

@@ -107,6 +107,22 @@ struct CTK_PLUGINFW_EXPORT ctkPluginConstants {
   static const QString FRAMEWORK_PLUGIN_LOAD_HINTS; // = "org.commontk.pluginfw.loadhints"
 
   /**
+   * Specifies the set of libraries which should be dynamically opened when starting
+   * the framework. The value of this property must be either of type QString
+   * or QStringList. The given libraries are loaded with QLibrary::load(), using the
+   * load hints specified in FRAMEWORK_PLUGIN_LOAD_HINTS. The library search path is
+   * defined by the QLibrary class.
+   *
+   * Setting this property can improve the initial framework start-up time dramatically if
+   * a lot of plug-ins with deeply nested library dependencies are installed. During
+   * initial framework start-up (no plug-in meta-data cached yet), the repeated loading
+   * and unloading of the installed plug-ins will then only lead to repeated loading
+   * and unloading of plug-in dependencies which are not contained in the transitive
+   * dependency closure of the given set of pre-loaded libraries.
+   */
+  static const QString FRAMEWORK_PRELOAD_LIBRARIES; // = "org.commontk.pluginfw.preloadlibs"
+
+  /**
    * Manifest header identifying the plugin's symbolic name.
    *
    * <p>

+ 35 - 0
Libs/PluginFramework/ctkPluginFrameworkContext.cpp

@@ -86,6 +86,32 @@ void ctkPluginFrameworkContext::init()
   services = new ctkServices(this);
   plugins = new ctkPlugins(this);
 
+  // Pre-load libraries
+  // This may speed up installing new plug-ins if they have dependencies on
+  // one of these libraries. It prevents repeated loading and unloading of the
+  // pre-loaded libraries during caching of the plug-in meta-data.
+  if (props[ctkPluginConstants::FRAMEWORK_PRELOAD_LIBRARIES].isValid())
+  {
+    QStringList preloadLibs = props[ctkPluginConstants::FRAMEWORK_PRELOAD_LIBRARIES].toStringList();
+    QLibrary::LoadHints loadHints;
+    QVariant loadHintsVariant = props[ctkPluginConstants::FRAMEWORK_PLUGIN_LOAD_HINTS];
+    if (loadHintsVariant.isValid())
+    {
+      loadHints = loadHintsVariant.value<QLibrary::LoadHints>();
+    }
+
+    foreach(QString preloadLib, preloadLibs)
+    {
+      QLibrary lib(preloadLib);
+      lib.setLoadHints(loadHints);
+      log() << "Pre-loading library" << preloadLib << "with hints [" << static_cast<int>(loadHints) << "]";
+      if (!lib.load())
+      {
+        qWarning() << "Pre-loading library" << preloadLib << "failed";
+      }
+    }
+  }
+
   plugins->load();
 
   log() << "inited";
@@ -219,8 +245,17 @@ void ctkPluginFrameworkContext::checkRequirePlugin(ctkPluginPrivate *plugin)
         else if (p2->state == ctkPlugin::INSTALLED) {
           QSet<ctkPluginPrivate*> oldTempResolved = tempResolved;
           tempResolved.insert(p2);
+
+          // TODO check if operation locking is correct in case of
+          // multi-threaded plug-in start up. Maybe refactor out the dependency
+          // checking (use the "package" lock)
+          ctkPluginPrivate::Locker sync(&p2->operationLock);
+          p2->operation.fetchAndStoreOrdered(ctkPluginPrivate::RESOLVING);
           checkRequirePlugin(p2);
           tempResolved = oldTempResolved;
+          p2->state = ctkPlugin::RESOLVED;
+          listeners.emitPluginChanged(ctkPluginEvent(ctkPluginEvent::RESOLVED, p2->q_func()));
+          p2->operation.fetchAndStoreOrdered(ctkPluginPrivate::IDLE);
           ok = p2;
         }
       }

+ 2 - 1
Libs/PluginFramework/ctkPluginFrameworkPrivate.cpp

@@ -93,7 +93,8 @@ void ctkPluginFrameworkPrivate::shutdown(bool restart)
     }
     break;
   case ctkPlugin::STOPPING:
-    // Shutdown already inprogress
+    // Shutdown already inprogress, fall through
+  case ctkPlugin::UNINSTALLED:
     break;
   }
 }

+ 1 - 1
Libs/PluginFramework/ctkPluginFrameworkPrivate_p.h

@@ -62,7 +62,7 @@ public:
   void uninitSystemPlugin();
 
   /**
-   * This method starts a thread that stop this Framework,
+   * This method starts a thread that stops this Framework,
    * stopping all started plug-ins.
    *
    * <p>If the framework is not started, this method does nothing.

+ 1 - 1
Libs/PluginFramework/ctkPluginPrivate.cpp

@@ -181,9 +181,9 @@ ctkPlugin::State ctkPluginPrivate::getUpdatedState()
       Locker sync(&operationLock);
       if (state == ctkPlugin::INSTALLED)
       {
+        operation.fetchAndStoreOrdered(RESOLVING);
         fwCtx->resolvePlugin(this);
         state = ctkPlugin::RESOLVED;
-        operation.fetchAndStoreOrdered(RESOLVING);
         // TODO plugin threading
         //bundleThread().bundleChanged(new BundleEvent(BundleEvent.RESOLVED, this));
         fwCtx->listeners.emitPluginChanged(ctkPluginEvent(ctkPluginEvent::RESOLVED, this->q_func()));