diff options
author | Florian Jung <florian.a.jung@web.de> | 2012-04-06 17:27:15 +0200 |
---|---|---|
committer | Florian Jung <florian.a.jung@web.de> | 2012-04-06 17:27:15 +0200 |
commit | aec14a264cdb19ccbd9e53596c58da9b60308909 (patch) | |
tree | 6d1c96febf7aaac8673698bc0cbbe93903906926 | |
parent | 829c7f8da9aa285029b9d636edda191b5c2b507b (diff) |
improved inter-thread communication.
the in-synth-CLI still partially uses the non-synced communication. TODO!
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | synth/communication.cpp | 70 | ||||
-rw-r--r-- | synth/communication.h | 35 | ||||
-rw-r--r-- | synth/in_synth_cli.cpp | 52 | ||||
-rw-r--r-- | synth/jack.cpp | 60 |
5 files changed, 148 insertions, 72 deletions
@@ -12,10 +12,11 @@ TODO für den synth (macht notencompiler hoffentlich obsolet) o evtl wieder AM implementieren: hätte hoffentlich dann keinen negativen einfluss wenn unbenutzt - o kommunikation sauber synchronisieren: außerhalb von process() + x kommunikation sauber synchronisieren: außerhalb von process() wird nurnoch ne struct mit funktionspointer und argument-union in einen ringbuffer geschrieben. der eigentliche call erfolgt dann in process() + o saubere kommunikation bei ALLEN in-synth-CLI-sachen o defines säubern, schöner anordnen o frameskipping vlt immer einbauen? diff --git a/synth/communication.cpp b/synth/communication.cpp index f21e46f..4f9ce75 100644 --- a/synth/communication.cpp +++ b/synth/communication.cpp @@ -1,16 +1,76 @@ #include "communication.h" -pthread_mutex_t suspend_request_mutex; -suspend_request_t suspend_request; +#include <unistd.h> +#include <iostream> + +using namespace std; + +jack_ringbuffer_t* request_ringbuf; +jack_ringbuffer_t* result_ringbuf; +pthread_mutex_t request_mutex; + void init_communication() { - pthread_mutex_init(&suspend_request_mutex, NULL); + pthread_mutex_init(&request_mutex, NULL); - suspend_request.done=true; + request_ringbuf=jack_ringbuffer_create(sizeof(request_t)+1); + result_ringbuf=jack_ringbuffer_create(sizeof(int)+1); } void uninit_communication() { - pthread_mutex_destroy(&suspend_request_mutex); + jack_ringbuffer_free(request_ringbuf); + jack_ringbuffer_free(result_ringbuf); + + pthread_mutex_destroy(&request_mutex); +} + +int do_request(request_t request) +{ + pthread_mutex_lock(&request_mutex); // only one request at a time + + jack_ringbuffer_write(request_ringbuf, (char*)(&request), sizeof(request_t)); + + do // wait for the answer + { + usleep(10000); + } while (jack_ringbuffer_read_space(result_ringbuf)<sizeof(int)); + + int result; + if (jack_ringbuffer_read(result_ringbuf, (char*)(&result), sizeof(int)) != sizeof(int)) + cout << "FATAL: short read from result ringbuffer, expect breakage!" << endl; // TODO handle properly + + if (jack_ringbuffer_read_space(result_ringbuf)!=0) + cout << "FATAL: result ringbuffer not empty, expect breakage!" << endl; // TODO handle properly + + pthread_mutex_unlock(&request_mutex); + + return result; +} + +bool request_available() +{ + return (jack_ringbuffer_read_space(request_ringbuf)>=sizeof(request_t)); +} + +request_t get_request() +{ + request_t request; + + int len=jack_ringbuffer_read(request_ringbuf, (char*)(&request), sizeof(request_t)); + if (len==0) + cout << "ERROR: no request on the ringbuffer! nothing read, continuing..." << endl; + else if (len!=sizeof(request_t)) + { + cout << "possibly FATAL: short read from the request ringbuffer, expect breakage!" << endl; + request.type=request_t::NONE; + } + + return request; +} + +void request_finished(int result) +{ + jack_ringbuffer_write(result_ringbuf, (char*)(&result), sizeof(int)); } diff --git a/synth/communication.h b/synth/communication.h index 27f7186..8d11cd4 100644 --- a/synth/communication.h +++ b/synth/communication.h @@ -2,21 +2,36 @@ #define __COMMUNICATION_H__ #include <pthread.h> +#include <jack/ringbuffer.h> -struct suspend_request_t +struct request_t { - int prog; //if negative, all programs are affected - bool suspend; //true->suspend, false->use them again - bool done; //must be set to false by the requester, - //must be set to true after processing by the requestee + enum request_type_t { NONE, SUSPEND_PROGRAM, RESUME_PROGRAM, PANIC, RELEASE_ALL }; + request_type_t type; + int prog_or_chan; //if negative, all programs/channels are affected + + request_t() + { + type=NONE; + } + + request_t(request_type_t type_, int poc) + { + type=type_; + prog_or_chan=poc; + } }; +// init/uninit +void init_communication(); +void uninit_communication(); -extern pthread_mutex_t suspend_request_mutex; -extern suspend_request_t suspend_request; - +// for non-audio-threads. mutex-protected +int do_request(request_t request); +// for the audio-thread. NOT mutex-protected +bool request_available(); +request_t get_request(); +void request_finished(int); -void init_communication(); -void uninit_communication(); #endif diff --git a/synth/in_synth_cli.cpp b/synth/in_synth_cli.cpp index 4d4ef76..069e7bd 100644 --- a/synth/in_synth_cli.cpp +++ b/synth/in_synth_cli.cpp @@ -1,7 +1,6 @@ #include <iostream> #include <string> #include <signal.h> -#include <unistd.h> #include <stdlib.h> #include "in_synth_cli.h" @@ -26,33 +25,6 @@ void signal_handler(int sig) cout << endl << PROMPT << flush; } -void do_request(int prg_no, bool susp) -{ - pthread_mutex_lock(&suspend_request_mutex); - - suspend_request.prog=prg_no; - suspend_request.suspend=susp; - suspend_request.done=false; - - pthread_mutex_unlock(&suspend_request_mutex); - - - - while (true) - { - usleep(100000); - - pthread_mutex_lock(&suspend_request_mutex); - if (suspend_request.done) - { - pthread_mutex_unlock(&suspend_request_mutex); - break; - } - else - pthread_mutex_unlock(&suspend_request_mutex); - } -} - void lock_and_load_program(int prg_no, string file) { pthread_mutex_lock(&prog_load_mutex); @@ -61,7 +33,7 @@ void lock_and_load_program(int prg_no, string file) remove_watch(prg_no); #endif - do_request(prg_no, true); + do_request(request_t(request_t::SUSPEND_PROGRAM, prg_no)); if (load_program(file,program_settings[prg_no])) { @@ -78,7 +50,7 @@ void lock_and_load_program(int prg_no, string file) for (int i=0;i<N_CHANNELS;++i) channel[i]->maybe_reload_program(prg_no); - do_request(prg_no, false); + do_request(request_t(request_t::RESUME_PROGRAM, prg_no)); pthread_mutex_unlock(&prog_load_mutex); } @@ -89,7 +61,7 @@ void lock_and_load_program_no_watch_updates(int prg_no, string file) { pthread_mutex_lock(&prog_load_mutex); - do_request(prg_no, true); + do_request(request_t(request_t::SUSPEND_PROGRAM, prg_no)); if (load_program(file,program_settings[prg_no])) { @@ -102,20 +74,20 @@ void lock_and_load_program_no_watch_updates(int prg_no, string file) for (int i=0;i<N_CHANNELS;++i) channel[i]->maybe_reload_program(prg_no); - do_request(prg_no, false); + do_request(request_t(request_t::RESUME_PROGRAM, prg_no)); pthread_mutex_unlock(&prog_load_mutex); } void lock_and_change_lfo(int lfo_no, float freq) { - do_request(-1, true); + do_request(request_t(request_t::SUSPEND_PROGRAM, -1)); uninit_lfo(lfo_no); lfo_freq_hz[lfo_no]=freq; init_lfo(lfo_no); - do_request(-1, false); + do_request(request_t(request_t::RESUME_PROGRAM, -1)); } @@ -183,13 +155,12 @@ void do_in_synth_cli() else if (command=="panic") { if ((params=="") || (params=="all")) - for (int i=0;i<N_CHANNELS;++i) - channel[i]->panic(); + do_request(request_t(request_t::PANIC, -1)); else if (isnum(params)) { num=atoi(params.c_str()); if ((num>=0) && (num<N_CHANNELS)) - channel[num]->panic(); + do_request(request_t(request_t::PANIC, num)); else cout << "error: channel-number must be one of 0.."<<N_CHANNELS-1<<endl; } @@ -197,17 +168,18 @@ void do_in_synth_cli() else if (command=="release") { if ((params=="") || (params=="all")) - for (int i=0;i<N_CHANNELS;++i) - channel[i]->release_all(); + do_request(request_t(request_t::RELEASE_ALL, -1)); else if (isnum(params)) { num=atoi(params.c_str()); if ((num>=0) && (num<N_CHANNELS)) - channel[num]->release_all(); + do_request(request_t(request_t::RELEASE_ALL, num)); else cout << "error: channel-number must be one of 0.."<<N_CHANNELS-1<<endl; } } + // TODO: from here, no proper synchronisation with the audio thread + // is done. use do_request() everywhere! else if (command=="kill_program") { string prgstr, chanstr; diff --git a/synth/jack.cpp b/synth/jack.cpp index c86cbce..882d5fb 100644 --- a/synth/jack.cpp +++ b/synth/jack.cpp @@ -34,15 +34,45 @@ void manage_program_lock(int prog, bool lock) //TODO woandershinschieben? channel[i]->kill_program(prog); } -void process_request() +void process_request(request_t request) { - if (suspend_request.prog==-1) - for (int i=0;i<128;++i) - manage_program_lock(i,suspend_request.suspend); - else - manage_program_lock(suspend_request.prog,suspend_request.suspend); + switch (request.type) + { + case request_t::NONE: break; + + case request_t::SUSPEND_PROGRAM: + case request_t::RESUME_PROGRAM: + if (request.prog_or_chan==-1) + for (int i=0;i<128;++i) + manage_program_lock(i,request.type==request_t::SUSPEND_PROGRAM); + else + manage_program_lock(request.prog_or_chan,request.type==request_t::SUSPEND_PROGRAM); + + break; + + case request_t::PANIC: + if (request.prog_or_chan==-1) + for (int i=0;i<N_CHANNELS;++i) + channel[i]->panic(); + else + channel[request.prog_or_chan]->panic(); + + break; + + case request_t::RELEASE_ALL: + if (request.prog_or_chan==-1) + for (int i=0;i<N_CHANNELS;++i) + channel[i]->release_all(); + else + channel[request.prog_or_chan]->release_all(); + + break; + + default: + cout << "ERROR: bad request, ignoring it." << endl; + } - suspend_request.done=true; + request_finished(0); } @@ -217,10 +247,10 @@ int xrun_callback(void *notused) if (history.size() >= xrun_n) { - cout << "PANIC -- TOO MANY XRUNs! killing all voices" << endl<<endl; - for (int i=0;i<N_CHANNELS;++i) - channel[i]->panic(); - + cout << "PANIC -- TOO MANY XRUNs! killing all voices" << flush; + do_request(request_t(request_t::PANIC, -1)); + cout << " (done)" << endl << endl; + history.clear(); } @@ -254,11 +284,9 @@ int process_callback(jack_nframes_t nframes, void *notused) } - - pthread_mutex_lock(&suspend_request_mutex); - if (suspend_request.done==false) - process_request(); - pthread_mutex_unlock(&suspend_request_mutex); + if (request_available()) + process_request(get_request()); + |