diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/jalv.c | 2 | ||||
-rw-r--r-- | src/worker.c | 101 | ||||
-rw-r--r-- | src/worker.h | 39 |
3 files changed, 79 insertions, 63 deletions
@@ -1118,6 +1118,8 @@ jalv_open(Jalv* const jalv, int* argc, char*** argv) } } + jalv_worker_launch(jalv->worker); + // Activate plugin lilv_instance_activate(jalv->instance); diff --git a/src/worker.c b/src/worker.c index d34fedb..4592a40 100644 --- a/src/worker.c +++ b/src/worker.c @@ -15,17 +15,23 @@ #define MAX_PACKET_SIZE 4096U +typedef enum { + STATE_SINGLE_THREADED, ///< Single-threaded worker (only state) + STATE_STOPPED, ///< Thread is exited + STATE_LAUNCHED, ///< Thread is running + STATE_MUST_EXIT, ///< Thread exit requested +} WorkerState; + struct JalvWorkerImpl { ZixRing* requests; ///< Requests to the worker ZixRing* responses; ///< Responses from the worker void* response; ///< Worker response buffer ZixSem* lock; ///< Lock for plugin work() method - bool exit; ///< Exit flag ZixSem sem; ///< Worker semaphore + WorkerState state; ///< Worker state ZixThread thread; ///< Worker thread LV2_Handle handle; ///< Plugin handle const LV2_Worker_Interface* iface; ///< Plugin worker interface - bool threaded; ///< Run work in another thread }; static LV2_Worker_Status @@ -60,7 +66,7 @@ worker_func(void* const data) while (true) { // Wait for a request zix_sem_wait(&worker->sem); - if (worker->exit) { + if (worker->state == STATE_MUST_EXIT) { break; } @@ -88,88 +94,86 @@ worker_func(void* const data) } free(buf); + worker->state = STATE_STOPPED; return NULL; } -static ZixStatus -jalv_worker_launch(JalvWorker* const worker) -{ - ZixStatus st = ZIX_STATUS_SUCCESS; - - if ((st = zix_sem_init(&worker->sem, 0)) || - (st = zix_thread_create(&worker->thread, 4096U, worker_func, worker))) { - return st; - } - - ZixRing* const requests = zix_ring_new(NULL, MAX_PACKET_SIZE); - if (!requests) { - zix_thread_join(worker->thread); - zix_sem_destroy(&worker->sem); - return ZIX_STATUS_NO_MEM; - } - - zix_ring_mlock(requests); - worker->requests = requests; - return ZIX_STATUS_SUCCESS; -} - JalvWorker* jalv_worker_new(ZixSem* const lock, const bool threaded) { JalvWorker* const worker = (JalvWorker*)calloc(1, sizeof(JalvWorker)); + ZixRing* const requests = zix_ring_new(NULL, MAX_PACKET_SIZE); ZixRing* const responses = zix_ring_new(NULL, MAX_PACKET_SIZE); void* const response = calloc(1, MAX_PACKET_SIZE); if (worker && responses && response) { - worker->threaded = threaded; + worker->requests = requests; worker->responses = responses; worker->response = response; worker->lock = lock; - worker->exit = false; + worker->state = threaded ? STATE_STOPPED : STATE_SINGLE_THREADED; + zix_ring_mlock(requests); zix_ring_mlock(responses); - if (!threaded || !jalv_worker_launch(worker)) { - return worker; - } + return worker; } free(response); zix_ring_free(responses); + zix_ring_free(requests); free(worker); return NULL; } void -jalv_worker_attach(JalvWorker* const worker, - const LV2_Worker_Interface* const iface, - LV2_Handle handle) +jalv_worker_free(JalvWorker* const worker) { if (worker) { - worker->iface = iface; - worker->handle = handle; + jalv_worker_exit(worker); + zix_ring_free(worker->requests); + zix_ring_free(worker->responses); + free(worker->response); + free(worker); + } +} + +ZixStatus +jalv_worker_launch(JalvWorker* const worker) +{ + ZixStatus st = ZIX_STATUS_SUCCESS; + if (worker->state == STATE_STOPPED) { + if ((st = zix_sem_init(&worker->sem, 0))) { + return st; + } + + if ((st = zix_thread_create(&worker->thread, 4096U, worker_func, worker))) { + zix_sem_destroy(&worker->sem); + return st; + } + + worker->state = STATE_LAUNCHED; } + return ZIX_STATUS_SUCCESS; } void jalv_worker_exit(JalvWorker* const worker) { - if (worker && worker->threaded) { - worker->exit = true; + if (worker && worker->state == STATE_LAUNCHED) { + worker->state = STATE_MUST_EXIT; zix_sem_post(&worker->sem); zix_thread_join(worker->thread); - worker->threaded = false; } } void -jalv_worker_free(JalvWorker* const worker) +jalv_worker_attach(JalvWorker* const worker, + const LV2_Worker_Interface* const iface, + LV2_Handle handle) { if (worker) { - jalv_worker_exit(worker); - zix_ring_free(worker->requests); - zix_ring_free(worker->responses); - free(worker->response); - free(worker); + worker->iface = iface; + worker->handle = handle; } } @@ -181,17 +185,16 @@ jalv_worker_schedule(LV2_Worker_Schedule_Handle handle, JalvWorker* const worker = (JalvWorker*)handle; LV2_Worker_Status st = LV2_WORKER_SUCCESS; - if (!worker || !size) { - return LV2_WORKER_ERR_UNKNOWN; - } + if (!worker || !size || worker->state == STATE_STOPPED) { + st = LV2_WORKER_ERR_UNKNOWN; - if (worker->threaded) { + } else if (worker->state == STATE_LAUNCHED) { // Schedule a request to be executed by the worker thread if (!(st = jalv_worker_write_packet(worker->requests, size, data))) { zix_sem_post(&worker->sem); } - } else { + } else if (worker->state == STATE_SINGLE_THREADED) { // Execute work immediately in this thread zix_sem_wait(worker->lock); st = worker->iface->work( diff --git a/src/worker.h b/src/worker.h index 88b011b..b95fcc2 100644 --- a/src/worker.h +++ b/src/worker.h @@ -6,10 +6,10 @@ #include "attributes.h" -#include "zix/sem.h" - #include "lv2/core/lv2.h" #include "lv2/worker/worker.h" +#include "zix/sem.h" +#include "zix/status.h" #include <stdbool.h> #include <stdint.h> @@ -37,18 +37,23 @@ JalvWorker* jalv_worker_new(ZixSem* lock, bool threaded); /** - Attach the worker to a plugin instance. - - This must be called before scheduling any work. + Free a worker allocated with jalv_worker_new(). - @param worker Worker to activate and attach to a plugin. - @param iface Worker interface from plugin. - @param handle Handle to the LV2 plugin this worker is for. + Calls jalv_worker_exit() to terminate the running thread if necessary. */ void -jalv_worker_attach(JalvWorker* worker, - const LV2_Worker_Interface* iface, - LV2_Handle handle); +jalv_worker_free(JalvWorker* worker); + +/** + Launch the worker's thread. + + For threaded workers, this launches the thread if it isn't already running. + For non-threaded workers, this does nothing. + + @return Zero on success, or a non-zero error code if launching failed. +*/ +ZixStatus +jalv_worker_launch(JalvWorker* worker); /** Terminate the worker's thread if necessary. @@ -60,12 +65,18 @@ void jalv_worker_exit(JalvWorker* worker); /** - Free a worker allocated with jalv_worker_new(). + Attach the worker to a plugin instance. - Calls jalv_worker_exit() to terminate the running thread if necessary. + This must be called before scheduling any work. + + @param worker Worker to activate and attach to a plugin. + @param iface Worker interface from plugin. + @param handle Handle to the LV2 plugin this worker is for. */ void -jalv_worker_free(JalvWorker* worker); +jalv_worker_attach(JalvWorker* worker, + const LV2_Worker_Interface* iface, + LV2_Handle handle); /** Schedule work to be performed by the worker in the audio thread. |