Browse Source

Protect jack metadata usage with a mutex; other position fixes

Signed-off-by: falkTX <falktx@falktx.com>
tags/v2.2.0-RC1
falkTX 4 years ago
parent
commit
0f53835c6d
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
4 changed files with 180 additions and 133 deletions
  1. +2
    -1
      source/backend/engine/CarlaEngineGraph.cpp
  2. +166
    -124
      source/backend/engine/CarlaEngineJack.cpp
  3. +5
    -1
      source/frontend/patchcanvas/canvasbox.py
  4. +7
    -7
      source/frontend/patchcanvas/patchcanvas.py

+ 2
- 1
source/backend/engine/CarlaEngineGraph.cpp View File

@@ -2831,7 +2831,8 @@ bool CarlaEngine::patchbayDisconnect(const bool external, const uint connectionI
bool CarlaEngine::patchbaySetGroupPos(const bool sendHost, const bool sendOSC, const bool external,
const uint groupId, const int x1, const int y1, const int x2, const int y2)
{
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->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK ||
pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY, false);
CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(), false);
carla_debug("CarlaEngine::patchbaySetGroupPos(%u, %i, %i, %i, %i)", groupId, x1, y1, x2, y2);



+ 166
- 124
source/backend/engine/CarlaEngineJack.cpp View File

@@ -1244,6 +1244,7 @@ public:
fUsedGroups(),
fUsedPorts(),
fUsedConnections(),
fThreadSafeMetadataMutex(),
fPatchbayProcThreadProtectionMutex(),
fRetConns(),
fPostPonedEvents(),
@@ -1281,7 +1282,8 @@ public:
uint getMaxClientNameSize() const noexcept override
{
#ifndef BUILD_BRIDGE
if (pData->options.processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT || pData->options.processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
if (pData->options.processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT ||
pData->options.processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
#endif
{
try {
@@ -1430,27 +1432,31 @@ public:
}
}

if (char* const uuidstr = jackbridge_client_get_uuid(fClient))
{
jack_uuid_t uuid;
const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);

if (jackbridge_uuid_parse(uuidstr, &uuid))
if (char* const uuidstr = jackbridge_client_get_uuid(fClient))
{
jack_uuid_t uuid;

if (jackbridge_uuid_parse(uuidstr, &uuid))
{
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
const CarlaString& tcp(pData->osc.getServerPathTCP());
const CarlaString& udp(pData->osc.getServerPathUDP());
const CarlaString& tcp(pData->osc.getServerPathTCP());
const CarlaString& udp(pData->osc.getServerPathUDP());

if (tcp.isNotEmpty())
jackbridge_set_property(fClient, uuid,
"https://kx.studio/ns/carla/osc-tcp", tcp, URI_TYPE_STRING);
if (tcp.isNotEmpty())
jackbridge_set_property(fClient, uuid,
"https://kx.studio/ns/carla/osc-tcp", tcp, URI_TYPE_STRING);

if (tcp.isNotEmpty())
jackbridge_set_property(fClient, uuid,
"https://kx.studio/ns/carla/osc-udp", udp, URI_TYPE_STRING);
if (tcp.isNotEmpty())
jackbridge_set_property(fClient, uuid,
"https://kx.studio/ns/carla/osc-udp", udp, URI_TYPE_STRING);
#endif
}
}

jackbridge_free(uuidstr);
jackbridge_free(uuidstr);
}
}

if (jackbridge_activate(fClient))
@@ -1613,10 +1619,13 @@ public:
const int value1, const int value2, const int value3,
const float valuef, const char* const valueStr) noexcept override
{
if (action == ENGINE_CALLBACK_PROJECT_LOAD_FINISHED && fTimebaseMaster)
if (action == ENGINE_CALLBACK_PROJECT_LOAD_FINISHED)
{
// project finished loading, need to set bpm here, so we force an update of timebase master
transportRelocate(pData->timeInfo.frame);
if (fTimebaseMaster)
{
// project finished loading, need to set bpm here, so we force an update of timebase master
transportRelocate(pData->timeInfo.frame);
}
}

CarlaEngine::callback(sendHost, sendOsc, action, pluginId, value1, value2, value3, valuef, valueStr);
@@ -1631,63 +1640,67 @@ public:
fPostPonedUUIDs.swapWith(uuids);
}

for (int i=0; i<uuids.size(); ++i)
{
jack_uuid_t uuid = uuids.getUnchecked(i);

char uuidstr[JACK_UUID_STRING_SIZE];
carla_zeroStruct(uuidstr);
jackbridge_uuid_unparse(uuid, uuidstr);
const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);

if (char* const clientName = jackbridge_get_client_name_by_uuid(fClient, uuidstr))
for (int i=0; i<uuids.size(); ++i)
{
CARLA_SAFE_ASSERT_RETURN(clientName != nullptr && clientName[0] != '\0',);
jack_uuid_t uuid = uuids.getUnchecked(i);

uint groupId;
char uuidstr[JACK_UUID_STRING_SIZE];
carla_zeroStruct(uuidstr);
jackbridge_uuid_unparse(uuid, uuidstr);

if (char* const clientName = jackbridge_get_client_name_by_uuid(fClient, uuidstr))
{
const CarlaMutexLocker cml(fUsedGroups.mutex);
groupId = fUsedGroups.getGroupId(clientName);
}
CARLA_SAFE_ASSERT_RETURN(clientName != nullptr && clientName[0] != '\0',);

jackbridge_free(clientName);
CARLA_SAFE_ASSERT_RETURN(groupId != 0,);

char* value = nullptr;
char* type = nullptr;
uint groupId;

if (jackbridge_get_property(uuid, URI_POSITION, &value, &type)
&& value != nullptr
&& type != nullptr
&& std::strcmp(type, URI_TYPE_STRING) == 0)
{
if (char* sep1 = std::strstr(value, ":"))
{
int x1, y1 = 0, x2 = 0, y2 = 0;
*sep1++ = '\0';
x1 = std::atoi(value);
const CarlaMutexLocker cml(fUsedGroups.mutex);
groupId = fUsedGroups.getGroupId(clientName);
}

if (char* sep2 = std::strstr(sep1, ":"))
jackbridge_free(clientName);
CARLA_SAFE_ASSERT_RETURN(groupId != 0,);

char* value = nullptr;
char* type = nullptr;

if (jackbridge_get_property(uuid, URI_POSITION, &value, &type)
&& value != nullptr
&& type != nullptr
&& std::strcmp(type, URI_TYPE_STRING) == 0)
{
if (char* sep1 = std::strstr(value, ":"))
{
*sep2++ = '\0';
y1 = std::atoi(sep1);
int x1, y1 = 0, x2 = 0, y2 = 0;
*sep1++ = '\0';
x1 = std::atoi(value);

if (char* sep3 = std::strstr(sep2, ":"))
if (char* sep2 = std::strstr(sep1, ":"))
{
*sep3++ = '\0';
x2 = std::atoi(sep2);
y2 = std::atoi(sep3);
*sep2++ = '\0';
y1 = std::atoi(sep1);

if (char* sep3 = std::strstr(sep2, ":"))
{
*sep3++ = '\0';
x2 = std::atoi(sep2);
y2 = std::atoi(sep3);
}

callback(fExternalPatchbayHost, fExternalPatchbayOsc,
ENGINE_CALLBACK_PATCHBAY_CLIENT_POSITION_CHANGED,
groupId, x1, y1, x2, static_cast<float>(y2),
nullptr);
}

callback(fExternalPatchbayHost, fExternalPatchbayOsc,
ENGINE_CALLBACK_PATCHBAY_CLIENT_POSITION_CHANGED,
groupId, x1, y1, x2, static_cast<float>(y2),
nullptr);
}
}

jackbridge_free(value);
jackbridge_free(type);
jackbridge_free(value);
jackbridge_free(type);
}
}
}
}
@@ -1812,6 +1825,8 @@ public:
jackbridge_set_process_callback(client, carla_jack_process_callback_plugin, plugin);
jackbridge_on_shutdown(client, carla_jack_shutdown_callback_plugin, plugin);

const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);

if (char* const uuidstr = jackbridge_client_get_uuid(client))
{
jack_uuid_t uuid;
@@ -1819,7 +1834,7 @@ public:
if (jackbridge_uuid_parse(uuidstr, &uuid))
{
char strBufId[24];
std::snprintf(strBufId, 24, "%u", plugin->getId());
std::snprintf(strBufId, 23, "%u", plugin->getId());
strBufId[23] = '\0';

jackbridge_set_property(client, uuid,
@@ -2165,6 +2180,7 @@ public:
const uint groupId, const int x1, const int y1, const int x2, const int y2) override
{
CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(! pData->loadingProject, false);

if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY && ! external)
return CarlaEngine::patchbaySetGroupPos(sendHost, sendOSC, false, groupId, x1, y1, x2, y2);
@@ -2178,21 +2194,27 @@ public:
CARLA_SAFE_ASSERT_RETURN(groupName != nullptr && groupName[0] != '\0', false);
}

jack_uuid_t uuid;
bool ok;

{
char* const uuidstr = jackbridge_get_uuid_for_client_name(fClient, groupName);
CARLA_SAFE_ASSERT_RETURN(uuidstr != nullptr && uuidstr[0] != '\0', false);
const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);

const bool parsed = jackbridge_uuid_parse(uuidstr, &uuid);
jackbridge_free(uuidstr);
CARLA_SAFE_ASSERT_RETURN(parsed, false);
}
jack_uuid_t uuid;
{
char* const uuidstr = jackbridge_get_uuid_for_client_name(fClient, groupName);
CARLA_SAFE_ASSERT_RETURN(uuidstr != nullptr && uuidstr[0] != '\0', false);

char valueStr[STR_MAX];
std::snprintf(valueStr, STR_MAX-1, "%i:%i:%i:%i", x1, y1, x2, y2);
valueStr[STR_MAX-1] = '\0';
const bool parsed = jackbridge_uuid_parse(uuidstr, &uuid);
jackbridge_free(uuidstr);
CARLA_SAFE_ASSERT_RETURN(parsed, false);
}

char valueStr[STR_MAX];
std::snprintf(valueStr, STR_MAX-1, "%i:%i:%i:%i", x1, y1, x2, y2);
valueStr[STR_MAX-1] = '\0';

const bool ok = jackbridge_set_property(fClient, uuid, URI_POSITION, valueStr, URI_TYPE_STRING);
ok = jackbridge_set_property(fClient, uuid, URI_POSITION, valueStr, URI_TYPE_STRING);
}

callback(sendHost, sendOSC,
ENGINE_CALLBACK_PATCHBAY_CLIENT_POSITION_CHANGED,
@@ -2367,6 +2389,7 @@ public:
return CarlaEngine::getPatchbayPositions(external, count);

const CarlaMutexLocker cml(fUsedGroups.mutex);
const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);

if (const std::size_t maxCount = fUsedGroups.list.count())
{
@@ -2536,22 +2559,30 @@ public:
CARLA_SAFE_ASSERT(groupId != 0);
}

jack_uuid_t uuid;
{
char* const uuidstr = jackbridge_get_uuid_for_client_name(fClient, ppos.name);
CARLA_SAFE_ASSERT_RETURN(uuidstr != nullptr && uuidstr[0] != '\0',);
const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);

const bool parsed = jackbridge_uuid_parse(uuidstr, &uuid);
jackbridge_free(uuidstr);
CARLA_SAFE_ASSERT_RETURN(parsed,);
}
jack_uuid_t uuid;
{
char* const uuidstr = jackbridge_get_uuid_for_client_name(fClient, ppos.name);
CARLA_SAFE_ASSERT_RETURN(uuidstr != nullptr && uuidstr[0] != '\0',);

const bool parsed = jackbridge_uuid_parse(uuidstr, &uuid);
jackbridge_free(uuidstr);
CARLA_SAFE_ASSERT_RETURN(parsed,);
}

char valueStr[STR_MAX];
std::snprintf(valueStr, STR_MAX-1, "%i:%i:%i:%i", ppos.x1, ppos.y1, ppos.x2, ppos.y2);
valueStr[STR_MAX-1] = '\0';
char valueStr[STR_MAX];
std::snprintf(valueStr, STR_MAX-1, "%i:%i:%i:%i", ppos.x1, ppos.y1, ppos.x2, ppos.y2);
valueStr[STR_MAX-1] = '\0';

jackbridge_set_property(fClient, uuid, URI_POSITION, valueStr, URI_TYPE_STRING);
jackbridge_set_property(fClient, uuid, URI_POSITION, valueStr, URI_TYPE_STRING);
}

# if 0
/* NOTE: This does not seem to be needed, as JACK notifies the caller about meta-data changes,
* even for the client that triggered the change. Odd..
*/
if (groupId != 0)
{
callback(true, true,
@@ -2559,6 +2590,7 @@ public:
groupId, ppos.x1, ppos.y1, ppos.x2, static_cast<float>(ppos.y2),
nullptr);
}
# endif
}
#endif

@@ -3284,6 +3316,7 @@ private:
PatchbayGroupList fUsedGroups;
PatchbayPortList fUsedPorts;
PatchbayConnectionList fUsedConnections;
CarlaRecursiveMutex fThreadSafeMetadataMutex;
CarlaMutex fPatchbayProcThreadProtectionMutex;

mutable CharStringListPtr fRetConns;
@@ -3296,6 +3329,8 @@ private:
if (pData->options.processMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
return;

const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);

jack_uuid_t uuid;
{
char* const uuidstr = jackbridge_get_uuid_for_client_name(fClient, clientName);
@@ -3320,6 +3355,9 @@ private:
CARLA_SAFE_ASSERT_RETURN(std::strcmp(type, URI_TYPE_STRING) == 0,);

clientBelongsToUs = fClientName == value;

jackbridge_free(value);
jackbridge_free(type);
}

{
@@ -3565,62 +3603,66 @@ private:
0, 0.0f,
ourName);

for (LinkedList<GroupToIdData>::Itenerator it = groupCallbackData.begin2(); it.valid(); it.next())
{
const GroupToIdData& group(it.getValue(groupFallback));

callback(sendHost, sendOSC,
ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED,
group.id,
group.icon,
group.pluginId,
0, 0.0f,
group.strVal);
const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);

jack_uuid_t uuid;
for (LinkedList<GroupToIdData>::Itenerator it = groupCallbackData.begin2(); it.valid(); it.next())
{
char* const uuidstr = jackbridge_get_uuid_for_client_name(fClient, group.strVal);
CARLA_SAFE_ASSERT_RETURN(uuidstr != nullptr && uuidstr[0] != '\0',);

const bool parsed = jackbridge_uuid_parse(uuidstr, &uuid);
jackbridge_free(uuidstr);
CARLA_SAFE_ASSERT_RETURN(parsed,);
}
const GroupToIdData& group(it.getValue(groupFallback));

char* value = nullptr;
char* type = nullptr;
callback(sendHost, sendOSC,
ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED,
group.id,
group.icon,
group.pluginId,
0, 0.0f,
group.strVal);

if (jackbridge_get_property(uuid, URI_POSITION, &value, &type)
&& value != nullptr
&& type != nullptr
&& std::strcmp(type, URI_TYPE_STRING) == 0)
{
if (char* sep1 = std::strstr(value, ":"))
jack_uuid_t uuid;
{
int x1, y1 = 0, x2 = 0, y2 = 0;
*sep1++ = '\0';
x1 = std::atoi(value);
char* const uuidstr = jackbridge_get_uuid_for_client_name(fClient, group.strVal);
CARLA_SAFE_ASSERT_RETURN(uuidstr != nullptr && uuidstr[0] != '\0',);

const bool parsed = jackbridge_uuid_parse(uuidstr, &uuid);
jackbridge_free(uuidstr);
CARLA_SAFE_ASSERT_RETURN(parsed,);
}

char* value = nullptr;
char* type = nullptr;

if (char* sep2 = std::strstr(sep1, ":"))
if (jackbridge_get_property(uuid, URI_POSITION, &value, &type)
&& value != nullptr
&& type != nullptr
&& std::strcmp(type, URI_TYPE_STRING) == 0)
{
if (char* sep1 = std::strstr(value, ":"))
{
*sep2++ = '\0';
y1 = std::atoi(sep1);
int x1, y1 = 0, x2 = 0, y2 = 0;
*sep1++ = '\0';
x1 = std::atoi(value);

if (char* sep3 = std::strstr(sep2, ":"))
if (char* sep2 = std::strstr(sep1, ":"))
{
*sep3++ = '\0';
x2 = std::atoi(sep2);
y2 = std::atoi(sep3);
*sep2++ = '\0';
y1 = std::atoi(sep1);

if (char* sep3 = std::strstr(sep2, ":"))
{
*sep3++ = '\0';
x2 = std::atoi(sep2);
y2 = std::atoi(sep3);
}
}
}

jackbridge_free(value);
jackbridge_free(type);
jackbridge_free(value);
jackbridge_free(type);

callback(sendHost, sendOSC,
ENGINE_CALLBACK_PATCHBAY_CLIENT_POSITION_CHANGED,
group.id, x1, y1, x2, static_cast<float>(y2),
nullptr);
callback(sendHost, sendOSC,
ENGINE_CALLBACK_PATCHBAY_CLIENT_POSITION_CHANGED,
group.id, x1, y1, x2, static_cast<float>(y2),
nullptr);
}
}
}
}


+ 5
- 1
source/frontend/patchcanvas/canvasbox.py View File

@@ -226,7 +226,7 @@ class CanvasBox(QGraphicsObject):
self.updatePositions()

def setShadowOpacity(self, opacity):
if self.shadow:
if self.shadow is not None:
self.shadow.setOpacity(opacity)

def addPortFromGroup(self, port_id, port_mode, port_type, port_name, is_alternate):
@@ -234,7 +234,9 @@ class CanvasBox(QGraphicsObject):
if options.auto_hide_groups:
if options.eyecandy == EYECANDY_FULL:
CanvasItemFX(self, True, False)
self.blockSignals(True)
self.setVisible(True)
self.blockSignals(False)

new_widget = CanvasPort(self.m_group_id, port_id, port_name, port_mode, port_type, is_alternate, self)

@@ -266,7 +268,9 @@ class CanvasBox(QGraphicsObject):
if options.eyecandy == EYECANDY_FULL:
CanvasItemFX(self, False, False)
else:
self.blockSignals(True)
self.setVisible(False)
self.blockSignals(False)

def addLineFromGroup(self, line, connection_id):
new_cbline = cb_line_t(line, connection_id)


+ 7
- 7
source/frontend/patchcanvas/patchcanvas.py View File

@@ -329,6 +329,7 @@ def addGroup(group_id, group_name, split=SPLIT_UNDEF, icon=ICON_APPLICATION):

group_box = CanvasBox(group_id, group_name, icon)
group_box.positionChanged.connect(canvas.qobject.boxPositionChanged)
group_box.blockSignals(True)

group_dict = group_dict_t()
group_dict.group_id = group_id
@@ -343,29 +344,26 @@ def addGroup(group_id, group_name, split=SPLIT_UNDEF, icon=ICON_APPLICATION):
if split == SPLIT_YES:
group_box.setSplit(True, PORT_MODE_OUTPUT)

group_box.blockSignals(True)
if features.handle_group_pos:
group_box.setPos(getStoredCanvasPosition(group_name + "_OUTPUT", CanvasGetNewGroupPos(False)))
elif old_matching_group is not None:
group_box.setPos(old_matching_group[1])
else:
group_box.setPos(CanvasGetNewGroupPos(False))
group_box.blockSignals(False)

group_sbox = CanvasBox(group_id, group_name, icon)
group_sbox.setSplit(True, PORT_MODE_INPUT)
group_sbox.positionChanged.connect(canvas.qobject.sboxPositionChanged)
group_sbox.blockSignals(True)
group_sbox.setSplit(True, PORT_MODE_INPUT)

group_dict.widgets[1] = group_sbox

group_sbox.blockSignals(True)
if features.handle_group_pos:
group_sbox.setPos(getStoredCanvasPosition(group_name + "_INPUT", CanvasGetNewGroupPos(True)))
elif old_matching_group is not None and old_matching_group[0]:
group_sbox.setPos(old_matching_group[2])
else:
group_sbox.setPos(CanvasGetNewGroupPos(True))
group_sbox.blockSignals(False)

canvas.last_z_value += 1
group_sbox.setZValue(canvas.last_z_value)
@@ -374,6 +372,7 @@ def addGroup(group_id, group_name, split=SPLIT_UNDEF, icon=ICON_APPLICATION):
CanvasItemFX(group_sbox, True, False)

group_sbox.checkItemPos()
group_sbox.blockSignals(False)

else:
group_box.setSplit(False)
@@ -387,11 +386,12 @@ def addGroup(group_id, group_name, split=SPLIT_UNDEF, icon=ICON_APPLICATION):
horizontal = bool(icon == ICON_HARDWARE or icon == ICON_LADISH_ROOM)
group_box.setPos(CanvasGetNewGroupPos(horizontal))

group_box.checkItemPos()

canvas.last_z_value += 1
group_box.setZValue(canvas.last_z_value)

group_box.checkItemPos()
group_box.blockSignals(False)

canvas.group_list.append(group_dict)

if options.eyecandy == EYECANDY_FULL and not options.auto_hide_groups:


Loading…
Cancel
Save