From 45c2a69122b9141f84d3f8064f41d5f6160d9ca2 Mon Sep 17 00:00:00 2001 From: cbdev Date: Wed, 21 Jun 2017 21:11:22 +0200 Subject: Improve documentation, allow event collection during event processing --- midimonster.c | 74 ++++++++++++++++++++++++++++++++++++++++------------------- midimonster.h | 49 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 24 deletions(-) diff --git a/midimonster.c b/midimonster.c index 03b2699..8f30686 100644 --- a/midimonster.c +++ b/midimonster.c @@ -8,14 +8,24 @@ #include "backend.h" #include "plugin.h" +typedef struct /*_event_collection*/ { + size_t alloc; + size_t n; + channel** channel; + channel_value* value; +} event_collection; + static size_t mappings = 0; static channel_mapping* map = NULL; static size_t fds = 0; static managed_fd* fd = NULL; -static size_t ev_alloc = 0; -static size_t evs = 0; -static channel** ev_channel = NULL; -static channel_value* ev_value = NULL; + +static event_collection event_pool[2] = { + {0}, + {0} +}; +static event_collection* primary = event_pool; + volatile static sig_atomic_t shutdown_requested = 0; void signal_handler(int signum){ @@ -150,35 +160,39 @@ int mm_channel_event(channel* c, channel_value v){ } //resize event structures to fit additional events - if(evs + map[u].destinations >= ev_alloc){ - ev_channel = realloc(ev_channel, (ev_alloc + map[u].destinations) * sizeof(channel*)); - ev_value = realloc(ev_value, (ev_alloc + map[u].destinations) * sizeof(channel_value)); + if(primary->n + map[u].destinations >= primary->alloc){ + primary->channel = realloc(primary->channel, (primary->alloc + map[u].destinations) * sizeof(channel*)); + primary->value = realloc(primary->value, (primary->alloc + map[u].destinations) * sizeof(channel_value)); - if(!ev_channel || !ev_value){ + if(!primary->channel || !primary->value){ fprintf(stderr, "Failed to allocate memory\n"); - ev_alloc = 0; - evs = 0; + primary->alloc = 0; + primary->n = 0; return 1; } - ev_alloc += map[u].destinations; + primary->alloc += map[u].destinations; } //enqueue channel events //FIXME this might lead to one channel being mentioned multiple times in an apply call for(p = 0; p < map[u].destinations; p++){ - ev_channel[evs + p] = map[u].to[p]; - ev_value[evs + p] = v; + primary->channel[primary->n + p] = map[u].to[p]; + primary->value[primary->n + p] = v; } - evs += map[u].destinations; + primary->n += map[u].destinations; return 0; } void event_free(){ - free(ev_channel); - free(ev_value); - ev_alloc = 0; + size_t u; + + for(u = 0; u < sizeof(event_pool) / sizeof(event_collection); u++){ + free(event_pool[u].channel); + free(event_pool[u].value); + event_pool[u].alloc = 0; + } } int usage(char* fn){ @@ -190,6 +204,7 @@ int usage(char* fn){ int main(int argc, char** argv){ fd_set all_fds, read_fds; + event_collection* secondary = NULL; struct timeval tv; size_t u, n; managed_fd* signaled_fds = NULL; @@ -267,14 +282,25 @@ int main(int argc, char** argv){ goto bail; } - //push collected events to target backends - if(evs && backends_notify(evs, ev_channel, ev_value)){ - fprintf(stderr, "Backends failed to handle output\n"); - goto bail; - } + while(primary->n){ + //swap primary and secondary event collectors + for(u = 0; u < sizeof(event_pool)/sizeof(event_collection); u++){ + if(primary != event_pool + u){ + secondary = primary; + primary = event_pool + u; + break; + } + } - //reset the event count - evs = 0; + //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; + } + + //reset the event count + secondary->n = 0; + } } rv = EXIT_SUCCESS; diff --git a/midimonster.h b/midimonster.h index 8d439f5..3cf6771 100644 --- a/midimonster.h +++ b/midimonster.h @@ -12,6 +12,55 @@ struct _backend_channel; struct _backend_instance; struct _managed_fd; +/* + * Backend module callback defines + * + * The lifecycle of a backend module is as follows + * * int init() + * The only function that should be exported by the shared object. + * Called when the shared object is attached. Should register + * a backend structure with the core. + * Returning anything other than zero causes midimonster to fail the + * startup checks. + * * mmbackend_configure + * Parse backend-global configuration options from the user-supplied + * configuration file. Returning a non-zero value fails config parsing. + * * mmbackend_instance + * Allocate space for a backend instance. Returning NULL signals an out-of-memory + * condition and terminates the program. + * * mmbackend_configure_instance + * Parse instance configuration from the user-supplied configuration + * file. Returning a non-zero value fails config parsing. + * * mmbackend_channel + * Parse a channel-spec to be mapped to/from. Returning NULL signals an + * out-of-memory condition and terminates the program. + * * mmbackend_start + * Called after all instances have been created and all mappings + * have been set up. May be used to connect to backing hardware + * or to update runtime-specific data in the various data structures. + * Returning a non-zero value signals an error starting the backend + * and stops further progress. + * * Normal processing loop starts here + * * mmbackend_process_fd + * Handle data from signaled fds registered via mm_manage_fd. + * Push generated events to the core with mm_channel_event. + * All registered fds that are ready to read are pushed at once. + * Backends that have not registered any fds are still called with + * nfds set to 0 in order to support polling backends. + * Returning a non-zero value signals an error and gracefully terminates + * the program. + * * mmbackend_handle_event + * An event resulted in a channel for an instance being set. + * Called once per changed instance with all updated channels for that + * specific instance. + * Returning a non-zero value terminates the program. + * * (optional) mmbackend_interval + * Return the maximum sleep interval for this backend in milliseconds. + * If not implemented, a maximum interval of one second is used. + * * mmbackend_shutdown + * Clean up all allocations, finalize all hardware connections. + * Return value is currently ignored. + */ typedef int (*mmbackend_handle_event)(struct _backend_instance* inst, size_t channels, struct _backend_channel** c, struct _channel_value* v); typedef struct _backend_instance* (*mmbackend_create_instance)(); typedef struct _backend_channel* (*mmbackend_parse_channel)(struct _backend_instance* instance, char* spec); -- cgit v1.2.3