Chris@92: /* -*- c-basic-offset: 8 indent-tabs-mode: t -*- */ fazekasgy@37: /* fazekasgy@37: fazekasgy@37: * Vampy : This plugin is a wrapper around the Vamp plugin API. fazekasgy@37: * It allows for writing Vamp plugins in Python. fazekasgy@37: fazekasgy@37: * Centre for Digital Music, Queen Mary University of London. fazekasgy@37: * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources fazekasgy@37: * for licence information.) fazekasgy@37: fazekasgy@37: */ fazekasgy@37: fazekasgy@37: /* fazekasgy@37: PyExtensionManager: This class is responsible for initialisation fazekasgy@37: and cleanup of the extension module, as well as the loaded plugin fazekasgy@37: module namespaces. fazekasgy@37: fazekasgy@37: NOTES: Why do we need to clean up the module? fazekasgy@37: fazekasgy@37: The module exposed by Vampy to the embedded interpreter contains fazekasgy@37: callback functions. These functions are accessed via function fazekasgy@37: pointers stored in the extension module's namespace dictionary. fazekasgy@37: fazekasgy@37: Unfortunately, when the shared library is unloaded and reloaded fazekasgy@37: during a host session, these addresses might change. fazekasgy@37: Therefore, we reinitialise the module dict before each use. fazekasgy@37: However, this will cause garbage collection errors or segmentation fazekasgy@37: faults, when elements of the dict of the previous session are fazekasgy@37: attempted to free. Therefore, we clear the dictinary describing fazekasgy@37: the module namespace and replace all fuction pointers with Py_None fazekasgy@37: objects in individual plugin module namespaces. The reference fazekasgy@37: count on these can be safely decremented next time vampy is loaded fazekasgy@37: and the namespaces are reinitialised. fazekasgy@37: fazekasgy@37: Why doesn't the GC clean this up correctly? fazekasgy@37: fazekasgy@37: In a normal Python session the GC would deallocate the module fazekasgy@37: dict at the end. In embedded python, although the GC appears fazekasgy@37: to be called when the shared lib is unloaded, the interpreter fazekasgy@37: is reused. Since there is no C/API call to unload modules, fazekasgy@37: and at the time of unloading vampy the wrapped function pointers fazekasgy@37: are still valid, the GC doesn't collect them, nor are they freed fazekasgy@37: by the interpreter. When vampy is reloaded however, the module fazekasgy@37: dict will contain invalid addresses. The above procedure solves fazekasgy@37: this problem. fazekasgy@37: fazekasgy@37: fazekasgy@37: */ fazekasgy@37: fazekasgy@37: fazekasgy@37: #ifndef _PYEXTENSIONMANAGER_H_ fazekasgy@37: #define _PYEXTENSIONMANAGER_H_ fazekasgy@37: fazekasgy@37: using std::cerr; fazekasgy@37: using std::endl; fazekasgy@37: using std::string; fazekasgy@37: using std::vector; fazekasgy@37: fazekasgy@37: class PyExtensionManager fazekasgy@37: { fazekasgy@37: public: fazekasgy@37: PyExtensionManager(); fazekasgy@37: ~PyExtensionManager(); fazekasgy@37: bool initExtension(); fazekasgy@37: void setPlugModuleNames(vector pyPlugs); fazekasgy@37: void deleteModuleName(string plugKey); fazekasgy@37: Chris@92: static const char* m_exposedNames[]; Chris@92: fazekasgy@37: private: fazekasgy@37: vector m_plugModuleNames; fazekasgy@37: PyObject* m_pyGlobalNamespace; fazekasgy@37: PyObject* m_pyVampyNamespace; fazekasgy@37: fazekasgy@37: void cleanAllLocals() const; fazekasgy@37: void cleanLocalNamespace(const char* plugModuleName) const; fazekasgy@37: void updateAllLocals() const; fazekasgy@37: void updateLocalNamespace(const char* plugModuleName) const; fazekasgy@37: fazekasgy@37: void printDict(PyObject* inDict) const; fazekasgy@37: bool cleanModule() const; fazekasgy@37: fazekasgy@37: }; fazekasgy@37: fazekasgy@37: #endif fazekasgy@37: fazekasgy@37: