aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorcbdev <cb@cbcdn.com>2020-03-10 20:42:55 +0100
committercbdev <cb@cbcdn.com>2020-03-10 20:42:55 +0100
commitd757a9c63371fcf5f9aa832d58ed4b8bdf634909 (patch)
tree81dadda52d65e5ed21c234cddd739d49cdb6a0aa
parent4ebcda3a1b0d90c44e91a5dfe455ad59fe694cbe (diff)
downloadmidimonster-d757a9c63371fcf5f9aa832d58ed4b8bdf634909.tar.gz
midimonster-d757a9c63371fcf5f9aa832d58ed4b8bdf634909.tar.bz2
midimonster-d757a9c63371fcf5f9aa832d58ed4b8bdf634909.zip
Restructure core loop, add check for zero-descriptor case
-rw-r--r--TODO1
-rw-r--r--backend.c3
-rw-r--r--midimonster.c197
3 files changed, 125 insertions, 76 deletions
diff --git a/TODO b/TODO
index 900cc1b..1ea91f4 100644
--- a/TODO
+++ b/TODO
@@ -7,3 +7,4 @@ make event collectors threadsafe to stop marshalling data...
collect & check backend API version
windows strerror
move all connection establishment to _start to be able to hot-stop/start all backends
+only call _handle and _interval on backends with instances
diff --git a/backend.c b/backend.c
index e9c3829..ef8f66a 100644
--- a/backend.c
+++ b/backend.c
@@ -4,6 +4,7 @@
#else
#define MM_API __attribute__((dllexport))
#endif
+#define BACKEND_NAME "core/be"
#include "midimonster.h"
#include "backend.h"
@@ -227,10 +228,12 @@ struct timeval backend_timeout(){
if(backends[u].interval){
res = backends[u].interval();
if((res / 1000) < secs){
+ DBGPF("Updating interval to %" PRIu32 " msecs by request from %s", res, backends[u].name);
secs = res / 1000;
msecs = res % 1000;
}
else if(res / 1000 == secs && (res % 1000) < msecs){
+ DBGPF("Updating interval to %" PRIu32 " msecs by request from %s", res, backends[u].name);
msecs = res % 1000;
}
}
diff --git a/midimonster.c b/midimonster.c
index b8594b4..3212f7f 100644
--- a/midimonster.c
+++ b/midimonster.c
@@ -9,6 +9,7 @@
#else
#define MM_API __attribute__((dllexport))
#endif
+#define BACKEND_NAME "core"
#include "midimonster.h"
#include "config.h"
#include "backend.h"
@@ -325,18 +326,126 @@ static int args_parse(int argc, char** argv, char** cfg_file){
return 0;
}
-int main(int argc, char** argv){
- fd_set all_fds, read_fds;
+static int core_process(size_t nfds, managed_fd* signaled_fds){
event_collection* secondary = NULL;
- struct timeval tv;
- size_t u, n;
+ size_t u;
+
+ //run backend processing, collect events
+ DBGPF("%lu backend FDs signaled\n", nfds);
+ if(backends_handle(nfds, signaled_fds)){
+ return 1;
+ }
+
+ while(primary->n){
+ //swap primary and secondary event collectors
+ DBGPF("Swapping event collectors, %lu events in primary\n", primary->n);
+ for(u = 0; u < sizeof(event_pool) / sizeof(event_collection); u++){
+ if(primary != event_pool + u){
+ secondary = primary;
+ primary = event_pool + u;
+ break;
+ }
+ }
+
+ //push collected events to target backends
+ if(secondary->n && backends_notify(secondary->n, secondary->channel, secondary->value)){
+ fprintf(stderr, "Backends failed to handle output\n");
+ return 1;
+ }
+
+ //reset the event count
+ secondary->n = 0;
+ }
+
+ return 0;
+}
+
+static int core_loop(){
+ fd_set all_fds, read_fds;
managed_fd* signaled_fds = NULL;
- int rv = EXIT_FAILURE, error, maxfd = -1;
- char* cfg_file = DEFAULT_CFG;
+ struct timeval tv;
+ int error, maxfd = -1;
+ size_t n, u;
#ifdef _WIN32
char* error_message = NULL;
+ #else
+ struct timespec ts;
#endif
+ FD_ZERO(&all_fds);
+
+ //process events
+ while(!shutdown_requested){
+ //rebuild fd set if necessary
+ if(fd_set_dirty){
+ all_fds = fds_collect(&maxfd);
+ signaled_fds = realloc(signaled_fds, fds * sizeof(managed_fd));
+ if(!signaled_fds){
+ fprintf(stderr, "Failed to allocate memory\n");
+ return 1;
+ }
+ fd_set_dirty = 0;
+ }
+
+ //wait for & translate events
+ read_fds = all_fds;
+ tv = backend_timeout();
+
+ //check whether there are any fds active, windows does not like select() without descriptors
+ if(maxfd >= 0){
+ error = select(maxfd + 1, &read_fds, NULL, NULL, &tv);
+ if(error < 0){
+ #ifndef _WIN32
+ fprintf(stderr, "select failed: %s\n", strerror(errno));
+ #else
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, WSAGetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &error_message, 0, NULL);
+ fprintf(stderr, "select failed: %s\n", error_message);
+ LocalFree(error_message);
+ error_message = NULL;
+ #endif
+ free(signaled_fds);
+ return 1;
+ }
+ }
+ else{
+ DBGPF("No descriptors, sleeping for %zu msec", tv.tv_sec * 1000 + tv.tv_usec / 1000);
+ #ifdef _WIN32
+ Sleep(tv.tv_sec * 1000 + tv.tv_usec / 1000);
+ #else
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ error = nanosleep(&ts, NULL);
+ #endif
+ }
+
+ //update this iteration's timestamp
+ update_timestamp();
+
+ //find all signaled fds
+ n = 0;
+ for(u = 0; u < fds; u++){
+ if(fd[u].fd >= 0 && FD_ISSET(fd[u].fd, &read_fds)){
+ signaled_fds[n] = fd[u];
+ n++;
+ }
+ }
+
+ //fetch and process events
+ if(core_process(n, signaled_fds)){
+ free(signaled_fds);
+ return 1;
+ }
+ }
+
+ free(signaled_fds);
+ return 0;
+}
+
+int main(int argc, char** argv){
+ int rv = EXIT_FAILURE;
+ char* cfg_file = DEFAULT_CFG;
+
//parse commandline arguments
if(args_parse(argc, argv, &cfg_file)){
return EXIT_FAILURE;
@@ -347,7 +456,6 @@ int main(int argc, char** argv){
return EXIT_FAILURE;
}
- FD_ZERO(&all_fds);
//initialize backends
if(plugins_load(PLUGINS)){
fprintf(stderr, "Failed to initialize a backend\n");
@@ -377,80 +485,17 @@ int main(int argc, char** argv){
signal(SIGINT, signal_handler);
- //process events
- while(!shutdown_requested){
- //rebuild fd set if necessary
- if(fd_set_dirty){
- all_fds = fds_collect(&maxfd);
- signaled_fds = realloc(signaled_fds, fds * sizeof(managed_fd));
- if(!signaled_fds){
- fprintf(stderr, "Failed to allocate memory\n");
- goto bail;
- }
- fd_set_dirty = 0;
- }
-
- //wait for & translate events
- read_fds = all_fds;
- tv = backend_timeout();
- error = select(maxfd + 1, &read_fds, NULL, NULL, &tv);
- if(error < 0){
- #ifndef _WIN32
- fprintf(stderr, "select failed: %s\n", strerror(errno));
- #else
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, WSAGetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &error_message, 0, NULL);
- fprintf(stderr, "select failed: %s\n", error_message);
- LocalFree(error_message);
- error_message = NULL;
- #endif
- break;
- }
-
- //find all signaled fds
- n = 0;
- for(u = 0; u < fds; u++){
- if(fd[u].fd >= 0 && FD_ISSET(fd[u].fd, &read_fds)){
- signaled_fds[n] = fd[u];
- n++;
- }
- }
-
- //update this iteration's timestamp
- update_timestamp();
-
- //run backend processing, collect events
- DBGPF("%lu backend FDs signaled\n", n);
- if(backends_handle(n, signaled_fds)){
- goto bail;
- }
-
- while(primary->n){
- //swap primary and secondary event collectors
- DBGPF("Swapping event collectors, %lu events in primary\n", primary->n);
- for(u = 0; u < sizeof(event_pool) / sizeof(event_collection); u++){
- if(primary != event_pool + u){
- secondary = primary;
- primary = event_pool + u;
- break;
- }
- }
-
- //push collected events to target backends
- if(secondary->n && backends_notify(secondary->n, secondary->channel, secondary->value)){
- fprintf(stderr, "Backends failed to handle output\n");
- goto bail;
- }
+ if(!fds){
+ fprintf(stderr, "No descriptors registered for multiplexing\n");
+ }
- //reset the event count
- secondary->n = 0;
- }
+ //run the core loop
+ if(!core_loop()){
+ rv = EXIT_SUCCESS;
}
- rv = EXIT_SUCCESS;
bail:
//free all data
- free(signaled_fds);
backends_stop();
channels_free();
instances_free();