2010-01-16 5 views
4

J'ai réussi à charger un plugin C++ en utilisant une classe de chargeur de plugins personnalisée. Chaque plugin a une fonction extern "C" create_instance qui retourne une nouvelle instance en utilisant "new".impossible d'appeler avec succès la fonction dans le plugin chargé dynamiquement en C++

Un plugin est une classe abstraite avec quelques fonctions non-virtuelles et plusieurs variables protégées (std :: vector refList en fait partie).

La classe plugin_loader charge avec succès et demande même une méthode virtuelle de la classe chargée (à savoir « std :: plugin string :: getName() ».

La fonction principale crée une instance de « hôte » qui contient un vecteur de référence a compté des pointeurs intelligents, refptr, dans la classe "plugin", puis crée une instance de plugin_loader qui fait en fait le dlopen/dlsym, et crée une instance de refptr en lui passant create_instance(). le refptr créé à la fonction addPlugin de l'hôte host :: addPlugin réussit appelle plusieurs fonctions sur l'instance du plugin passé et l'ajoute finalement à un vecteur < refptr <plugin> >.

La fonction principale s'abonne ensuite à plusieurs événements Apple et appelle RunApplicationEventLoop(). Le rappel d'événement décode le résultat et appelle ensuite une fonction dans l'hôte, host :: sendToPlugin, qui identifie le plugin auquel l'événement est destiné, puis appelle le gestionnaire dans le plugin. C'est à ce moment que les choses s'arrêtent de fonctionner. Host :: sendToPlugin lit le résultat et détermine le plugin auquel envoyer l'événement.

J'utilise un plugin extrêmement basique créé comme un plugin de débogage qui retourne des valeurs statiques pour chaque fonction non-nulle.

Tout appel sur une fonction virtuelle dans le plugin du vecteur provoque une exception d'accès incorrecte. J'ai essayé de remplacer le refptrs avec des pointeurs réguliers et aussi boost :: shared_ptrs et je reçois toujours la même exception. Je sais que l'instance du plugin est valide car je peux examiner l'instance dans le débogueur de Xcode et même voir les éléments dans la refList du plugin.

Je pense que cela pourrait être un problème de threading car les plugins ont été créés dans le thread principal pendant que le callback fonctionne dans un thread séparé. I pense choses sont toujours en cours d'exécution dans le thread principal à en juger par le backtrace lorsque le programme rencontre l'erreur, mais je ne connais pas l'implémentation de RunApplicationEventLoop d'Apple, donc je ne peux pas être sûr.

Des idées sur les raisons pour lesquelles cela se produit?

class plugin 
{ 
public: 
    virtual std::string getName(); 

protected: 
    std::vector<std::string> refList; 
}; 

et la classe pluginloader:

template<typename T> class pluginLoader 
{ 
    public: pluginLoader(std::string path); 
    // initializes private mPath string with path to dylib 

    bool open(); 
    // opens the dylib and looks up the createInstance function. Returns true if successful, false otherwise 

    T * create_instance(); 
    // Returns a new instance of T, NULL if unsuccessful 
}; 

class host 
{ 
public: 
     addPlugin(int id, plugin * plug); 
     sendToPlugin(); // this is the problem method 
     static host * me; 

private: 
    std::vector<plugin *> plugins; // or vector<shared_ptr<plugin> > or vector<refptr<plugin> > 
}; 

code d'événement de pomme de host.cpp; EDIT: Il est exécuté sur OSX 10.5.8 et j'utilise GCC 4.0 avec Xcode. Ceci est pas conçu pour être une application multi-plateforme.

EDIT: Pour être clair, le plugin fonctionne jusqu'à ce que la boucle d'événement fournie par Apple appelle ma fonction de rappel. Lorsque la fonction de rappel rappelle l'hôte, les choses s'arrêtent.C'est le problème que j'ai, tout le reste fonctionne jusqu'à ce point.

+1

Un extrait de code pourrait vous aider. –

+0

Nommer l'OS serait également utile. Comme Apple est mentionné, je suis en train de dire que c'est le dernier Mac OS. –

+0

il * est * os x, 10.5. Je pense que c'est plus général que cela en ce qu'il implique un rappel d'événement. Comme pour un extrait de code, plugins [id] -> getName() ;. Peu importe la méthode que j'appelle, je sais que la cible existe et j'ai été capable d'appeler des méthodes dans le thread principal. – user150113

Répondre

1

Sans voir tout votre code, il ne sera pas facile de déterminer exactement ce qui ne va pas. Certaines choses à regarder:

  • Assurez-vous que le linker ne jette rien. Sur gcc, essayez les options de compilation -Wl -E - nous l'utilisons sur Linux, mais ne semblent pas en avoir besoin sur les Mac.
  • Assurez-vous de ne pas décharger accidentellement la bibliothèque dynamique avant de l'avoir terminée. RAII ne fonctionne pas pour le déchargement des bibliothèques dynamiques sauf si vous arrêtez également les exceptions à la bordure de la bibliothèque dynamique.

Vous voudrez peut-être examiner notre bibliothèque qui fonctionne sous Linux, Mac et Windows. Le code de chargement dynamique (avec une charge d'autres éléments de bibliothèque) est disponible à http://svn.felspar.com/public/fost-base/trunk/

Nous n'utilisons pas le mécanisme dlsym - c'est un peu difficile à utiliser correctement (et de manière portable). Au lieu de cela nous créons une bibliothèque de plugins par nom et mettons ce qui est fondamentalement des usines dedans là. Vous pouvez examiner comment cela fonctionne en examinant la façon dont .so avec les suites de tests peut être chargé dynamiquement. Un chargeur d'exemple est à http://svn.felspar.com/public/fost-base/trunk/fost-base/Cpp/fost-ftest/ftest.cpp et l'enregistrement de la suite de tests est au http://svn.felspar.com/public/fost-base/trunk/fost-base/Cpp/fost-test/testsuite.cpp. Le threadsafe_store contient les fabriques par nom et le constructeur de la suite enregistre la fabrique.

+0

Je ne le décharge pas car les plugins restent en ligne pendant toute la durée de vie de l'application. J'utilise le modèle d'usine et ça fonctionne, tout fonctionne parfaitement sur le fil principal. Dès que le thread principal démarre RunApplicationEventLoop et qu'un événement commence à être traité dans un thread séparé, les choses s'arrêtent. J'ai modifié la question avec un peu plus de code lié aux événements Apple, peut-être que ça va aider. – user150113

0

J'échapperaient complètement le fait que je était appeler dlclose dans dtor de mon plugin_loader et pour une raison quelconque les plugins ont été se entre l'appel détruits de RunApplicatoinEventLoop et l'appel à sendToPlugin. J'ai enlevé dlclose et les choses fonctionnent maintenant.

+0

Si vous regardez l'implémentation que nous avons, il y a une implémentation de fostlib :: atexit() supplémentaire qui permet de planifier l'exécution de dlclose lorsque l'application se termine. De cette façon, tout est encore détruit proprement. Vous pouvez voir le code sur http://svn.felspar.com/public/fost-base/trunk/fost-base/Cpp/fost-core/dynlib-linux.cpp - tout ce qu'il fait est de différer la suppression sur le pointeur interne de pimpl jusqu'à ce que l'application se termine (le nom de fichier implique que c'est Linux, mais le même code est également utilisé sur le Mac). – KayEss

+0

BTW, n'est-ce pas exactement le deuxième point que j'ai fait dans ma réponse? "Assurez-vous de ne pas décharger accidentellement la bibliothèque dynamique avant de l'avoir terminée." – KayEss