mem: improve memory handling

Add a memory pool to manage blocks of memory. Make it possible
to allocate and import blocks.

Add add_mem and remove_mem to the core events to signal a client
of a block of memory. Remove the client-node add_mem.

Make a global pool for memory and a per client pool where we
import and share the memory we need with the client.

Use the new memory pool to track and map memory in clients.
This commit is contained in:
Wim Taymans 2019-07-23 17:41:25 +02:00
parent a8bc8e1b1e
commit 2caf81c97c
16 changed files with 903 additions and 689 deletions

View file

@ -51,7 +51,6 @@
#define MAX_BUFFERS 64
#define MAX_AREAS 1024
#define MAX_IO 32
#define MAX_MIX 128
#define CHECK_IN_PORT_ID(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_INPUTS)
@ -70,25 +69,11 @@
#define CHECK_PORT_BUFFER(this,b,p) (b < p->n_buffers)
struct mem {
uint32_t id;
int ref;
int fd;
uint32_t type;
uint32_t flags;
};
struct buffer {
struct spa_buffer *outbuf;
struct spa_buffer buffer;
struct spa_meta metas[4];
struct spa_data datas[4];
uint32_t memid;
};
struct io {
uint32_t id;
uint32_t memid;
};
struct mix {
@ -98,7 +83,6 @@ struct mix {
struct port *port;
uint32_t n_buffers;
struct buffer buffers[MAX_BUFFERS];
struct io ios[MAX_IO];
};
struct port {
@ -133,7 +117,6 @@ struct node {
struct spa_hook_list hooks;
struct spa_callbacks callbacks;
struct io ios[MAX_IO];
struct pw_resource *resource;
@ -214,55 +197,6 @@ do_port_use_buffers(struct impl *impl,
/** \endcond */
static struct mem *ensure_mem(struct impl *impl, int fd, uint32_t type, uint32_t flags)
{
struct mem *m, *f = NULL;
pw_array_for_each(m, &impl->mems) {
if (m->ref <= 0)
f = m;
else if (m->fd == fd)
goto found;
}
if (f == NULL) {
m = pw_array_add(&impl->mems, sizeof(struct mem));
if (m == NULL)
return NULL;
m->id = pw_array_get_len(&impl->mems, struct mem) - 1;
}
else {
m = f;
}
m->fd = fd;
m->type = type;
m->flags = flags;
m->ref = 0;
pw_log_debug(NAME " %p: add mem %d", impl, m->id);
pw_client_node_resource_add_mem(impl->node.resource,
m->id,
type,
m->fd,
m->flags);
found:
m->ref++;
pw_log_debug(NAME " %p: mem %d, ref %d", impl, m->id, m->ref);
return m;
}
static inline struct mem *find_mem_fd(struct impl *impl, int fd)
{
struct mem *m;
pw_array_for_each(m, &impl->mems) {
if (m->fd == fd)
return m;
}
return NULL;
}
static struct mix *find_mix(struct port *p, uint32_t mix_id)
{
struct mix *mix;
@ -274,13 +208,6 @@ static struct mix *find_mix(struct port *p, uint32_t mix_id)
return mix;
}
static void init_ios(struct io *ios)
{
int i;
for (i = 0; i < MAX_IO; i++)
ios[i].id = SPA_ID_INVALID;
}
static void mix_init(struct mix *mix, struct port *p, uint32_t id)
{
mix->valid = true;
@ -288,7 +215,6 @@ static void mix_init(struct mix *mix, struct port *p, uint32_t id)
mix->port = p;
mix->active = false;
mix->n_buffers = 0;
init_ios(mix->ios);
}
@ -304,66 +230,17 @@ static struct mix *ensure_mix(struct impl *impl, struct port *p, uint32_t mix_id
return mix;
}
static void clear_io(struct node *node, struct io *io)
{
struct mem *m;
m = pw_array_get_unchecked(&node->impl->mems, io->memid, struct mem);
m->ref--;
io->id = SPA_ID_INVALID;
spa_log_debug(node->log, "node %p: clear io %p %d mem %u %d", node, io, io->id, io->memid, m->ref);
}
static struct io *update_io(struct node *this,
struct io *ios, uint32_t id, uint32_t memid)
{
int i;
struct io *io, *f = NULL;
for (i = 0; i < MAX_IO; i++) {
io = &ios[i];
if (io->id == SPA_ID_INVALID)
f = io;
else if (io->id == id) {
if (io->memid != memid) {
clear_io(this, io);
if (memid == SPA_ID_INVALID)
io->id = SPA_ID_INVALID;
}
goto found;
}
}
if (f == NULL || memid == SPA_ID_INVALID)
return NULL;
io = f;
io->id = id;
io->memid = memid;
spa_log_debug(this->log, "node %p: add io %p %s %d", this, io,
spa_debug_type_find_name(spa_type_io, id), memid);
found:
return io;
}
static void clear_ios(struct node *this, struct io *ios)
{
int i;
for (i = 0; i < MAX_IO; i++) {
struct io *io = &ios[i];
if (io->id != SPA_ID_INVALID)
clear_io(this, io);
}
}
static int clear_buffers(struct node *this, struct mix *mix)
{
uint32_t i, j;
struct impl *impl = this->impl;
if (this->resource == NULL)
return 0;
for (i = 0; i < mix->n_buffers; i++) {
struct buffer *b = &mix->buffers[i];
struct mem *m;
struct pw_memblock *m;
spa_log_debug(this->log, "node %p: clear buffer %d", this, i);
@ -375,14 +252,11 @@ static int clear_buffers(struct node *this, struct mix *mix)
uint32_t id;
id = SPA_PTR_TO_UINT32(b->buffer.datas[j].data);
m = pw_array_get_unchecked(&impl->mems, id, struct mem);
m->ref--;
pw_log_debug(NAME " %p: mem %d, ref %d", impl, m->id, m->ref);
m = pw_mempool_find_id(this->resource->client->pool, id);
if (m)
pw_log_debug(NAME " %p: mem %d", impl, m->id);
}
}
m = pw_array_get_unchecked(&impl->mems, b->memid, struct mem);
m->ref--;
pw_log_debug(NAME " %p: mem %d, ref %d", impl, m->id, m->ref);
}
mix->n_buffers = 0;
return 0;
@ -396,7 +270,6 @@ static void mix_clear(struct node *this, struct mix *mix)
return;
do_port_use_buffers(this->impl, port->direction, port->id,
mix->id, NULL, 0);
clear_ios(this, mix->ios);
mix->valid = false;
}
@ -458,8 +331,7 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
{
struct node *this = object;
struct impl *impl;
struct pw_memblock *mem;
struct mem *m;
struct pw_memblock *mem, *m;
uint32_t memid, mem_offset, mem_size;
spa_return_val_if_fail(this != NULL, -EINVAL);
@ -473,19 +345,18 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
return -EIO;
if (data) {
if ((mem = pw_memblock_find(data)) == NULL)
if ((mem = pw_mempool_find_ptr(impl->core->pool, data)) == NULL)
return -EINVAL;
mem_offset = SPA_PTRDIFF(data, mem->ptr);
mem_size = mem->size;
if (mem_size - mem_offset < size)
mem_offset = SPA_PTRDIFF(data, mem->map->ptr);
if (mem_offset + size > mem->map->size)
return -EINVAL;
mem_offset += mem->offset;
mem_size = size;
m = ensure_mem(impl, mem->fd, SPA_DATA_MemFd, mem->flags);
m = pw_mempool_import_block(this->resource->client->pool, mem);
if (m == NULL)
return -errno;
mem_size = size;
memid = m->id;
}
else {
@ -493,8 +364,6 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
mem_offset = mem_size = 0;
}
update_io(this, this->ios, id, memid);
return pw_client_node_resource_set_io(this->resource,
id,
memid,
@ -762,8 +631,7 @@ static int do_port_set_io(struct impl *impl,
uint32_t id, void *data, size_t size)
{
struct node *this = &impl->node;
struct pw_memblock *mem;
struct mem *m;
struct pw_memblock *mem, *m;
uint32_t memid, mem_offset, mem_size;
struct port *port;
struct mix *mix;
@ -783,17 +651,17 @@ static int do_port_set_io(struct impl *impl,
return -EINVAL;
if (data) {
if ((mem = pw_memblock_find(data)) == NULL)
if ((mem = pw_mempool_find_ptr(impl->core->pool, data)) == NULL)
return -EINVAL;
mem_offset = SPA_PTRDIFF(data, mem->ptr);
if (mem_offset + size > mem->size)
mem_offset = SPA_PTRDIFF(data, mem->map->ptr);
if (mem_offset + size > mem->map->size)
return -EINVAL;
mem_offset += mem->offset;
m = ensure_mem(impl, mem->fd, SPA_DATA_MemFd, mem->flags);
m = pw_mempool_import_block(this->resource->client->pool, mem);
if (m == NULL)
return -errno;
memid = m->id;
mem_size = size;
}
@ -802,8 +670,6 @@ static int do_port_set_io(struct impl *impl,
mem_offset = mem_size = 0;
}
update_io(this, mix->ios, id, memid);
return pw_client_node_resource_port_set_io(this->resource,
direction, port_id,
mix_id,
@ -867,8 +733,7 @@ do_port_use_buffers(struct impl *impl,
for (i = 0; i < n_buffers; i++) {
struct buffer *b = &mix->buffers[i];
struct pw_memblock *mem;
struct mem *m;
struct pw_memblock *mem, *m;
size_t data_size;
void *baseptr;
@ -884,7 +749,7 @@ do_port_use_buffers(struct impl *impl,
else
return -EINVAL;
if ((mem = pw_memblock_find(baseptr)) == NULL)
if ((mem = pw_mempool_find_ptr(impl->core->pool, baseptr)) == NULL)
return -EINVAL;
data_size = buffers[i]->n_datas * sizeof(struct spa_chunk);
@ -897,14 +762,13 @@ do_port_use_buffers(struct impl *impl,
data_size += d->maxsize;
}
m = ensure_mem(impl, mem->fd, SPA_DATA_MemFd, mem->flags);
m = pw_mempool_import_block(this->resource->client->pool, mem);
if (m == NULL)
return -errno;
b->memid = m->id;
mb[i].buffer = &b->buffer;
mb[i].mem_id = b->memid;
mb[i].offset = SPA_PTRDIFF(baseptr, SPA_MEMBER(mem->ptr, mem->offset, void));
mb[i].mem_id = m->id;
mb[i].offset = SPA_PTRDIFF(baseptr, SPA_MEMBER(mem->map->ptr, 0, void));
mb[i].size = data_size;
spa_log_debug(this->log, "buffer %d %d %d %d", i, mb[i].mem_id,
mb[i].offset, mb[i].size);
@ -920,7 +784,8 @@ do_port_use_buffers(struct impl *impl,
if (d->type == SPA_DATA_DmaBuf ||
d->type == SPA_DATA_MemFd) {
m = ensure_mem(impl, d->fd, d->type, d->flags);
m = pw_mempool_import(this->resource->client->pool,
d->type, d->fd, d->flags);
if (m == NULL)
return -errno;
b->buffer.datas[j].data = SPA_UINT32_TO_PTR(m->id);
@ -1207,8 +1072,6 @@ node_init(struct node *this,
spa_hook_list_init(&this->hooks);
spa_list_init(&this->pending_list);
init_ios(this->ios);
this->data_source.func = node_on_data_fd_events;
this->data_source.data = this;
this->data_source.fd = -1;
@ -1222,8 +1085,6 @@ static int node_clear(struct node *this)
{
uint32_t i;
clear_ios(this, this->ios);
for (i = 0; i < this->n_params; i++)
free(this->params[i]);
free(this->params);
@ -1293,7 +1154,7 @@ void pw_client_node_registered(struct pw_client_node *this, struct pw_global *gl
struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this);
struct pw_node *node = this->node;
uint32_t node_id = global->id;
struct mem *m;
struct pw_memblock *m;
pw_log_debug(NAME " %p: %d", this, node_id);
pw_client_node_resource_transport(this->resource,
@ -1301,9 +1162,9 @@ void pw_client_node_registered(struct pw_client_node *this, struct pw_global *gl
impl->other_fds[0],
impl->other_fds[1]);
m = ensure_mem(impl, node->activation->fd, SPA_DATA_MemFd, node->activation->flags);
m = pw_mempool_import_block(this->resource->client->pool, node->activation);
if (m == NULL) {
pw_log_debug(NAME " %p: can't ensure mem: %m", this);
pw_log_debug(NAME " %p: can't import block: %m", this);
return;
}
@ -1344,14 +1205,13 @@ static void node_initialized(void *data)
size = sizeof(struct spa_io_buffers) * MAX_AREAS;
if (pw_memblock_alloc(PW_MEMBLOCK_FLAG_WITH_FD |
PW_MEMBLOCK_FLAG_MAP_READWRITE |
PW_MEMBLOCK_FLAG_SEAL,
size,
&impl->io_areas) < 0)
if (pw_mempool_alloc(impl->core->pool,
PW_MEMBLOCK_FLAG_MAP |
PW_MEMBLOCK_FLAG_SEAL,
size, &impl->io_areas) < 0)
return;
pw_log_debug(NAME " %p: io areas %p", node, impl->io_areas->ptr);
pw_log_debug(NAME " %p: io areas %p", node, impl->io_areas->map->ptr);
if ((global = pw_node_get_global(node)) != NULL)
pw_client_node_registered(this, global);
@ -1373,9 +1233,8 @@ static void node_free(void *data)
if (this->resource)
pw_resource_destroy(this->resource);
pw_array_clear(&impl->mems);
if (impl->io_areas)
pw_memblock_free(impl->io_areas);
pw_memblock_unref(impl->io_areas);
pw_map_clear(&impl->io_map);
@ -1399,13 +1258,13 @@ static int port_init_mix(void *data, struct pw_port_mix *mix)
if (mix->id == SPA_ID_INVALID)
return -errno;
mix->io = SPA_MEMBER(impl->io_areas->ptr,
mix->io = SPA_MEMBER(impl->io_areas->map->ptr,
mix->id * sizeof(struct spa_io_buffers), void);
mix->io->buffer_id = SPA_ID_INVALID;
mix->io->status = SPA_STATUS_NEED_BUFFER;
pw_log_debug(NAME " %p: init mix io %d %p %p", impl, mix->id, mix->io,
impl->io_areas->ptr);
impl->io_areas->map->ptr);
return 0;
}
@ -1418,7 +1277,7 @@ static int port_release_mix(void *data, struct pw_port_mix *mix)
struct mix *m;
pw_log_debug(NAME " %p: remove mix io %d %p %p", impl, mix->id, mix->io,
impl->io_areas->ptr);
impl->io_areas->map->ptr);
if ((m = find_mix(port, mix->port.port_id)) == NULL || !m->valid)
return -EINVAL;
@ -1607,17 +1466,16 @@ static void node_peer_added(void *data, struct pw_node *peer)
{
struct impl *impl = data;
struct node *this = &impl->node;
struct mem *m;
struct pw_memblock *m;
if (this->resource == NULL)
return;
m = ensure_mem(impl, peer->activation->fd, SPA_DATA_MemFd, peer->activation->flags);
m = pw_mempool_import_block(this->resource->client->pool, peer->activation);
if (m == NULL) {
pw_log_debug(NAME " %p: can't ensure mem: %m", this);
return;
}
pw_log_debug(NAME " %p: peer %p %u added %u", &impl->this, peer,
peer->info.id, m->id);
@ -1633,19 +1491,18 @@ static void node_peer_removed(void *data, struct pw_node *peer)
{
struct impl *impl = data;
struct node *this = &impl->node;
struct mem *m;
struct pw_memblock *m;
if (this->resource == NULL)
return;
m = find_mem_fd(impl, peer->activation->fd);
m = pw_mempool_find_fd(this->resource->client->pool,
peer->activation->fd);
if (m == NULL) {
pw_log_warn(NAME " %p: unknown peer %p fd:%d", &impl->this, peer,
peer->source.fd);
return;
}
m->ref--;
pw_log_debug(NAME " %p: peer %p %u removed", &impl->this, peer,
peer->info.id);
@ -1655,6 +1512,7 @@ static void node_peer_removed(void *data, struct pw_node *peer)
SPA_ID_INVALID,
0,
0);
pw_memblock_unref(m);
}
static void node_driver_changed(void *data, struct pw_node *old, struct pw_node *driver)
@ -1737,7 +1595,6 @@ struct pw_client_node *pw_client_node_new(struct pw_resource *resource,
this->flags = do_register ? 0 : 1;
pw_map_init(&impl->io_map, 64, 64);
pw_array_init(&impl->mems, 64);
if ((name = pw_properties_get(properties, PW_KEY_NODE_NAME)) == NULL)
name = NAME;

View file

@ -262,30 +262,6 @@ static int client_node_marshal_event_method(void *object, const struct spa_event
return pw_protocol_native_end_proxy(proxy, b);
}
static int client_node_demarshal_add_mem(void *object, const struct pw_protocol_native_message *msg)
{
struct pw_proxy *proxy = object;
struct spa_pod_parser prs;
uint32_t mem_id, type, memfd_idx, flags;
int memfd;
spa_pod_parser_init(&prs, msg->data, msg->size);
if (spa_pod_parser_get_struct(&prs,
SPA_POD_Int(&mem_id),
SPA_POD_Id(&type),
SPA_POD_Int(&memfd_idx),
SPA_POD_Int(&flags)) < 0)
return -EINVAL;
memfd = pw_protocol_native_get_proxy_fd(proxy, memfd_idx);
pw_proxy_notify(proxy, struct pw_client_node_proxy_events, add_mem, 0,
mem_id,
type,
memfd, flags);
return 0;
}
static int client_node_demarshal_transport(void *object, const struct pw_protocol_native_message *msg)
{
struct pw_proxy *proxy = object;
@ -564,27 +540,6 @@ static int client_node_demarshal_set_io(void *object, const struct pw_protocol_n
return 0;
}
static int
client_node_marshal_add_mem(void *object,
uint32_t mem_id,
uint32_t type,
int memfd, uint32_t flags)
{
struct pw_protocol_native_message *msg;
struct pw_resource *resource = object;
struct spa_pod_builder *b;
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_NODE_PROXY_EVENT_ADD_MEM, &msg);
spa_pod_builder_add_struct(b,
SPA_POD_Int(mem_id),
SPA_POD_Id(type),
SPA_POD_Int(pw_protocol_native_add_resource_fd(resource, memfd)),
SPA_POD_Int(flags));
return pw_protocol_native_end_resource(resource, b);
}
static int client_node_marshal_transport(void *object, uint32_t node_id, int readfd, int writefd)
{
struct pw_protocol_native_message *msg;
@ -1053,7 +1008,6 @@ pw_protocol_native_client_node_method_demarshal[PW_CLIENT_NODE_PROXY_METHOD_NUM]
static const struct pw_client_node_proxy_events pw_protocol_native_client_node_event_marshal = {
PW_VERSION_CLIENT_NODE_PROXY_EVENTS,
.add_mem = &client_node_marshal_add_mem,
.transport = &client_node_marshal_transport,
.set_param = &client_node_marshal_set_param,
.set_io = &client_node_marshal_set_io,
@ -1070,7 +1024,6 @@ static const struct pw_client_node_proxy_events pw_protocol_native_client_node_e
static const struct pw_protocol_native_demarshal
pw_protocol_native_client_node_event_demarshal[PW_CLIENT_NODE_PROXY_EVENT_NUM] =
{
[PW_CLIENT_NODE_PROXY_EVENT_ADD_MEM] = { &client_node_demarshal_add_mem, 0 },
[PW_CLIENT_NODE_PROXY_EVENT_TRANSPORT] = { &client_node_demarshal_transport, 0 },
[PW_CLIENT_NODE_PROXY_EVENT_SET_PARAM] = { &client_node_demarshal_set_param, 0 },
[PW_CLIENT_NODE_PROXY_EVENT_SET_IO] = { &client_node_demarshal_set_io, 0 },

View file

@ -41,35 +41,22 @@
#include "extensions/client-node.h"
#define MAX_MIX 4096
#define MAX_IO 32
/** \cond */
struct mapping {
void *ptr;
struct pw_map_range map;
int prot;
};
struct mem {
uint32_t id;
int fd;
uint32_t flags;
uint32_t ref;
struct mapping map;
};
struct buffer_mem {
uint32_t mem_id;
struct mapping map;
};
struct buffer {
uint32_t id;
struct spa_buffer *buf;
struct buffer_mem *mem;
struct pw_memmap **mem;
uint32_t n_mem;
};
struct io {
uint32_t id;
struct pw_memmap *mem;
};
struct mix {
struct spa_list link;
struct pw_port *port;
@ -77,11 +64,12 @@ struct mix {
struct pw_port_mix mix;
struct pw_array buffers;
bool active;
struct io ios[MAX_IO];
};
struct link {
uint32_t node_id;
uint32_t mem_id;
struct pw_memmap *map;
struct pw_node_target target;
int signalfd;
};
@ -97,8 +85,6 @@ struct node_data {
struct spa_list mix[2];
struct spa_list free_mix;
struct pw_array mems;
struct pw_node *node;
struct spa_hook node_listener;
int do_free:1;
@ -109,6 +95,7 @@ struct node_data {
struct spa_hook proxy_listener;
struct pw_proxy *proxy;
struct io ios[MAX_IO];
struct spa_io_position *position;
struct pw_array links;
@ -116,6 +103,50 @@ struct node_data {
/** \endcond */
static void init_ios(struct io *ios)
{
int i;
for (i = 0; i < MAX_IO; i++)
ios[i].id = SPA_ID_INVALID;
}
static void clear_io(struct io *io)
{
pw_log_debug("%p clear id:%u mem:%p", io, io->id, io->mem);
pw_memmap_free(io->mem);
io->mem = NULL;
io->id = SPA_ID_INVALID;
}
static struct io *update_io(struct node_data *data, struct io *ios,
uint32_t id, struct pw_memmap *mem)
{
int i;
struct io *io, *f = NULL;
pw_log_debug("node %p: update id:%u mem:%p", data, id, mem);
for (i = 0; i < MAX_IO; i++) {
io = &ios[i];
if (io->id == SPA_ID_INVALID && f == NULL)
f = io;
else if (io->id == id) {
if (io->mem && io->mem != mem)
clear_io(io);
f = io;
break;
}
}
if (f == NULL)
return NULL;
io = f;
io->id = id;
io->mem = mem;
return io;
}
static struct link *find_activation(struct pw_array *links, uint32_t node_id)
{
struct link *l;
@ -127,112 +158,26 @@ static struct link *find_activation(struct pw_array *links, uint32_t node_id)
return NULL;
}
static struct mem *find_mem(struct node_data *data, uint32_t id)
{
struct mem *m;
pw_array_for_each(m, &data->mems) {
if (m->id == id)
return m;
}
return NULL;
}
static struct mem *find_mem_ptr(struct node_data *data, void *ptr)
{
struct mem *m;
pw_array_for_each(m, &data->mems) {
if (ptr >= m->map.ptr && ptr < SPA_MEMBER(m->map.ptr, m->map.map.size, void))
return m;
}
return NULL;
}
static void *mem_map(struct node_data *data, struct mapping *map,
int fd, int prot, uint32_t offset, uint32_t size)
{
struct mapping m;
void *ptr;
pw_map_range_init(&m.map, offset, size, data->core->sc_pagesize);
if (map->ptr == NULL || map->map.offset != m.map.offset || map->map.size != m.map.size) {
m.ptr = mmap(map->ptr, m.map.size, prot, MAP_SHARED, fd, m.map.offset);
if (m.ptr == MAP_FAILED) {
pw_log_error("remote %p: Failed to mmap memory %d size:%d: %m", data, fd, size);
return NULL;
}
map->map = m.map;
map->ptr = m.ptr;
pw_log_debug("remote %p: fd %d map %d %d %p", data, fd, m.map.offset, m.map.size, m.ptr);
}
ptr = SPA_MEMBER(map->ptr, m.map.start, void);
pw_log_debug("remote %p: fd %d ptr %p (%d %d)", data, fd, ptr, offset, size);
return ptr;
}
static void *mem_unmap(struct node_data *data, struct mapping *map)
{
if (map->ptr != NULL) {
if (munmap(map->ptr, map->map.size) < 0)
pw_log_warn("failed to unmap: %m");
}
return NULL;
}
static void clear_mem(struct node_data *data, struct mem *m)
{
if (m->fd != -1) {
bool has_ref = false;
int fd;
struct mem *m2;
pw_log_debug("remote %p: clear mem %p %d %d", data, m, m->id, m->fd);
fd = m->fd;
m->fd = -1;
m->id = SPA_ID_INVALID;
pw_array_for_each(m2, &data->mems) {
if (m2->fd == fd) {
has_ref = true;
break;
}
}
if (!has_ref) {
m->map.ptr = mem_unmap(data, &m->map);
close(fd);
}
}
}
static void clear_link(struct node_data *data, struct link *link)
{
struct mem *m;
link->node_id = SPA_ID_INVALID;
link->target.activation = NULL;
m = find_mem(data, link->mem_id);
if (m && --m->ref == 0)
clear_mem(data, m);
pw_memmap_free(link->map);
close(link->signalfd);
spa_list_remove(&link->target.link);
}
static void clean_transport(struct node_data *data)
{
struct mem *m;
struct link *l;
if (!data->have_transport)
return;
pw_array_for_each(m, &data->mems)
clear_mem(data, m);
pw_array_clear(&data->mems);
pw_array_for_each(l, &data->links)
clear_link(data, l);
pw_array_for_each(l, &data->links) {
if (l->node_id != SPA_ID_INVALID)
clear_link(data, l);
}
pw_array_clear(&data->links);
close(data->rtwritefd);
@ -248,6 +193,7 @@ static void mix_init(struct mix *mix, struct pw_port *port, uint32_t mix_id)
mix->active = false;
pw_array_init(&mix->buffers, 32);
pw_array_ensure_size(&mix->buffers, sizeof(struct buffer) * 64);
init_ios(mix->ios);
}
static int
@ -331,35 +277,6 @@ static struct mix *ensure_mix(struct node_data *data,
return mix;
}
static int client_node_add_mem(void *object,
uint32_t mem_id,
uint32_t type, int memfd, uint32_t flags)
{
struct pw_proxy *proxy = object;
struct node_data *data = proxy->user_data;
struct mem *m;
m = find_mem(data, mem_id);
if (m) {
pw_log_warn("duplicate mem %u, fd %d, flags %d",
mem_id, memfd, flags);
return -EINVAL;
}
m = pw_array_add(&data->mems, sizeof(struct mem));
if (m == NULL)
return -errno;
pw_log_debug("add mem %u, fd %d, flags %d", mem_id, memfd, flags);
m->id = mem_id;
m->fd = memfd;
m->flags = flags;
m->ref = 0;
m->map.map = PW_MAP_RANGE_INIT;
m->map.ptr = NULL;
return 0;
}
static int client_node_transport(void *object, uint32_t node_id,
int readfd, int writefd)
@ -523,39 +440,36 @@ client_node_set_io(void *object,
{
struct pw_proxy *proxy = object;
struct node_data *data = proxy->user_data;
struct mem *m;
struct pw_memmap *mm;
void *ptr;
if (memid == SPA_ID_INVALID) {
ptr = NULL;
size = 0;
mm = ptr = NULL;
}
else {
m = find_mem(data, memid);
if (m == NULL) {
pw_log_warn("unknown memory id %u", memid);
return -EINVAL;
}
ptr = mem_map(data, &m->map, m->fd,
PROT_READ|PROT_WRITE, offset, size);
if (ptr == NULL) {
pw_proxy_error(proxy, -errno, "set_io: mmap failed: %m");
mm = pw_mempool_map_id(proxy->remote->pool, memid,
PROT_READ|PROT_WRITE, offset, size);
if (mm == NULL) {
pw_log_warn("can't map memory id %u: %m", memid);
return -errno;
}
m->ref++;
ptr = mm->ptr;
}
pw_log_debug("node %p: set io %s %p", proxy,
spa_debug_type_find_name(spa_type_io, id), ptr);
if (id == SPA_IO_Position) {
if (ptr == NULL && data->position) {
m = find_mem_ptr(data, data->position);
if (m && --m->ref == 0)
clear_mem(data, m);
}
update_io(data, data->ios, id, mm);
switch (id) {
case SPA_IO_Position:
data->position = ptr;
break;
default:
break;
}
return spa_node_set_io(data->node->node, id, ptr, size);
}
@ -631,15 +545,9 @@ static int clear_buffers(struct node_data *data, struct mix *mix)
pw_array_for_each(b, &mix->buffers) {
for (i = 0; i < b->n_mem; i++) {
struct buffer_mem *bm = &b->mem[i];
struct mem *m;
pw_log_debug("port %p: clear buffer %d mem %d",
port, b->id, bm->mem_id);
m = find_mem(data, bm->mem_id);
if (m && --m->ref == 0)
clear_mem(data, m);
pw_log_debug("port %p: clear buffer %d map %p",
port, b->id, b->mem[i]);
pw_memmap_free(b->mem[i]);
}
b->n_mem = 0;
free(b->buf);
@ -714,14 +622,14 @@ client_node_port_use_buffers(void *object,
bufs = alloca(n_buffers * sizeof(struct spa_buffer *));
for (i = 0; i < n_buffers; i++) {
struct buffer_mem bmem = { 0, };
size_t size;
off_t offset;
struct mem *m;
struct pw_memmap *mm;
m = find_mem(data, buffers[i].mem_id);
if (m == NULL) {
res = -ENODEV;
mm = pw_mempool_map_id(proxy->remote->pool, buffers[i].mem_id,
prot, buffers[i].offset, buffers[i].size);
if (mm == NULL) {
res = -errno;
goto error_exit_cleanup;
}
@ -732,24 +640,17 @@ client_node_port_use_buffers(void *object,
}
bid->id = i;
bmem.mem_id = m->id;
bmem.map.ptr = mem_map(data, &bmem.map, m->fd, prot,
buffers[i].offset, buffers[i].size);
if (bmem.map.ptr == NULL) {
res = -errno;
goto error_exit_cleanup;
}
if (mlock(bmem.map.ptr, bmem.map.map.size) < 0)
pw_log_warn("Failed to mlock memory %u %u: %m",
bmem.map.map.offset, bmem.map.map.size);
if (mlock(mm->ptr, mm->size) < 0)
pw_log_warn("Failed to mlock memory %p %u: %m",
mm->ptr, mm->size);
size = sizeof(struct spa_buffer);
size += sizeof(struct buffer_mem);
size += sizeof(struct pw_memmap *);
for (j = 0; j < buffers[i].buffer->n_metas; j++)
size += sizeof(struct spa_meta);
for (j = 0; j < buffers[i].buffer->n_datas; j++) {
size += sizeof(struct spa_data);
size += sizeof(struct buffer_mem);
size += sizeof(struct pw_memmap *);
}
b = bid->buf = malloc(size);
@ -763,20 +664,18 @@ client_node_port_use_buffers(void *object,
b->datas = SPA_MEMBER(b->metas, sizeof(struct spa_meta) * b->n_metas,
struct spa_data);
bid->mem = SPA_MEMBER(b->datas, sizeof(struct spa_data) * b->n_datas,
struct buffer_mem);
struct pw_memmap *);
bid->n_mem = 0;
bid->mem[bid->n_mem++] = mm;
bid->mem[bid->n_mem++] = bmem;
m->ref++;
pw_log_debug("add buffer %d %d %u %u", m->id,
bid->id, bmem.map.map.offset, bmem.map.map.size);
pw_log_debug("add buffer %d %d %u %u", mm->block->id,
bid->id, buffers[i].offset, buffers[i].size);
offset = 0;
for (j = 0; j < b->n_metas; j++) {
struct spa_meta *m = &b->metas[j];
memcpy(m, &buffers[i].buffer->metas[j], sizeof(struct spa_meta));
m->data = SPA_MEMBER(bmem.map.ptr, offset, void);
m->data = SPA_MEMBER(mm->ptr, offset, void);
offset += SPA_ROUND_UP_N(m->size, 8);
}
@ -785,14 +684,14 @@ client_node_port_use_buffers(void *object,
memcpy(d, &buffers[i].buffer->datas[j], sizeof(struct spa_data));
d->chunk =
SPA_MEMBER(bmem.map.ptr, offset + sizeof(struct spa_chunk) * j,
SPA_MEMBER(mm->ptr, offset + sizeof(struct spa_chunk) * j,
struct spa_chunk);
if (d->type == SPA_DATA_MemFd || d->type == SPA_DATA_DmaBuf) {
if (d->type == SPA_DATA_MemId) {
uint32_t mem_id = SPA_PTR_TO_UINT32(d->data);
struct mem *bm = find_mem(data, mem_id);
struct buffer_mem bm2;
struct pw_memblock *bm;
bm = pw_mempool_find_id(proxy->remote->pool, mem_id);
if (bm == NULL) {
pw_log_error("unknown buffer mem %u", mem_id);
res = -ENODEV;
@ -800,18 +699,14 @@ client_node_port_use_buffers(void *object,
}
d->fd = bm->fd;
bm->ref++;
bm2.mem_id = bm->id;
bm2.map.ptr = NULL;
d->data = bm2.map.ptr;
bid->mem[bid->n_mem++] = bm2;
d->type = bm->type;
d->data = NULL;
pw_log_debug(" data %d %u -> fd %d maxsize %d",
j, bm->id, bm->fd, d->maxsize);
} else if (d->type == SPA_DATA_MemPtr) {
int offs = SPA_PTR_TO_INT(d->data);
d->data = SPA_MEMBER(bmem.map.ptr, offs, void);
d->data = SPA_MEMBER(mm->ptr, offs, void);
d->fd = -1;
pw_log_debug(" data %d %u -> mem %p maxsize %d",
j, bid->id, d->data, d->maxsize);
@ -848,7 +743,7 @@ client_node_port_set_io(void *object,
struct pw_proxy *proxy = object;
struct node_data *data = proxy->user_data;
struct mix *mix;
struct mem *m;
struct pw_memmap *mm;
void *ptr;
int res = 0;
@ -859,39 +754,32 @@ client_node_port_set_io(void *object,
}
if (memid == SPA_ID_INVALID) {
ptr = NULL;
mm = ptr = NULL;
size = 0;
}
else {
m = find_mem(data, memid);
if (m == NULL) {
res = -ENODEV;
goto error_exit;
}
ptr = mem_map(data, &m->map, m->fd,
PROT_READ|PROT_WRITE, offset, size);
if (ptr == NULL) {
mm = pw_mempool_map_id(proxy->remote->pool, memid,
PROT_READ|PROT_WRITE, offset, size);
if (mm == NULL) {
res = -errno;
goto error_exit;
}
m->ref++;
ptr = mm->ptr;
}
pw_log_debug("port %p: set io %s %p %p", mix->port,
pw_log_debug("port %p: set io:%s new:%p old:%p", mix->port,
spa_debug_type_find_name(spa_type_io, id), ptr, mix->mix.io);
update_io(data, mix->ios, id, mm);
if (id == SPA_IO_Buffers) {
if (ptr == NULL && mix->mix.io) {
if (ptr == NULL && mix->mix.io)
deactivate_mix(data, mix);
m = find_mem_ptr(data, mix->mix.io);
if (m && --m->ref == 0)
clear_mem(data, m);
}
mix->mix.io = ptr;
if (ptr)
activate_mix(data, mix);
}
if ((res = spa_node_port_set_io(mix->port->mix,
direction, mix_id,
id, ptr, size)) < 0) {
@ -936,28 +824,24 @@ client_node_set_activation(void *object,
struct pw_proxy *proxy = object;
struct node_data *data = proxy->user_data;
struct pw_node *node = data->node;
struct mem *m;
struct pw_memmap *mm;
struct pw_node_activation *ptr;
struct link *link;
int res = 0;
if (memid == SPA_ID_INVALID) {
ptr = NULL;
mm = NULL;
size = 0;
}
else {
m = find_mem(data, memid);
if (m == NULL) {
res = -ENODEV;
goto error_exit;
}
ptr = mem_map(data, &m->map, m->fd,
PROT_READ|PROT_WRITE, offset, size);
if (ptr == NULL) {
mm = pw_mempool_map_id(proxy->remote->pool, memid,
PROT_READ|PROT_WRITE, offset, size);
if (mm == NULL) {
res = -errno;
goto error_exit;
}
m->ref++;
ptr = mm->ptr;
}
pw_log_debug("node %p: set activation %d %p %u %u", node, node_id, ptr, offset, size);
@ -975,7 +859,7 @@ client_node_set_activation(void *object,
goto error_exit;
}
link->node_id = node_id;
link->mem_id = memid;
link->map = mm;
link->target.activation = ptr;
link->signalfd = signalfd;
link->target.signal = link_signal_func;
@ -1007,7 +891,6 @@ error_exit:
static const struct pw_client_node_proxy_events client_node_events = {
PW_VERSION_CLIENT_NODE_PROXY_EVENTS,
.add_mem = client_node_add_mem,
.transport = client_node_transport,
.set_param = client_node_set_param,
.set_io = client_node_set_io,
@ -1226,6 +1109,7 @@ static struct pw_proxy *node_export(struct pw_remote *remote, void *object, bool
data->core = pw_node_get_core(node);
data->node_proxy = (struct pw_client_node_proxy *)proxy;
data->remote_id = SPA_ID_INVALID;
init_ios(data->ios);
node->exported = true;
@ -1235,8 +1119,6 @@ static struct pw_proxy *node_export(struct pw_remote *remote, void *object, bool
for (i = 0; i < MAX_MIX; i++)
spa_list_append(&data->free_mix, &data->mix_pool[i].link);
pw_array_init(&data->mems, 64);
pw_array_ensure_size(&data->mems, sizeof(struct mem) * 64);
pw_array_init(&data->links, 64);
pw_array_ensure_size(&data->links, sizeof(struct link) * 64);