aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--backends/maweb.c2
-rw-r--r--core/backend.c47
-rw-r--r--core/backend.h1
-rw-r--r--midimonster.c4
-rw-r--r--midimonster.h25
5 files changed, 69 insertions, 10 deletions
diff --git a/backends/maweb.c b/backends/maweb.c
index 39ef7a6..8b878b0 100644
--- a/backends/maweb.c
+++ b/backends/maweb.c
@@ -1111,7 +1111,7 @@ static int maweb_start(size_t n, instance** inst){
//re-set channel identifiers
for(p = 0; p < data->channels; p++){
- data->channel[p].chan->ident = p;
+ mm_channel_update(data->channel[p].chan, p);
}
//try to connect to any available host
diff --git a/core/backend.c b/core/backend.c
index 16e095c..8a8588f 100644
--- a/core/backend.c
+++ b/core/backend.c
@@ -94,9 +94,9 @@ int backends_notify(size_t nev, channel** c, channel_value* v){
MM_API channel* mm_channel(instance* inst, uint64_t ident, uint8_t create){
size_t u, bucket = channelstore_hash(inst, ident);
- DBGPF("\tSearching for inst %" PRIu64 " ident %" PRIu64, inst, ident);
+ DBGPF("\tSearching for inst %" PRIu64 " ident %" PRIu64, (uint64_t) inst, ident);
for(u = 0; u < channels.n[bucket]; u++){
- DBGPF("\tBucket %" PRIsize_t " entry %" PRIsize_t " inst %" PRIu64 " ident %" PRIu64, bucket, u, channels.entry[bucket][u]->instance, channels.entry[bucket][u]->ident);
+ DBGPF("\tBucket %" PRIsize_t " entry %" PRIsize_t " inst %" PRIu64 " ident %" PRIu64, bucket, u, (uint64_t) channels.entry[bucket][u]->instance, channels.entry[bucket][u]->ident);
if(channels.entry[bucket][u]->instance == inst
&& channels.entry[bucket][u]->ident == ident){
DBGPF("Requested channel %" PRIu64 " on instance %s already exists, reusing (bucket %" PRIsize_t ", %" PRIsize_t " search steps)\n", ident, inst->name, bucket, u);
@@ -128,6 +128,49 @@ MM_API channel* mm_channel(instance* inst, uint64_t ident, uint8_t create){
return channels.entry[bucket][(channels.n[bucket]++)];
}
+MM_API void mm_channel_update(channel* chan, uint64_t ident){
+ size_t bucket = channelstore_hash(chan->instance, chan->ident), new_bucket = channelstore_hash(chan->instance, ident);
+ size_t u;
+
+ DBGPF("Updating identifier for inst %" PRIu64 " ident %" PRIu64 " (bucket %" PRIsize_t " to %" PRIsize_t ") to %" PRIu64, (uint64_t) chan->instance, chan->ident, bucket, new_bucket, ident);
+
+ if(bucket == new_bucket){
+ chan->ident = ident;
+ return;
+ }
+
+ for(u = 0; u < channels.n[bucket]; u++){
+ if(channels.entry[bucket][u]->instance == chan->instance
+ && channels.entry[bucket][u]->ident == chan->ident){
+ break;
+ }
+ }
+
+ if(u == channels.n[bucket]){
+ DBGPF("Failed to find channel to update in bucket %" PRIsize_t, bucket);
+ return;
+ }
+
+ DBGPF("Removing channel from slot %" PRIsize_t " of %" PRIsize_t " of bucket %" PRIsize_t, u, channels.n[bucket], bucket);
+ //remove channel from old bucket
+ for(; u < channels.n[bucket] - 1; u++){
+ channels.entry[bucket][u] = channels.entry[bucket][u + 1];
+ }
+
+ //add to new bucket
+ channels.entry[new_bucket] = realloc(channels.entry[new_bucket], (channels.n[new_bucket] + 1) * sizeof(channel*));
+ if(!channels.entry[new_bucket]){
+ fprintf(stderr, "Failed to allocate memory\n");
+ channels.n[new_bucket] = 0;
+ return;
+ }
+
+ channels.entry[new_bucket][channels.n[new_bucket]] = chan;
+ chan->ident = ident;
+ channels.n[bucket]--;
+ channels.n[new_bucket]++;
+}
+
instance* mm_instance(backend* b){
size_t u = 0, n = 0;
diff --git a/core/backend.h b/core/backend.h
index 6a69508..46c6c3a 100644
--- a/core/backend.h
+++ b/core/backend.h
@@ -12,6 +12,7 @@ instance* mm_instance(backend* b);
/* Backend API */
MM_API channel* mm_channel(instance* inst, uint64_t ident, uint8_t create);
+MM_API void mm_channel_update(channel* chan, uint64_t ident);
MM_API instance* mm_instance_find(char* name, uint64_t ident);
MM_API int mm_backend_instances(char* name, size_t* ninst, instance*** inst);
MM_API int mm_backend_register(backend b);
diff --git a/midimonster.c b/midimonster.c
index 51fe7ad..5817ac7 100644
--- a/midimonster.c
+++ b/midimonster.c
@@ -346,7 +346,7 @@ static int core_process(size_t nfds, managed_fd* signaled_fds){
size_t u, swaps = 0;
//run backend processing, collect events
- DBGPF("%lu backend FDs signaled\n", nfds);
+ DBGPF("%lu backend FDs signaled", nfds);
if(backends_handle(nfds, signaled_fds)){
return 1;
}
@@ -354,7 +354,7 @@ static int core_process(size_t nfds, managed_fd* signaled_fds){
//limit number of collector swaps per iteration to prevent complete deadlock
while(routing.events->n && swaps < MM_SWAP_LIMIT){
//swap primary and secondary event collectors
- DBGPF("Swapping event collectors, %lu events in primary\n", routing.events->n);
+ DBGPF("Swapping event collectors, %lu events in primary", routing.events->n);
for(u = 0; u < sizeof(routing.pool) / sizeof(routing.pool[0]); u++){
if(routing.events != routing.pool + u){
secondary = routing.events;
diff --git a/midimonster.h b/midimonster.h
index 9552b7e..89688c4 100644
--- a/midimonster.h
+++ b/midimonster.h
@@ -227,15 +227,21 @@ MM_API int mm_backend_register(backend b);
MM_API instance* mm_instance_find(char* backend, uint64_t ident);
/*
- * Provides a pointer to a channel structure, pre-filled with the provided
- * instance reference and identifier.
+ * This function is the main interface to the core-provided channel registry.
+ * This API is just a convenience function. Creating and managing a
+ * backend-internal channel store is possible (and encouraged for performance
+ * reasons).
+ *
+ * Channels are identified by the (instance, ident) tuple within the registry.
+ *
+ * This API provides a pointer to a channel structure, pre-filled with the
+ * provided instance reference and identifier.
* The `create` parameter is a boolean flag indicating whether a channel
* matching the `ident` parameter should be created in the global channel store
* if none exists yet. If the instance already registered a channel matching
* `ident`, a pointer to the existing channel is returned.
- * This API is just a convenience function. Creating and managing a
- * backend-internal channel store is possible (and encouraged for performance
- * reasons). When returning pointers from a backend-local channel store, the
+ *
+ * When returning pointers from a backend-local channel store, the
* returned pointers must stay valid over the lifetime of the instance and
* provide valid `instance` members, as they are used for callbacks.
* For each channel with a non-NULL `impl` field registered using
@@ -245,6 +251,15 @@ MM_API instance* mm_instance_find(char* backend, uint64_t ident);
MM_API channel* mm_channel(instance* i, uint64_t ident, uint8_t create);
/*
+ * When using the core-provided channel registry, the identification
+ * member of the structure must only be updated using this API.
+ * The tuple of (instance, ident) is used as key to the backing
+ * storage of the channel registry, thus the registry must be notified
+ * of changes.
+ */
+MM_API void mm_channel_update(channel* c, uint64_t ident);
+
+/*
* Register (manage = 1) or unregister (manage = 0) a file descriptor to be
* selected on. The backend will be notified when the descriptor becomes ready
* to read via its registered mmbackend_process_fd call. The `impl` argument