fix: defer freeing old channel array until RT thread sees new pointer

Co-authored-by: aider (deepseek/deepseek-reasoner) <aider@aider.chat>
This commit is contained in:
Loic Coenen
2026-05-10 10:50:03 +00:00
parent b7827e7311
commit 9da4481300

View File

@@ -30,6 +30,10 @@ spsc_queue_t cmd_queue;
static int pending_unregister_idx = -1;
static int pending_unregister_cycle = 0;
/* Deferred free of old channel array (must not free while RT thread may hold pointer) */
static struct channel_t *pending_old = NULL;
static int pending_old_cycle = 0;
/* Helper: grow the channel array so that index idx is valid */
static int ensure_capacity(jack_client_t *client, int idx) {
(void)client;
@@ -45,10 +49,12 @@ static int ensure_capacity(jack_client_t *client, int idx) {
/* copy existing channels */
if (cur_cap > 0)
memcpy(new_arr, atomic_load(&channels), cur_cap * sizeof(struct channel_t));
/* atomically publish new array */
/* atomically publish new array, defer free of old */
struct channel_t *old = atomic_exchange(&channels, new_arr);
atomic_store(&channel_capacity, new_cap);
free(old);
/* schedule old pointer for later deallocation (after RT cycle) */
pending_old = old;
pending_old_cycle = atomic_load(&global_rt_cycles);
return 0;
}
@@ -397,4 +403,13 @@ void looper_process_commands(jack_client_t *client) {
pending_unregister_idx = -1;
}
}
/* Deferred free of old channel array wait until RT thread has seen new pointer */
if (pending_old != NULL) {
int current_cycle = atomic_load(&global_rt_cycles);
if (current_cycle - pending_old_cycle >= 1) {
free(pending_old);
pending_old = NULL;
}
}
}