diff --git a/source/backend/engine/CarlaEngineBridge.cpp b/source/backend/engine/CarlaEngineBridge.cpp index f4d870517..925a86550 100644 --- a/source/backend/engine/CarlaEngineBridge.cpp +++ b/source/backend/engine/CarlaEngineBridge.cpp @@ -168,11 +168,11 @@ struct BridgeRtClientControl : public CarlaRingBufferControl { return jackbridge_sem_post(&data->sem.client); } - bool waitForServer(const uint secs) noexcept + bool waitForServer(const uint secs, bool* const timedOut) noexcept { CARLA_SAFE_ASSERT_RETURN(data != nullptr, false); - return jackbridge_sem_timedwait(&data->sem.server, secs); + return jackbridge_sem_timedwait(&data->sem.server, secs, timedOut); } PluginBridgeRtClientOpcode readOpcode() noexcept @@ -270,8 +270,8 @@ struct BridgeNonRtServerControl : public CarlaRingBufferControl BridgeNonRtServerControl() noexcept : mutex(), - filename(), - data(nullptr) + filename(), + data(nullptr) { carla_zeroChar(shm, 64); jackbridge_shm_init(shm); @@ -1178,10 +1178,19 @@ public: protected: void run() override { + bool timedOut, quitReceived = false; + for (; ! shouldThreadExit();) { - if (! fShmRtClientControl.waitForServer(5)) + if (! fShmRtClientControl.waitForServer(5, &timedOut)) { + /* + * As a special case we ignore timeouts for plugin bridges. + * Some big Windows plugins (Kontakt, FL Studio VST) can time out when initializing or doing UI stuff. + * If any other error happens the plugin bridge is stopped. + */ + if (timedOut) continue; + carla_stderr2("Bridge timed-out, final post..."); fShmRtClientControl.postClient(); carla_stderr2("Bridge timed-out, done."); @@ -1400,6 +1409,7 @@ protected: } case kPluginBridgeRtClientQuit: + quitReceived = true; signalThreadShouldExit(); break; } @@ -1410,6 +1420,18 @@ protected: } callback(ENGINE_CALLBACK_ENGINE_STOPPED, 0, 0, 0, 0.0f, nullptr); + + if (! quitReceived) + { + const char* const message("Plugin bridge error, process thread has stopped"); + const std::size_t messageSize(std::strlen(message)); + + const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex); + fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerError); + fShmNonRtServerControl.writeUInt(messageSize); + fShmNonRtServerControl.writeCustomData(message, messageSize); + fShmNonRtServerControl.commitWrite(); + } } // called from process thread above diff --git a/source/backend/plugin/CarlaPluginBridge.cpp b/source/backend/plugin/CarlaPluginBridge.cpp index b7333b90c..b8a0c6868 100644 --- a/source/backend/plugin/CarlaPluginBridge.cpp +++ b/source/backend/plugin/CarlaPluginBridge.cpp @@ -242,13 +242,13 @@ struct BridgeRtClientControl : public CarlaRingBufferControl { setRingBuffer(nullptr, false); } - bool waitForClient(const uint secs) noexcept + bool waitForClient(const uint secs, bool* const timedOut) noexcept { CARLA_SAFE_ASSERT_RETURN(data != nullptr, false); jackbridge_sem_post(&data->sem.server); - return jackbridge_sem_timedwait(&data->sem.client, secs); + return jackbridge_sem_timedwait(&data->sem.client, secs, timedOut); } void writeOpcode(const PluginBridgeRtClientOpcode opcode) noexcept @@ -741,6 +741,7 @@ public: fInitError(false), fSaved(false), fTimedOut(false), + fTimedError(false), fLastPongCounter(-1), fBridgeBinary(), fBridgeThread(engine, this), @@ -786,7 +787,7 @@ public: fShmRtClientControl.commitWrite(); if (! fTimedOut) - fShmRtClientControl.waitForClient(3); + waitForClient("stopping", 3); } fBridgeThread.stopThread(3000); @@ -1317,6 +1318,8 @@ public: void activate() noexcept override { + CARLA_SAFE_ASSERT_RETURN(! fTimedError,); + { const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex); @@ -1324,18 +1327,17 @@ public: fShmNonRtClientControl.commitWrite(); } - bool timedOut = true; + fTimedOut = false; try { - timedOut = waitForClient(1); + waitForClient("activate", 2); } CARLA_SAFE_EXCEPTION("activate - waitForClient"); - - if (! timedOut) - fTimedOut = false; } void deactivate() noexcept override { + CARLA_SAFE_ASSERT_RETURN(! fTimedError,); + { const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex); @@ -1343,14 +1345,11 @@ public: fShmNonRtClientControl.commitWrite(); } - bool timedOut = true; + fTimedOut = false; try { - timedOut = waitForClient(1); + waitForClient("deactivate", 2); } CARLA_SAFE_EXCEPTION("deactivate - waitForClient"); - - if (! timedOut) - fTimedOut = false; } void process(const float** const audioIn, float** const audioOut, const float** const cvIn, float** const cvOut, const uint32_t frames) override @@ -1358,7 +1357,7 @@ public: // -------------------------------------------------------------------------------------------------------- // Check if active - if (fTimedOut || ! pData->active) + if (fTimedOut || fTimedError || ! pData->active) { // disable any output sound for (uint32_t i=0; i < pData->audioOut.count; ++i) @@ -1599,6 +1598,7 @@ public: bool processSingle(const float** const audioIn, float** const audioOut, const float** const cvIn, float** const cvOut, const uint32_t frames) { + CARLA_SAFE_ASSERT_RETURN(! fTimedError, false); CARLA_SAFE_ASSERT_RETURN(frames > 0, false); if (pData->audioIn.count > 0) @@ -1673,10 +1673,12 @@ public: fShmRtClientControl.commitWrite(); } - if (! waitForClient(2)) + waitForClient("process", 1); + + if (fTimedOut) { pData->singleMutex.unlock(); - return true; + return false; } for (uint32_t i=0; i < fInfo.aOuts; ++i) @@ -1763,7 +1765,7 @@ public: fShmNonRtClientControl.commitWrite(); } - fShmRtClientControl.waitForClient(1); + waitForClient("buffersize", 1); } void sampleRateChanged(const double newSampleRate) override @@ -1775,7 +1777,7 @@ public: fShmNonRtClientControl.commitWrite(); } - fShmRtClientControl.waitForClient(1); + waitForClient("samplerate", 1); } void offlineModeChanged(const bool isOffline) override @@ -1786,7 +1788,7 @@ public: fShmNonRtClientControl.commitWrite(); } - fShmRtClientControl.waitForClient(1); + waitForClient("offline", 1); } // ------------------------------------------------------------------- @@ -2273,10 +2275,20 @@ public: carla_zeroChar(error, errorSize+1); fShmNonRtServerControl.readCustomData(error, errorSize); - pData->engine->setLastError(error); + if (fInitiated) + { + pData->engine->callback(ENGINE_CALLBACK_ERROR, pData->id, 0, 0, 0.0f, error); - fInitError = true; - fInitiated = true; + // just in case + pData->engine->setLastError(error); + fInitError = true; + } + else + { + pData->engine->setLastError(error); + fInitError = true; + fInitiated = true; + } } break; } } @@ -2453,6 +2465,7 @@ private: bool fInitError; bool fSaved; bool fTimedOut; + bool fTimedError; int32_t fLastPongCounter; @@ -2505,21 +2518,26 @@ private: fShmRtClientControl.commitWrite(); - waitForClient(); + waitForClient("resize-pool"); } - bool waitForClient(const uint secs = 5) + void waitForClient(const char* const action, const uint secs = 5) { - CARLA_SAFE_ASSERT_RETURN(! fTimedOut, false); + CARLA_SAFE_ASSERT_RETURN(! fTimedOut,); + CARLA_SAFE_ASSERT_RETURN(! fTimedError,); - if (! fShmRtClientControl.waitForClient(secs)) + if (fShmRtClientControl.waitForClient(secs, &fTimedOut)) + return; + + if (fTimedOut) { - carla_stderr("waitForClient() timeout here"); - fTimedOut = true; - return false; + carla_stderr("waitForClient(%s) timeout here", action); + } + else + { + fTimedError = true; + carla_stderr("waitForClient(%s) error while waiting", action); } - - return true; } CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginBridge) diff --git a/source/jackbridge/JackBridge.hpp b/source/jackbridge/JackBridge.hpp index 99a5448fe..1150bbca7 100644 --- a/source/jackbridge/JackBridge.hpp +++ b/source/jackbridge/JackBridge.hpp @@ -393,7 +393,7 @@ __cdecl bool jackbridge_set_property_change_callback(jack_client_t* client, Jack __cdecl bool jackbridge_sem_init(void* sem) noexcept; __cdecl void jackbridge_sem_destroy(void* sem) noexcept; __cdecl bool jackbridge_sem_post(void* sem) noexcept; -__cdecl bool jackbridge_sem_timedwait(void* sem, uint secs) noexcept; +__cdecl bool jackbridge_sem_timedwait(void* sem, uint secs, bool* timedOut) noexcept; __cdecl bool jackbridge_shm_is_valid(const void* shm) noexcept; __cdecl void jackbridge_shm_init(void* shm) noexcept; diff --git a/source/jackbridge/JackBridge2.cpp b/source/jackbridge/JackBridge2.cpp index 30e56a677..a5282be72 100644 --- a/source/jackbridge/JackBridge2.cpp +++ b/source/jackbridge/JackBridge2.cpp @@ -55,20 +55,18 @@ bool jackbridge_sem_post(void* sem) noexcept #endif } -bool jackbridge_sem_timedwait(void* sem, uint secs) noexcept +bool jackbridge_sem_timedwait(void* sem, uint secs, bool* timedOut) noexcept { + CARLA_SAFE_ASSERT_RETURN(timedOut != nullptr, false); #ifdef JACKBRIDGE_DUMMY return false; #else if (carla_sem_timedwait((sem_t*)sem, secs)) + { + *timedOut = false; return true; - /* - * As a sspecial case we ignore timeouts for plugin bridges. - * Some big Windows plugins (Kontakt, FL Studio VST) can time out when initializing. - * If any other error happens the plugin bridge is stopped. - */ - if (errno == ETIMEDOUT) - return true; + } + *timedOut = (errno == ETIMEDOUT); return false; #endif } diff --git a/source/jackbridge/JackBridgeExport.cpp b/source/jackbridge/JackBridgeExport.cpp index 24fc22e18..3b2a6a2fc 100644 --- a/source/jackbridge/JackBridgeExport.cpp +++ b/source/jackbridge/JackBridgeExport.cpp @@ -540,9 +540,9 @@ bool jackbridge_sem_post(void* sem) noexcept return getBridgeInstance().sem_post_ptr(sem); } -bool jackbridge_sem_timedwait(void* sem, uint secs) noexcept +bool jackbridge_sem_timedwait(void* sem, uint secs, bool* timedOut) noexcept { - return getBridgeInstance().sem_timedwait_ptr(sem, secs); + return getBridgeInstance().sem_timedwait_ptr(sem, secs, timedOut); } bool jackbridge_shm_is_valid(const void* shm) noexcept diff --git a/source/jackbridge/JackBridgeExport.hpp b/source/jackbridge/JackBridgeExport.hpp index 39c07f926..8071eae6e 100644 --- a/source/jackbridge/JackBridgeExport.hpp +++ b/source/jackbridge/JackBridgeExport.hpp @@ -109,7 +109,7 @@ typedef bool (__cdecl *jackbridgesym_set_property_change_callback)(jack_client_t typedef bool (__cdecl *jackbridgesym_sem_init)(void* sem); typedef void (__cdecl *jackbridgesym_sem_destroy)(void* sem); typedef bool (__cdecl *jackbridgesym_sem_post)(void* sem); -typedef bool (__cdecl *jackbridgesym_sem_timedwait)(void* sem, uint secs); +typedef bool (__cdecl *jackbridgesym_sem_timedwait)(void* sem, uint secs, bool* timedOut); typedef bool (__cdecl *jackbridgesym_shm_is_valid)(const void* shm); typedef void (__cdecl *jackbridgesym_shm_init)(void* shm); typedef void (__cdecl *jackbridgesym_shm_attach)(void* shm, const char* name); diff --git a/source/utils/CarlaBridgeUtils.hpp b/source/utils/CarlaBridgeUtils.hpp index c08c10f2b..d632636d4 100644 --- a/source/utils/CarlaBridgeUtils.hpp +++ b/source/utils/CarlaBridgeUtils.hpp @@ -105,7 +105,7 @@ enum PluginBridgeNonRtServerOpcode { kPluginBridgeNonRtServerReady, kPluginBridgeNonRtServerSaved, kPluginBridgeNonRtServerUiClosed, - kPluginBridgeNonRtServerError + kPluginBridgeNonRtServerError // uint/size, str[] }; // -----------------------------------------------------------------------