diff options
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | src/jalv.c | 133 | ||||
-rw-r--r-- | src/worker.c | 9 |
3 files changed, 95 insertions, 50 deletions
@@ -13,6 +13,7 @@ jalv (1.6.7) unstable; urgency=medium * Fix memory leaks * Fix outdated man pages * Fix spurious transport messages + * Fix thread-safety of plugin/UI communication rings * Flush stdout after printing control values in console interface * Print status information consistently to stdout * Propagate worker errors to the scheduler when possible @@ -20,7 +21,7 @@ jalv (1.6.7) unstable; urgency=medium * Remove Qt4 support * Switch to meson build system - -- David Robillard <d@drobilla.net> Wed, 10 Aug 2022 16:51:40 +0000 + -- David Robillard <d@drobilla.net> Wed, 10 Aug 2022 17:04:22 +0000 jalv (1.6.6) stable; urgency=medium @@ -494,6 +494,42 @@ jalv_ui_is_resizable(Jalv* jalv) return !fs_matches && !nrs_matches; } +static void +jalv_send_control_to_plugin(Jalv* const jalv, + uint32_t port_index, + uint32_t buffer_size, + const void* buffer) +{ + if (buffer_size != sizeof(float)) { + jalv_log(JALV_LOG_ERR, "UI wrote invalid control size %u\n", buffer_size); + + } else { + jalv_write_control( + jalv, jalv->ui_to_plugin, port_index, *(const float*)buffer); + } +} + +static void +jalv_send_event_to_plugin(Jalv* const jalv, + uint32_t port_index, + uint32_t buffer_size, + const void* buffer) +{ + const LV2_Atom* const atom = (const LV2_Atom*)buffer; + + if (buffer_size < sizeof(LV2_Atom)) { + jalv_log(JALV_LOG_ERR, "UI wrote impossible atom size\n"); + + } else if (sizeof(LV2_Atom) + atom->size != buffer_size) { + jalv_log(JALV_LOG_ERR, "UI wrote corrupt atom size\n"); + + } else { + jalv_dump_atom(jalv, stdout, "UI => Plugin", atom, 36); + jalv_write_event( + jalv, jalv->ui_to_plugin, port_index, atom->size, atom->type, atom + 1U); + } +} + void jalv_send_to_plugin(void* const jalv_handle, uint32_t port_index, @@ -503,30 +539,21 @@ jalv_send_to_plugin(void* const jalv_handle, { Jalv* const jalv = (Jalv*)jalv_handle; - if (protocol != 0 && protocol != jalv->urids.atom_eventTransfer) { + if (port_index >= jalv->num_ports) { + jalv_log(JALV_LOG_ERR, "UI wrote to invalid port index %u\n", port_index); + + } else if (protocol == 0U) { + jalv_send_control_to_plugin(jalv, port_index, buffer_size, buffer); + + } else if (protocol == jalv->urids.atom_eventTransfer) { + jalv_send_event_to_plugin(jalv, port_index, buffer_size, buffer); + + } else { jalv_log(JALV_LOG_ERR, "UI wrote with unsupported protocol %u (%s)\n", protocol, unmap_uri(jalv, protocol)); - return; - } - - if (port_index >= jalv->num_ports) { - jalv_log(JALV_LOG_ERR, "UI wrote to invalid port index %u\n", port_index); - return; - } - - if (protocol == jalv->urids.atom_eventTransfer) { - jalv_dump_atom(jalv, stdout, "UI => Plugin", (const LV2_Atom*)buffer, 36); } - - char buf[MSG_BUFFER_SIZE]; - ControlChange* ev = (ControlChange*)buf; - ev->index = port_index; - ev->protocol = protocol; - ev->size = buffer_size; - memcpy(ev + 1, buffer, buffer_size); - zix_ring_write(jalv->ui_to_plugin, buf, sizeof(ControlChange) + buffer_size); } void @@ -536,10 +563,13 @@ jalv_apply_ui_events(Jalv* jalv, uint32_t nframes) return; } - ControlChange ev; + ControlChange ev = {0U, 0U, 0U}; const size_t space = zix_ring_read_space(jalv->ui_to_plugin); for (size_t i = 0; i < space; i += sizeof(ev) + ev.size) { - zix_ring_read(jalv->ui_to_plugin, &ev, sizeof(ev)); + if (zix_ring_read(jalv->ui_to_plugin, &ev, sizeof(ev)) != sizeof(ev)) { + jalv_log(JALV_LOG_ERR, "Failed to read header from UI ring buffer\n"); + break; + } char buffer[MSG_BUFFER_SIZE]; if (zix_ring_read(jalv->ui_to_plugin, buffer, ev.size) != ev.size) { @@ -592,6 +622,27 @@ jalv_init_ui(Jalv* jalv) } } +static int +jalv_write_control_change(Jalv* const jalv, + ZixRing* const target, + const void* const header, + const uint32_t header_size, + const void* const body, + const uint32_t body_size) +{ + ZixRingTransaction tx = zix_ring_begin_write(target); + if (zix_ring_amend_write(target, &tx, header, header_size) || + zix_ring_amend_write(target, &tx, body, body_size)) { + jalv_log(JALV_LOG_ERR, + target == jalv->plugin_to_ui ? "Plugin => UI buffer overflow" + : "UI => Plugin buffer overflow"); + return -1; + } + + zix_ring_commit_write(target, &tx); + return 0; +} + int jalv_write_event(Jalv* const jalv, ZixRing* const target, @@ -601,23 +652,18 @@ jalv_write_event(Jalv* const jalv, const void* const body) { // TODO: Be more discriminate about what to send - char evbuf[sizeof(ControlChange) + sizeof(LV2_Atom)]; - ControlChange* ev = (ControlChange*)evbuf; - ev->index = port_index; - ev->protocol = jalv->urids.atom_eventTransfer; - ev->size = sizeof(LV2_Atom) + size; - - LV2_Atom* atom = (LV2_Atom*)(ev + 1); - atom->type = type; - atom->size = size; - - if (zix_ring_write_space(target) >= sizeof(evbuf) + size) { - zix_ring_write(target, evbuf, sizeof(evbuf)); - zix_ring_write(target, (const char*)body, size); - return 0; - } - return 1; + typedef struct { + ControlChange change; + LV2_Atom atom; + } Header; + + const Header header = { + {port_index, jalv->urids.atom_eventTransfer, sizeof(LV2_Atom) + size}, + {size, type}}; + + return jalv_write_control_change( + jalv, target, &header, sizeof(header), body, size); } int @@ -626,17 +672,10 @@ jalv_write_control(Jalv* const jalv, const uint32_t port_index, const float value) { - (void)jalv; - - char buf[sizeof(ControlChange) + sizeof(value)]; - - ControlChange* const ev = (ControlChange*)buf; - ev->index = port_index; - ev->protocol = 0U; - ev->size = sizeof(value); - *(float*)(ev + 1) = value; + const ControlChange header = {port_index, 0, sizeof(value)}; - return zix_ring_write(target, buf, sizeof(buf)) != sizeof(buf); + return jalv_write_control_change( + jalv, target, &header, sizeof(header), &value, sizeof(value)); } void diff --git a/src/worker.c b/src/worker.c index 7f502e1..b062723 100644 --- a/src/worker.c +++ b/src/worker.c @@ -15,8 +15,13 @@ static LV2_Worker_Status jalv_worker_write_packet(ZixRing* const target, uint32_t size, const void* data) { - zix_ring_write(target, (const char*)&size, sizeof(size)); - zix_ring_write(target, (const char*)data, size); + ZixRingTransaction tx = zix_ring_begin_write(target); + if (zix_ring_amend_write(target, &tx, &size, sizeof(size)) || + zix_ring_amend_write(target, &tx, data, size)) { + return LV2_WORKER_ERR_NO_SPACE; + } + + zix_ring_commit_write(target, &tx); return LV2_WORKER_SUCCESS; } |