Browse Source

Better handling of plugin-bridge timeouts

tags/1.9.6
falkTX 10 years ago
parent
commit
245af25738
7 changed files with 87 additions and 49 deletions
  1. +27
    -5
      source/backend/engine/CarlaEngineBridge.cpp
  2. +49
    -31
      source/backend/plugin/CarlaPluginBridge.cpp
  3. +1
    -1
      source/jackbridge/JackBridge.hpp
  4. +6
    -8
      source/jackbridge/JackBridge2.cpp
  5. +2
    -2
      source/jackbridge/JackBridgeExport.cpp
  6. +1
    -1
      source/jackbridge/JackBridgeExport.hpp
  7. +1
    -1
      source/utils/CarlaBridgeUtils.hpp

+ 27
- 5
source/backend/engine/CarlaEngineBridge.cpp View File

@@ -168,11 +168,11 @@ struct BridgeRtClientControl : public CarlaRingBufferControl<SmallStackBuffer> {
return jackbridge_sem_post(&data->sem.client); 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); 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 PluginBridgeRtClientOpcode readOpcode() noexcept
@@ -270,8 +270,8 @@ struct BridgeNonRtServerControl : public CarlaRingBufferControl<HugeStackBuffer>


BridgeNonRtServerControl() noexcept BridgeNonRtServerControl() noexcept
: mutex(), : mutex(),
filename(),
data(nullptr)
filename(),
data(nullptr)
{ {
carla_zeroChar(shm, 64); carla_zeroChar(shm, 64);
jackbridge_shm_init(shm); jackbridge_shm_init(shm);
@@ -1178,10 +1178,19 @@ public:
protected: protected:
void run() override void run() override
{ {
bool timedOut, quitReceived = false;

for (; ! shouldThreadExit();) 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..."); carla_stderr2("Bridge timed-out, final post...");
fShmRtClientControl.postClient(); fShmRtClientControl.postClient();
carla_stderr2("Bridge timed-out, done."); carla_stderr2("Bridge timed-out, done.");
@@ -1400,6 +1409,7 @@ protected:
} }


case kPluginBridgeRtClientQuit: case kPluginBridgeRtClientQuit:
quitReceived = true;
signalThreadShouldExit(); signalThreadShouldExit();
break; break;
} }
@@ -1410,6 +1420,18 @@ protected:
} }


callback(ENGINE_CALLBACK_ENGINE_STOPPED, 0, 0, 0, 0.0f, nullptr); 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 // called from process thread above


+ 49
- 31
source/backend/plugin/CarlaPluginBridge.cpp View File

@@ -242,13 +242,13 @@ struct BridgeRtClientControl : public CarlaRingBufferControl<SmallStackBuffer> {
setRingBuffer(nullptr, false); 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); CARLA_SAFE_ASSERT_RETURN(data != nullptr, false);


jackbridge_sem_post(&data->sem.server); 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 void writeOpcode(const PluginBridgeRtClientOpcode opcode) noexcept
@@ -741,6 +741,7 @@ public:
fInitError(false), fInitError(false),
fSaved(false), fSaved(false),
fTimedOut(false), fTimedOut(false),
fTimedError(false),
fLastPongCounter(-1), fLastPongCounter(-1),
fBridgeBinary(), fBridgeBinary(),
fBridgeThread(engine, this), fBridgeThread(engine, this),
@@ -786,7 +787,7 @@ public:
fShmRtClientControl.commitWrite(); fShmRtClientControl.commitWrite();


if (! fTimedOut) if (! fTimedOut)
fShmRtClientControl.waitForClient(3);
waitForClient("stopping", 3);
} }


fBridgeThread.stopThread(3000); fBridgeThread.stopThread(3000);
@@ -1317,6 +1318,8 @@ public:


void activate() noexcept override void activate() noexcept override
{ {
CARLA_SAFE_ASSERT_RETURN(! fTimedError,);

{ {
const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex); const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex);


@@ -1324,18 +1327,17 @@ public:
fShmNonRtClientControl.commitWrite(); fShmNonRtClientControl.commitWrite();
} }


bool timedOut = true;
fTimedOut = false;


try { try {
timedOut = waitForClient(1);
waitForClient("activate", 2);
} CARLA_SAFE_EXCEPTION("activate - waitForClient"); } CARLA_SAFE_EXCEPTION("activate - waitForClient");

if (! timedOut)
fTimedOut = false;
} }


void deactivate() noexcept override void deactivate() noexcept override
{ {
CARLA_SAFE_ASSERT_RETURN(! fTimedError,);

{ {
const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex); const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex);


@@ -1343,14 +1345,11 @@ public:
fShmNonRtClientControl.commitWrite(); fShmNonRtClientControl.commitWrite();
} }


bool timedOut = true;
fTimedOut = false;


try { try {
timedOut = waitForClient(1);
waitForClient("deactivate", 2);
} CARLA_SAFE_EXCEPTION("deactivate - waitForClient"); } 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 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 // Check if active


if (fTimedOut || ! pData->active)
if (fTimedOut || fTimedError || ! pData->active)
{ {
// disable any output sound // disable any output sound
for (uint32_t i=0; i < pData->audioOut.count; ++i) 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) 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); CARLA_SAFE_ASSERT_RETURN(frames > 0, false);


if (pData->audioIn.count > 0) if (pData->audioIn.count > 0)
@@ -1673,10 +1673,12 @@ public:
fShmRtClientControl.commitWrite(); fShmRtClientControl.commitWrite();
} }


if (! waitForClient(2))
waitForClient("process", 1);

if (fTimedOut)
{ {
pData->singleMutex.unlock(); pData->singleMutex.unlock();
return true;
return false;
} }


for (uint32_t i=0; i < fInfo.aOuts; ++i) for (uint32_t i=0; i < fInfo.aOuts; ++i)
@@ -1763,7 +1765,7 @@ public:
fShmNonRtClientControl.commitWrite(); fShmNonRtClientControl.commitWrite();
} }


fShmRtClientControl.waitForClient(1);
waitForClient("buffersize", 1);
} }


void sampleRateChanged(const double newSampleRate) override void sampleRateChanged(const double newSampleRate) override
@@ -1775,7 +1777,7 @@ public:
fShmNonRtClientControl.commitWrite(); fShmNonRtClientControl.commitWrite();
} }


fShmRtClientControl.waitForClient(1);
waitForClient("samplerate", 1);
} }


void offlineModeChanged(const bool isOffline) override void offlineModeChanged(const bool isOffline) override
@@ -1786,7 +1788,7 @@ public:
fShmNonRtClientControl.commitWrite(); fShmNonRtClientControl.commitWrite();
} }


fShmRtClientControl.waitForClient(1);
waitForClient("offline", 1);
} }


// ------------------------------------------------------------------- // -------------------------------------------------------------------
@@ -2273,10 +2275,20 @@ public:
carla_zeroChar(error, errorSize+1); carla_zeroChar(error, errorSize+1);
fShmNonRtServerControl.readCustomData(error, errorSize); 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; } break;
} }
} }
@@ -2453,6 +2465,7 @@ private:
bool fInitError; bool fInitError;
bool fSaved; bool fSaved;
bool fTimedOut; bool fTimedOut;
bool fTimedError;


int32_t fLastPongCounter; int32_t fLastPongCounter;


@@ -2505,21 +2518,26 @@ private:


fShmRtClientControl.commitWrite(); 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) CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginBridge)


+ 1
- 1
source/jackbridge/JackBridge.hpp View File

@@ -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 bool jackbridge_sem_init(void* sem) noexcept;
__cdecl void jackbridge_sem_destroy(void* sem) noexcept; __cdecl void jackbridge_sem_destroy(void* sem) noexcept;
__cdecl bool jackbridge_sem_post(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 bool jackbridge_shm_is_valid(const void* shm) noexcept;
__cdecl void jackbridge_shm_init(void* shm) noexcept; __cdecl void jackbridge_shm_init(void* shm) noexcept;


+ 6
- 8
source/jackbridge/JackBridge2.cpp View File

@@ -55,20 +55,18 @@ bool jackbridge_sem_post(void* sem) noexcept
#endif #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 #ifdef JACKBRIDGE_DUMMY
return false; return false;
#else #else
if (carla_sem_timedwait((sem_t*)sem, secs)) if (carla_sem_timedwait((sem_t*)sem, secs))
{
*timedOut = false;
return true; 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; return false;
#endif #endif
} }


+ 2
- 2
source/jackbridge/JackBridgeExport.cpp View File

@@ -540,9 +540,9 @@ bool jackbridge_sem_post(void* sem) noexcept
return getBridgeInstance().sem_post_ptr(sem); 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 bool jackbridge_shm_is_valid(const void* shm) noexcept


+ 1
- 1
source/jackbridge/JackBridgeExport.hpp View File

@@ -109,7 +109,7 @@ typedef bool (__cdecl *jackbridgesym_set_property_change_callback)(jack_client_t
typedef bool (__cdecl *jackbridgesym_sem_init)(void* sem); typedef bool (__cdecl *jackbridgesym_sem_init)(void* sem);
typedef void (__cdecl *jackbridgesym_sem_destroy)(void* sem); typedef void (__cdecl *jackbridgesym_sem_destroy)(void* sem);
typedef bool (__cdecl *jackbridgesym_sem_post)(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 bool (__cdecl *jackbridgesym_shm_is_valid)(const void* shm);
typedef void (__cdecl *jackbridgesym_shm_init)(void* shm); typedef void (__cdecl *jackbridgesym_shm_init)(void* shm);
typedef void (__cdecl *jackbridgesym_shm_attach)(void* shm, const char* name); typedef void (__cdecl *jackbridgesym_shm_attach)(void* shm, const char* name);


+ 1
- 1
source/utils/CarlaBridgeUtils.hpp View File

@@ -105,7 +105,7 @@ enum PluginBridgeNonRtServerOpcode {
kPluginBridgeNonRtServerReady, kPluginBridgeNonRtServerReady,
kPluginBridgeNonRtServerSaved, kPluginBridgeNonRtServerSaved,
kPluginBridgeNonRtServerUiClosed, kPluginBridgeNonRtServerUiClosed,
kPluginBridgeNonRtServerError
kPluginBridgeNonRtServerError // uint/size, str[]
}; };


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------


Loading…
Cancel
Save