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