diff PyPlugin.cpp @ 3:134313c59d82

* Add global mutex to PyPlugin -- all plugin method calls are strictly serialised in order to avoid problems with Python interpreter's lack of thread safety.
author cannam
date Fri, 14 Mar 2008 12:02:15 +0000
parents e20e214bdfb5
children e1b508f2f914
line wrap: on
line diff
--- a/PyPlugin.cpp	Wed Mar 12 12:42:19 2008 +0000
+++ b/PyPlugin.cpp	Fri Mar 14 12:02:15 2008 +0000
@@ -48,8 +48,7 @@
 
 */
 
-//#include "Python.h"
-#include "/usr/include/python/Python.h"
+#include <Python.h>
 #include "PyPlugin.h"
 
 #ifdef _WIN32
@@ -66,14 +65,14 @@
 using std::endl;
 using std::map;
 
-extern volatile bool mutex;
-
 // Maps to associate strings with enum values
 static std::map<std::string, eOutDescriptors> outKeys;
 static std::map<std::string, eSampleTypes> sampleKeys;
 static std::map<std::string, eFeatureFields> ffKeys;
 static std::map<std::string, p::eParmDescriptors> parmKeys;
 
+Mutex PyPlugin::m_pythonInterpreterMutex;
+
 void initMaps()
 {
 	outKeys["identifier"] = identifier;
@@ -170,33 +169,20 @@
 	m_class(pluginKey.substr(pluginKey.rfind(':')+1,pluginKey.size()-1)),
 	m_path((pluginKey.substr(0,pluginKey.rfind(pathsep))))
 {	
-
-/*TODO: this is a nasty way of ensuring the process is 
-finished before we create a new instance accessing the Python/C API.
-The Python/C API is not fully thread safe. 
-Calling into a python class while the process is doing heavy 
-computation may cause segmentation fault. 
-Manipulating the GIL and thread states only gave me a grief so far.*/
-	
-	if (mutex) {
-		cerr << "PyPlugin::PyPlugin:" << m_class 
-		<< " Warning: Waiting for clear signal from parallel process." << endl;
-		while (mutex) { }
-	}	
 }
 
 PyPlugin::~PyPlugin()
 {
 	cerr << "PyPlugin::PyPlugin:" << m_class 
 	<< " Instance deleted." << endl;
-	//for safety only. has been cleared after process.
-	mutex = false;	
 }
 
 
 string
 PyPlugin::getIdentifier() const
 {	
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
 	char method[]="getIdentifier"; 
 	cerr << "[call] " << method << endl;
 	string rString="VampPy-x";
@@ -226,6 +212,7 @@
 string
 PyPlugin::getName() const
 {
+	MutexLocker locker(&m_pythonInterpreterMutex);
 
 	char method[]="getName";
 	cerr << "[call] " << method << endl;
@@ -254,6 +241,8 @@
 string
 PyPlugin::getDescription() const
 {
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
 	char method[]="getDescription";
 	cerr << "[call] " << method << endl;
 	string rString="Not given. (Hint: Implement getDescription method.)";
@@ -281,6 +270,8 @@
 string
 PyPlugin::getMaker() const
 {
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
 	char method[]="getMaker";
 	cerr << "[call] " << method << endl;
 	string rString="Generic VamPy Plugin.";
@@ -314,6 +305,8 @@
 string
 PyPlugin::getCopyright() const
 {
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
 	char method[]="getCopyright";
 	cerr << "[call] " << method << endl;
 	string rString="BSD License";
@@ -343,6 +336,8 @@
 bool
 PyPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
 {
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
     if (channels < getMinChannelCount() ||
 	channels > getMaxChannelCount()) return false;
 
@@ -390,11 +385,14 @@
 void
 PyPlugin::reset()
 {
+	//!!! implement this!
     m_previousSample = 0.0f;
 }
 
 PyPlugin::InputDomain PyPlugin::getInputDomain() const 
 { 
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
 	char method[]="getInputDomain";
 	cerr << "[call] " << method << endl;
 	PyPlugin::InputDomain rValue = TimeDomain; // TimeDomain
@@ -420,6 +418,8 @@
 
 size_t PyPlugin::getPreferredBlockSize() const 
 { 
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
 	char method[]="getPreferredBlockSize";
 	cerr << "[call] " << method << endl;
 	size_t rValue=0; //not set by default
@@ -443,6 +443,8 @@
 //size_t PyPlugin::getPreferredStepSize() const { return 0; }
 size_t PyPlugin::getPreferredStepSize() const 
 { 
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
 	char method[]="getPreferredStepSize";
 	cerr << "[call] " << method << endl;
 	size_t rValue=0; //not set by default
@@ -465,6 +467,8 @@
 
 size_t PyPlugin::getMinChannelCount() const 
 { 
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
 	char method[]="getMinChannelCount";
 	cerr << "[call] " << method << endl;
 	size_t rValue=1; //default value
@@ -487,6 +491,8 @@
 
 size_t PyPlugin::getMaxChannelCount() const 
 { 
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
 	char method[]="getMaxChannelCount";	
 	cerr << "[call] " << method << endl;
 	size_t rValue=1; //default value
@@ -511,6 +517,8 @@
 PyPlugin::OutputList
 PyPlugin::getOutputDescriptors() const
 {
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
 	//PyEval_AcquireThread(newThreadState);
 	OutputList list;
 	OutputDescriptor od;
@@ -612,6 +620,8 @@
 PyPlugin::ParameterList
 PyPlugin::getParameterDescriptors() const
 {
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
 	ParameterList list;
 	ParameterDescriptor pd;
 	char method[]="getParameterDescriptors";
@@ -693,6 +703,8 @@
 
 void PyPlugin::setParameter(std::string paramid, float newval)
 {
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
 	char method[]="setParameter";
 	cerr << "[call] " << method << endl;
 
@@ -722,6 +734,8 @@
 
 float PyPlugin::getParameter(std::string paramid) const
 {
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
 	char method[]="getParameter";
 	cerr << "[call] " << method << endl;
 	float rValue = 0.0f;
@@ -763,12 +777,13 @@
 PyPlugin::process(const float *const *inputBuffers,
                       Vamp::RealTime timestamp)
 {
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
     if (m_stepSize == 0) {
 	cerr << "ERROR: PyPlugin::process: "
 	     << "Plugin has not been initialised" << endl;
 	return FeatureSet();
     }
-	mutex = true;
 	static char method[]="process";
 
 #ifdef _DEBUG	
@@ -812,7 +827,6 @@
 			}
 			Py_CLEAR(pyMethod);
 			Py_CLEAR(pyOutputList);
-			mutex = false;
 			return FeatureSet();
 		}
 			
@@ -887,11 +901,9 @@
 
 		}//for i = FeatureSet
 		Py_CLEAR(pyOutputList);
-		mutex = false;
 		return returnFeatures;
 
 	}//if (has_attribute)
-	mutex = false;
 	return FeatureSet(); 
 }
 
@@ -900,11 +912,12 @@
 PyPlugin::FeatureSet
 PyPlugin::getRemainingFeatures()
 {
+	MutexLocker locker(&m_pythonInterpreterMutex);
+
 	static char method[]="getRemainingFeatures";
 	cerr << "[call] " << method << endl;
 
 	//check if the method is implemented
-	mutex = true;
 	if ( ! PyObject_HasAttrString(m_pyInstance,method) ) {
 		return FeatureSet(); 
 		}
@@ -926,7 +939,6 @@
 			}
 			Py_CLEAR(pyMethod);
 			Py_CLEAR(pyOutputList);
-			mutex = false;
 			return FeatureSet();
 		}
 		Py_DECREF(pyMethod);
@@ -979,7 +991,6 @@
 			}// for j 			
 		}//for i 
 		Py_CLEAR(pyOutputList);
-		mutex = false;
 		return returnFeatures;
 }