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<string> pyPlugs);
fazekasgy@37: 	void deleteModuleName(string plugKey);
fazekasgy@37: 
fazekasgy@37: private:
Chris@66: 	static const char* m_exposedNames[];
fazekasgy@37: 	
fazekasgy@37: 	vector<string> 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: