| fazekasgy@37 | 1 /* | 
| fazekasgy@37 | 2 | 
| fazekasgy@37 | 3  * Vampy : This plugin is a wrapper around the Vamp plugin API. | 
| fazekasgy@37 | 4  * It allows for writing Vamp plugins in Python. | 
| fazekasgy@37 | 5 | 
| fazekasgy@37 | 6  * Centre for Digital Music, Queen Mary University of London. | 
| fazekasgy@37 | 7  * Copyright (C) 2008-2009 Gyorgy Fazekas, QMUL. (See Vamp sources | 
| fazekasgy@37 | 8  * for licence information.) | 
| fazekasgy@37 | 9 | 
| fazekasgy@37 | 10 */ | 
| fazekasgy@37 | 11 | 
| fazekasgy@37 | 12 /* | 
| fazekasgy@37 | 13 PyExtensionManager: This class is responsible for initialisation | 
| fazekasgy@37 | 14 and cleanup of the extension module, as well as the loaded plugin | 
| fazekasgy@37 | 15 module namespaces. | 
| fazekasgy@37 | 16 | 
| fazekasgy@37 | 17 NOTES: Why do we need to clean up the module? | 
| fazekasgy@37 | 18 | 
| fazekasgy@37 | 19 The module exposed by Vampy to the embedded interpreter contains | 
| fazekasgy@37 | 20 callback functions. These functions are accessed via function | 
| fazekasgy@37 | 21 pointers stored in the extension module's namespace dictionary. | 
| fazekasgy@37 | 22 | 
| fazekasgy@37 | 23 Unfortunately, when the shared library is unloaded and reloaded | 
| fazekasgy@37 | 24 during a host session, these addresses might change. | 
| fazekasgy@37 | 25 Therefore, we reinitialise the module dict before each use. | 
| fazekasgy@37 | 26 However, this will cause garbage collection errors or segmentation | 
| fazekasgy@37 | 27 faults, when elements of the dict of the previous session are | 
| fazekasgy@37 | 28 attempted to free. Therefore, we clear the dictinary describing | 
| fazekasgy@37 | 29 the module namespace and replace all fuction pointers with Py_None | 
| fazekasgy@37 | 30 objects in individual plugin module namespaces. The reference | 
| fazekasgy@37 | 31 count on these can be safely decremented next time vampy is loaded | 
| fazekasgy@37 | 32 and the namespaces are reinitialised. | 
| fazekasgy@37 | 33 | 
| fazekasgy@37 | 34 Why doesn't the GC clean this up correctly? | 
| fazekasgy@37 | 35 | 
| fazekasgy@37 | 36 In a normal Python session the GC would deallocate the module | 
| fazekasgy@37 | 37 dict at the end. In embedded python, although the GC appears | 
| fazekasgy@37 | 38 to be called when the shared lib is unloaded, the interpreter | 
| fazekasgy@37 | 39 is reused. Since there is no C/API call to unload modules, | 
| fazekasgy@37 | 40 and at the time of unloading vampy the wrapped function pointers | 
| fazekasgy@37 | 41 are still valid, the GC doesn't collect them, nor are they freed | 
| fazekasgy@37 | 42 by the interpreter. When vampy is reloaded however, the module | 
| fazekasgy@37 | 43 dict will contain invalid addresses. The above procedure solves | 
| fazekasgy@37 | 44 this problem. | 
| fazekasgy@37 | 45 | 
| fazekasgy@37 | 46 | 
| fazekasgy@37 | 47 */ | 
| fazekasgy@37 | 48 | 
| fazekasgy@37 | 49 | 
| fazekasgy@37 | 50 #ifndef _PYEXTENSIONMANAGER_H_ | 
| fazekasgy@37 | 51 #define _PYEXTENSIONMANAGER_H_ | 
| fazekasgy@37 | 52 | 
| fazekasgy@37 | 53 using std::cerr; | 
| fazekasgy@37 | 54 using std::endl; | 
| fazekasgy@37 | 55 using std::string; | 
| fazekasgy@37 | 56 using std::vector; | 
| fazekasgy@37 | 57 | 
| fazekasgy@37 | 58 class PyExtensionManager | 
| fazekasgy@37 | 59 { | 
| fazekasgy@37 | 60 public: | 
| fazekasgy@37 | 61 	PyExtensionManager(); | 
| fazekasgy@37 | 62 	~PyExtensionManager(); | 
| fazekasgy@37 | 63 	bool initExtension(); | 
| fazekasgy@37 | 64 	void setPlugModuleNames(vector<string> pyPlugs); | 
| fazekasgy@37 | 65 	void deleteModuleName(string plugKey); | 
| fazekasgy@37 | 66 | 
| fazekasgy@37 | 67 private: | 
| fazekasgy@37 | 68 	static char* m_exposedNames[]; | 
| fazekasgy@37 | 69 | 
| fazekasgy@37 | 70 	vector<string> m_plugModuleNames; | 
| fazekasgy@37 | 71 	PyObject* m_pyGlobalNamespace; | 
| fazekasgy@37 | 72 	PyObject* m_pyVampyNamespace; | 
| fazekasgy@37 | 73 | 
| fazekasgy@37 | 74 	void cleanAllLocals() const; | 
| fazekasgy@37 | 75 	void cleanLocalNamespace(const char* plugModuleName) const; | 
| fazekasgy@37 | 76 	void updateAllLocals() const; | 
| fazekasgy@37 | 77 	void updateLocalNamespace(const char* plugModuleName) const; | 
| fazekasgy@37 | 78 | 
| fazekasgy@37 | 79 	void printDict(PyObject* inDict) const; | 
| fazekasgy@37 | 80 	bool cleanModule() const; | 
| fazekasgy@37 | 81 | 
| fazekasgy@37 | 82 }; | 
| fazekasgy@37 | 83 | 
| fazekasgy@37 | 84 #endif | 
| fazekasgy@37 | 85 | 
| fazekasgy@37 | 86 |