Skip to content

Commit

Permalink
Replace determination-renderer semaphore with a futex-based system
Browse files Browse the repository at this point in the history
  • Loading branch information
white-axe committed Sep 2, 2024
1 parent 6a35e50 commit 449d120
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 36 deletions.
1 change: 1 addition & 0 deletions pkgs/determination-renderer/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ cmake_minimum_required(VERSION 3.15)
project(determination-renderer)
add_subdirectory(carla/cmake)
add_executable(determination-renderer)
set_property(TARGET determination-renderer PROPERTY CXX_STANDARD 20)
target_link_libraries(determination-renderer PUBLIC carla::standalone jack)
target_sources(determination-renderer PRIVATE renderer.cpp)
64 changes: 28 additions & 36 deletions pkgs/determination-renderer/src/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,14 @@

#include <algorithm>
#include <atomic>
#include <cassert>
#include <cstring>
#include <iostream>
#include <iomanip>
#include <mutex>
#include <semaphore.h>
#include "carla/source/jackbridge/JackBridge.hpp"
#include "carla/source/includes/CarlaNativePlugin.h"

static sem_t semaphore;

enum State {
WaitForRenderFinish,
WaitForFreewheelOn,
Expand All @@ -33,9 +31,6 @@ static jack_time_t elapsedTime;
static jack_nframes_t currentFrame;
static std::mutex mutex;

static uint8_t buf[6 * 682];
static uint8_t *bufptr = buf;

static CarlaHostHandle handle;
static FILE *pipeFile;
static jack_client_t *client;
Expand All @@ -51,31 +46,31 @@ static const char *error = NULL;
jack_client_t *determination_get_jack_client(CarlaHostHandle handle);
void determination_set_process_callback(CarlaHostHandle handle, void (*callback)(jack_nframes_t, bool));

// Sets the state to `val` and wakes up a thread waiting for the state to change, if any.
inline void post(State val) {
state.store(val);
sem_post(&semaphore);
if (state.exchange(val) != val)
state.notify_one();
}

inline State wait() {
while (sem_wait(&semaphore)) {
// If a signal handler is called while `sem_wait()` is waiting,
// `sem_wait()` may stop waiting and return with a nonzero return value after the signal handler returns.
// We actually want to continue waiting for the semaphore to be posted in that case,
// hence why we're spinning here.
}
return state.load();
}

inline State store_and_wait(State val) {
// Sets the state to `val`, waits for the state to change and then returns the new state.
inline State wait(State val) {
state.store(val);
return wait();
State result;
do
state.wait(val);
while ((result = state.load()) == val);
return result;
}

inline State store_and_wait_for(State val, State cond) {
State result = store_and_wait(val);
while (result != cond)
result = wait();
return result;
// If the current state is not equal to `expected`, returns immediately with the current state.
// Otherwise, sets the state to `desired`, waits for the state to change and then returns the new state.
inline State wait_if(State expected, State desired) {
if (state.compare_exchange_strong(expected, desired)) {
do
state.wait(desired);
while ((expected = state.load()) == desired);
}
return expected;
}

inline void update_progress(jack_position_t *pos, jack_time_t newElapsedTime) {
Expand All @@ -91,6 +86,9 @@ inline int32_t convert_sample(float sample) {
}

static void process(jack_nframes_t nframes, bool freewheel) {
static uint8_t buf[6 * 682];
static uint8_t *bufptr = buf;

switch (state.load()) {
case WaitForRenderFinish:
case LogRenderProgress:
Expand Down Expand Up @@ -216,18 +214,19 @@ inline bool render(char *projectPath) {
determination_set_process_callback(handle, process);

// Block this thread until `process()` detects that freewheeling is enabled
store_and_wait_for(WaitForFreewheelOn, Ok);
wait(WaitForFreewheelOn);

std::cerr << "[determination-renderer] Starting JACK transport" << std::endl;
carla_transport_play(handle);

// Block this thread until `process()` detects that the JACK transport has reached the end position or an error occurred
std::cerr << "[determination-renderer] Rendering audio" << std::endl;
State result = store_and_wait(WaitForRenderFinish);
State result = wait(WaitForRenderFinish);
for (;;) {
switch (result) {
case LogRenderProgress:
log_progress();
result = wait_if(LogRenderProgress, WaitForRenderFinish);
break;
case Ok:
log_progress();
Expand All @@ -239,12 +238,12 @@ inline bool render(char *projectPath) {
default:
break;
}
result = wait();
}
}

int main(int argc, char **argv) {
std::cerr << "[determination-renderer] Initializing" << std::endl;
assert(state.is_always_lock_free());
start = std::strtoll(argv[2], NULL, 10);
end = std::strtoll(argv[3], NULL, 10);
progressDelay = std::strtoll(argv[4], NULL, 10);
Expand All @@ -263,12 +262,6 @@ int main(int argc, char **argv) {
carla_engine_close(handle);
return 1;
}
if (sem_init(&semaphore, 0, 0)) {
std::cerr << "\e[91m[determination-renderer] Failed to initialize semaphore\e[0m" << std::endl;
std::fclose(pipeFile);
carla_engine_close(handle);
return 1;
}

bool ok = render(argv[1]);
if (!ok)
Expand All @@ -284,11 +277,10 @@ int main(int argc, char **argv) {
std::cerr << "[determination-renderer] Failed to disable JACK freewheel mode" << std::endl;
} else {
// Block this thread until `process()` detects that freewheeling is disabled
store_and_wait_for(WaitForFreewheelOff, Ok);
wait(WaitForFreewheelOff);
}

std::cerr << "[determination-renderer] Cleaning up" << std::endl;
sem_destroy(&semaphore);
std::fclose(pipeFile);
carla_engine_close(handle);

Expand Down

0 comments on commit 449d120

Please sign in to comment.