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
|