Browse Source

Use futexes for linux bridges, closes #234

(needs a full rebuild of carla and bridges)
tags/1.9.7
falkTX 10 years ago
parent
commit
14dd677220
6 changed files with 77 additions and 24 deletions
  1. +2
    -2
      source/backend/engine/CarlaEngineBridge.cpp
  2. +24
    -12
      source/backend/plugin/CarlaPluginBridge.cpp
  3. +1
    -1
      source/jackbridge/JackBridge.hpp
  4. +2
    -2
      source/jackbridge/JackBridge2.cpp
  5. +2
    -2
      source/jackbridge/JackBridgeExport.cpp
  6. +46
    -5
      source/utils/CarlaSemUtils.hpp

+ 2
- 2
source/backend/engine/CarlaEngineBridge.cpp View File

@@ -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


+ 24
- 12
source/backend/plugin/CarlaPluginBridge.cpp View File

@@ -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;


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

@@ -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;


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

@@ -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
} }




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

@@ -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


+ 46
- 5
source/utils/CarlaSemUtils.hpp View File

@@ -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);


Loading…
Cancel
Save