changeset 1081:027d8b943be5

Do not attempt to switch from read-only to read-write mode if an error is pending (may cause mutex deadlock)
author Chris Cannam
date Wed, 10 Jun 2015 13:12:29 +0100
parents f35c1f9bfaa2
children b6092700a73e
files data/fft/FFTDataServer.cpp data/fft/FFTDataServer.h data/fft/FFTFileCacheReader.cpp
diffstat 3 files changed, 48 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/data/fft/FFTDataServer.cpp	Wed Jun 10 13:12:06 2015 +0100
+++ b/data/fft/FFTDataServer.cpp	Wed Jun 10 13:12:29 2015 +0100
@@ -902,6 +902,7 @@
         if (!cache) return 0;
 
         if (!cache->haveSetColumnAt(col)) {
+            if (getError() != "") return false;
             Profiler profiler("FFTDataServer::getMagnitudeAt: filling");
 #ifdef DEBUG_FFT_SERVER
             std::cerr << "FFTDataServer::getMagnitudeAt: calling fillColumn("
@@ -938,6 +939,7 @@
         if (!cache) return false;
 
         if (!cache->haveSetColumnAt(col)) {
+            if (getError() != "") return false;
             Profiler profiler("FFTDataServer::getMagnitudesAt: filling");
             fillColumn(x);
         }
@@ -968,6 +970,7 @@
         if (!cache) return 0;
 
         if (!cache->haveSetColumnAt(col)) {
+            if (getError() != "") return false;
             Profiler profiler("FFTDataServer::getNormalizedMagnitudeAt: filling");
             fillColumn(x);
         }
@@ -1000,6 +1003,7 @@
         if (!cache) return false;
 
         if (!cache->haveSetColumnAt(col)) {
+            if (getError() != "") return false;
             Profiler profiler("FFTDataServer::getNormalizedMagnitudesAt: filling");
             fillColumn(x);
         }
@@ -1032,6 +1036,7 @@
         if (!cache) return 0;
 
         if (!cache->haveSetColumnAt(col)) {
+            if (getError() != "") return false;
             Profiler profiler("FFTDataServer::getMaximumMagnitudeAt: filling");
             fillColumn(x);
         }
@@ -1060,6 +1065,7 @@
         if (!cache) return 0;
 
         if (!cache->haveSetColumnAt(col)) {
+            if (getError() != "") return false;
             Profiler profiler("FFTDataServer::getPhaseAt: filling");
             fillColumn(x);
         }
@@ -1092,6 +1098,7 @@
         if (!cache) return false;
 
         if (!cache->haveSetColumnAt(col)) {
+            if (getError() != "") return false;
             Profiler profiler("FFTDataServer::getPhasesAt: filling");
             fillColumn(x);
         }
@@ -1131,6 +1138,11 @@
         }
 
         if (!cache->haveSetColumnAt(col)) {
+            if (getError() != "") {
+                real = 0;
+                imaginary = 0;
+                return;
+            }
             Profiler profiler("FFTDataServer::getValuesAt: filling");
 #ifdef DEBUG_FFT_SERVER
             std::cerr << "FFTDataServer::getValuesAt(" << x << ", " << y << "): filling" << std::endl;
@@ -1165,6 +1177,7 @@
         if (!cache) return false;
 
         if (!cache->haveSetColumnAt(col)) {
+            if (getError() != "") return false;
             Profiler profiler("FFTDataServer::getValuesAt: filling");
             fillColumn(x);
         }
@@ -1395,9 +1408,19 @@
 QString
 FFTDataServer::getError() const
 {
-    if (m_error != "") return m_error;
-    else if (m_fillThread) return m_fillThread->getError();
-    else return "";
+    QString err;
+    if (m_error != "") {
+        err = m_error;
+        cerr << "FFTDataServer::getError: err (server " << this << ") = " << err << endl;
+    } else {
+        MutexLocker locker(&m_fftBuffersLock, "FFTDataServer::getError");
+        if (m_fillThread) {
+            err = m_fillThread->getError();
+            cerr << "FFTDataServer::getError: err (server " << this << ", from thread " << m_fillThread
+                 << ") = " << err << endl;
+        }
+    }
+    return err;
 }
 
 int
@@ -1475,8 +1498,10 @@
             try {
                 m_server.fillColumn(int((f - start) / m_server.m_windowIncrement));
             } catch (std::exception &e) {
-                std::cerr << "FFTDataServer::FillThread::run: exception: " << e.what() << std::endl;
-                m_error = e.what();
+                MutexLocker locker(&m_server.m_fftBuffersLock,
+                                   "FFTDataServer::run::m_fftBuffersLock [err]");
+                m_threadError = e.what();
+                std::cerr << "FFTDataServer::FillThread::run: exception: " << m_threadError << " (thread = " << this << " from server " << &m_server << ")" << std::endl;
                 m_server.fillComplete();
                 m_completion = 100;
                 m_extent = end;
@@ -1524,8 +1549,10 @@
         try {
             m_server.fillColumn(int((f - start) / m_server.m_windowIncrement));
         } catch (std::exception &e) {
-            std::cerr << "FFTDataServer::FillThread::run: exception: " << e.what() << std::endl;
-            m_error = e.what();
+            MutexLocker locker(&m_server.m_fftBuffersLock,
+                               "FFTDataServer::run::m_fftBuffersLock [err]");
+            m_threadError = e.what();
+                std::cerr << "FFTDataServer::FillThread::run: exception: " << m_threadError << " (thread = " << this << " from server " << &m_server << ")" << std::endl;
             m_server.fillComplete();
             m_completion = 100;
             m_extent = end;
--- a/data/fft/FFTDataServer.h	Wed Jun 10 13:12:06 2015 +0100
+++ b/data/fft/FFTDataServer.h	Wed Jun 10 13:12:29 2015 +0100
@@ -70,13 +70,13 @@
     const DenseTimeValueModel *getModel() const { return m_model; }
     int        getChannel() const { return m_channel; }
     WindowType getWindowType() const { return m_windower.getType(); }
-    int     getWindowSize() const { return m_windowSize; }
-    int     getWindowIncrement() const { return m_windowIncrement; }
-    int     getFFTSize() const { return m_fftSize; }
+    int        getWindowSize() const { return m_windowSize; }
+    int        getWindowIncrement() const { return m_windowIncrement; }
+    int        getFFTSize() const { return m_fftSize; }
     bool       getPolar() const { return m_polar; }
 
-    int     getWidth() const  { return m_width;  }
-    int     getHeight() const { return m_height; }
+    int        getWidth() const  { return m_width;  }
+    int        getHeight() const { return m_height; }
 
     float      getMagnitudeAt(int x, int y);
     float      getNormalizedMagnitudeAt(int x, int y);
@@ -196,6 +196,7 @@
             return 0;
         }
         m_cacheVectorLock.unlock();
+        if (getError() != "") return 0;
         if (!makeCache(c)) return 0;
         return getCacheReader(x, col);
     }
@@ -230,7 +231,7 @@
 
     void getStorageAdvice(int w, int h, bool &memory, bool &compact);
         
-    QMutex m_fftBuffersLock;
+    mutable QMutex m_fftBuffersLock;
     QWaitCondition m_condition;
 
     fftsample *m_fftInput;
@@ -247,7 +248,7 @@
 
         sv_frame_t getExtent() const { return m_extent; }
         int getCompletion() const { return m_completion ? m_completion : 1; }
-        QString getError() const { return m_error; }
+        QString getError() const { return m_threadError; }
         virtual void run();
 
     protected:
@@ -255,7 +256,7 @@
         sv_frame_t m_extent;
         int m_completion;
         sv_frame_t m_fillFrom;
-        QString m_error;
+        QString m_threadError;
     };
 
     bool m_exiting;
--- a/data/fft/FFTFileCacheReader.cpp	Wed Jun 10 13:12:06 2015 +0100
+++ b/data/fft/FFTFileCacheReader.cpp	Wed Jun 10 13:12:29 2015 +0100
@@ -24,6 +24,8 @@
 
 #include <iostream>
 
+//#define DEBUG_FFT_FILE_CACHE_READER 1
+
 
 // The underlying matrix has height (m_height * 2 + 1).  In each
 // column we store magnitude at [0], [2] etc and phase at [1], [3]
@@ -44,7 +46,9 @@
            writer->getWidth(),
            writer->getHeight() * 2 + m_factorSize))
 {
-//    cerr << "FFTFileCacheReader: storage type is " << (storageType == FFTCache::Compact ? "Compact" : storageType == Polar ? "Polar" : "Rectangular") << endl;
+#ifdef DEBUG_FFT_FILE_CACHE_READER
+    cerr << "FFTFileCacheReader: storage type is " << (m_storageType == FFTCache::Compact ? "Compact" : m_storageType == FFTCache::Polar ? "Polar" : "Rectangular") << endl;
+#endif
 }
 
 FFTFileCacheReader::~FFTFileCacheReader()