| @@ -41,7 +41,7 @@ using juce::Time; | |||||
| using juce::Thread; | using juce::Thread; | ||||
| template<typename T> | template<typename T> | ||||
| bool jackbridge_shm_map2(void* shm, T*& value) noexcept | |||||
| bool jackbridge_shm_map3(void* shm, T*& value) noexcept | |||||
| { | { | ||||
| value = (T*)jackbridge_shm_map(shm, sizeof(T)); | value = (T*)jackbridge_shm_map(shm, sizeof(T)); | ||||
| return (value != nullptr); | return (value != nullptr); | ||||
| @@ -51,102 +51,6 @@ CARLA_BACKEND_START_NAMESPACE | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| struct BridgeRtClientControl : public CarlaRingBufferControl<SmallStackBuffer> { | |||||
| CarlaString filename; | |||||
| BridgeRtClientData* data; | |||||
| char shm[64]; | |||||
| BridgeRtClientControl() noexcept | |||||
| : filename(), | |||||
| data(nullptr) | |||||
| { | |||||
| carla_zeroChars(shm, 64); | |||||
| jackbridge_shm_init(shm); | |||||
| } | |||||
| ~BridgeRtClientControl() noexcept override | |||||
| { | |||||
| // should be cleared by now | |||||
| CARLA_SAFE_ASSERT(data == nullptr); | |||||
| clear(); | |||||
| } | |||||
| void clear() noexcept | |||||
| { | |||||
| filename.clear(); | |||||
| if (data != nullptr) | |||||
| unmapData(); | |||||
| if (! jackbridge_shm_is_valid(shm)) | |||||
| return; | |||||
| jackbridge_shm_close(shm); | |||||
| jackbridge_shm_init(shm); | |||||
| } | |||||
| bool attach() noexcept | |||||
| { | |||||
| // must be invalid right now | |||||
| CARLA_SAFE_ASSERT_RETURN(! jackbridge_shm_is_valid(shm), false); | |||||
| jackbridge_shm_attach(shm, filename); | |||||
| return jackbridge_shm_is_valid(shm); | |||||
| } | |||||
| bool mapData() noexcept | |||||
| { | |||||
| CARLA_SAFE_ASSERT(data == nullptr); | |||||
| if (jackbridge_shm_map2<BridgeRtClientData>(shm, data)) | |||||
| { | |||||
| CARLA_SAFE_ASSERT(data->midiOut[0] == 0); | |||||
| setRingBuffer(&data->ringBuffer, false); | |||||
| CARLA_SAFE_ASSERT_RETURN(jackbridge_sem_connect(&data->sem.server), false); | |||||
| CARLA_SAFE_ASSERT_RETURN(jackbridge_sem_connect(&data->sem.client), false); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| void unmapData() noexcept | |||||
| { | |||||
| data = nullptr; | |||||
| setRingBuffer(nullptr, false); | |||||
| } | |||||
| PluginBridgeRtClientOpcode readOpcode() noexcept | |||||
| { | |||||
| return static_cast<PluginBridgeRtClientOpcode>(readUInt()); | |||||
| } | |||||
| // helper class that automatically posts semaphore on destructor | |||||
| struct WaitHelper { | |||||
| BridgeRtClientData* const data; | |||||
| const bool ok; | |||||
| WaitHelper(BridgeRtClientControl& c) noexcept | |||||
| : data(c.data), | |||||
| ok(jackbridge_sem_timedwait(&data->sem.server, 5000, false)) {} | |||||
| ~WaitHelper() noexcept | |||||
| { | |||||
| if (ok) | |||||
| jackbridge_sem_post(&data->sem.client, false); | |||||
| } | |||||
| CARLA_DECLARE_NON_COPY_STRUCT(WaitHelper) | |||||
| }; | |||||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeRtClientControl) | |||||
| }; | |||||
| // ------------------------------------------------------------------- | |||||
| struct BridgeNonRtClientControl : public CarlaRingBufferControl<BigStackBuffer> { | struct BridgeNonRtClientControl : public CarlaRingBufferControl<BigStackBuffer> { | ||||
| CarlaString filename; | CarlaString filename; | ||||
| BridgeNonRtClientData* data; | BridgeNonRtClientData* data; | ||||
| @@ -199,7 +103,7 @@ struct BridgeNonRtClientControl : public CarlaRingBufferControl<BigStackBuffer> | |||||
| { | { | ||||
| CARLA_SAFE_ASSERT(data == nullptr); | CARLA_SAFE_ASSERT(data == nullptr); | ||||
| if (jackbridge_shm_map2<BridgeNonRtClientData>(shm, data)) | |||||
| if (jackbridge_shm_map3<BridgeNonRtClientData>(shm, data)) | |||||
| { | { | ||||
| setRingBuffer(&data->ringBuffer, false); | setRingBuffer(&data->ringBuffer, false); | ||||
| return true; | return true; | ||||
| @@ -278,7 +182,7 @@ struct BridgeNonRtServerControl : public CarlaRingBufferControl<HugeStackBuffer> | |||||
| { | { | ||||
| CARLA_SAFE_ASSERT(data == nullptr); | CARLA_SAFE_ASSERT(data == nullptr); | ||||
| if (jackbridge_shm_map2<BridgeNonRtServerData>(shm, data)) | |||||
| if (jackbridge_shm_map3<BridgeNonRtServerData>(shm, data)) | |||||
| { | { | ||||
| setRingBuffer(&data->ringBuffer, false); | setRingBuffer(&data->ringBuffer, false); | ||||
| return true; | return true; | ||||
| @@ -366,15 +270,13 @@ public: | |||||
| fShmNonRtClientControl(), | fShmNonRtClientControl(), | ||||
| fShmNonRtServerControl(), | fShmNonRtServerControl(), | ||||
| fBaseNameAudioPool(audioPoolBaseName), | fBaseNameAudioPool(audioPoolBaseName), | ||||
| fBaseNameRtClientControl(rtClientBaseName), | |||||
| fIsOffline(false), | fIsOffline(false), | ||||
| fFirstIdle(true), | fFirstIdle(true), | ||||
| fLastPingTime(-1) | fLastPingTime(-1) | ||||
| { | { | ||||
| carla_debug("CarlaEngineBridge::CarlaEngineBridge(\"%s\", \"%s\", \"%s\", \"%s\")", audioPoolBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName); | carla_debug("CarlaEngineBridge::CarlaEngineBridge(\"%s\", \"%s\", \"%s\", \"%s\")", audioPoolBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName); | ||||
| fShmRtClientControl.filename = PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT; | |||||
| fShmRtClientControl.filename += rtClientBaseName; | |||||
| fShmNonRtClientControl.filename = PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_CLIENT; | fShmNonRtClientControl.filename = PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_CLIENT; | ||||
| fShmNonRtClientControl.filename += nonRtClientBaseName; | fShmNonRtClientControl.filename += nonRtClientBaseName; | ||||
| @@ -408,7 +310,7 @@ public: | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (! fShmRtClientControl.attach()) | |||||
| if (! fShmRtClientControl.attachClient(fBaseNameRtClientControl)) | |||||
| { | { | ||||
| clear(); | clear(); | ||||
| carla_stderr("Failed to attach to rt client control shared memory"); | carla_stderr("Failed to attach to rt client control shared memory"); | ||||
| @@ -1588,6 +1490,7 @@ private: | |||||
| BridgeNonRtServerControl fShmNonRtServerControl; | BridgeNonRtServerControl fShmNonRtServerControl; | ||||
| CarlaString fBaseNameAudioPool; | CarlaString fBaseNameAudioPool; | ||||
| CarlaString fBaseNameRtClientControl; | |||||
| bool fIsOffline; | bool fIsOffline; | ||||
| bool fFirstIdle; | bool fFirstIdle; | ||||
| @@ -51,137 +51,6 @@ static const ExternalMidiNote kExternalMidiNoteFallback = { -1, 0, 0 }; | |||||
| // ------------------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------------------- | ||||
| struct BridgeRtClientControl : public CarlaRingBufferControl<SmallStackBuffer> { | |||||
| BridgeRtClientData* data; | |||||
| CarlaString filename; | |||||
| bool needsSemDestroy; | |||||
| carla_shm_t shm; | |||||
| BridgeRtClientControl() | |||||
| : data(nullptr), | |||||
| filename(), | |||||
| needsSemDestroy(false) | |||||
| #ifdef CARLA_PROPER_CPP11_SUPPORT | |||||
| , shm(carla_shm_t_INIT) {} | |||||
| #else | |||||
| { | |||||
| carla_shm_init(shm); | |||||
| } | |||||
| #endif | |||||
| ~BridgeRtClientControl() noexcept override | |||||
| { | |||||
| // should be cleared by now | |||||
| CARLA_SAFE_ASSERT(data == nullptr); | |||||
| clear(); | |||||
| } | |||||
| bool initialize() noexcept | |||||
| { | |||||
| char tmpFileBase[64]; | |||||
| std::sprintf(tmpFileBase, PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT "XXXXXX"); | |||||
| shm = carla_shm_create_temp(tmpFileBase); | |||||
| CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm), false); | |||||
| if (! mapData()) | |||||
| { | |||||
| carla_shm_close(shm); | |||||
| carla_shm_init(shm); | |||||
| return false; | |||||
| } | |||||
| CARLA_SAFE_ASSERT(data != nullptr); | |||||
| if (! jackbridge_sem_init(&data->sem.server)) | |||||
| { | |||||
| unmapData(); | |||||
| carla_shm_close(shm); | |||||
| carla_shm_init(shm); | |||||
| return false; | |||||
| } | |||||
| if (! jackbridge_sem_init(&data->sem.client)) | |||||
| { | |||||
| jackbridge_sem_destroy(&data->sem.server); | |||||
| unmapData(); | |||||
| carla_shm_close(shm); | |||||
| carla_shm_init(shm); | |||||
| return false; | |||||
| } | |||||
| filename = tmpFileBase; | |||||
| needsSemDestroy = true; | |||||
| return true; | |||||
| } | |||||
| void clear() noexcept | |||||
| { | |||||
| filename.clear(); | |||||
| if (needsSemDestroy) | |||||
| { | |||||
| jackbridge_sem_destroy(&data->sem.client); | |||||
| jackbridge_sem_destroy(&data->sem.server); | |||||
| needsSemDestroy = false; | |||||
| } | |||||
| if (data != nullptr) | |||||
| unmapData(); | |||||
| if (! carla_is_shm_valid(shm)) | |||||
| return; | |||||
| carla_shm_close(shm); | |||||
| carla_shm_init(shm); | |||||
| } | |||||
| bool mapData() noexcept | |||||
| { | |||||
| CARLA_SAFE_ASSERT(data == nullptr); | |||||
| if (carla_shm_map<BridgeRtClientData>(shm, data)) | |||||
| { | |||||
| std::memset(data, 0, sizeof(BridgeRtClientData)); | |||||
| setRingBuffer(&data->ringBuffer, true); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| void unmapData() noexcept | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(data != nullptr,); | |||||
| carla_shm_unmap(shm, data); | |||||
| data = nullptr; | |||||
| setRingBuffer(nullptr, false); | |||||
| } | |||||
| bool waitForClient(const uint msecs) noexcept | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(data != nullptr, false); | |||||
| jackbridge_sem_post(&data->sem.server, true); | |||||
| return jackbridge_sem_timedwait(&data->sem.client, msecs, true); | |||||
| } | |||||
| void writeOpcode(const PluginBridgeRtClientOpcode opcode) noexcept | |||||
| { | |||||
| writeUInt(static_cast<uint32_t>(opcode)); | |||||
| } | |||||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeRtClientControl) | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| struct BridgeNonRtClientControl : public CarlaRingBufferControl<BigStackBuffer> { | struct BridgeNonRtClientControl : public CarlaRingBufferControl<BigStackBuffer> { | ||||
| BridgeNonRtClientData* data; | BridgeNonRtClientData* data; | ||||
| CarlaString filename; | CarlaString filename; | ||||
| @@ -2483,7 +2352,7 @@ public: | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (! fShmRtClientControl.initialize()) | |||||
| if (! fShmRtClientControl.initializeServer()) | |||||
| { | { | ||||
| carla_stderr("Failed to initialize RT client control"); | carla_stderr("Failed to initialize RT client control"); | ||||
| fShmAudioPool.clear(); | fShmAudioPool.clear(); | ||||
| @@ -38,6 +38,15 @@ | |||||
| // ------------------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------------------- | ||||
| template<typename T> | |||||
| bool jackbridge_shm_map2(void* shm, T*& value) noexcept | |||||
| { | |||||
| value = (T*)jackbridge_shm_map(shm, sizeof(T)); | |||||
| return (value != nullptr); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| BridgeAudioPool::BridgeAudioPool() noexcept | BridgeAudioPool::BridgeAudioPool() noexcept | ||||
| : data(nullptr), | : data(nullptr), | ||||
| dataSize(0), | dataSize(0), | ||||
| @@ -136,3 +145,185 @@ void BridgeAudioPool::resize(const uint32_t bufferSize, const uint32_t audioPort | |||||
| } | } | ||||
| // ------------------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------------------- | ||||
| BridgeRtClientControl::BridgeRtClientControl() noexcept | |||||
| : data(nullptr), | |||||
| filename(), | |||||
| needsSemDestroy(false) | |||||
| { | |||||
| carla_zeroChars(shm, 64); | |||||
| jackbridge_shm_init(shm); | |||||
| } | |||||
| BridgeRtClientControl::~BridgeRtClientControl() noexcept | |||||
| { | |||||
| // should be cleared by now | |||||
| CARLA_SAFE_ASSERT(data == nullptr); | |||||
| clear(); | |||||
| } | |||||
| bool BridgeRtClientControl::initializeServer() noexcept | |||||
| { | |||||
| #ifndef BUILD_BRIDGE | |||||
| char tmpFileBase[64]; | |||||
| std::sprintf(tmpFileBase, PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT "XXXXXX"); | |||||
| const carla_shm_t shm2 = carla_shm_create_temp(tmpFileBase); | |||||
| CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm2), false); | |||||
| void* const shmptr = shm; | |||||
| carla_shm_t& shm1 = *(carla_shm_t*)shmptr; | |||||
| carla_copyStruct(shm1, shm2); | |||||
| // NEW | |||||
| if (! mapData()) | |||||
| { | |||||
| jackbridge_shm_close(shm); | |||||
| jackbridge_shm_init(shm); | |||||
| return false; | |||||
| } | |||||
| CARLA_SAFE_ASSERT(data != nullptr); | |||||
| if (! jackbridge_sem_init(&data->sem.server)) | |||||
| { | |||||
| unmapData(); | |||||
| jackbridge_shm_close(shm); | |||||
| jackbridge_shm_init(shm); | |||||
| return false; | |||||
| } | |||||
| if (! jackbridge_sem_init(&data->sem.client)) | |||||
| { | |||||
| jackbridge_sem_destroy(&data->sem.server); | |||||
| unmapData(); | |||||
| jackbridge_shm_close(shm); | |||||
| jackbridge_shm_init(shm); | |||||
| return false; | |||||
| } | |||||
| // NEW | |||||
| filename = tmpFileBase; | |||||
| needsSemDestroy = true; | |||||
| return true; | |||||
| #else | |||||
| return false; | |||||
| #endif | |||||
| } | |||||
| bool BridgeRtClientControl::attachClient(const char* const basename) noexcept | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(basename != nullptr && basename[0] != '\0', false); | |||||
| #ifdef BUILD_BRIDGE | |||||
| // must be invalid right now | |||||
| CARLA_SAFE_ASSERT_RETURN(! jackbridge_shm_is_valid(shm), false); | |||||
| filename = PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT; | |||||
| filename += basename; | |||||
| jackbridge_shm_attach(shm, filename); | |||||
| return jackbridge_shm_is_valid(shm); | |||||
| #else | |||||
| return false; | |||||
| #endif | |||||
| } | |||||
| void BridgeRtClientControl::clear() noexcept | |||||
| { | |||||
| filename.clear(); | |||||
| if (needsSemDestroy) | |||||
| { | |||||
| jackbridge_sem_destroy(&data->sem.client); | |||||
| jackbridge_sem_destroy(&data->sem.server); | |||||
| needsSemDestroy = false; | |||||
| } | |||||
| if (data != nullptr) | |||||
| unmapData(); | |||||
| if (! jackbridge_shm_is_valid(shm)) | |||||
| return; | |||||
| jackbridge_shm_close(shm); | |||||
| jackbridge_shm_init(shm); | |||||
| } | |||||
| bool BridgeRtClientControl::mapData() noexcept | |||||
| { | |||||
| CARLA_SAFE_ASSERT(data == nullptr); | |||||
| if (jackbridge_shm_map2<BridgeRtClientData>(shm, data)) | |||||
| { | |||||
| #ifndef BUILD_BRIDGE | |||||
| std::memset(data, 0, sizeof(BridgeRtClientData)); | |||||
| setRingBuffer(&data->ringBuffer, true); | |||||
| #else | |||||
| CARLA_SAFE_ASSERT(data->midiOut[0] == 0); | |||||
| setRingBuffer(&data->ringBuffer, false); | |||||
| CARLA_SAFE_ASSERT_RETURN(jackbridge_sem_connect(&data->sem.server), false); | |||||
| CARLA_SAFE_ASSERT_RETURN(jackbridge_sem_connect(&data->sem.client), false); | |||||
| #endif | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| void BridgeRtClientControl::unmapData() noexcept | |||||
| { | |||||
| #ifndef BUILD_BRIDGE | |||||
| CARLA_SAFE_ASSERT_RETURN(data != nullptr,); | |||||
| jackbridge_shm_unmap(shm, data); | |||||
| #endif | |||||
| data = nullptr; | |||||
| setRingBuffer(nullptr, false); | |||||
| } | |||||
| bool BridgeRtClientControl::waitForClient(const uint msecs) noexcept | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(msecs > 0, false); | |||||
| CARLA_SAFE_ASSERT_RETURN(data != nullptr, false); | |||||
| #ifndef BUILD_BRIDGE | |||||
| jackbridge_sem_post(&data->sem.server, true); | |||||
| return jackbridge_sem_timedwait(&data->sem.client, msecs, true); | |||||
| #else | |||||
| return false; | |||||
| #endif | |||||
| } | |||||
| PluginBridgeRtClientOpcode BridgeRtClientControl::readOpcode() noexcept | |||||
| { | |||||
| #ifdef BUILD_BRIDGE | |||||
| return static_cast<PluginBridgeRtClientOpcode>(readUInt()); | |||||
| #else | |||||
| return kPluginBridgeRtClientNull; | |||||
| #endif | |||||
| } | |||||
| void BridgeRtClientControl::writeOpcode(const PluginBridgeRtClientOpcode opcode) noexcept | |||||
| { | |||||
| #ifndef BUILD_BRIDGE | |||||
| writeUInt(static_cast<uint32_t>(opcode)); | |||||
| #endif | |||||
| } | |||||
| BridgeRtClientControl::WaitHelper::WaitHelper(BridgeRtClientControl& c) noexcept | |||||
| : data(c.data), | |||||
| ok(jackbridge_sem_timedwait(&data->sem.server, 5000, false)) {} | |||||
| BridgeRtClientControl::WaitHelper::~WaitHelper() noexcept | |||||
| { | |||||
| if (ok) | |||||
| jackbridge_sem_post(&data->sem.client, false); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -218,4 +218,43 @@ struct BridgeAudioPool { | |||||
| // ------------------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------------------- | ||||
| struct BridgeRtClientControl : public CarlaRingBufferControl<SmallStackBuffer> { | |||||
| BridgeRtClientData* data; | |||||
| CarlaString filename; | |||||
| bool needsSemDestroy; // client only | |||||
| char shm[64]; | |||||
| BridgeRtClientControl() noexcept; | |||||
| ~BridgeRtClientControl() noexcept override; | |||||
| bool initializeServer() noexcept; | |||||
| bool attachClient(const char* const basename) noexcept; | |||||
| void clear() noexcept; | |||||
| bool mapData() noexcept; | |||||
| void unmapData() noexcept; | |||||
| // Client calls | |||||
| bool waitForClient(const uint msecs) noexcept; | |||||
| void writeOpcode(const PluginBridgeRtClientOpcode opcode) noexcept; | |||||
| // Servers calls | |||||
| PluginBridgeRtClientOpcode readOpcode() noexcept; | |||||
| // helper class that automatically posts semaphore on destructor | |||||
| struct WaitHelper { | |||||
| BridgeRtClientData* const data; | |||||
| const bool ok; | |||||
| WaitHelper(BridgeRtClientControl& c) noexcept; | |||||
| ~WaitHelper() noexcept; | |||||
| CARLA_DECLARE_NON_COPY_STRUCT(WaitHelper) | |||||
| }; | |||||
| CARLA_DECLARE_NON_COPY_STRUCT(BridgeRtClientControl) | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| #endif // CARLA_BRIDGE_UTILS_HPP_INCLUDED | #endif // CARLA_BRIDGE_UTILS_HPP_INCLUDED | ||||