diff options
| -rw-r--r-- | midimonster.c | 74 | ||||
| -rw-r--r-- | 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);  | 
