@@ -168,11 +168,11 @@ struct BridgeRtClientControl : public CarlaRingBufferControl<SmallStackBuffer> { | |||
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<HugeStackBuffer> | |||
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 | |||
@@ -242,13 +242,13 @@ struct BridgeRtClientControl : public CarlaRingBufferControl<SmallStackBuffer> { | |||
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) | |||
@@ -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; | |||
@@ -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 | |||
} | |||
@@ -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 | |||
@@ -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); | |||
@@ -105,7 +105,7 @@ enum PluginBridgeNonRtServerOpcode { | |||
kPluginBridgeNonRtServerReady, | |||
kPluginBridgeNonRtServerSaved, | |||
kPluginBridgeNonRtServerUiClosed, | |||
kPluginBridgeNonRtServerError | |||
kPluginBridgeNonRtServerError // uint/size, str[] | |||
}; | |||
// ----------------------------------------------------------------------- | |||