(needs a full rebuild of carla and bridges)tags/1.9.7
| @@ -175,7 +175,7 @@ struct BridgeRtClientControl : public CarlaRingBufferControl<SmallStackBuffer> { | |||||
| WaitHelper(BridgeRtClientControl& c) noexcept | WaitHelper(BridgeRtClientControl& c) noexcept | ||||
| : data(c.data), | : data(c.data), | ||||
| ok(jackbridge_sem_timedwait(&data->sem.server, 5)) {} | |||||
| ok(jackbridge_sem_timedwait(&data->sem.server, 5000)) {} | |||||
| ~WaitHelper() noexcept | ~WaitHelper() noexcept | ||||
| { | { | ||||
| @@ -494,7 +494,7 @@ public: | |||||
| carla_stdout(" sizeof(BridgeNonRtClientData): %i/" P_SIZE, shmNonRtClientDataSize, sizeof(BridgeNonRtClientData)); | carla_stdout(" sizeof(BridgeNonRtClientData): %i/" P_SIZE, shmNonRtClientDataSize, sizeof(BridgeNonRtClientData)); | ||||
| carla_stdout(" sizeof(BridgeNonRtServerData): %i/" P_SIZE, shmNonRtServerDataSize, sizeof(BridgeNonRtServerData)); | carla_stdout(" sizeof(BridgeNonRtServerData): %i/" P_SIZE, shmNonRtServerDataSize, sizeof(BridgeNonRtServerData)); | ||||
| if (shmRtClientDataSize != sizeof(BridgeRtClientData) || shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) || shmNonRtServerDataSize != sizeof(BridgeNonRtServerData)) | |||||
| if (shmRtClientDataSize != sizeof(BridgeRtClientData) || shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) || shmNonRtServerDataSize != sizeof(BridgeNonRtServerData)) | |||||
| return false; | return false; | ||||
| // tell backend we're live | // tell backend we're live | ||||
| @@ -240,13 +240,13 @@ struct BridgeRtClientControl : public CarlaRingBufferControl<SmallStackBuffer> { | |||||
| setRingBuffer(nullptr, false); | setRingBuffer(nullptr, false); | ||||
| } | } | ||||
| bool waitForClient(const uint secs) noexcept | |||||
| bool waitForClient(const uint msecs) 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, msecs); | |||||
| } | } | ||||
| void writeOpcode(const PluginBridgeRtClientOpcode opcode) noexcept | void writeOpcode(const PluginBridgeRtClientOpcode opcode) noexcept | ||||
| @@ -738,6 +738,7 @@ public: | |||||
| fSaved(true), | fSaved(true), | ||||
| fTimedOut(false), | fTimedOut(false), | ||||
| fTimedError(false), | fTimedError(false), | ||||
| fProcWaitTime(0), | |||||
| fLastPongTime(-1), | fLastPongTime(-1), | ||||
| fBridgeBinary(), | fBridgeBinary(), | ||||
| fBridgeThread(engine, this), | fBridgeThread(engine, this), | ||||
| @@ -783,7 +784,7 @@ public: | |||||
| fShmRtClientControl.commitWrite(); | fShmRtClientControl.commitWrite(); | ||||
| if (! fTimedOut) | if (! fTimedOut) | ||||
| waitForClient("stopping", 3); | |||||
| waitForClient("stopping", 3000); | |||||
| } | } | ||||
| fBridgeThread.stopThread(3000); | fBridgeThread.stopThread(3000); | ||||
| @@ -1379,7 +1380,7 @@ public: | |||||
| fTimedOut = false; | fTimedOut = false; | ||||
| try { | try { | ||||
| waitForClient("activate", 2); | |||||
| waitForClient("activate", 2000); | |||||
| } CARLA_SAFE_EXCEPTION("activate - waitForClient"); | } CARLA_SAFE_EXCEPTION("activate - waitForClient"); | ||||
| } | } | ||||
| @@ -1397,7 +1398,7 @@ public: | |||||
| fTimedOut = false; | fTimedOut = false; | ||||
| try { | try { | ||||
| waitForClient("deactivate", 2); | |||||
| waitForClient("deactivate", 2000); | |||||
| } CARLA_SAFE_EXCEPTION("deactivate - waitForClient"); | } CARLA_SAFE_EXCEPTION("deactivate - waitForClient"); | ||||
| } | } | ||||
| @@ -1780,7 +1781,7 @@ public: | |||||
| fShmRtClientControl.commitWrite(); | fShmRtClientControl.commitWrite(); | ||||
| } | } | ||||
| waitForClient("process", 1); | |||||
| waitForClient("process", fProcWaitTime); | |||||
| if (fTimedOut) | if (fTimedOut) | ||||
| { | { | ||||
| @@ -1875,7 +1876,10 @@ public: | |||||
| fShmNonRtClientControl.commitWrite(); | fShmNonRtClientControl.commitWrite(); | ||||
| } | } | ||||
| waitForClient("buffersize", 1); | |||||
| //fProcWaitTime = newBufferSize*1000/pData->engine->getSampleRate(); | |||||
| fProcWaitTime = 1000; | |||||
| waitForClient("buffersize", 1000); | |||||
| } | } | ||||
| void sampleRateChanged(const double newSampleRate) override | void sampleRateChanged(const double newSampleRate) override | ||||
| @@ -1887,7 +1891,10 @@ public: | |||||
| fShmNonRtClientControl.commitWrite(); | fShmNonRtClientControl.commitWrite(); | ||||
| } | } | ||||
| waitForClient("samplerate", 1); | |||||
| //fProcWaitTime = pData->engine->getBufferSize()*1000/newSampleRate; | |||||
| fProcWaitTime = 1000; | |||||
| waitForClient("samplerate", 1000); | |||||
| } | } | ||||
| void offlineModeChanged(const bool isOffline) override | void offlineModeChanged(const bool isOffline) override | ||||
| @@ -1898,7 +1905,7 @@ public: | |||||
| fShmNonRtClientControl.commitWrite(); | fShmNonRtClientControl.commitWrite(); | ||||
| } | } | ||||
| waitForClient("offline", 1); | |||||
| waitForClient("offline", 1000); | |||||
| } | } | ||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| @@ -2509,6 +2516,10 @@ public: | |||||
| fShmNonRtClientControl.commitWrite(); | fShmNonRtClientControl.commitWrite(); | ||||
| // testing dummy message | |||||
| fShmRtClientControl.writeOpcode(kPluginBridgeRtClientNull); | |||||
| fShmRtClientControl.commitWrite(); | |||||
| // init bridge thread | // init bridge thread | ||||
| { | { | ||||
| char shmIdsStr[6*4+1]; | char shmIdsStr[6*4+1]; | ||||
| @@ -2599,6 +2610,7 @@ private: | |||||
| bool fSaved; | bool fSaved; | ||||
| bool fTimedOut; | bool fTimedOut; | ||||
| bool fTimedError; | bool fTimedError; | ||||
| uint fProcWaitTime; | |||||
| int64_t fLastPongTime; | int64_t fLastPongTime; | ||||
| @@ -2650,15 +2662,15 @@ private: | |||||
| fShmRtClientControl.writeULong(static_cast<uint64_t>(fShmAudioPool.size)); | fShmRtClientControl.writeULong(static_cast<uint64_t>(fShmAudioPool.size)); | ||||
| fShmRtClientControl.commitWrite(); | fShmRtClientControl.commitWrite(); | ||||
| waitForClient("resize-pool", 5); | |||||
| waitForClient("resize-pool", 5000); | |||||
| } | } | ||||
| void waitForClient(const char* const action, const uint secs) | |||||
| void waitForClient(const char* const action, const uint msecs) | |||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(! fTimedOut,); | CARLA_SAFE_ASSERT_RETURN(! fTimedOut,); | ||||
| CARLA_SAFE_ASSERT_RETURN(! fTimedError,); | CARLA_SAFE_ASSERT_RETURN(! fTimedError,); | ||||
| if (fShmRtClientControl.waitForClient(secs)) | |||||
| if (fShmRtClientControl.waitForClient(msecs)) | |||||
| return; | return; | ||||
| fTimedOut = true; | fTimedOut = true; | ||||
| @@ -397,7 +397,7 @@ JACKBRIDGE_API bool jackbridge_set_property_change_callback(jack_client_t* clien | |||||
| JACKBRIDGE_API bool jackbridge_sem_init(void* sem) noexcept; | JACKBRIDGE_API bool jackbridge_sem_init(void* sem) noexcept; | ||||
| JACKBRIDGE_API void jackbridge_sem_destroy(void* sem) noexcept; | JACKBRIDGE_API void jackbridge_sem_destroy(void* sem) noexcept; | ||||
| JACKBRIDGE_API void jackbridge_sem_post(void* sem) noexcept; | JACKBRIDGE_API void jackbridge_sem_post(void* sem) noexcept; | ||||
| JACKBRIDGE_API bool jackbridge_sem_timedwait(void* sem, uint secs) noexcept; | |||||
| JACKBRIDGE_API bool jackbridge_sem_timedwait(void* sem, uint msecs) noexcept; | |||||
| JACKBRIDGE_API bool jackbridge_shm_is_valid(const void* shm) noexcept; | JACKBRIDGE_API bool jackbridge_shm_is_valid(const void* shm) noexcept; | ||||
| JACKBRIDGE_API void jackbridge_shm_init(void* shm) noexcept; | JACKBRIDGE_API void jackbridge_shm_init(void* shm) noexcept; | ||||
| @@ -52,14 +52,14 @@ void jackbridge_sem_post(void* sem) noexcept | |||||
| #endif | #endif | ||||
| } | } | ||||
| bool jackbridge_sem_timedwait(void* sem, uint secs) noexcept | |||||
| bool jackbridge_sem_timedwait(void* sem, uint msecs) noexcept | |||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(sem != nullptr, false); | CARLA_SAFE_ASSERT_RETURN(sem != nullptr, false); | ||||
| #ifdef JACKBRIDGE_DUMMY | #ifdef JACKBRIDGE_DUMMY | ||||
| return false; | return false; | ||||
| #else | #else | ||||
| return carla_sem_timedwait(*(carla_sem_t*)sem, secs); | |||||
| return carla_sem_timedwait(*(carla_sem_t*)sem, msecs); | |||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -548,9 +548,9 @@ void jackbridge_sem_post(void* sem) noexcept | |||||
| getBridgeInstance().sem_post_ptr(sem); | getBridgeInstance().sem_post_ptr(sem); | ||||
| } | } | ||||
| bool jackbridge_sem_timedwait(void* sem, uint secs) noexcept | |||||
| bool jackbridge_sem_timedwait(void* sem, uint msecs) noexcept | |||||
| { | { | ||||
| return getBridgeInstance().sem_timedwait_ptr(sem, secs); | |||||
| return getBridgeInstance().sem_timedwait_ptr(sem, msecs); | |||||
| } | } | ||||
| bool jackbridge_shm_is_valid(const void* shm) noexcept | bool jackbridge_shm_is_valid(const void* shm) noexcept | ||||
| @@ -22,15 +22,24 @@ | |||||
| #include <ctime> | #include <ctime> | ||||
| #define CARLA_USE_FUTEXES | |||||
| #ifdef CARLA_OS_WIN | #ifdef CARLA_OS_WIN | ||||
| struct carla_sem_t { HANDLE handle; }; | struct carla_sem_t { HANDLE handle; }; | ||||
| #elif defined(CARLA_OS_MAC) | #elif defined(CARLA_OS_MAC) | ||||
| // TODO | // TODO | ||||
| struct carla_sem_t { char dummy; }; | struct carla_sem_t { char dummy; }; | ||||
| #elif defined(CARLA_USE_FUTEXES) | |||||
| # include <cerrno> | |||||
| # include <syscall.h> | |||||
| # include <sys/time.h> | |||||
| # include <linux/futex.h> | |||||
| struct carla_sem_t { int count; }; | |||||
| #else | #else | ||||
| # include <cerrno> | |||||
| # include <semaphore.h> | |||||
| # include <sys/time.h> | # include <sys/time.h> | ||||
| # include <sys/types.h> | # include <sys/types.h> | ||||
| # include <semaphore.h> | |||||
| struct carla_sem_t { sem_t sem; }; | struct carla_sem_t { sem_t sem; }; | ||||
| #endif | #endif | ||||
| @@ -40,6 +49,7 @@ struct carla_sem_t { sem_t sem; }; | |||||
| static inline | static inline | ||||
| bool carla_sem_create2(carla_sem_t& sem) noexcept | bool carla_sem_create2(carla_sem_t& sem) noexcept | ||||
| { | { | ||||
| carla_zeroStruct(sem); | |||||
| #if defined(CARLA_OS_WIN) | #if defined(CARLA_OS_WIN) | ||||
| SECURITY_ATTRIBUTES sa; | SECURITY_ATTRIBUTES sa; | ||||
| carla_zeroStruct(sa); | carla_zeroStruct(sa); | ||||
| @@ -51,6 +61,9 @@ bool carla_sem_create2(carla_sem_t& sem) noexcept | |||||
| return (sem.handle != INVALID_HANDLE_VALUE); | return (sem.handle != INVALID_HANDLE_VALUE); | ||||
| #elif defined(CARLA_OS_MAC) | #elif defined(CARLA_OS_MAC) | ||||
| return false; // TODO | return false; // TODO | ||||
| #elif defined(CARLA_USE_FUTEXES) | |||||
| sem.count = 0; | |||||
| return true; | |||||
| #else | #else | ||||
| return (::sem_init(&sem.sem, 1, 0) == 0); | return (::sem_init(&sem.sem, 1, 0) == 0); | ||||
| #endif | #endif | ||||
| @@ -83,6 +96,9 @@ void carla_sem_destroy2(carla_sem_t& sem) noexcept | |||||
| ::CloseHandle(sem.handle); | ::CloseHandle(sem.handle); | ||||
| #elif defined(CARLA_OS_MAC) | #elif defined(CARLA_OS_MAC) | ||||
| // TODO | // TODO | ||||
| #elif defined(CARLA_USE_FUTEXES) | |||||
| // nothing to do | |||||
| (void)sem; | |||||
| #else | #else | ||||
| ::sem_destroy(&sem.sem); | ::sem_destroy(&sem.sem); | ||||
| #endif | #endif | ||||
| @@ -110,6 +126,10 @@ void carla_sem_post(carla_sem_t& sem) noexcept | |||||
| ::ReleaseSemaphore(sem.handle, 1, nullptr); | ::ReleaseSemaphore(sem.handle, 1, nullptr); | ||||
| #elif defined(CARLA_OS_MAC) | #elif defined(CARLA_OS_MAC) | ||||
| // TODO | // TODO | ||||
| #elif defined(CARLA_USE_FUTEXES) | |||||
| const bool unlocked = __sync_bool_compare_and_swap(&sem.count, 0, 1); | |||||
| CARLA_SAFE_ASSERT_RETURN(unlocked,); | |||||
| ::syscall(__NR_futex, &sem.count, FUTEX_WAKE, 1, nullptr, nullptr, 0); | |||||
| #else | #else | ||||
| ::sem_post(&sem.sem); | ::sem_post(&sem.sem); | ||||
| #endif | #endif | ||||
| @@ -119,21 +139,42 @@ void carla_sem_post(carla_sem_t& sem) noexcept | |||||
| * Wait for a semaphore (lock). | * Wait for a semaphore (lock). | ||||
| */ | */ | ||||
| static inline | static inline | ||||
| bool carla_sem_timedwait(carla_sem_t& sem, const uint secs) noexcept | |||||
| bool carla_sem_timedwait(carla_sem_t& sem, const uint msecs) noexcept | |||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(secs > 0, false); | |||||
| CARLA_SAFE_ASSERT_RETURN(msecs > 0, false); | |||||
| #if defined(CARLA_OS_WIN) | #if defined(CARLA_OS_WIN) | ||||
| return (::WaitForSingleObject(sem.handle, secs*1000) == WAIT_OBJECT_0); | return (::WaitForSingleObject(sem.handle, secs*1000) == WAIT_OBJECT_0); | ||||
| #elif defined(CARLA_OS_MAC) | #elif defined(CARLA_OS_MAC) | ||||
| // TODO | |||||
| return false; // TODO | |||||
| #elif defined(CARLA_USE_FUTEXES) | |||||
| timespec timeout; | |||||
| timeout.tv_sec = static_cast<time_t>(msecs / 1000); | |||||
| timeout.tv_nsec = static_cast<time_t>(msecs % 1000); | |||||
| for (; ! __sync_bool_compare_and_swap(&sem.count, 1, 0);) | |||||
| { | |||||
| if (syscall(__NR_futex, &sem.count, FUTEX_WAIT, 0, &timeout, nullptr, 0) == 0) | |||||
| { | |||||
| __sync_fetch_and_sub(&sem.count, 1); | |||||
| return true; | |||||
| } | |||||
| //if (errno == EAGAIN) | |||||
| // continue; | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| #else | #else | ||||
| if (::sem_trywait(&sem.sem) == 0) | if (::sem_trywait(&sem.sem) == 0) | ||||
| return true; | return true; | ||||
| timespec timeout; | timespec timeout; | ||||
| ::clock_gettime(CLOCK_REALTIME, &timeout); | ::clock_gettime(CLOCK_REALTIME, &timeout); | ||||
| timeout.tv_sec += static_cast<time_t>(secs); | |||||
| timeout.tv_sec += static_cast<time_t>(msecs / 1000); | |||||
| timeout.tv_nsec += static_cast<time_t>(msecs % 1000); | |||||
| try { | try { | ||||
| return (::sem_timedwait(&sem.sem, &timeout) == 0); | return (::sem_timedwait(&sem.sem, &timeout) == 0); | ||||