From df131ea4f913fea43c266517a154caa08ff9b088 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Tue, 8 Feb 2011 15:55:59 +0100 Subject: Updated program files are now reloaded automatically --- TODO | 8 +++ TODO.done | 2 + synth/Makefile | 2 +- synth/cli.cpp | 6 +- synth/globals.cpp | 1 + synth/globals.h | 1 + synth/in_synth_cli.cpp | 37 ++++++++++++ synth/in_synth_cli.h | 8 +++ synth/main.cpp | 32 +++++++++- synth/watch_files.cpp | 160 +++++++++++++++++++++++++++++++++++++++++++++++++ synth/watch_files.h | 9 +++ 11 files changed, 263 insertions(+), 3 deletions(-) create mode 100644 synth/watch_files.cpp create mode 100644 synth/watch_files.h diff --git a/TODO b/TODO index 587f253..a454c84 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,15 @@ +!!! interface der compilten note und korrespondierende funktion + im synth stimmen nicht mehr überein! ÄNDERN! + !!! SEGFAULT beim laden einer nicht-existenten datei per in-synth-cli wenn man danach die noten spielen will. nicht reproduzierbar TODO für den synth + o file-watcher ist unsauber: inotify_map_mutex und prog_load_mutex + werden eigentlich zu spät erstellt; bei EXTREM schnellen events + könnte ein noch nicht existenter mutex gelockt werden + o lock_and_load_program_no_watch_updates und auch die requests + passen nicht wirklich ins in-synth-cli. vlt woandershin schieben? o im in-synth-cli: lfos- und snh-neusetzen ist falsch es muss IMMER gelockt werden. allerdings muss maybe_calc_lfos gelockt werden, die noten können diff --git a/TODO.done b/TODO.done index e354909..9a931b4 100644 --- a/TODO.done +++ b/TODO.done @@ -76,6 +76,7 @@ TODO für den synth x mehr wellen für wave[] x wenn aufgehängt, kann er mit ctrl+c nicht mehr abgebrochen werden! x ctrl+d führt zu bug + x watcher implementieren (per inotify) TODO fürs CLI @@ -98,6 +99,7 @@ TODO fürs CLI x .so unloaden! * lfo-maxima getrennt regeln. [abgelehnt] x on-the-fly panic, einzelne channels, einzelne instrumente, etc + x CLI-flag für watch-files/don't-watch TODO für den compiler diff --git a/synth/Makefile b/synth/Makefile index a9ec0a1..39b6e80 100644 --- a/synth/Makefile +++ b/synth/Makefile @@ -3,7 +3,7 @@ CFLAGS=-Wall -O2 -g CXXFLAGS=$(CFLAGS) LDFLAGS=-lm `pkg-config --cflags --libs jack` -OBJ=channel.o cli.o defines.o envelope.o filter.o globals.o jack.o load.o main.o note.o note_skel.o parser.o programs.o readwave.o util.o note_loader.o in_synth_cli.o communication.o shared_object_manager.o lfos.o +OBJ=channel.o cli.o defines.o envelope.o filter.o globals.o jack.o load.o main.o note.o note_skel.o parser.o programs.o readwave.o util.o note_loader.o in_synth_cli.o communication.o shared_object_manager.o lfos.o watch_files.o BIN=synth DEPENDFILE = .depend diff --git a/synth/cli.cpp b/synth/cli.cpp index eb52c95..4d5cc2f 100644 --- a/synth/cli.cpp +++ b/synth/cli.cpp @@ -30,6 +30,8 @@ void parse_args(int argc, char** argv) {"xruns", required_argument, 0, 'x'}, {"dir", required_argument, 0, 'd'}, {"directory", required_argument, 0, 'd'}, + {"no-watch-files", no_argument, 0, 'w'}, + {"dont-watch-files", no_argument, 0, 'w'}, {"program", required_argument, 0, 'p'}, {"cleanup-interval", required_argument, 0, 'i'}, {"lfo0-freq", required_argument, 0, 400}, //FINDLFO @@ -59,7 +61,7 @@ void parse_args(int argc, char** argv) while (optind " +pthread_mutex_t prog_load_mutex; + void signal_handler(int sig) { cout << endl << PROMPT << flush; @@ -49,12 +52,18 @@ void do_request(int prg_no, bool susp) void lock_and_load_program(int prg_no, string file) { + pthread_mutex_lock(&prog_load_mutex); + + remove_watch(prg_no); + do_request(prg_no, true); if (load_program(file,program_settings[prg_no])) { cout << "success" << endl; programfile[prg_no]=file; + + add_watch(prg_no); } else cout << "failed" << endl; @@ -63,6 +72,32 @@ void lock_and_load_program(int prg_no, string file) channel[i]->maybe_reload_program(prg_no); do_request(prg_no, false); + + pthread_mutex_unlock(&prog_load_mutex); +} + +//only use this, if you don't want the file-watches to be updated +//i.e., only when reloading a program! +void lock_and_load_program_no_watch_updates(int prg_no, string file) +{ + pthread_mutex_lock(&prog_load_mutex); + + do_request(prg_no, true); + + if (load_program(file,program_settings[prg_no])) + { + cout << "success" << endl; + programfile[prg_no]=file; + } + else + cout << "failed" << endl; + + for (int i=0;imaybe_reload_program(prg_no); + + do_request(prg_no, false); + + pthread_mutex_unlock(&prog_load_mutex); } void lock_and_change_lfo(int lfo_no, float freq) @@ -83,6 +118,8 @@ void do_in_synth_cli() string command; string params; int num; + + pthread_mutex_init(&prog_load_mutex, NULL); if (signal(2,signal_handler)==SIG_ERR) output_warning("WARNING: failed to set signal handler in the in-synth-cli. pressing ctrl+c will\n" diff --git a/synth/in_synth_cli.h b/synth/in_synth_cli.h index 27ae216..18f7a62 100644 --- a/synth/in_synth_cli.h +++ b/synth/in_synth_cli.h @@ -1,6 +1,14 @@ #ifndef __IN_SYNTH_CLI_H__ #define __IN_SYNTH_CLI_H__ +#include + +using namespace std; + void do_in_synth_cli(); + +//only use this, if you don't want the file-watches to be updated +//i.e., only when reloading a program! +void lock_and_load_program_no_watch_updates(int prg_no, string file); #endif diff --git a/synth/main.cpp b/synth/main.cpp index a9d7ef0..32b2b84 100644 --- a/synth/main.cpp +++ b/synth/main.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "jack.h" #include "load.h" @@ -15,6 +16,7 @@ #include "communication.h" #include "note_loader.h" #include "lfos.h" +#include "watch_files.h" using namespace std; @@ -22,9 +24,10 @@ using namespace std; void cleanup(); void dump_options(); +pthread_t watcher_thread=-1; int main(int argc, char** argv) -{ +{ init_communication(); for (int i=0;i +#include +#include +#include + +#include "watch_files.h" +#include "util.h" +#include "globals.h" +#include "in_synth_cli.h" + +using namespace std; + +int fd=-1; +map > inotify_map; +pthread_mutex_t inotify_map_mutex; + +void watch_files_cleanup(void* unused) +{ + if (fd==-1) + { + output_verbose("NOTE: no cleaning necessary for watch-files-thread"); + } + else + { + output_verbose("NOTE: cleaning up for watch-files-thread..."); + + } +} + +void* watch_files(void* unused) +{ + pthread_cleanup_push(watch_files_cleanup, NULL); + + pthread_mutex_init(&inotify_map_mutex, NULL); + + fd=inotify_init(); + if (fd==-1) + { + output_warning("WARNING: could not initalize inotify. you must inform me about\n" + " updated files manually."); + while (true) sleep(10); + } + else + { + for (int i=0;i<128;i++) // add watches for all loaded programs + if (programfile[i]!="") + add_watch(i); + + inotify_event ev; + size_t s; + while (true) + { + s=read (fd, &ev, sizeof(inotify_event)); + while (s& tmp=inotify_map[ev.wd]; + for (set::iterator it=tmp.begin(); it!=tmp.end(); it++) + str+="#"+IntToStr(*it)+" "; + + output_verbose("NOTE: reloading programs "+str+"..."); + } + + set& tmp=inotify_map[ev.wd]; + for (set::iterator it=tmp.begin(); it!=tmp.end(); it++) + lock_and_load_program_no_watch_updates(*it, programfile[*it]); + } + else if (ev.mask & (IN_MOVE_SELF | IN_DELETE_SELF)) + { + if (verbose) + { + string str=""; + set& tmp=inotify_map[ev.wd]; + for (set::iterator it=tmp.begin(); it!=tmp.end(); it++) + str+="#"+IntToStr(*it)+" "; + + output_verbose("NOTE: removed watch for programs "+str); + } + + inotify_map.erase(ev.wd); + inotify_rm_watch(fd,ev.wd); + } + else if (ev.mask != IN_IGNORED) + { + output_note("NOTE: in watch_files-thread: unknown event received ("+IntToStrHex(ev.mask)+")"); + } + + pthread_mutex_unlock(&inotify_map_mutex); + } + } + + pthread_cleanup_pop(0); +} + +void remove_watch(int prog) +{ + if (watchfiles) + { + map >::iterator mit; + set* tmp; + set::iterator sit; + + pthread_mutex_lock(&inotify_map_mutex); + + //search in all known watch descriptors + for (mit=inotify_map.begin(); mit!=inotify_map.end(); mit++) + { + tmp=&(mit->second); + sit=tmp->find(prog); + + //search for some wd which affects $prog + if (sit!=tmp->end()) //found? + { + //erase $prog from the affect-set + tmp->erase(sit); + if (tmp->empty()) + { + //if the affect-set is now empty, we can garbage-collect + //the wd (i.e., remove it) + cout << "garbage collecting wd #"<first<first); + inotify_map.erase(mit); + } + + //we're done now + break; + } + } + + pthread_mutex_unlock(&inotify_map_mutex); + } +} + +void add_watch(int prog) +{ + if (watchfiles) + { + int wd=inotify_add_watch(fd, programfile[prog].c_str(), IN_MODIFY | IN_MOVE_SELF | IN_DELETE_SELF); + + pthread_mutex_lock(&inotify_map_mutex); + + if (wd!=-1) + { + inotify_map[wd].insert(prog); + } + else + { + //TODO: warning + } + + pthread_mutex_unlock(&inotify_map_mutex); + } +} diff --git a/synth/watch_files.h b/synth/watch_files.h new file mode 100644 index 0000000..b9c7d2d --- /dev/null +++ b/synth/watch_files.h @@ -0,0 +1,9 @@ +#ifndef __WATCH_FILES_H__ +#define __WATCH_FILES_H__ + +void* watch_files(void* unused); + +void add_watch(int prog); +void remove_watch(int prog); + +#endif -- cgit v1.2.1