client-node: store mix in pw_map so that they are not copied

struct mix contain pointers to themselves (see do_port_use_buffers) and
cannot be copied by value, so they should not be stored in pw_array.

Store them in pw_map instead.
This commit is contained in:
Pauli Virtanen 2023-11-19 17:00:18 +02:00
parent 44bfeaac6e
commit 7f5f88c04a

View file

@ -49,7 +49,6 @@ struct buffer {
}; };
struct mix { struct mix {
unsigned int valid:1;
uint32_t mix_id; uint32_t mix_id;
struct port *port; struct port *port;
uint32_t peer_id; uint32_t peer_id;
@ -79,7 +78,7 @@ struct port {
unsigned int removed:1; unsigned int removed:1;
unsigned int destroyed:1; unsigned int destroyed:1;
struct pw_array mix; struct pw_map mix;
}; };
struct impl { struct impl {
@ -191,42 +190,62 @@ do_port_use_buffers(struct impl *impl,
static struct mix *find_mix(struct port *p, uint32_t mix_id) static struct mix *find_mix(struct port *p, uint32_t mix_id)
{ {
struct mix *mix; if (mix_id == SPA_ID_INVALID)
mix_id = 0;
else
mix_id++;
return pw_map_lookup(&p->mix, mix_id);
}
static struct mix *create_mix(struct port *p, uint32_t mix_id)
{
struct mix *mix = NULL;
size_t len; size_t len;
int res;
if (mix_id == SPA_ID_INVALID) if (mix_id == SPA_ID_INVALID)
mix_id = 0; mix_id = 0;
else else
mix_id++; mix_id++;
len = pw_array_get_len(&p->mix, struct mix); if (pw_map_lookup(&p->mix, mix_id) != NULL) {
if (mix_id >= len) { errno = EEXIST;
size_t need = sizeof(struct mix) * (mix_id + 1 - len); return NULL;
void *ptr = pw_array_add(&p->mix, need);
if (ptr == NULL)
return NULL;
memset(ptr, 0, need);
} }
mix = pw_array_get_unchecked(&p->mix, mix_id, struct mix);
return mix;
}
static void mix_init(struct mix *mix, struct port *p, uint32_t mix_id) /* pad map size */
{ for (len = pw_map_get_size(&p->mix); len < mix_id; ++len)
mix->valid = true; if ((res = pw_map_insert_at(&p->mix, len, NULL)) < 0)
goto fail;
mix = calloc(1, sizeof(struct mix));
if (mix == NULL)
return NULL;
if ((res = pw_map_insert_at(&p->mix, mix_id, mix)) < 0)
goto fail;
mix->mix_id = mix_id; mix->mix_id = mix_id;
mix->port = p; mix->port = p;
mix->n_buffers = 0; mix->n_buffers = 0;
return mix;
fail:
free(mix);
errno = -res;
return NULL;
} }
static struct mix *create_mix(struct impl *impl, struct port *p, uint32_t mix_id) static void free_mix(struct port *p, struct mix *mix)
{ {
struct mix *mix; if (mix == NULL)
return;
if ((mix = find_mix(p, mix_id)) == NULL || mix->valid) /* never realloc so it's safe to call from pw_map_foreach */
return NULL; if (mix->mix_id < pw_map_get_size(&p->mix))
mix_init(mix, p, mix_id); pw_map_insert_at(&p->mix, mix->mix_id, NULL);
return mix;
free(mix);
} }
static void clear_data(struct impl *impl, struct spa_data *d) static void clear_data(struct impl *impl, struct spa_data *d)
@ -280,11 +299,10 @@ static void mix_clear(struct impl *impl, struct mix *mix)
{ {
struct port *port = mix->port; struct port *port = mix->port;
if (!mix->valid)
return;
do_port_use_buffers(impl, port->direction, port->id, do_port_use_buffers(impl, port->direction, port->id,
mix->mix_id, 0, NULL, 0); mix->mix_id, 0, NULL, 0);
mix->valid = false;
free_mix(port, mix);
} }
static int impl_node_enum_params(void *object, int seq, static int impl_node_enum_params(void *object, int seq,
@ -498,21 +516,25 @@ do_update_port(struct impl *impl,
} }
} }
static int mix_clear_cb(void *item, void *data)
{
if (item)
mix_clear(data, item);
return 0;
}
static void static void
clear_port(struct impl *impl, struct port *port) clear_port(struct impl *impl, struct port *port)
{ {
struct mix *mix;
spa_log_debug(impl->log, "%p: clear port %p", impl, port); spa_log_debug(impl->log, "%p: clear port %p", impl, port);
do_update_port(impl, port, do_update_port(impl, port,
PW_CLIENT_NODE_PORT_UPDATE_PARAMS | PW_CLIENT_NODE_PORT_UPDATE_PARAMS |
PW_CLIENT_NODE_PORT_UPDATE_INFO, 0, NULL, NULL); PW_CLIENT_NODE_PORT_UPDATE_INFO, 0, NULL, NULL);
pw_array_for_each(mix, &port->mix) pw_map_for_each(&port->mix, mix_clear_cb, impl);
mix_clear(impl, mix); pw_map_clear(&port->mix);
pw_array_clear(&port->mix); pw_map_init(&port->mix, 0, 2);
pw_array_init(&port->mix, sizeof(struct mix) * 2);
pw_map_insert_at(&impl->ports[port->direction], port->id, NULL); pw_map_insert_at(&impl->ports[port->direction], port->id, NULL);
@ -606,6 +628,13 @@ impl_node_port_enum_params(void *object, int seq,
return found ? 0 : -ENOENT; return found ? 0 : -ENOENT;
} }
static int clear_buffers_cb(void *item, void *data)
{
if (item)
clear_buffers(data, item);
return 0;
}
static int static int
impl_node_port_set_param(void *object, impl_node_port_set_param(void *object,
enum spa_direction direction, uint32_t port_id, enum spa_direction direction, uint32_t port_id,
@ -614,7 +643,6 @@ impl_node_port_set_param(void *object,
{ {
struct impl *impl = object; struct impl *impl = object;
struct port *port; struct port *port;
struct mix *mix;
spa_return_val_if_fail(impl != NULL, -EINVAL); spa_return_val_if_fail(impl != NULL, -EINVAL);
@ -626,10 +654,9 @@ impl_node_port_set_param(void *object,
direction, port_id, direction, port_id,
spa_debug_type_find_name(spa_type_param, id), id); spa_debug_type_find_name(spa_type_param, id), id);
if (id == SPA_PARAM_Format) { if (id == SPA_PARAM_Format)
pw_array_for_each(mix, &port->mix) pw_map_for_each(&port->mix, clear_buffers_cb, impl);
clear_buffers(impl, mix);
}
if (impl->resource == NULL) if (impl->resource == NULL)
return param == NULL ? 0 : -EIO; return param == NULL ? 0 : -EIO;
@ -658,7 +685,7 @@ static int do_port_set_io(struct impl *impl,
if (port == NULL) if (port == NULL)
return data == NULL ? 0 : -EINVAL; return data == NULL ? 0 : -EINVAL;
if ((mix = find_mix(port, mix_id)) == NULL || !mix->valid) if ((mix = find_mix(port, mix_id)) == NULL)
return -EINVAL; return -EINVAL;
old = pw_mempool_find_tag(impl->client_pool, tag, sizeof(tag)); old = pw_mempool_find_tag(impl->client_pool, tag, sizeof(tag));
@ -731,7 +758,7 @@ do_port_use_buffers(struct impl *impl,
if (direction == SPA_DIRECTION_OUTPUT) if (direction == SPA_DIRECTION_OUTPUT)
mix_id = SPA_ID_INVALID; mix_id = SPA_ID_INVALID;
if ((mix = find_mix(p, mix_id)) == NULL || !mix->valid) if ((mix = find_mix(p, mix_id)) == NULL)
return -EINVAL; return -EINVAL;
clear_buffers(impl, mix); clear_buffers(impl, mix);
@ -1019,7 +1046,7 @@ static int client_node_port_buffers(void *data,
if (direction == SPA_DIRECTION_OUTPUT) if (direction == SPA_DIRECTION_OUTPUT)
mix_id = SPA_ID_INVALID; mix_id = SPA_ID_INVALID;
if ((mix = find_mix(p, mix_id)) == NULL || !mix->valid) if ((mix = find_mix(p, mix_id)) == NULL)
goto invalid; goto invalid;
if (mix->n_buffers != n_buffers) if (mix->n_buffers != n_buffers)
@ -1383,12 +1410,12 @@ static int port_init_mix(void *data, struct pw_impl_port_mix *mix)
uint32_t idx, pos, len; uint32_t idx, pos, len;
struct pw_memblock *area; struct pw_memblock *area;
if ((m = create_mix(impl, port, mix->port.port_id)) == NULL) if ((m = create_mix(port, mix->port.port_id)) == NULL)
return -ENOMEM; return -ENOMEM;
mix->id = pw_map_insert_new(&impl->io_map, NULL); mix->id = pw_map_insert_new(&impl->io_map, NULL);
if (mix->id == SPA_ID_INVALID) { if (mix->id == SPA_ID_INVALID) {
m->valid = false; free_mix(port, m);
return -errno; return -errno;
} }
@ -1422,7 +1449,7 @@ static int port_init_mix(void *data, struct pw_impl_port_mix *mix)
return 0; return 0;
no_mem: no_mem:
pw_map_remove(&impl->io_map, mix->id); pw_map_remove(&impl->io_map, mix->id);
m->valid = false; free_mix(port, m);
return -ENOMEM; return -ENOMEM;
} }
@ -1435,7 +1462,7 @@ static int port_release_mix(void *data, struct pw_impl_port_mix *mix)
pw_log_debug("%p: remove mix id:%d io:%p", pw_log_debug("%p: remove mix id:%d io:%p",
impl, mix->id, mix->io); impl, mix->id, mix->io);
if ((m = find_mix(port, mix->port.port_id)) == NULL || !m->valid) if ((m = find_mix(port, mix->port.port_id)) == NULL)
return -EINVAL; return -EINVAL;
if (impl->resource && impl->resource->version >= 4) if (impl->resource && impl->resource->version >= 4)
@ -1444,7 +1471,7 @@ static int port_release_mix(void *data, struct pw_impl_port_mix *mix)
mix->port.port_id, SPA_ID_INVALID, NULL); mix->port.port_id, SPA_ID_INVALID, NULL);
pw_map_remove(&impl->io_map, mix->id); pw_map_remove(&impl->io_map, mix->id);
m->valid = false; free_mix(port, m);
return 0; return 0;
} }
@ -1571,12 +1598,12 @@ static void node_port_init(void *data, struct pw_impl_port *port)
p->direction = port->direction; p->direction = port->direction;
p->id = port->port_id; p->id = port->port_id;
p->impl = impl; p->impl = impl;
pw_array_init(&p->mix, sizeof(struct mix) * 2); pw_map_init(&p->mix, 2, 2);
p->mix_node.iface = SPA_INTERFACE_INIT( p->mix_node.iface = SPA_INTERFACE_INIT(
SPA_TYPE_INTERFACE_Node, SPA_TYPE_INTERFACE_Node,
SPA_VERSION_NODE, SPA_VERSION_NODE,
&impl_port_mix, p); &impl_port_mix, p);
create_mix(impl, p, SPA_ID_INVALID); create_mix(p, SPA_ID_INVALID);
pw_map_insert_at(&impl->ports[p->direction], p->id, p); pw_map_insert_at(&impl->ports[p->direction], p->id, p);
return; return;