From 3057fcf15717a3dd58ea4916f52e4e0b4e584671 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 30 Sep 2013 22:09:12 -0400 Subject: [PATCH] add property change notifications --- include/engine.h | 2 +- include/internal.h | 13 +++-- jackd/engine.c | 108 ++++++++++++++++++++++++++++++++++++++++-- libjack/client.c | 43 +++++++++++++++-- libjack/metadata.c | 24 ++++++++++ libjack/transclient.c | 2 + tools | 2 +- 7 files changed, 180 insertions(+), 14 deletions(-) diff --git a/include/engine.h b/include/engine.h index eac8511..12e571f 100644 --- a/include/engine.h +++ b/include/engine.h @@ -254,7 +254,7 @@ int jack_stop_freewheeling (jack_engine_t* engine, int engine_exiting); jack_client_internal_t * jack_client_by_name (jack_engine_t *engine, const char *name); -int jack_deliver_event (jack_engine_t *, jack_client_internal_t *, jack_event_t *); +int jack_deliver_event (jack_engine_t *, jack_client_internal_t *, jack_event_t *, ...); void jack_engine_signal_problems (jack_engine_t* engine); diff --git a/include/internal.h b/include/internal.h index 55982d6..02b2de0 100644 --- a/include/internal.h +++ b/include/internal.h @@ -223,7 +223,7 @@ typedef enum { ClientUnregistered, SaveSession, LatencyCallback, - PropertyCallback + PropertyChange } JackEventType; const char* jack_event_type_name (JackEventType); @@ -235,7 +235,7 @@ typedef struct { char name[JACK_PORT_NAME_SIZE]; jack_port_id_t port_id; jack_port_id_t self_id; - jack_uuid_t property_owner; + jack_uuid_t uuid; } x; union { uint32_t n; @@ -394,7 +394,8 @@ typedef enum { GetUUIDByClientName = 27, ReserveName = 30, SessionReply = 31, - SessionHasCallback = 32 + SessionHasCallback = 32, + PropertyChangeNotify = 33 } RequestType; struct _jack_request { @@ -448,6 +449,12 @@ struct _jack_request { char path[PATH_MAX+1]; char init[JACK_LOAD_INIT_LIMIT]; } POST_PACKED_STRUCTURE intclient; + struct { + jack_property_change_t change; + jack_uuid_t uuid; + size_t keylen; + const char* key; /* not delivered inline to server, see oop_client_deliver_request() */ + } POST_PACKED_STRUCTURE property; jack_uuid_t client_id; jack_nframes_t nframes; jack_time_t timeout; diff --git a/jackd/engine.c b/jackd/engine.c index f5e2fa2..6959d27 100644 --- a/jackd/engine.c +++ b/jackd/engine.c @@ -141,6 +141,7 @@ static void jack_do_reserve_name (jack_engine_t *engine, jack_request_t *req); static void jack_do_session_reply (jack_engine_t *engine, jack_request_t *req ); static void jack_compute_new_latency (jack_engine_t *engine); static int jack_do_has_session_cb (jack_engine_t *engine, jack_request_t *req); +static void jack_property_change_notify (jack_engine_t *engine, jack_property_change_t change, jack_uuid_t uuid, const char* key); static inline int jack_rolling_interval (jack_time_t period_usecs) @@ -1193,7 +1194,7 @@ do_request (jack_engine_t *engine, jack_request_t *req, int *reply_fd) */ pthread_mutex_lock (&engine->request_lock); - DEBUG ("got a request of type %d", req->type); + DEBUG ("got a request of type %d (%s)", req->type, jack_event_type_name (req->type)); switch (req->type) { case RegisterPort: @@ -1355,12 +1356,17 @@ do_request (jack_engine_t *engine, jack_request_t *req, int *reply_fd) jack_rdlock_graph (engine); req->status = jack_do_has_session_cb (engine, req); jack_unlock_graph (engine); + break; + case PropertyChangeNotify: + jack_property_change_notify (engine, req->x.property.change, req->x.property.uuid, req->x.property.key); + break; + default: /* some requests are handled entirely on the client * side, by adjusting the shared memory area(s) */ break; } - + pthread_mutex_unlock (&engine->request_lock); DEBUG ("status of request: %d", req->status); @@ -1423,12 +1429,29 @@ handle_external_client_request (jack_engine_t *engine, int fd) } } + if (req.type == PropertyChangeNotify) { + if (req.x.property.keylen) { + req.x.property.key = (char*) malloc (req.x.property.keylen); + if ((r = read (client->request_fd, (char*) req.x.property.key, req.x.property.keylen)) != req.x.property.keylen) { + jack_error ("cannot read property key from client (%d/%d/%s)", + r, sizeof(req), strerror (errno)); + return -1; + } + } else { + req.x.property.key = 0; + } + } + reply_fd = client->request_fd; jack_unlock_graph (engine); do_request (engine, &req, &reply_fd); jack_lock_graph (engine); + if (req.type == PropertyChangeNotify && req.x.property.key) { + free ((char *) req.x.property.key); + } + if (reply_fd >= 0) { DEBUG ("replying to client"); if (write (reply_fd, &req, sizeof (req)) @@ -2616,7 +2639,7 @@ jack_deliver_event_to_all (jack_engine_t *engine, jack_event_t *event) jack_unlock_graph (engine); } -static void jack_do_get_client_by_uuid ( jack_engine_t *engine, jack_request_t *req) +static void jack_do_get_client_by_uuid (jack_engine_t *engine, jack_request_t *req) { JSList *node; req->status = -1; @@ -2875,9 +2898,14 @@ jack_notify_all_port_interested_clients (jack_engine_t *engine, jack_uuid_t src, int jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, - jack_event_t *event) + jack_event_t *event, ...) { + va_list ap; char status=0; + char* key = 0; + size_t keylen = 0; + + va_start (ap, event); /* caller must hold the graph lock */ @@ -2896,6 +2924,21 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, DEBUG ("client %s is still alive", client->control->name); + /* Check property change events for matching key_size and keys */ + + if (event->type == PropertyChange) { + key = va_arg (ap, char*); + if (key && key[0] != '\0') { + keylen = strlen (key) + 1; + if (event->y.key_size != keylen) { + jack_error ("property change key %s sent with wrong length (%d vs %d)", key, event->y.key_size, keylen); + return -1; + } + } + } + + va_end (ap); + if (jack_client_is_internal (client)) { switch (event->type) { @@ -2938,6 +2981,13 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, } break; + case PropertyChange: + if (client->control->property_cbset) { + client->private_client->property_cb + (event->x.uuid, key, event->z.property_change, client->private_client->property_cb_arg); + } + break; + case LatencyCallback: jack_client_handle_latency_callback (client->private_client, event, (client->control->type == ClientDriver)); break; @@ -2965,6 +3015,20 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, jack_engine_signal_problems (engine); } + /* for property changes, deliver the extra data representing + the variable length "key" that has changed in some way. + */ + + if (event->type == PropertyChange) { + if (write (client->event_fd, key, keylen) != keylen) { + jack_error ("cannot send property change key to client [%s] (%s)", + client->control->name, + strerror (errno)); + client->error += JACK_ERROR_WITH_SOCKETS; + jack_engine_signal_problems (engine); + } + } + if (client->error) { status = -1; } else { @@ -4399,7 +4463,7 @@ jack_port_do_unregister (jack_engine_t *engine, jack_request_t *req) shared = &engine->control->ports[req->x.port_info.port_id]; - if (shared->client_id != req->x.port_info.client_id) { + if (jack_uuid_compare (shared->client_id, req->x.port_info.client_id) != 0) { char buf[JACK_UUID_STRING_SIZE]; jack_uuid_unparse (req->x.port_info.client_id, buf); jack_error ("Client %s is not allowed to remove port %s", @@ -4556,6 +4620,40 @@ jack_port_registration_notify (jack_engine_t *engine, } } +void +jack_property_change_notify (jack_engine_t *engine, + jack_property_change_t change, + jack_uuid_t uuid, + const char* key) +{ + jack_event_t event; + jack_client_internal_t *client; + JSList *node; + + event.type = PropertyChange; + event.z.property_change = change; + jack_uuid_copy (event.x.uuid, uuid); + event.y.key_size = strlen (key) + 1; + + for (node = engine->clients; node; node = jack_slist_next (node)) { + + client = (jack_client_internal_t *) node->data; + + if (!client->control->active) { + continue; + } + + if (client->control->port_register_cbset) { + if (jack_deliver_event (engine, client, &event, key)) { + jack_error ("cannot send port registration" + " notification to %s (%s)", + client->control->name, + strerror (errno)); + } + } + } +} + void jack_client_registration_notify (jack_engine_t *engine, const char* name, int yn) diff --git a/libjack/client.c b/libjack/client.c index 809ed0f..99b4895 100644 --- a/libjack/client.c +++ b/libjack/client.c @@ -250,6 +250,21 @@ oop_client_deliver_request (void *ptr, jack_request_t *req) wok = (write (client->request_fd, req, sizeof (*req)) == sizeof (*req)); + + /* if necessary, add variable length key data after a PropertyChange request + */ + + if (req->type == PropertyChangeNotify) { + if (req->x.property.keylen) { + if (write (client->request_fd, req->x.property.key, req->x.property.keylen) != req->x.property.keylen) { + jack_error ("cannot send property key of length %d to server", + req->x.property.keylen); + req->status = -1; + return req->status; + } + } + } + rok = (read (client->request_fd, req, sizeof (*req)) == sizeof (*req)); @@ -281,8 +296,7 @@ jack_client_deliver_request (const jack_client_t *client, jack_request_t *req) * the server. */ - return client->deliver_request (client->deliver_arg, - req); + return client->deliver_request (client->deliver_arg, req); } #if JACK_USE_MACH_THREADS @@ -1711,6 +1725,7 @@ jack_client_process_events (jack_client_t* client) jack_client_control_t *control = client->control; JSList *node; jack_port_t* port; + char* key = 0; DEBUG ("process events"); @@ -1728,7 +1743,17 @@ jack_client_process_events (jack_client_t* client) strerror (errno)); return -1; } - + + if (event.type == PropertyChange) { + key = (char *) malloc (event.y.key_size); + if (read (client->event_fd, key, event.y.key_size) != + event.y.key_size) { + jack_error ("cannot read property change key (%s)", + strerror (errno)); + return -1; + } + } + status = 0; switch (event.type) { @@ -1821,6 +1846,14 @@ jack_client_process_events (jack_client_t* client) case LatencyCallback: status = jack_client_handle_latency_callback (client, &event, 0 ); break; + case PropertyChange: + if (control->property_cbset) { + client->property_cb (event.x.uuid, key, event.z.property_change, client->property_cb_arg); + } + if (key) { + free (key); + } + break; } DEBUG ("client has dealt with the event, writing " @@ -1832,7 +1865,7 @@ jack_client_process_events (jack_client_t* client) "engine (%s)", strerror (errno)); return -1; } - } + } return 0; } @@ -3015,6 +3048,8 @@ jack_event_type_name (JackEventType type) return "save session"; case LatencyCallback: return "latency callback"; + case PropertyChange: + return "property change callback"; default: break; } diff --git a/libjack/metadata.c b/libjack/metadata.c index ff1b45f..a5692d8 100644 --- a/libjack/metadata.c +++ b/libjack/metadata.c @@ -72,9 +72,22 @@ jack_properties_uninit () void jack_free_description(jack_description_t* desc) { + /* XXX iterate over each property, free values, then free desc itself */ return; } +static int +jack_property_change_notify (jack_client_t* client, jack_uuid_t uuid, const char* key, jack_property_change_t change) +{ + jack_request_t req; + req.type = PropertyChangeNotify; + req.x.property.change = change; + jack_uuid_copy (req.x.property.uuid, uuid); + req.x.property.keylen = key ? strlen (key) + 1 : 0; + req.x.property.key = key; + return jack_client_deliver_request (client, &req); +} + static void make_key_dbt (DBT* dbt, jack_uuid_t subject, const char* key) { @@ -138,6 +151,8 @@ jack_set_property (jack_client_t* client, return -1; } + jack_property_change_notify (client, subject, key, PropertyChanged); + return 0; } @@ -404,6 +419,9 @@ jack_remove_property (jack_client_t* client, jack_uuid_t subject, const char* ke jack_error ("Cannot delete key %s (%s)", key, db_strerror (ret)); return -1; } + + jack_property_change_notify (client, subject, key, PropertyDeleted); + return 0; } @@ -465,6 +483,8 @@ jack_remove_properties (jack_client_t* client, jack_uuid_t subject) cursor->close (cursor); + jack_property_change_notify (client, subject, NULL, PropertyDeleted); + return retval; } @@ -472,6 +492,7 @@ int jack_remove_all_properties (jack_client_t* client) { int ret; + jack_uuid_t empty_uuid; if (jack_property_init (NULL)) { return -1; @@ -482,5 +503,8 @@ jack_remove_all_properties (jack_client_t* client) return -1; } + jack_uuid_clear (empty_uuid); + jack_property_change_notify (client, empty_uuid, NULL, PropertyDeleted); + return 0; } diff --git a/libjack/transclient.c b/libjack/transclient.c index 06c886c..b4861fd 100644 --- a/libjack/transclient.c +++ b/libjack/transclient.c @@ -25,6 +25,8 @@ #include #include +#include + #include "atomicity.h" #include "internal.h" #include "local.h" diff --git a/tools b/tools index 9222d7a..6ac302b 160000 --- a/tools +++ b/tools @@ -1 +1 @@ -Subproject commit 9222d7a4eeb4fb18916db7c4b8487841ea1ab531 +Subproject commit 6ac302ba8664e20c6c03d6da7fa8adeb7949925f