fix: add timeout, memory checks, and CPU limits to prevent system freeze
Co-authored-by: aider (deepseek/deepseek-coder) <aider@aider.chat>
This commit is contained in:
@@ -10,6 +10,8 @@
|
||||
#include <jack/midiport.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#ifndef M_PI
|
||||
@@ -18,12 +20,15 @@
|
||||
|
||||
// Test configuration
|
||||
#define TEST_SAMPLE_RATE 48000
|
||||
#define TEST_NFRAMES 1024
|
||||
#define TEST_DURATION_SECONDS 2
|
||||
#define TEST_NFRAMES 256
|
||||
#define TEST_DURATION_SECONDS 1
|
||||
#define MAX_CHANNELS 8
|
||||
#define MAX_SCENES 8
|
||||
#define MAX_CLIPS 512
|
||||
|
||||
// Hard timeout (seconds)
|
||||
#define TEST_TIMEOUT_SECONDS 30
|
||||
|
||||
// Global test state
|
||||
static pid_t looper_pid = -1;
|
||||
static jack_client_t *test_client = NULL;
|
||||
@@ -32,10 +37,11 @@ static jack_port_t *test_audio_in[MAX_CHANNELS];
|
||||
static jack_port_t *test_midi_out;
|
||||
static jack_port_t *test_midi_in;
|
||||
static atomic_bool test_running;
|
||||
static atomic_bool test_timeout;
|
||||
static atomic_int tests_passed;
|
||||
static atomic_int tests_failed;
|
||||
|
||||
// Test audio buffers
|
||||
// Test audio buffers (reduced size)
|
||||
static float test_output_buffer[MAX_CHANNELS][TEST_NFRAMES * TEST_DURATION_SECONDS];
|
||||
static atomic_size_t test_output_count[MAX_CHANNELS];
|
||||
|
||||
@@ -92,9 +98,21 @@ static int test_process_callback(jack_nframes_t nframes, void *arg) {
|
||||
// ============================================================
|
||||
|
||||
static int start_looper(const char *client_name) {
|
||||
// Check if binary exists
|
||||
if (access("./jack-looper", X_OK) != 0) {
|
||||
fprintf(stderr, "Error: ./jack-looper binary not found or not executable\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
looper_pid = fork();
|
||||
if (looper_pid == 0) {
|
||||
// Child process - start jack-looper
|
||||
// Set CPU limit for child
|
||||
struct rlimit cpu_limit;
|
||||
cpu_limit.rlim_cur = 10; // 10 seconds CPU time
|
||||
cpu_limit.rlim_max = 10;
|
||||
setrlimit(RLIMIT_CPU, &cpu_limit);
|
||||
|
||||
execl("./jack-looper", "jack-looper", "-n", client_name, "-i", NULL);
|
||||
perror("execl failed");
|
||||
exit(1);
|
||||
@@ -190,7 +208,21 @@ static void send_sine_wave(int channel, float frequency, float amplitude, jack_n
|
||||
jack_nframes_t total_samples = (sample_rate * duration) / 1000;
|
||||
jack_nframes_t processed = 0;
|
||||
|
||||
while (processed < total_samples && atomic_load(&test_running)) {
|
||||
struct timeval start_time;
|
||||
gettimeofday(&start_time, NULL);
|
||||
|
||||
while (processed < total_samples && atomic_load(&test_running) && !atomic_load(&test_timeout)) {
|
||||
// Check for timeout
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
double elapsed = (now.tv_sec - start_time.tv_sec) +
|
||||
(now.tv_usec - start_time.tv_usec) / 1000000.0;
|
||||
if (elapsed > TEST_TIMEOUT_SECONDS) {
|
||||
fprintf(stderr, "TIMEOUT: send_sine_wave exceeded %d seconds\n", TEST_TIMEOUT_SECONDS);
|
||||
atomic_store(&test_timeout, true);
|
||||
break;
|
||||
}
|
||||
|
||||
jack_nframes_t nframes = (total_samples - processed < TEST_NFRAMES)
|
||||
? (total_samples - processed) : TEST_NFRAMES;
|
||||
|
||||
@@ -202,12 +234,13 @@ static void send_sine_wave(int channel, float frequency, float amplitude, jack_n
|
||||
}
|
||||
|
||||
processed += nframes;
|
||||
usleep(10000); // 10ms delay to let JACK process
|
||||
usleep(50000); // 50ms delay to reduce CPU usage
|
||||
}
|
||||
}
|
||||
|
||||
static void send_midi_note(int note, int velocity) {
|
||||
if (!test_client) return;
|
||||
if (atomic_load(&test_timeout)) return;
|
||||
|
||||
jack_nframes_t nframes = TEST_NFRAMES;
|
||||
void *buf = jack_port_get_buffer(test_midi_out, nframes);
|
||||
@@ -369,13 +402,48 @@ static void test_volume_control(void) {
|
||||
// Main test runner
|
||||
// ============================================================
|
||||
|
||||
// Watchdog thread - hard kill if test hangs
|
||||
static void *watchdog_thread(void *arg) {
|
||||
(void)arg;
|
||||
sleep(TEST_TIMEOUT_SECONDS + 5); // 5 seconds grace period
|
||||
if (atomic_load(&test_running)) {
|
||||
fprintf(stderr, "WATCHDOG: Test exceeded %d seconds, killing process\n",
|
||||
TEST_TIMEOUT_SECONDS + 5);
|
||||
kill(getpid(), SIGKILL);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
printf("=== Audio and MIDI Routing Integration Tests ===\n");
|
||||
printf("Note: These tests require JACK to be running\n\n");
|
||||
|
||||
// Check available memory
|
||||
long pages = sysconf(_SC_PHYS_PAGES);
|
||||
long page_size = sysconf(_SC_PAGE_SIZE);
|
||||
long phys_mem = pages * page_size;
|
||||
long needed = sizeof(test_output_buffer);
|
||||
if (needed > phys_mem / 2) {
|
||||
fprintf(stderr, "Not enough memory for test buffers (need %ld, have %ld)\n",
|
||||
needed, phys_mem / 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Set CPU limit for this process
|
||||
struct rlimit cpu_limit;
|
||||
cpu_limit.rlim_cur = TEST_TIMEOUT_SECONDS;
|
||||
cpu_limit.rlim_max = TEST_TIMEOUT_SECONDS;
|
||||
setrlimit(RLIMIT_CPU, &cpu_limit);
|
||||
|
||||
atomic_store(&tests_passed, 0);
|
||||
atomic_store(&tests_failed, 0);
|
||||
atomic_store(&test_running, true);
|
||||
atomic_store(&test_timeout, false);
|
||||
|
||||
// Start watchdog thread
|
||||
pthread_t watchdog;
|
||||
pthread_create(&watchdog, NULL, watchdog_thread, NULL);
|
||||
pthread_detach(watchdog);
|
||||
|
||||
// Start jack-looper
|
||||
printf("Starting jack-looper...\n");
|
||||
|
||||
Reference in New Issue
Block a user