Browse Source

Use a CriticalSection when engine UI/main calls

tags/1.9.4
falkTX 10 years ago
parent
commit
c7a4e7e5b9
4 changed files with 152 additions and 0 deletions
  1. +26
    -0
      source/backend/engine/CarlaEngine.cpp
  2. +7
    -0
      source/backend/engine/CarlaEngineInternal.hpp
  3. +11
    -0
      source/backend/engine/CarlaEngineJack.cpp
  4. +108
    -0
      source/utils/CarlaMutex.hpp

+ 26
- 0
source/backend/engine/CarlaEngine.cpp View File

@@ -569,6 +569,7 @@ bool CarlaEngine::init(const char* const clientName)
CARLA_SAFE_ASSERT_RETURN_ERR(pData->bufEvents.out == nullptr, "Invalid engine internal data (err #5)");
CARLA_SAFE_ASSERT_RETURN_ERR(clientName != nullptr && clientName[0] != '\0', "Invalid client name");
carla_debug("CarlaEngine::init(\"%s\")", clientName);
CARLA_ENGINE_THREAD_SAFE_SECTION

pData->aboutToClose = false;
pData->curPluginCount = 0;
@@ -633,6 +634,7 @@ bool CarlaEngine::close()
CARLA_SAFE_ASSERT_RETURN_ERR(pData->nextPluginId == pData->maxPluginNumber, "Invalid engine internal data (err #8)");
CARLA_SAFE_ASSERT_RETURN_ERR(pData->nextAction.opcode == kEnginePostActionNull, "Invalid engine internal data (err #9)");
carla_debug("CarlaEngine::close()");
CARLA_ENGINE_THREAD_SAFE_SECTION

pData->aboutToClose = true;

@@ -683,6 +685,7 @@ void CarlaEngine::idle()
CARLA_ASSERT(pData->nextAction.opcode == kEnginePostActionNull); // TESTING, remove later
CARLA_ASSERT(pData->nextPluginId == pData->maxPluginNumber); // TESTING, remove later
CARLA_ASSERT(pData->plugins != nullptr); // this one too maybe
CARLA_ENGINE_THREAD_SAFE_SECTION

for (unsigned int i=0; i < pData->curPluginCount; ++i)
{
@@ -710,6 +713,7 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, cons
CARLA_SAFE_ASSERT_RETURN_ERR(ptype != PLUGIN_NONE, "Invalid plugin params (err #2)");
CARLA_SAFE_ASSERT_RETURN_ERR((filename != nullptr && filename[0] != '\0') || (label != nullptr && label[0] != '\0'), "Invalid plugin params (err #3)");
carla_debug("CarlaEngine::addPlugin(%i:%s, %i:%s, \"%s\", \"%s\", \"%s\", %p)", btype, BinaryType2Str(btype), ptype, PluginType2Str(ptype), filename, name, label, extra);
CARLA_ENGINE_THREAD_SAFE_SECTION

unsigned int id;
CarlaPlugin* oldPlugin = nullptr;
@@ -948,6 +952,7 @@ bool CarlaEngine::removePlugin(const unsigned int id)
CARLA_SAFE_ASSERT_RETURN_ERR(pData->nextAction.opcode == kEnginePostActionNull, "Invalid engine internal data (err #16)");
CARLA_SAFE_ASSERT_RETURN_ERR(id < pData->curPluginCount, "Invalid plugin Id (err #1)");
carla_debug("CarlaEngine::removePlugin(%i)", id);
CARLA_ENGINE_THREAD_SAFE_SECTION

CarlaPlugin* const plugin(pData->plugins[id].plugin);

@@ -979,6 +984,7 @@ bool CarlaEngine::removeAllPlugins()
CARLA_SAFE_ASSERT_RETURN_ERR(pData->nextPluginId == pData->maxPluginNumber, "Invalid engine internal data (err #19)");
CARLA_SAFE_ASSERT_RETURN_ERR(pData->nextAction.opcode == kEnginePostActionNull, "Invalid engine internal data (err #20)");
carla_debug("CarlaEngine::removeAllPlugins()");
CARLA_ENGINE_THREAD_SAFE_SECTION

if (pData->curPluginCount == 0)
return true;
@@ -1018,6 +1024,7 @@ const char* CarlaEngine::renamePlugin(const unsigned int id, const char* const n
CARLA_SAFE_ASSERT_RETURN_ERRN(id < pData->curPluginCount, "Invalid plugin Id (err #2)");
CARLA_SAFE_ASSERT_RETURN_ERRN(newName != nullptr && newName[0] != '\0', "Invalid plugin name");
carla_debug("CarlaEngine::renamePlugin(%i, \"%s\")", id, newName);
CARLA_ENGINE_THREAD_SAFE_SECTION

CarlaPlugin* const plugin(pData->plugins[id].plugin);

@@ -1041,6 +1048,7 @@ bool CarlaEngine::clonePlugin(const unsigned int id)
CARLA_SAFE_ASSERT_RETURN_ERR(pData->nextAction.opcode == kEnginePostActionNull, "Invalid engine internal data (err #27)");
CARLA_SAFE_ASSERT_RETURN_ERR(id < pData->curPluginCount, "Invalid plugin Id (err #3)");
carla_debug("CarlaEngine::clonePlugin(%i)", id);
CARLA_ENGINE_THREAD_SAFE_SECTION

CarlaPlugin* const plugin(pData->plugins[id].plugin);

@@ -1071,6 +1079,7 @@ bool CarlaEngine::replacePlugin(const unsigned int id)
CARLA_SAFE_ASSERT_RETURN_ERR(pData->nextAction.opcode == kEnginePostActionNull, "Invalid engine internal data (err #31)");
CARLA_SAFE_ASSERT_RETURN_ERR(id < pData->curPluginCount, "Invalid plugin Id (err #4)");
carla_debug("CarlaEngine::replacePlugin(%i)", id);
CARLA_ENGINE_THREAD_SAFE_SECTION

CarlaPlugin* const plugin(pData->plugins[id].plugin);

@@ -1091,6 +1100,7 @@ bool CarlaEngine::switchPlugins(const unsigned int idA, const unsigned int idB)
CARLA_SAFE_ASSERT_RETURN_ERR(idA < pData->curPluginCount, "Invalid plugin Id (err #5)");
CARLA_SAFE_ASSERT_RETURN_ERR(idB < pData->curPluginCount, "Invalid plugin Id (err #6)");
carla_debug("CarlaEngine::switchPlugins(%i)", idA, idB);
CARLA_ENGINE_THREAD_SAFE_SECTION

CarlaPlugin* const pluginA(pData->plugins[idA].plugin);
CarlaPlugin* const pluginB(pData->plugins[idB].plugin);
@@ -1137,6 +1147,7 @@ const char* CarlaEngine::getUniquePluginName(const char* const name) const
CARLA_SAFE_ASSERT_RETURN(pData->nextAction.opcode == kEnginePostActionNull, nullptr);
CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', nullptr);
carla_debug("CarlaEngine::getUniquePluginName(\"%s\")", name);
CARLA_ENGINE_THREAD_SAFE_SECTION

CarlaString sname;
sname = name;
@@ -1223,6 +1234,7 @@ bool CarlaEngine::loadFile(const char* const filename)
{
CARLA_SAFE_ASSERT_RETURN_ERR(filename != nullptr && filename[0] != '\0', "Invalid filename (err #1)");
carla_debug("CarlaEngine::loadFile(\"%s\")", filename);
CARLA_ENGINE_THREAD_SAFE_SECTION

QFileInfo fileInfo(filename);

@@ -1354,6 +1366,7 @@ bool CarlaEngine::loadProject(const char* const filename)
{
CARLA_SAFE_ASSERT_RETURN_ERR(filename != nullptr && filename[0] != '\0', "Invalid filename (err #2)");
carla_debug("CarlaEngine::loadProject(\"%s\")", filename);
CARLA_ENGINE_THREAD_SAFE_SECTION

QFile file(filename);

@@ -1450,6 +1463,7 @@ bool CarlaEngine::saveProject(const char* const filename)
{
CARLA_SAFE_ASSERT_RETURN_ERR(filename != nullptr && filename[0] != '\0', "Invalid filename (err #3)");
carla_debug("CarlaEngine::saveProject(\"%s\")", filename);
CARLA_ENGINE_THREAD_SAFE_SECTION

QFile file(filename);

@@ -1587,6 +1601,7 @@ float CarlaEngine::getOutputPeak(const unsigned int pluginId, const bool isLeft)
void CarlaEngine::callback(const EngineCallbackOpcode action, const unsigned int pluginId, const int value1, const int value2, const float value3, const char* const valueStr) noexcept
{
carla_debug("CarlaEngine::callback(%s, %i, %i, %i, %f, \"%s\")", EngineCallbackOpcode2Str(action), pluginId, value1, value2, value3, valueStr);
CARLA_ENGINE_THREAD_SAFE_SECTION

if (pData->callback != nullptr)
{
@@ -1599,6 +1614,7 @@ void CarlaEngine::callback(const EngineCallbackOpcode action, const unsigned int
void CarlaEngine::setCallback(const EngineCallbackFunc func, void* const ptr) noexcept
{
carla_debug("CarlaEngine::setCallback(%p, %p)", func, ptr);
CARLA_ENGINE_THREAD_SAFE_SECTION

pData->callback = func;
pData->callbackPtr = ptr;
@@ -1612,6 +1628,7 @@ const char* CarlaEngine::runFileCallback(const FileCallbackOpcode action, const
CARLA_SAFE_ASSERT_RETURN(title != nullptr && title[0] != '\0', nullptr);
CARLA_SAFE_ASSERT_RETURN(filter != nullptr && filter[0] != '\0', nullptr);
carla_debug("CarlaEngine::runFileCallback(%i:%s, %s, \"%s\", \"%s\")", action, FileCallbackOpcode2Str(action), bool2str(isDir), title, filter);
CARLA_ENGINE_THREAD_SAFE_SECTION

const char* ret = nullptr;

@@ -1627,6 +1644,8 @@ const char* CarlaEngine::runFileCallback(const FileCallbackOpcode action, const

void CarlaEngine::setFileCallback(const FileCallbackFunc func, void* const ptr) noexcept
{
CARLA_ENGINE_THREAD_SAFE_SECTION

pData->fileCallback = func;
pData->fileCallbackPtr = ptr;
}
@@ -1640,6 +1659,7 @@ bool CarlaEngine::patchbayConnect(const int portA, const int portB)
CARLA_SAFE_ASSERT_RETURN(pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY, false);
CARLA_SAFE_ASSERT_RETURN(pData->bufAudio.isReady, false);
carla_debug("CarlaEngineRtAudio::patchbayConnect(%i, %i)", portA, portB);
CARLA_ENGINE_THREAD_SAFE_SECTION

if (pData->bufAudio.usePatchbay)
{
@@ -1743,6 +1763,7 @@ bool CarlaEngine::patchbayDisconnect(const uint connectionId)
CARLA_SAFE_ASSERT_RETURN(pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY, false);
CARLA_SAFE_ASSERT_RETURN(pData->bufAudio.isReady, false);
carla_debug("CarlaEngineRtAudio::patchbayDisconnect(%i)", connectionId);
CARLA_ENGINE_THREAD_SAFE_SECTION

if (pData->bufAudio.usePatchbay)
{
@@ -1858,6 +1879,8 @@ const char* CarlaEngine::getLastError() const noexcept

void CarlaEngine::setLastError(const char* const error) const
{
CARLA_ENGINE_THREAD_SAFE_SECTION

pData->lastError = error;
}

@@ -1874,6 +1897,7 @@ void CarlaEngine::setAboutToClose() noexcept
void CarlaEngine::setOption(const EngineOption option, const int value, const char* const valueStr)
{
carla_debug("CarlaEngine::setOption(%i:%s, %i, \"%s\")", option, EngineOption2Str(option), value, valueStr);
CARLA_ENGINE_THREAD_SAFE_SECTION

if (isRunning() && (option == ENGINE_OPTION_PROCESS_MODE || option == ENGINE_OPTION_AUDIO_NUM_PERIODS || option == ENGINE_OPTION_AUDIO_DEVICE))
return carla_stderr("CarlaEngine::setOption(%i:%s, %i, \"%s\") - Cannot set this option while engine is running!", option, EngineOption2Str(option), value, valueStr);
@@ -2009,6 +2033,8 @@ const char* CarlaEngine::getOscServerPathUDP() const noexcept
#ifdef BUILD_BRIDGE
void CarlaEngine::setOscBridgeData(const CarlaOscData* const oscData) const noexcept
{
CARLA_ENGINE_THREAD_SAFE_SECTION

pData->oscData = oscData;
}
#endif


+ 7
- 0
source/backend/engine/CarlaEngineInternal.hpp View File

@@ -31,6 +31,11 @@
#define CARLA_SAFE_ASSERT_RETURN_ERR(cond, err) if (cond) pass(); else { carla_safe_assert(#cond, __FILE__, __LINE__); setLastError(err); return false; }
#define CARLA_SAFE_ASSERT_RETURN_ERRN(cond, err) if (cond) pass(); else { carla_safe_assert(#cond, __FILE__, __LINE__); setLastError(err); return nullptr; }

// -----------------------------------------------------------------------
// Global action lock for UI operations, used for osc only

#define CARLA_ENGINE_THREAD_SAFE_SECTION const CarlaCriticalSection::Scope _ccsl(pData->_cs);

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

CARLA_BACKEND_START_NAMESPACE
@@ -237,6 +242,8 @@ struct CarlaEngineProtectedData {
EngineInternalTime time;
EngineNextAction nextAction;

CarlaCriticalSection _cs; // for handling requests from multiple threads

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

CarlaEngineProtectedData(CarlaEngine* const engine);


+ 11
- 0
source/backend/engine/CarlaEngineJack.cpp View File

@@ -537,6 +537,7 @@ public:
bool init(const char* const clientName) override
{
carla_debug("CarlaEngineJack::init(\"%s\")", clientName);
CARLA_ENGINE_THREAD_SAFE_SECTION

fFreewheel = false;
fTransportState = JackTransportStopped;
@@ -624,6 +625,8 @@ public:
bool close() override
{
carla_debug("CarlaEngineJack::close()");
CARLA_ENGINE_THREAD_SAFE_SECTION

CarlaEngine::close();

#ifdef BUILD_BRIDGE
@@ -669,6 +672,8 @@ public:
#ifndef BUILD_BRIDGE
void idle() override
{
CARLA_ENGINE_THREAD_SAFE_SECTION

CarlaEngine::idle();

if (fNewGroups.count() == 0)
@@ -720,6 +725,8 @@ public:

CarlaEngineClient* addClient(CarlaPlugin* const plugin) override
{
CARLA_ENGINE_THREAD_SAFE_SECTION

jack_client_t* client = nullptr;

#ifdef BUILD_BRIDGE
@@ -762,6 +769,7 @@ public:
CARLA_SAFE_ASSERT_RETURN(id < pData->curPluginCount, nullptr);
CARLA_SAFE_ASSERT_RETURN(pData->plugins != nullptr, nullptr);
CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0', nullptr);
CARLA_ENGINE_THREAD_SAFE_SECTION

CarlaPlugin* const plugin(pData->plugins[id].plugin);

@@ -841,6 +849,7 @@ public:
bool patchbayConnect(int portA, int portB) override
{
CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false);
CARLA_ENGINE_THREAD_SAFE_SECTION

if (fClient == nullptr)
{
@@ -865,6 +874,7 @@ public:
bool patchbayDisconnect(uint connectionId) override
{
CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false);
CARLA_ENGINE_THREAD_SAFE_SECTION

for (LinkedList<ConnectionToId>::Itenerator it = fUsedConnections.begin(); it.valid(); it.next())
{
@@ -895,6 +905,7 @@ public:
bool patchbayRefresh() override
{
CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false);
CARLA_ENGINE_THREAD_SAFE_SECTION

fLastGroupId = 0;
fLastPortId = 0;


+ 108
- 0
source/utils/CarlaMutex.hpp View File

@@ -141,6 +141,114 @@ private:
CARLA_DECLARE_NON_COPY_CLASS(CarlaMutex)
};

// -----------------------------------------------------------------------
// CarlaCriticalSection class

class CarlaCriticalSection
{
public:
/*
* Constructor.
*/
CarlaCriticalSection() noexcept
{
#ifdef CARLA_OS_WIN
InitializeCriticalSection(&fSection);
#else
fCounter = 0;
fOwnerThread = 0;
pthread_mutex_init(&fMutex, nullptr);
#endif
}

/*
* Destructor.
*/
~CarlaCriticalSection() noexcept
{
#ifdef CARLA_OS_WIN
DeleteCriticalSection(&fSection);
#else
pthread_mutex_destroy(&fMutex);
#endif
}

/*
* Enter section.
*/
void enter() noexcept
{
#ifdef CARLA_OS_WIN
EnterCriticalSection(&fSection);
#else
const pthread_t thisThread(pthread_self());

if (fOwnerThread == thisThread)
{
++fCounter;
}
else
{
pthread_mutex_lock(&fMutex);
fOwnerThread = thisThread;
fCounter = 0;
}
#endif
}

/*
* Leave section.
*/
void leave() noexcept
{
#ifdef CARLA_OS_WIN
LeaveCriticalSection(&fSection);
#else
if (--fCounter < 0)
{
fOwnerThread = 0;
pthread_mutex_unlock(&fMutex);
}
#endif
}

/*
* Helper class to enter&leave during a function scope.
*/
class Scope
{
public:
Scope(CarlaCriticalSection& cs) noexcept
: fSection(cs)
{
fSection.enter();
}

~Scope() noexcept
{
fSection.leave();
}

private:
CarlaCriticalSection& fSection;

CARLA_PREVENT_HEAP_ALLOCATION
CARLA_DECLARE_NON_COPY_CLASS(Scope)
};

private:
#ifdef CARLA_OS_WIN
CRITICAL_SECTION fSection;
#else
int fCounter;
pthread_t fOwnerThread;
pthread_mutex_t fMutex;
#endif

CARLA_PREVENT_HEAP_ALLOCATION
CARLA_DECLARE_NON_COPY_CLASS(CarlaCriticalSection)
};

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

#endif // CARLA_MUTEX_HPP_INCLUDED

Loading…
Cancel
Save