# HG changeset patch
# User Chris Cannam
# Date 1227879373 0
# Node ID b6dc6c7f402cd2bfd6de62d4b066b1a53d3c1419
# Parent  05383ee78f3e0591a91f5d0dc680a1975c121828
Various fixes:
 * Fix handling of HTTP redirects (avoiding crashes... I hope)
 * Fix failure to delete FFT models when a feature extraction model
   transformer was abandoned (also a cause of crashes in the past)
 * Fix deadlock when said transform was abandoned before its source
   model was ready because the session was being cleared (and so the
   source model would never be ready)

diff -r 05383ee78f3e -r b6dc6c7f402c data/fft/FFTDataServer.cpp
--- a/data/fft/FFTDataServer.cpp	Thu Nov 27 22:09:58 2008 +0000
+++ b/data/fft/FFTDataServer.cpp	Fri Nov 28 13:36:13 2008 +0000
@@ -451,6 +451,7 @@
 
             if (i->second.second > 0) {
                 std::cerr << "WARNING: FFTDataServer::modelAboutToBeDeleted: Model " << model << " (\"" << model->objectName().toStdString() << "\") is about to be deleted, but is still being referred to by FFT server " << server << " with non-zero refcount " << i->second.second << std::endl;
+                server->suspendWrites();
                 return;
             }
             for (ServerQueue::iterator j = m_releasedServers.begin();
diff -r 05383ee78f3e -r b6dc6c7f402c data/fileio/FileSource.cpp
--- a/data/fileio/FileSource.cpp	Thu Nov 27 22:09:58 2008 +0000
+++ b/data/fileio/FileSource.cpp	Fri Nov 28 13:36:13 2008 +0000
@@ -29,7 +29,7 @@
 #include <iostream>
 #include <cstdlib>
 
-#define DEBUG_FILE_SOURCE 1
+//#define DEBUG_FILE_SOURCE 1
 
 int
 FileSource::m_count = 0;
@@ -108,6 +108,8 @@
         emit statusAvailable();
         emit ready();
     }
+
+    std::cerr << "FileSource::FileSource(string) exiting" << std::endl;
 }
 
 FileSource::FileSource(QUrl url, ProgressReporter *reporter) :
@@ -134,6 +136,8 @@
     }
 
     init();
+
+    std::cerr << "FileSource::FileSource(url) exiting" << std::endl;
 }
 
 FileSource::FileSource(const FileSource &rf) :
@@ -182,6 +186,8 @@
     }
 
     m_done = true;
+
+    std::cerr << "FileSource::FileSource(copy ctor) exiting" << std::endl;
 }
 
 FileSource::~FileSource()
@@ -311,7 +317,8 @@
 FileSource::initHttp()
 {
     m_ok = true;
-    m_http = new QHttp(m_url.host(), m_url.port(80));
+    int port = m_url.port();
+    m_http = new QHttp(m_url.host(), port < 0 ? 80 : port);
     connect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool)));
     connect(m_http, SIGNAL(dataReadProgress(int, int)),
             this, SLOT(dataReadProgress(int, int)));
@@ -475,6 +482,7 @@
     while (m_ok && !m_done) {
 //        std::cerr << "FileSource::waitForData: calling QApplication::processEvents" << std::endl;
         QCoreApplication::processEvents();
+        usleep(10000);
     }
 }
 
@@ -545,8 +553,9 @@
 void
 FileSource::httpResponseHeaderReceived(const QHttpResponseHeader &resp)
 {
-    m_lastStatus = resp.statusCode();
-    if (m_lastStatus / 100 == 3) {
+    std::cerr << "FileSource::httpResponseHeaderReceived" << std::endl;
+
+    if (resp.statusCode() / 100 == 3) {
         QString location = resp.value("Location");
 #ifdef DEBUG_FILE_SOURCE
         std::cerr << "FileSource::responseHeaderReceived: redirect to \""
@@ -555,19 +564,20 @@
         if (location != "") {
             QUrl newUrl(location);
             if (newUrl != m_url) {
+                cleanup();
+                deleteCacheFile();
                 m_url = newUrl;
+                m_localFile = 0;
                 m_lastStatus = 0;
-                disconnect(m_http, SIGNAL(done(bool)), this, SLOT(done(bool)));
-                disconnect(m_http, SIGNAL(dataReadProgress(int, int)),
-                           this, SLOT(dataReadProgress(int, int)));
-                m_http->abort();
-                m_http->deleteLater();
-                m_http = 0;
+                m_done = false;
+                m_refCounted = false;
                 init();
                 return;
             }
         }
     }
+
+    m_lastStatus = resp.statusCode();
     if (m_lastStatus / 100 >= 4) {
         m_errorString = QString("%1 %2")
             .arg(resp.statusCode()).arg(resp.reasonPhrase());
diff -r 05383ee78f3e -r b6dc6c7f402c data/model/FFTModel.h
--- a/data/model/FFTModel.h	Thu Nov 27 22:09:58 2008 +0000
+++ b/data/model/FFTModel.h	Fri Nov 28 13:36:13 2008 +0000
@@ -66,43 +66,43 @@
              size_t fillFromColumn = 0);
     ~FFTModel();
 
-    float getMagnitudeAt(size_t x, size_t y) {
+    inline float getMagnitudeAt(size_t x, size_t y) {
         return m_server->getMagnitudeAt(x << m_xshift, y << m_yshift);
     }
-    float getNormalizedMagnitudeAt(size_t x, size_t y) {
+    inline float getNormalizedMagnitudeAt(size_t x, size_t y) {
         return m_server->getNormalizedMagnitudeAt(x << m_xshift, y << m_yshift);
     }
-    float getMaximumMagnitudeAt(size_t x) {
+    inline float getMaximumMagnitudeAt(size_t x) {
         return m_server->getMaximumMagnitudeAt(x << m_xshift);
     }
-    float getPhaseAt(size_t x, size_t y) {
+    inline float getPhaseAt(size_t x, size_t y) {
         return m_server->getPhaseAt(x << m_xshift, y << m_yshift);
     }
-    void getValuesAt(size_t x, size_t y, float &real, float &imaginary) {
+    inline void getValuesAt(size_t x, size_t y, float &real, float &imaginary) {
         m_server->getValuesAt(x << m_xshift, y << m_yshift, real, imaginary);
     }
-    bool isColumnAvailable(size_t x) const {
+    inline bool isColumnAvailable(size_t x) const {
         return m_server->isColumnReady(x << m_xshift);
     }
 
-    float getMagnitudesAt(size_t x, float *values, size_t minbin = 0, size_t count = 0) {
+    inline float getMagnitudesAt(size_t x, float *values, size_t minbin = 0, size_t count = 0) {
         return m_server->getMagnitudesAt(x << m_xshift, values, minbin << m_yshift, count, getYRatio());
     }
-    float getNormalizedMagnitudesAt(size_t x, float *values, size_t minbin = 0, size_t count = 0) {
+    inline float getNormalizedMagnitudesAt(size_t x, float *values, size_t minbin = 0, size_t count = 0) {
         return m_server->getNormalizedMagnitudesAt(x << m_xshift, values, minbin << m_yshift, count, getYRatio());
     }
-    float getPhasesAt(size_t x, float *values, size_t minbin = 0, size_t count = 0) {
+    inline float getPhasesAt(size_t x, float *values, size_t minbin = 0, size_t count = 0) {
         return m_server->getPhasesAt(x << m_xshift, values, minbin << m_yshift, count, getYRatio());
     }
 
-    size_t getFillExtent() const { return m_server->getFillExtent(); }
+    inline size_t getFillExtent() const { return m_server->getFillExtent(); }
 
     // DenseThreeDimensionalModel and Model methods:
     //
-    virtual size_t getWidth() const {
+    inline virtual size_t getWidth() const {
         return m_server->getWidth() >> m_xshift;
     }
-    virtual size_t getHeight() const {
+    inline virtual size_t getHeight() const {
         // If there is no y-shift, the server's height (based on its
         // fftsize/2 + 1) is correct.  If there is a shift, then the
         // server is using a larger fft size than we want, so we shift
diff -r 05383ee78f3e -r b6dc6c7f402c transform/FeatureExtractionModelTransformer.cpp
--- a/transform/FeatureExtractionModelTransformer.cpp	Thu Nov 27 22:09:58 2008 +0000
+++ b/transform/FeatureExtractionModelTransformer.cpp	Fri Nov 28 13:36:13 2008 +0000
@@ -371,10 +371,11 @@
 
     if (!m_output) return;
 
-    while (!input->isReady()) {
+    while (!input->isReady() && !m_abandoned) {
         std::cerr << "FeatureExtractionModelTransformer::run: Waiting for input model to be ready..." << std::endl;
-        sleep(1);
+        usleep(500000);
     }
+    if (m_abandoned) return;
 
     size_t sampleRate = input->getSampleRate();
 
@@ -478,9 +479,13 @@
             getFrames(channelCount, blockFrame, blockSize, buffers);
         }
 
+        if (m_abandoned) break;
+
 	Vamp::Plugin::FeatureSet features = m_plugin->process
 	    (buffers, Vamp::RealTime::frame2RealTime(blockFrame, sampleRate));
 
+        if (m_abandoned) break;
+
 	for (size_t fi = 0; fi < features[m_outputFeatureNo].size(); ++fi) {
 	    Vamp::Plugin::Feature feature =
 		features[m_outputFeatureNo][fi];
@@ -495,23 +500,23 @@
 	blockFrame += stepSize;
     }
 
-    if (m_abandoned) return;
+    if (!m_abandoned) {
+        Vamp::Plugin::FeatureSet features = m_plugin->getRemainingFeatures();
 
-    Vamp::Plugin::FeatureSet features = m_plugin->getRemainingFeatures();
+        for (size_t fi = 0; fi < features[m_outputFeatureNo].size(); ++fi) {
+            Vamp::Plugin::Feature feature =
+                features[m_outputFeatureNo][fi];
+            addFeature(blockFrame, feature);
+        }
+    }
 
-    for (size_t fi = 0; fi < features[m_outputFeatureNo].size(); ++fi) {
-	Vamp::Plugin::Feature feature =
-	    features[m_outputFeatureNo][fi];
-	addFeature(blockFrame, feature);
-    }
+    setCompletion(100);
 
     if (frequencyDomain) {
         for (size_t ch = 0; ch < channelCount; ++ch) {
             delete fftModels[ch];
         }
     }
-
-    setCompletion(100);
 }
 
 void
diff -r 05383ee78f3e -r b6dc6c7f402c transform/RealTimeEffectModelTransformer.cpp
--- a/transform/RealTimeEffectModelTransformer.cpp	Thu Nov 27 22:09:58 2008 +0000
+++ b/transform/RealTimeEffectModelTransformer.cpp	Fri Nov 28 13:36:13 2008 +0000
@@ -121,10 +121,11 @@
     DenseTimeValueModel *input = getConformingInput();
     if (!input) return;
 
-    while (!input->isReady()) {
+    while (!input->isReady() && !m_abandoned) {
         std::cerr << "RealTimeEffectModelTransformer::run: Waiting for input model to be ready..." << std::endl;
-        sleep(1);
+        usleep(500000);
     }
+    if (m_abandoned) return;
 
     SparseTimeValueModel *stvm = dynamic_cast<SparseTimeValueModel *>(m_output);
     WritableWaveFileModel *wwfm = dynamic_cast<WritableWaveFileModel *>(m_output);