jack: improve locking

Protect the global metadata with a lock because we update this from
multiple clients. Avoid updating the metadata if it didn't change.

Add a simple lock to protect the session objects, they could be
accessed from the main thread or data thread. Use the simple lock
in methods that just read.

Use the new data loop invoke to make sure we sync the data update
with the data thread.

Stop the data loop when our position io is removed.
This commit is contained in:
Wim Taymans 2020-04-30 12:57:56 +02:00
parent acd9991bfc
commit 30d5a247e1
2 changed files with 181 additions and 100 deletions

View file

@ -36,20 +36,10 @@
#include <pipewire/pipewire.h> #include <pipewire/pipewire.h>
#include <extensions/metadata.h> #include <extensions/metadata.h>
static struct pw_array * get_descriptions(void)
{
if (globals.descriptions.extend == 0) {
pw_array_init(&globals.descriptions, 16);
}
return &globals.descriptions;
}
static jack_description_t *find_description(jack_uuid_t subject) static jack_description_t *find_description(jack_uuid_t subject)
{ {
struct pw_array *descriptions = get_descriptions();
jack_description_t *desc; jack_description_t *desc;
pw_array_for_each(desc, &globals.descriptions) {
pw_array_for_each(desc, descriptions) {
if (jack_uuid_compare(desc->subject, subject) == 0) if (jack_uuid_compare(desc->subject, subject) == 0)
return desc; return desc;
} }
@ -88,9 +78,8 @@ static int copy_description(jack_description_t *dst, jack_description_t *src)
static jack_description_t *add_description(jack_uuid_t subject) static jack_description_t *add_description(jack_uuid_t subject)
{ {
struct pw_array *descriptions = get_descriptions();
jack_description_t *desc; jack_description_t *desc;
desc = pw_array_add(descriptions, sizeof(*desc)); desc = pw_array_add(&globals.descriptions, sizeof(*desc));
if (desc != NULL) { if (desc != NULL) {
spa_zero(*desc); spa_zero(*desc);
jack_uuid_copy(&desc->subject, subject); jack_uuid_copy(&desc->subject, subject);
@ -100,9 +89,8 @@ static jack_description_t *add_description(jack_uuid_t subject)
static void remove_description(jack_description_t *desc) static void remove_description(jack_description_t *desc)
{ {
struct pw_array *descriptions = get_descriptions();
jack_free_description(desc, false); jack_free_description(desc, false);
pw_array_remove(descriptions, desc); pw_array_remove(&globals.descriptions, desc);
} }
static jack_property_t *find_property(jack_description_t *desc, const char *key) static jack_property_t *find_property(jack_description_t *desc, const char *key)
@ -149,12 +137,25 @@ static void remove_property(jack_description_t *desc, jack_property_t *prop)
remove_description(desc); remove_description(desc);
} }
static inline int strzcmp(const char *s1, const char *s2)
{
if (s1 == s2)
return 0;
if (s1 == NULL || s2 == NULL)
return 1;
return strcmp(s1, s1);
}
static void change_property(jack_property_t *prop, const char *value, const char *type) static void change_property(jack_property_t *prop, const char *value, const char *type)
{ {
free((char*)prop->data); if (strzcmp(prop->data, value) != 0) {
prop->data = strdup(value); free((char*)prop->data);
free((char*)prop->type); prop->data = strdup(value);
prop->type = strdup(type); }
if (strzcmp(prop->type, type) != 0) {
free((char*)prop->type);
prop->type = strdup(type);
}
} }
static int update_property(struct client *c, static int update_property(struct client *c,
@ -166,12 +167,12 @@ static int update_property(struct client *c,
jack_property_change_t change; jack_property_change_t change;
jack_description_t *desc; jack_description_t *desc;
pthread_mutex_lock(&globals.lock);
desc = find_description(subject); desc = find_description(subject);
if (key == NULL) { if (key == NULL) {
if (desc == NULL) if (desc != NULL)
return 0; remove_description(desc);
remove_description(desc);
change = PropertyDeleted; change = PropertyDeleted;
} else { } else {
jack_property_t *prop; jack_property_t *prop;
@ -180,8 +181,7 @@ static int update_property(struct client *c,
if (value == NULL || type == NULL) { if (value == NULL || type == NULL) {
if (prop == NULL) if (prop == NULL)
return 0; remove_property(desc, prop);
remove_property(desc, prop);
change = PropertyDeleted; change = PropertyDeleted;
} else if (prop == NULL) { } else if (prop == NULL) {
if (desc == NULL) if (desc == NULL)
@ -193,6 +193,8 @@ static int update_property(struct client *c,
change = PropertyChanged; change = PropertyChanged;
} }
} }
pthread_mutex_unlock(&globals.lock);
if (c->property_callback) if (c->property_callback)
c->property_callback(subject, key, change, c->property_arg); c->property_callback(subject, key, change, c->property_arg);
return 0; return 0;
@ -208,13 +210,15 @@ int jack_set_property(jack_client_t*client,
{ {
struct client *c = (struct client *) client; struct client *c = (struct client *) client;
uint32_t id; uint32_t id;
int res = -1;
spa_return_val_if_fail(c != NULL, -EINVAL); spa_return_val_if_fail(c != NULL, -EINVAL);
spa_return_val_if_fail(key != NULL, -EINVAL); spa_return_val_if_fail(key != NULL, -EINVAL);
spa_return_val_if_fail(value != NULL, -EINVAL); spa_return_val_if_fail(value != NULL, -EINVAL);
pw_thread_loop_lock(c->context.loop);
if (c->metadata == NULL) if (c->metadata == NULL)
return -1; goto done;
id = jack_uuid_to_index(subject); id = jack_uuid_to_index(subject);
@ -222,10 +226,12 @@ int jack_set_property(jack_client_t*client,
type = ""; type = "";
pw_log_info("set id:%u (%lu) '%s' to '%s@%s'", id, subject, key, value, type); pw_log_info("set id:%u (%lu) '%s' to '%s@%s'", id, subject, key, value, type);
pw_metadata_set_property(c->metadata->proxy, pw_metadata_set_property(c->metadata->proxy, id, key, type, value);
id, key, type, value); res = 0;
done:
pw_thread_loop_unlock(c->context.loop);
return 0; return res;
} }
SPA_EXPORT SPA_EXPORT
@ -236,22 +242,26 @@ int jack_get_property(jack_uuid_t subject,
{ {
jack_description_t *desc; jack_description_t *desc;
jack_property_t *prop; jack_property_t *prop;
int res = -1;
pthread_mutex_lock(&globals.lock);
desc = find_description(subject); desc = find_description(subject);
if (desc == NULL) if (desc == NULL)
return -1; goto done;
prop = find_property(desc, key); prop = find_property(desc, key);
if (prop == NULL) if (prop == NULL)
return -1; goto done;
*value = strdup(prop->data); *value = strdup(prop->data);
*type = strdup(prop->type); *type = strdup(prop->type);
res = 0;
pw_log_debug("subject:%"PRIu64" key:'%s' value:'%s' type:'%s'", pw_log_debug("subject:%"PRIu64" key:'%s' value:'%s' type:'%s'",
subject, key, *value, *type); subject, key, *value, *type);
done:
return 0; pthread_mutex_unlock(&globals.lock);
return res;
} }
SPA_EXPORT SPA_EXPORT
@ -271,13 +281,19 @@ int jack_get_properties (jack_uuid_t subject,
jack_description_t* desc) jack_description_t* desc)
{ {
jack_description_t *d; jack_description_t *d;
int res = -1;
spa_return_val_if_fail(desc != NULL, -EINVAL); spa_return_val_if_fail(desc != NULL, -EINVAL);
pthread_mutex_lock(&globals.lock);
d = find_description(subject); d = find_description(subject);
if (d == NULL) if (d == NULL)
return -1; goto done;
return copy_description(desc, d);
res = copy_description(desc, d);
done:
pthread_mutex_unlock(&globals.lock);
return res;
} }
SPA_EXPORT SPA_EXPORT
@ -285,15 +301,19 @@ int jack_get_all_properties (jack_description_t** result)
{ {
uint32_t i; uint32_t i;
jack_description_t *dst, *src; jack_description_t *dst, *src;
struct pw_array *descriptions = get_descriptions(); struct pw_array *descriptions;
uint32_t len = pw_array_get_len(descriptions, jack_description_t); uint32_t len;
src = descriptions->data;
pthread_mutex_lock(&globals.lock);
descriptions = &globals.descriptions;
len = pw_array_get_len(descriptions, jack_description_t);
src = descriptions->data;
dst = malloc(descriptions->size); dst = malloc(descriptions->size);
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
copy_description(&dst[i], &src[i]); copy_description(&dst[i], &src[i]);
*result = dst; *result = dst;
pthread_mutex_unlock(&globals.lock);
return len; return len;
} }
@ -302,20 +322,26 @@ int jack_remove_property (jack_client_t* client, jack_uuid_t subject, const char
{ {
struct client *c = (struct client *) client; struct client *c = (struct client *) client;
uint32_t id; uint32_t id;
int res = -1;
spa_return_val_if_fail(c != NULL, -EINVAL); spa_return_val_if_fail(c != NULL, -EINVAL);
spa_return_val_if_fail(key != NULL, -EINVAL); spa_return_val_if_fail(key != NULL, -EINVAL);
pw_thread_loop_lock(c->context.loop);
if (c->metadata == NULL) if (c->metadata == NULL)
return -1; goto done;
id = jack_uuid_to_index(subject); id = jack_uuid_to_index(subject);
pw_log_info("remove id:%u (%lu) '%s'", id, subject, key); pw_log_info("remove id:%u (%lu) '%s'", id, subject, key);
pw_metadata_set_property(c->metadata->proxy, pw_metadata_set_property(c->metadata->proxy,
id, key, NULL, NULL); id, key, NULL, NULL);
res = 0;
done:
pw_thread_loop_unlock(c->context.loop);
return 0; return res;
} }
SPA_EXPORT SPA_EXPORT
@ -323,19 +349,24 @@ int jack_remove_properties (jack_client_t* client, jack_uuid_t subject)
{ {
struct client *c = (struct client *) client; struct client *c = (struct client *) client;
uint32_t id; uint32_t id;
int res = -1;
spa_return_val_if_fail(c != NULL, -EINVAL); spa_return_val_if_fail(c != NULL, -EINVAL);
pw_thread_loop_lock(c->context.loop);
if (c->metadata == NULL) if (c->metadata == NULL)
return -1; goto done;
id = jack_uuid_to_index(subject); id = jack_uuid_to_index(subject);
pw_log_info("remove id:%u (%lu)", id, subject); pw_log_info("remove id:%u (%lu)", id, subject);
pw_metadata_set_property(c->metadata->proxy, pw_metadata_set_property(c->metadata->proxy,
id, NULL, NULL, NULL); id, NULL, NULL, NULL);
res = 0;
done:
pw_thread_loop_unlock(c->context.loop);
return 0; return res;
} }
SPA_EXPORT SPA_EXPORT
@ -345,7 +376,10 @@ int jack_remove_all_properties (jack_client_t* client)
spa_return_val_if_fail(c != NULL, -EINVAL); spa_return_val_if_fail(c != NULL, -EINVAL);
pw_thread_loop_lock(c->context.loop);
pw_metadata_clear(c->metadata->proxy); pw_metadata_clear(c->metadata->proxy);
pw_thread_loop_unlock(c->context.loop);
return 0; return 0;
} }

View file

@ -86,7 +86,7 @@ struct port;
struct globals { struct globals {
jack_thread_creator_t creator; jack_thread_creator_t creator;
jack_client_t *client; pthread_mutex_t lock;
struct pw_array descriptions; struct pw_array descriptions;
}; };
@ -214,11 +214,13 @@ struct link {
}; };
struct context { struct context {
struct pw_thread_loop *loop; struct pw_thread_loop *loop; /* thread_lock protects all below */
struct pw_context *context; struct pw_context *context;
struct pw_map globals;
struct spa_list free_objects; struct spa_list free_objects;
pthread_mutex_t lock; /* protects map and lists below, in addition to thread_lock */
struct pw_map globals;
struct spa_list ports; struct spa_list ports;
struct spa_list nodes; struct spa_list nodes;
struct spa_list links; struct spa_list links;
@ -317,7 +319,10 @@ struct client {
struct pw_node_activation *activation; struct pw_node_activation *activation;
uint32_t xrun_count; uint32_t xrun_count;
struct spa_list target_links; struct {
struct pw_node_activation *driver_activation;
struct spa_list target_links;
} rt;
unsigned int started:1; unsigned int started:1;
unsigned int active:1; unsigned int active:1;
@ -374,7 +379,9 @@ static struct object * alloc_object(struct client *c)
static void free_object(struct client *c, struct object *o) static void free_object(struct client *c, struct object *o)
{ {
pthread_mutex_lock(&c->context.lock);
spa_list_remove(&o->link); spa_list_remove(&o->link);
pthread_mutex_unlock(&c->context.lock);
spa_list_append(&c->context.free_objects, &o->link); spa_list_append(&c->context.free_objects, &o->link);
} }
@ -456,7 +463,6 @@ static struct port * alloc_port(struct client *c, enum spa_direction direction)
o->id = SPA_ID_INVALID; o->id = SPA_ID_INVALID;
o->port.node_id = c->node_id; o->port.node_id = c->node_id;
o->port.port_id = p->id; o->port.port_id = p->id;
spa_list_append(&c->context.ports, &o->link);
p->valid = true; p->valid = true;
p->zeroed = false; p->zeroed = false;
@ -466,6 +472,10 @@ static struct port * alloc_port(struct client *c, enum spa_direction direction)
spa_list_append(&c->ports[direction], &p->link); spa_list_append(&c->ports[direction], &p->link);
pthread_mutex_lock(&c->context.lock);
spa_list_append(&c->context.ports, &o->link);
pthread_mutex_unlock(&c->context.lock);
return p; return p;
} }
@ -687,8 +697,8 @@ do_remove_sources(struct spa_loop *loop,
static void unhandle_socket(struct client *c) static void unhandle_socket(struct client *c)
{ {
pw_loop_invoke(c->loop->loop, pw_data_loop_invoke(c->loop,
do_remove_sources, 1, NULL, 0, true, c); do_remove_sources, 1, NULL, 0, true, c);
} }
static void reuse_buffer(struct client *c, struct mix *mix, uint32_t id) static void reuse_buffer(struct client *c, struct mix *mix, uint32_t id)
@ -986,7 +996,7 @@ static inline uint32_t cycle_run(struct client *c)
int fd = c->socket_source->fd; int fd = c->socket_source->fd;
struct spa_io_position *pos = c->position; struct spa_io_position *pos = c->position;
struct pw_node_activation *activation = c->activation; struct pw_node_activation *activation = c->activation;
struct pw_node_activation *driver = c->driver_activation; struct pw_node_activation *driver = c->rt.driver_activation;
/* this is blocking if nothing ready */ /* this is blocking if nothing ready */
if (SPA_UNLIKELY(read(fd, &cmd, sizeof(cmd)) != sizeof(cmd))) { if (SPA_UNLIKELY(read(fd, &cmd, sizeof(cmd)) != sizeof(cmd))) {
@ -1062,7 +1072,7 @@ static inline void signal_sync(struct client *c)
activation->finish_time = nsec; activation->finish_time = nsec;
cmd = 1; cmd = 1;
spa_list_for_each(l, &c->target_links, target_link) { spa_list_for_each(l, &c->rt.target_links, target_link) {
struct pw_node_activation_state *state; struct pw_node_activation_state *state;
if (SPA_UNLIKELY(l->activation == NULL)) if (SPA_UNLIKELY(l->activation == NULL))
@ -1087,7 +1097,7 @@ static inline void signal_sync(struct client *c)
static inline void cycle_signal(struct client *c, int status) static inline void cycle_signal(struct client *c, int status)
{ {
struct pw_node_activation *driver = c->driver_activation; struct pw_node_activation *driver = c->rt.driver_activation;
struct pw_node_activation *activation = c->activation; struct pw_node_activation *activation = c->activation;
if (SPA_LIKELY(status == 0)) { if (SPA_LIKELY(status == 0)) {
@ -1138,9 +1148,19 @@ on_rtsocket_condition(void *data, int fd, uint32_t mask)
} }
} }
static int
do_clear_link(struct spa_loop *loop,
bool async, uint32_t seq, const void *data, size_t size, void *user_data)
{
struct link *link = user_data;
spa_list_remove(&link->target_link);
return 0;
}
static void clear_link(struct client *c, struct link *link) static void clear_link(struct client *c, struct link *link)
{ {
spa_list_remove(&link->target_link); pw_data_loop_invoke(c->loop,
do_clear_link, 1, NULL, 0, true, link);
pw_memmap_free(link->mem); pw_memmap_free(link->mem);
close(link->signalfd); close(link->signalfd);
spa_list_remove(&link->link); spa_list_remove(&link->link);
@ -1154,8 +1174,6 @@ static void clean_transport(struct client *c)
if (!c->has_transport) if (!c->has_transport)
return; return;
pw_data_loop_stop(c->loop);
unhandle_socket(c); unhandle_socket(c);
spa_list_consume(l, &c->links, link) spa_list_consume(l, &c->links, link)
@ -1238,6 +1256,15 @@ static int install_timemaster(struct client *c)
return 0; return 0;
} }
static int
do_update_driver_activation(struct spa_loop *loop,
bool async, uint32_t seq, const void *data, size_t size, void *user_data)
{
struct client *c = user_data;
c->rt.driver_activation = c->driver_activation;
return 0;
}
static int update_driver_activation(struct client *c) static int update_driver_activation(struct client *c)
{ {
struct link *link; struct link *link;
@ -1245,7 +1272,9 @@ static int update_driver_activation(struct client *c)
link = find_activation(&c->links, c->driver_id); link = find_activation(&c->links, c->driver_id);
c->driver_activation = link ? link->activation : NULL; c->driver_activation = link ? link->activation : NULL;
pw_data_loop_invoke(c->loop,
do_update_driver_activation, SPA_ID_INVALID, NULL, 0,
c->driver_activation == NULL, c);
install_timemaster(c); install_timemaster(c);
return 0; return 0;
@ -1283,12 +1312,13 @@ static int client_node_set_io(void *object,
switch (id) { switch (id) {
case SPA_IO_Position: case SPA_IO_Position:
if (ptr == NULL)
pw_data_loop_stop(c->loop);
c->position = ptr; c->position = ptr;
c->driver_id = ptr ? c->position->clock.id : SPA_ID_INVALID; c->driver_id = ptr ? c->position->clock.id : SPA_ID_INVALID;
update_driver_activation(c); update_driver_activation(c);
if (ptr) { if (ptr)
check_sample_rate(c); check_sample_rate(c);
}
break; break;
default: default:
break; break;
@ -1774,7 +1804,7 @@ do_activate_link(struct spa_loop *loop,
struct link *link = user_data; struct link *link = user_data;
struct client *c = link->client; struct client *c = link->client;
pw_log_trace("link %p activate", link); pw_log_trace("link %p activate", link);
spa_list_append(&c->target_links, &link->target_link); spa_list_append(&c->rt.target_links, &link->target_link);
return 0; return 0;
} }
@ -1829,7 +1859,7 @@ static int client_node_set_activation(void *object,
link->signalfd = signalfd; link->signalfd = signalfd;
spa_list_append(&c->links, &link->link); spa_list_append(&c->links, &link->link);
pw_loop_invoke(c->loop->loop, pw_data_loop_invoke(c->loop,
do_activate_link, SPA_ID_INVALID, NULL, 0, false, link); do_activate_link, SPA_ID_INVALID, NULL, 0, false, link);
} }
else { else {
@ -1948,7 +1978,10 @@ static void registry_event_global(void *data, uint32_t id,
o->node.priority = pw_properties_parse_int(str); o->node.priority = pw_properties_parse_int(str);
pw_log_debug(NAME" %p: add node %d", c, id); pw_log_debug(NAME" %p: add node %d", c, id);
pthread_mutex_lock(&c->context.lock);
spa_list_append(&c->context.nodes, &o->link); spa_list_append(&c->context.nodes, &o->link);
pthread_mutex_unlock(&c->context.lock);
} }
else if (strcmp(type, PW_TYPE_INTERFACE_Port) == 0) { else if (strcmp(type, PW_TYPE_INTERFACE_Port) == 0) {
const struct spa_dict_item *item; const struct spa_dict_item *item;
@ -2004,7 +2037,10 @@ static void registry_event_global(void *data, uint32_t id,
if (o == NULL) if (o == NULL)
goto exit; goto exit;
pthread_mutex_lock(&c->context.lock);
spa_list_append(&c->context.ports, &o->link); spa_list_append(&c->context.ports, &o->link);
pthread_mutex_unlock(&c->context.lock);
ot = pw_map_lookup(&c->context.globals, node_id); ot = pw_map_lookup(&c->context.globals, node_id);
if (ot == NULL || ot->type != INTERFACE_Node) if (ot == NULL || ot->type != INTERFACE_Node)
goto exit_free; goto exit_free;
@ -2042,7 +2078,9 @@ static void registry_event_global(void *data, uint32_t id,
o = alloc_object(c); o = alloc_object(c);
object_type = INTERFACE_Link; object_type = INTERFACE_Link;
pthread_mutex_lock(&c->context.lock);
spa_list_append(&c->context.links, &o->link); spa_list_append(&c->context.links, &o->link);
pthread_mutex_unlock(&c->context.lock);
if ((str = spa_dict_lookup(props, PW_KEY_LINK_OUTPUT_PORT)) == NULL) if ((str = spa_dict_lookup(props, PW_KEY_LINK_OUTPUT_PORT)) == NULL)
goto exit_free; goto exit_free;
@ -2079,10 +2117,12 @@ static void registry_event_global(void *data, uint32_t id,
o->type = object_type; o->type = object_type;
o->id = id; o->id = id;
pthread_mutex_lock(&c->context.lock);
size = pw_map_get_size(&c->context.globals); size = pw_map_get_size(&c->context.globals);
while (id > size) while (id > size)
pw_map_insert_at(&c->context.globals, size++, NULL); pw_map_insert_at(&c->context.globals, size++, NULL);
pw_map_insert_at(&c->context.globals, id, o); pw_map_insert_at(&c->context.globals, id, o);
pthread_mutex_unlock(&c->context.lock);
pw_thread_loop_unlock(c->context.loop); pw_thread_loop_unlock(c->context.loop);
@ -2192,6 +2232,7 @@ jack_client_t * jack_client_open (const char *client_name,
0); 0);
client->allow_mlock = client->context.context->defaults.mem_allow_mlock; client->allow_mlock = client->context.context->defaults.mem_allow_mlock;
spa_list_init(&client->context.free_objects); spa_list_init(&client->context.free_objects);
pthread_mutex_init(&client->context.lock, NULL);
spa_list_init(&client->context.nodes); spa_list_init(&client->context.nodes);
spa_list_init(&client->context.ports); spa_list_init(&client->context.ports);
spa_list_init(&client->context.links); spa_list_init(&client->context.links);
@ -2215,7 +2256,7 @@ jack_client_t * jack_client_open (const char *client_name,
goto init_failed; goto init_failed;
spa_list_init(&client->links); spa_list_init(&client->links);
spa_list_init(&client->target_links); spa_list_init(&client->rt.target_links);
client->buffer_frames = (uint32_t)-1; client->buffer_frames = (uint32_t)-1;
client->sample_rate = (uint32_t)-1; client->sample_rate = (uint32_t)-1;
@ -2301,8 +2342,6 @@ jack_client_t * jack_client_open (const char *client_name,
if (status) if (status)
*status = 0; *status = 0;
globals.client = (jack_client_t *)client;
pw_log_debug(NAME" %p: new", client); pw_log_debug(NAME" %p: new", client);
return (jack_client_t *)client; return (jack_client_t *)client;
@ -2349,9 +2388,9 @@ int jack_client_close (jack_client_t *client)
res = jack_deactivate(client); res = jack_deactivate(client);
pw_thread_loop_stop(c->context.loop);
pw_context_destroy(c->context.context); pw_context_destroy(c->context.context);
pw_thread_loop_stop(c->context.loop);
pw_thread_loop_destroy(c->context.loop); pw_thread_loop_destroy(c->context.loop);
pw_log_debug(NAME" %p: free", client); pw_log_debug(NAME" %p: free", client);
@ -2383,19 +2422,23 @@ char *jack_get_uuid_for_client_name (jack_client_t *client,
{ {
struct client *c = (struct client *) client; struct client *c = (struct client *) client;
struct object *o; struct object *o;
char *uuid = NULL;
spa_return_val_if_fail(c != NULL, NULL); spa_return_val_if_fail(c != NULL, NULL);
spa_return_val_if_fail(client_name != NULL, NULL); spa_return_val_if_fail(client_name != NULL, NULL);
pthread_mutex_lock(&c->context.lock);
spa_list_for_each(o, &c->context.nodes, link) { spa_list_for_each(o, &c->context.nodes, link) {
if (strcmp(o->node.name, client_name) == 0) { if (strcmp(o->node.name, client_name) == 0) {
char *uuid = spa_aprintf( "%" PRIu64, (cuuid << 32) | o->id); uuid = spa_aprintf( "%" PRIu64, (cuuid << 32) | o->id);
pw_log_debug(NAME" %p: name %s -> %s", pw_log_debug(NAME" %p: name %s -> %s",
client, client_name, uuid); client, client_name, uuid);
return uuid; break;
} }
} }
return NULL; pthread_mutex_unlock(&c->context.lock);
return uuid;
} }
SPA_EXPORT SPA_EXPORT
@ -2406,6 +2449,7 @@ char *jack_get_client_name_by_uuid (jack_client_t *client,
struct object *o; struct object *o;
jack_uuid_t uuid; jack_uuid_t uuid;
jack_uuid_t cuuid = 0x2; jack_uuid_t cuuid = 0x2;
char *name = NULL;
spa_return_val_if_fail(c != NULL, NULL); spa_return_val_if_fail(c != NULL, NULL);
spa_return_val_if_fail(client_uuid != NULL, NULL); spa_return_val_if_fail(client_uuid != NULL, NULL);
@ -2413,14 +2457,17 @@ char *jack_get_client_name_by_uuid (jack_client_t *client,
if (jack_uuid_parse(client_uuid, &uuid) < 0) if (jack_uuid_parse(client_uuid, &uuid) < 0)
return NULL; return NULL;
pthread_mutex_lock(&c->context.lock);
spa_list_for_each(o, &c->context.nodes, link) { spa_list_for_each(o, &c->context.nodes, link) {
if ((cuuid << 32 | o->id) == uuid) { if ((cuuid << 32 | o->id) == uuid) {
pw_log_debug(NAME" %p: uuid %s (%"PRIu64")-> %s", pw_log_debug(NAME" %p: uuid %s (%"PRIu64")-> %s",
client, client_uuid, uuid, o->node.name); client, client_uuid, uuid, o->node.name);
return strdup(o->node.name); name = strdup(o->node.name);
break;
} }
} }
return NULL; pthread_mutex_unlock(&c->context.lock);
return name;
} }
SPA_EXPORT SPA_EXPORT
@ -2442,14 +2489,16 @@ static int do_activate(struct client *c)
{ {
int res; int res;
pw_data_loop_start(c->loop);
pw_thread_loop_lock(c->context.loop); pw_thread_loop_lock(c->context.loop);
if ((res = pw_data_loop_start(c->loop)) < 0)
goto done;
pw_log_debug(NAME" %p: activate", c); pw_log_debug(NAME" %p: activate", c);
pw_client_node_set_active(c->node, true); pw_client_node_set_active(c->node, true);
res = do_sync(c); res = do_sync(c);
done:
pw_thread_loop_unlock(c->context.loop); pw_thread_loop_unlock(c->context.loop);
return res; return res;
} }
@ -2490,6 +2539,8 @@ int jack_deactivate (jack_client_t *client)
pw_thread_loop_lock(c->context.loop); pw_thread_loop_lock(c->context.loop);
pw_log_debug(NAME" %p: deactivate", c); pw_log_debug(NAME" %p: deactivate", c);
pw_data_loop_stop(c->loop);
pw_client_node_set_active(c->node, false); pw_client_node_set_active(c->node, false);
c->activation->pending_new_pos = false; c->activation->pending_new_pos = false;
@ -2499,12 +2550,11 @@ int jack_deactivate (jack_client_t *client)
pw_thread_loop_unlock(c->context.loop); pw_thread_loop_unlock(c->context.loop);
pw_data_loop_stop(c->loop);
if (res < 0) if (res < 0)
return res; return res;
c->active = false; c->active = false;
return 0; return 0;
} }
@ -3250,13 +3300,13 @@ int jack_port_connected (const jack_port_t *port)
c = o->client; c = o->client;
pw_thread_loop_lock(c->context.loop); pthread_mutex_lock(&c->context.lock);
spa_list_for_each(l, &c->context.links, link) { spa_list_for_each(l, &c->context.links, link) {
if (l->port_link.src == o->id || if (l->port_link.src == o->id ||
l->port_link.dst == o->id) l->port_link.dst == o->id)
res++; res++;
} }
pw_thread_loop_unlock(c->context.loop); pthread_mutex_unlock(&c->context.lock);
return res; return res;
} }
@ -3275,7 +3325,7 @@ int jack_port_connected_to (const jack_port_t *port,
c = o->client; c = o->client;
pw_thread_loop_lock(c->context.loop); pthread_mutex_lock(&c->context.lock);
p = find_port(c, port_name); p = find_port(c, port_name);
if (p == NULL) if (p == NULL)
@ -3293,7 +3343,7 @@ int jack_port_connected_to (const jack_port_t *port,
res = 1; res = 1;
exit: exit:
pw_thread_loop_unlock(c->context.loop); pthread_mutex_lock(&c->context.lock);
return res; return res;
} }
@ -3323,8 +3373,7 @@ const char ** jack_port_get_all_connections (const jack_client_t *client,
res = malloc(sizeof(char*) * (CONNECTION_NUM_FOR_PORT + 1)); res = malloc(sizeof(char*) * (CONNECTION_NUM_FOR_PORT + 1));
pw_thread_loop_lock(c->context.loop); pthread_mutex_lock(&c->context.lock);
spa_list_for_each(l, &c->context.links, link) { spa_list_for_each(l, &c->context.links, link) {
if (l->port_link.src == o->id) if (l->port_link.src == o->id)
p = pw_map_lookup(&c->context.globals, l->port_link.dst); p = pw_map_lookup(&c->context.globals, l->port_link.dst);
@ -3340,7 +3389,7 @@ const char ** jack_port_get_all_connections (const jack_client_t *client,
if (count == CONNECTION_NUM_FOR_PORT) if (count == CONNECTION_NUM_FOR_PORT)
break; break;
} }
pw_thread_loop_unlock(c->context.loop); pthread_mutex_unlock(&c->context.lock);
if (count == 0) { if (count == 0) {
free(res); free(res);
@ -3560,11 +3609,9 @@ int jack_port_request_monitor_by_name (jack_client_t *client,
spa_return_val_if_fail(c != NULL, -EINVAL); spa_return_val_if_fail(c != NULL, -EINVAL);
spa_return_val_if_fail(port_name != NULL, -EINVAL); spa_return_val_if_fail(port_name != NULL, -EINVAL);
pw_thread_loop_lock(c->context.loop); pthread_mutex_lock(&c->context.lock);
p = find_port(c, port_name); p = find_port(c, port_name);
pthread_mutex_unlock(&c->context.lock);
pw_thread_loop_unlock(c->context.loop);
if (p == NULL) { if (p == NULL) {
pw_log_error(NAME" %p: jack_port_request_monitor_by_name called" pw_log_error(NAME" %p: jack_port_request_monitor_by_name called"
@ -3885,11 +3932,11 @@ const char ** jack_get_ports (jack_client_t *client,
if (type_name_pattern && type_name_pattern[0]) if (type_name_pattern && type_name_pattern[0])
regcomp(&type_regex, type_name_pattern, REG_EXTENDED | REG_NOSUB); regcomp(&type_regex, type_name_pattern, REG_EXTENDED | REG_NOSUB);
pw_thread_loop_lock(c->context.loop);
pw_log_debug(NAME" %p: ports id:%d name:%s type:%s flags:%08lx", c, id, pw_log_debug(NAME" %p: ports id:%d name:%s type:%s flags:%08lx", c, id,
port_name_pattern, type_name_pattern, flags); port_name_pattern, type_name_pattern, flags);
pthread_mutex_lock(&c->context.lock);
count = 0; count = 0;
spa_list_for_each(o, &c->context.ports, link) { spa_list_for_each(o, &c->context.ports, link) {
pw_log_debug(NAME" %p: check port type:%d flags:%08lx name:%s", c, pw_log_debug(NAME" %p: check port type:%d flags:%08lx name:%s", c,
@ -3917,6 +3964,8 @@ const char ** jack_get_ports (jack_client_t *client,
c, o->port.name, o->port.priority, count); c, o->port.name, o->port.priority, count);
tmp[count++] = o; tmp[count++] = o;
} }
pthread_mutex_unlock(&c->context.lock);
if (count > 0) { if (count > 0) {
qsort(tmp, count, sizeof(struct object *), port_compare_func); qsort(tmp, count, sizeof(struct object *), port_compare_func);
@ -3928,8 +3977,6 @@ const char ** jack_get_ports (jack_client_t *client,
res = NULL; res = NULL;
} }
pw_thread_loop_unlock(c->context.loop);
if (port_name_pattern && port_name_pattern[0]) if (port_name_pattern && port_name_pattern[0])
regfree(&port_regex); regfree(&port_regex);
if (type_name_pattern && type_name_pattern[0]) if (type_name_pattern && type_name_pattern[0])
@ -3946,11 +3993,9 @@ jack_port_t * jack_port_by_name (jack_client_t *client, const char *port_name)
spa_return_val_if_fail(c != NULL, NULL); spa_return_val_if_fail(c != NULL, NULL);
pw_thread_loop_lock(c->context.loop); pthread_mutex_lock(&c->context.lock);
res = find_port(c, port_name); res = find_port(c, port_name);
pthread_mutex_unlock(&c->context.lock);
pw_thread_loop_unlock(c->context.loop);
return (jack_port_t *)res; return (jack_port_t *)res;
} }
@ -3964,7 +4009,7 @@ jack_port_t * jack_port_by_id (jack_client_t *client,
spa_return_val_if_fail(c != NULL, NULL); spa_return_val_if_fail(c != NULL, NULL);
pw_thread_loop_lock(c->context.loop); pthread_mutex_lock(&c->context.lock);
o = pw_map_lookup(&c->context.globals, port_id); o = pw_map_lookup(&c->context.globals, port_id);
pw_log_debug(NAME" %p: port %d -> %p", c, port_id, o); pw_log_debug(NAME" %p: port %d -> %p", c, port_id, o);
@ -3975,7 +4020,7 @@ jack_port_t * jack_port_by_id (jack_client_t *client,
res = o; res = o;
exit: exit:
pw_thread_loop_unlock(c->context.loop); pthread_mutex_unlock(&c->context.lock);
return (jack_port_t *)res; return (jack_port_t *)res;
} }
@ -4239,7 +4284,7 @@ jack_transport_state_t jack_transport_query (const jack_client_t *client,
spa_return_val_if_fail(c != NULL, JackTransportStopped); spa_return_val_if_fail(c != NULL, JackTransportStopped);
if (SPA_LIKELY((a = c->driver_activation) != NULL)) if (SPA_LIKELY((a = c->rt.driver_activation) != NULL))
jack_state = position_to_jack(a, pos); jack_state = position_to_jack(a, pos);
else if (pos != NULL) else if (pos != NULL)
memset(pos, 0, sizeof(jack_position_t)); memset(pos, 0, sizeof(jack_position_t));
@ -4258,7 +4303,7 @@ jack_nframes_t jack_get_current_transport_frame (const jack_client_t *client)
spa_return_val_if_fail(c != NULL, -EINVAL); spa_return_val_if_fail(c != NULL, -EINVAL);
if (SPA_UNLIKELY((a = c->driver_activation) == NULL)) if (SPA_UNLIKELY((a = c->rt.driver_activation) == NULL))
return -EIO; return -EIO;
pos = &a->position; pos = &a->position;
@ -4284,7 +4329,7 @@ int jack_transport_reposition (jack_client_t *client,
spa_return_val_if_fail(c != NULL, -EINVAL); spa_return_val_if_fail(c != NULL, -EINVAL);
a = c->driver_activation; a = c->rt.driver_activation;
na = c->activation; na = c->activation;
if (!a || !na) if (!a || !na)
return -EIO; return -EIO;
@ -4305,7 +4350,7 @@ int jack_transport_reposition (jack_client_t *client,
static void update_command(struct client *c, uint32_t command) static void update_command(struct client *c, uint32_t command)
{ {
struct pw_node_activation *a = c->driver_activation; struct pw_node_activation *a = c->rt.driver_activation;
if (!a) if (!a)
return; return;
ATOMIC_STORE(a->command, command); ATOMIC_STORE(a->command, command);
@ -4642,7 +4687,7 @@ int jack_get_video_image_size(jack_client_t *client, jack_image_size_t *size)
spa_return_val_if_fail(c != NULL, 0); spa_return_val_if_fail(c != NULL, 0);
a = c->driver_activation; a = c->rt.driver_activation;
if (SPA_UNLIKELY(a == NULL)) if (SPA_UNLIKELY(a == NULL))
a = c->activation; a = c->activation;
if (SPA_UNLIKELY(a == NULL)) if (SPA_UNLIKELY(a == NULL))
@ -4663,4 +4708,6 @@ static void reg(void) __attribute__ ((constructor));
static void reg(void) static void reg(void)
{ {
pw_init(NULL, NULL); pw_init(NULL, NULL);
pthread_mutex_init(&globals.lock, NULL);
pw_array_init(&globals.descriptions, 16);
} }