diff options
-rw-r--r-- | spa/include/spa/buffer/meta.h | 13 | ||||
-rw-r--r-- | spa/include/spa/utils/list.h | 5 | ||||
-rw-r--r-- | spa/lib/debug.c | 7 | ||||
-rw-r--r-- | src/modules/module-client-node/client-node.c | 47 | ||||
-rw-r--r-- | src/modules/module-client-node/transport.c | 36 | ||||
-rw-r--r-- | src/pipewire/link.c | 65 | ||||
-rw-r--r-- | src/pipewire/mem.c | 100 | ||||
-rw-r--r-- | src/pipewire/mem.h | 10 | ||||
-rw-r--r-- | src/pipewire/port.c | 8 | ||||
-rw-r--r-- | src/pipewire/private.h | 4 |
10 files changed, 163 insertions, 132 deletions
diff --git a/spa/include/spa/buffer/meta.h b/spa/include/spa/buffer/meta.h index 54b4aee3..fcd87955 100644 --- a/spa/include/spa/buffer/meta.h +++ b/spa/include/spa/buffer/meta.h @@ -36,7 +36,6 @@ extern "C" { #define SPA_TYPE_META__Header SPA_TYPE_META_BASE "Header" #define SPA_TYPE_META__VideoCrop SPA_TYPE_META_BASE "VideoCrop" -#define SPA_TYPE_META__Shared SPA_TYPE_META_BASE "Shared" /** * A metadata element. @@ -78,16 +77,6 @@ struct spa_meta_video_crop { }; /** - * Describes the shared memory that holds buffer meta/chunk/data - */ -struct spa_meta_shared { - uint32_t flags; /**< flags */ - int fd; /**< file descriptor of memory */ - uint32_t offset; /**< offset in memory */ - uint32_t size; /**< size of memory */ -}; - -/** * Describes a control location in the buffer. */ struct spa_meta_control { @@ -98,7 +87,6 @@ struct spa_meta_control { struct spa_type_meta { uint32_t Header; uint32_t VideoCrop; - uint32_t Shared; }; static inline void spa_type_meta_map(struct spa_type_map *map, struct spa_type_meta *type) @@ -106,7 +94,6 @@ static inline void spa_type_meta_map(struct spa_type_map *map, struct spa_type_m if (type->Header == 0) { type->Header = spa_type_map_get_id(map, SPA_TYPE_META__Header); type->VideoCrop = spa_type_map_get_id(map, SPA_TYPE_META__VideoCrop); - type->Shared = spa_type_map_get_id(map, SPA_TYPE_META__Shared); } } diff --git a/spa/include/spa/utils/list.h b/spa/include/spa/utils/list.h index b5b86445..7d5a798f 100644 --- a/spa/include/spa/utils/list.h +++ b/spa/include/spa/utils/list.h @@ -29,10 +29,11 @@ struct spa_list { struct spa_list *prev; }; +#define SPA_LIST_INIT(list) (struct spa_list){ list, list }; + static inline void spa_list_init(struct spa_list *list) { - list->next = list; - list->prev = list; + *list = SPA_LIST_INIT(list); } static inline void spa_list_insert(struct spa_list *list, struct spa_list *elem) diff --git a/spa/lib/debug.c b/spa/lib/debug.c index 58106e6b..0ba16935 100644 --- a/spa/lib/debug.c +++ b/spa/lib/debug.c @@ -79,13 +79,6 @@ int spa_debug_buffer(const struct spa_buffer *buffer) fprintf(stderr, " y: %d\n", h->y); fprintf(stderr, " width: %d\n", h->width); fprintf(stderr, " height: %d\n", h->height); - } else if (!strcmp(type_name, SPA_TYPE_META__Shared)) { - struct spa_meta_shared *h = m->data; - fprintf(stderr, " struct spa_meta_shared:\n"); - fprintf(stderr, " flags: %d\n", h->flags); - fprintf(stderr, " fd: %d\n", h->fd); - fprintf(stderr, " offset: %d\n", h->offset); - fprintf(stderr, " size: %d\n", h->size); } else { fprintf(stderr, " Unknown:\n"); spa_debug_dump_mem(m->data, m->size); diff --git a/src/modules/module-client-node/client-node.c b/src/modules/module-client-node/client-node.c index dbc8467f..2986178b 100644 --- a/src/modules/module-client-node/client-node.c +++ b/src/modules/module-client-node/client-node.c @@ -550,10 +550,9 @@ spa_proxy_node_port_use_buffers(struct spa_node *node, struct proxy *this; struct impl *impl; struct port *port; - uint32_t i, j, k; + uint32_t i, j; size_t n_mem; struct pw_client_node_buffer *mb; - struct spa_meta_shared *msh; struct pw_type *t; this = SPA_CONTAINER_OF(node, struct proxy, node); @@ -586,35 +585,53 @@ spa_proxy_node_port_use_buffers(struct spa_node *node, n_mem = 0; for (i = 0; i < n_buffers; i++) { struct buffer *b = &port->buffers[i]; - - msh = spa_buffer_find_meta(buffers[i], t->meta.Shared); - if (msh == NULL) { - spa_log_error(this->log, "missing shared metadata on buffer %d", i); - return -EINVAL; - } + struct pw_memblock *m; + size_t data_size; + void *baseptr; b->outbuf = buffers[i]; memcpy(&b->buffer, buffers[i], sizeof(struct spa_buffer)); b->buffer.datas = b->datas; b->buffer.metas = b->metas; + if (buffers[i]->n_metas > 0) + baseptr = buffers[i]->metas[0].data; + else if (buffers[i]->n_datas > 0) + baseptr = buffers[i]->datas[0].chunk; + else + return -EINVAL; + + if ((m = pw_memblock_find(baseptr)) == NULL) + return -EINVAL; + + data_size = 0; + for (j = 0; j < buffers[i]->n_metas; j++) { + data_size += buffers[i]->metas[j].size; + } + for (j = 0; j < buffers[i]->n_datas; j++) { + struct spa_data *d = buffers[i]->datas; + data_size += sizeof(struct spa_chunk); + if (d->type == t->data.MemPtr) + data_size += d->maxsize; + } + mb[i].buffer = &b->buffer; mb[i].mem_id = n_mem++; mb[i].offset = 0; - mb[i].size = msh->size; + mb[i].size = data_size; pw_client_node_resource_port_add_mem(this->resource, direction, port_id, mb[i].mem_id, t->data.MemFd, - msh->fd, msh->flags, msh->offset, msh->size); + m->fd, m->flags, + SPA_PTRDIFF(baseptr, m->ptr + m->offset), + data_size); - for (j = 0, k = 0; j < buffers[i]->n_metas; j++) { - if (buffers[i]->metas[j].type != t->meta.Shared) - memcpy(&b->buffer.metas[k++], &buffers[i]->metas[j], sizeof(struct spa_meta)); - } - b->buffer.n_metas = k; + for (j = 0; j < buffers[i]->n_metas; j++) + memcpy(&b->buffer.metas[j], &buffers[i]->metas[j], sizeof(struct spa_meta)); + b->buffer.n_metas = j; for (j = 0; j < buffers[i]->n_datas; j++) { struct spa_data *d = &buffers[i]->datas[j]; diff --git a/src/modules/module-client-node/transport.c b/src/modules/module-client-node/transport.c index 27c2cf1c..21add9bd 100644 --- a/src/modules/module-client-node/transport.c +++ b/src/modules/module-client-node/transport.c @@ -36,7 +36,7 @@ struct transport { struct pw_client_node_transport trans; - struct pw_memblock mem; + struct pw_memblock *mem; size_t offset; struct pw_client_node_message current; @@ -106,7 +106,7 @@ static void destroy(struct pw_client_node_transport *trans) pw_log_debug("transport %p: destroy", trans); - pw_memblock_free(&impl->mem); + pw_memblock_free(impl->mem); free(impl); } @@ -184,7 +184,7 @@ pw_client_node_transport_new(uint32_t max_input_ports, uint32_t max_output_ports { struct transport *impl; struct pw_client_node_transport *trans; - struct pw_client_node_area area; + struct pw_client_node_area area = { 0 }; area.max_input_ports = max_input_ports; area.n_input_ports = 0; @@ -198,12 +198,14 @@ pw_client_node_transport_new(uint32_t max_input_ports, uint32_t max_output_ports trans = &impl->trans; impl->offset = 0; - pw_memblock_alloc(PW_MEMBLOCK_FLAG_WITH_FD | + if (pw_memblock_alloc(PW_MEMBLOCK_FLAG_WITH_FD | PW_MEMBLOCK_FLAG_MAP_READWRITE | - PW_MEMBLOCK_FLAG_SEAL, area_get_size(&area), &impl->mem); + PW_MEMBLOCK_FLAG_SEAL, area_get_size(&area), + &impl->mem) < 0) + return NULL; - memcpy(impl->mem.ptr, &area, sizeof(struct pw_client_node_area)); - transport_setup_area(impl->mem.ptr, trans); + memcpy(impl->mem->ptr, &area, sizeof(struct pw_client_node_area)); + transport_setup_area(impl->mem->ptr, trans); transport_reset_area(trans); trans->destroy = destroy; @@ -220,6 +222,7 @@ pw_client_node_transport_new_from_info(struct pw_client_node_transport_info *inf struct transport *impl; struct pw_client_node_transport *trans; void *tmp; + int res; impl = calloc(1, sizeof(struct transport)); if (impl == NULL) @@ -227,19 +230,19 @@ pw_client_node_transport_new_from_info(struct pw_client_node_transport_info *inf trans = &impl->trans; - impl->mem.flags = PW_MEMBLOCK_FLAG_MAP_READWRITE | PW_MEMBLOCK_FLAG_WITH_FD; - impl->mem.fd = info->memfd; - impl->mem.offset = info->offset; - impl->mem.size = info->size; - if (pw_memblock_map(&impl->mem) < 0) { + if ((res = pw_memblock_import(PW_MEMBLOCK_FLAG_MAP_READWRITE | + PW_MEMBLOCK_FLAG_WITH_FD, + info->memfd, + info->offset, + info->size, &impl->mem)) < 0) { pw_log_warn("transport %p: failed to map fd %d: %s", impl, info->memfd, - strerror(errno)); + spa_strerror(res)); goto mmap_failed; } impl->offset = info->offset; - transport_setup_area(impl->mem.ptr, trans); + transport_setup_area(impl->mem->ptr, trans); tmp = trans->output_buffer; trans->output_buffer = trans->input_buffer; @@ -258,6 +261,7 @@ pw_client_node_transport_new_from_info(struct pw_client_node_transport_info *inf mmap_failed: free(impl); + errno = -res; return NULL; } @@ -276,9 +280,9 @@ int pw_client_node_transport_get_info(struct pw_client_node_transport *trans, { struct transport *impl = (struct transport *) trans; - info->memfd = impl->mem.fd; + info->memfd = impl->mem->fd; info->offset = impl->offset; - info->size = impl->mem.size; + info->size = impl->mem->size; return 0; } diff --git a/src/pipewire/link.c b/src/pipewire/link.c index 0843089a..a3cf1b30 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -269,20 +269,10 @@ static struct spa_pod *find_param(struct spa_pod **params, int n_params, uint32_ * +|-| struct spa_data *datas | pointer to array of datas * || +------------------------------+ * |+>| struct spa_meta | - * | | uint32_t type | Shared meta type, first one always shared - * |+-| void *data | pointer to inlined shared metadata - * || | uint32_t size | sizeof(struct spa_meta_shared) - * || | struct spa_meta | - * || | uint32_t type | more metadata - * +||-| void *data | pointer to mmaped metadata in shared memory - * ||| | uint32_t size | size of metadata - * ||| | ... <n_metas> | more metas follow - * ||| +------------------------------+ - * ||+>| struct spa_meta_shared | inlined shared metadata - * || | uint32_t flags | - * || | int fd | fd of the shared memory block - * || | uint32_t offset | offset of meta/chunk/data for this buffer - * || | uint32_t size | size of meta/chunk/data for this buffer + * | | uint32_t type | metadata + * +|--| void *data | pointer to mmaped metadata in shared memory + * || | uint32_t size | size of metadata + * || | ... <n_metas> | more metas follow * || +------------------------------+ * |+->| struct spa_data | * | | uint32_t type | memory type, either MemFd or INVALID @@ -326,7 +316,7 @@ static struct spa_buffer **alloc_buffers(struct pw_link *this, uint32_t n_datas, size_t *data_sizes, ssize_t *data_strides, - struct pw_memblock *mem) + struct pw_memblock **mem) { struct spa_buffer **buffers, *bp; uint32_t i; @@ -335,22 +325,13 @@ static struct spa_buffer **alloc_buffers(struct pw_link *this, void *ddp; uint32_t n_metas; struct spa_meta *metas; + struct pw_memblock *m; n_metas = data_size = meta_size = 0; - /* each buffer has 1 meta shared */ skel_size = sizeof(struct spa_buffer); - skel_size += sizeof(struct spa_meta); - skel_size += sizeof(struct spa_meta_shared); - metas = alloca(sizeof(struct spa_meta) * (n_params + 1)); - - /* add shared metadata this should not go into shared - * memory or else a client can damage it so we inline it after - * the array of spa_meta. */ - metas[n_metas].type = this->core->type.meta.Shared; - metas[n_metas].size = sizeof(struct spa_meta_shared); - n_metas++; + metas = alloca(sizeof(struct spa_meta) * n_params); /* collect metadata */ for (i = 0; i < n_params; i++) { @@ -386,40 +367,27 @@ static struct spa_buffer **alloc_buffers(struct pw_link *this, pw_memblock_alloc(PW_MEMBLOCK_FLAG_WITH_FD | PW_MEMBLOCK_FLAG_MAP_READWRITE | - PW_MEMBLOCK_FLAG_SEAL, n_buffers * data_size, mem); + PW_MEMBLOCK_FLAG_SEAL, n_buffers * data_size, &m); for (i = 0; i < n_buffers; i++) { int j; struct spa_buffer *b; - struct spa_meta_shared *msh; void *p; buffers[i] = b = SPA_MEMBER(bp, skel_size * i, struct spa_buffer); - p = SPA_MEMBER(mem->ptr, data_size * i, void); - - msh = SPA_MEMBER(b, sizeof(struct spa_buffer), struct spa_meta_shared); - msh->flags = 0; - msh->fd = mem->fd; - msh->offset = data_size * i; - msh->size = data_size; + p = SPA_MEMBER(m->ptr, data_size * i, void); b->id = i; b->n_metas = n_metas; - b->metas = SPA_MEMBER(msh, sizeof(struct spa_meta_shared), struct spa_meta); + b->metas = SPA_MEMBER(b, sizeof(struct spa_buffer), struct spa_meta); for (j = 0; j < n_metas; j++) { struct spa_meta *m = &b->metas[j]; m->type = metas[j].type; m->size = metas[j].size; - - if (m->type == this->core->type.meta.Shared) { - m->data = msh; - } - else { - m->data = p; - p += m->size; - } + m->data = p; + p += m->size; } /* pointer to data structure */ b->n_datas = n_datas; @@ -435,10 +403,10 @@ static struct spa_buffer **alloc_buffers(struct pw_link *this, if (data_sizes[j] > 0) { d->type = this->core->type.data.MemFd; d->flags = 0; - d->fd = mem->fd; - d->mapoffset = SPA_PTRDIFF(ddp, mem->ptr); + d->fd = m->fd; + d->mapoffset = SPA_PTRDIFF(ddp, m->ptr); d->maxsize = data_sizes[j]; - d->data = SPA_MEMBER(mem->ptr, d->mapoffset, void); + d->data = SPA_MEMBER(m->ptr, d->mapoffset, void); d->chunk->offset = 0; d->chunk->size = 0; d->chunk->stride = data_strides[j]; @@ -450,6 +418,7 @@ static struct spa_buffer **alloc_buffers(struct pw_link *this, } } } + *mem = m; return buffers; } @@ -1298,7 +1267,7 @@ void pw_link_destroy(struct pw_link *link) if (link->buffer_owner == link) { free(link->buffers); - pw_memblock_free(&link->buffer_mem); + pw_memblock_free(link->buffer_mem); } free(impl); } diff --git a/src/pipewire/mem.c b/src/pipewire/mem.c index 4e17c3a0..a6412d1a 100644 --- a/src/pipewire/mem.c +++ b/src/pipewire/mem.c @@ -33,6 +33,10 @@ #include <stdlib.h> #include <sys/syscall.h> +#include <spa/utils/list.h> + +#include <pipewire/map.h> +#include <pipewire/array.h> #include <pipewire/log.h> #include <pipewire/mem.h> @@ -77,6 +81,12 @@ static inline int memfd_create(const char *name, unsigned int flags) #define F_SEAL_WRITE 0x0008 /* prevent writes */ #endif +struct memblock { + struct pw_memblock mem; + struct spa_list link; +}; + +static struct spa_list _memblocks = SPA_LIST_INIT(&_memblocks); #define USE_MEMFD @@ -140,75 +150,106 @@ int pw_memblock_map(struct pw_memblock *mem) * \return 0 on success, < 0 on error * \memberof pw_memblock */ -int pw_memblock_alloc(enum pw_memblock_flags flags, size_t size, struct pw_memblock *mem) +int pw_memblock_alloc(enum pw_memblock_flags flags, size_t size, struct pw_memblock **mem) { + struct memblock tmp, *p; + struct pw_memblock *m; bool use_fd; - if (mem == NULL || size == 0) + if (mem == NULL) return -EINVAL; - mem->offset = 0; - mem->flags = flags; - mem->size = size; - mem->ptr = NULL; + m = &tmp.mem; + m->offset = 0; + m->flags = flags; + m->size = size; + m->ptr = NULL; use_fd = ! !(flags & (PW_MEMBLOCK_FLAG_MAP_TWICE | PW_MEMBLOCK_FLAG_WITH_FD)); if (use_fd) { #ifdef USE_MEMFD - mem->fd = memfd_create("pipewire-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING); - if (mem->fd == -1) { + m->fd = memfd_create("pipewire-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING); + if (m->fd == -1) { pw_log_error("Failed to create memfd: %s\n", strerror(errno)); return -errno; } #else char filename[] = "/dev/shm/pipewire-tmpfile.XXXXXX"; - mem->fd = mkostemp(filename, O_CLOEXEC); - if (mem->fd == -1) { + m->fd = mkostemp(filename, O_CLOEXEC); + if (m->fd == -1) { pw_log_error("Failed to create temporary file: %s\n", strerror(errno)); return -errno; } unlink(filename); #endif - if (ftruncate(mem->fd, size) < 0) { + if (ftruncate(m->fd, size) < 0) { pw_log_warn("Failed to truncate temporary file: %s", strerror(errno)); - close(mem->fd); + close(m->fd); return -errno; } #ifdef USE_MEMFD if (flags & PW_MEMBLOCK_FLAG_SEAL) { unsigned int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL; - if (fcntl(mem->fd, F_ADD_SEALS, seals) == -1) { + if (fcntl(m->fd, F_ADD_SEALS, seals) == -1) { pw_log_warn("Failed to add seals: %s", strerror(errno)); } } #endif - if (pw_memblock_map(mem) != 0) + if (pw_memblock_map(m) != 0) goto mmap_failed; } else { - mem->ptr = malloc(size); - if (mem->ptr == NULL) - return -ENOMEM; - mem->fd = -1; + if (size > 0) { + m->ptr = malloc(size); + if (m->ptr == NULL) + return -ENOMEM; + } + m->fd = -1; } - if (!(flags & PW_MEMBLOCK_FLAG_WITH_FD) && mem->fd != -1) { - close(mem->fd); - mem->fd = -1; + if (!(flags & PW_MEMBLOCK_FLAG_WITH_FD) && m->fd != -1) { + close(m->fd); + m->fd = -1; } + + p = calloc(1, sizeof(struct memblock)); + *p = tmp; + spa_list_prepend(&_memblocks, &p->link); + *mem = &p->mem; + return 0; mmap_failed: - close(mem->fd); + close(m->fd); return -ENOMEM; } +int +pw_memblock_import(enum pw_memblock_flags flags, + int fd, off_t offset, size_t size, + struct pw_memblock **mem) +{ + int res; + + if ((res = pw_memblock_alloc(0, 0, mem)) < 0) + return res; + + (*mem)->flags = flags; + (*mem)->fd = fd; + (*mem)->offset = offset; + (*mem)->size = size; + + return pw_memblock_map(*mem); +} + /** Free a memblock * \param mem a memblock * \memberof pw_memblock */ void pw_memblock_free(struct pw_memblock *mem) { + struct memblock *m = (struct memblock *)mem; + if (mem == NULL) return; @@ -220,6 +261,17 @@ void pw_memblock_free(struct pw_memblock *mem) } else { free(mem->ptr); } - mem->ptr = NULL; - mem->fd = -1; + spa_list_remove(&m->link); + free(mem); +} + +struct pw_memblock * pw_memblock_find(const void *ptr) +{ + struct memblock *m; + + spa_list_for_each(m, &_memblocks, link) { + if (ptr >= m->mem.ptr && ptr < m->mem.ptr + m->mem.size) + return &m->mem; + } + return NULL; } diff --git a/src/pipewire/mem.h b/src/pipewire/mem.h index cf281071..079fbc5f 100644 --- a/src/pipewire/mem.h +++ b/src/pipewire/mem.h @@ -49,7 +49,12 @@ struct pw_memblock { }; int -pw_memblock_alloc(enum pw_memblock_flags flags, size_t size, struct pw_memblock *mem); +pw_memblock_alloc(enum pw_memblock_flags flags, size_t size, struct pw_memblock **mem); + +int +pw_memblock_import(enum pw_memblock_flags flags, + int fd, off_t offset, size_t size, + struct pw_memblock **mem); int pw_memblock_map(struct pw_memblock *mem); @@ -57,6 +62,9 @@ pw_memblock_map(struct pw_memblock *mem); void pw_memblock_free(struct pw_memblock *mem); +/** Find memblock for given \a ptr */ +struct pw_memblock * pw_memblock_find(const void *ptr); + #ifdef __cplusplus } #endif diff --git a/src/pipewire/port.c b/src/pipewire/port.c index e675f753..4d7ef490 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -348,7 +348,7 @@ void pw_port_destroy(struct pw_port *port) if (port->allocated) { free(port->buffers); - pw_memblock_free(&port->buffer_mem); + pw_memblock_free(port->buffer_mem); } if (port->properties) @@ -394,7 +394,7 @@ int pw_port_set_param(struct pw_port *port, uint32_t id, uint32_t flags, if (param == NULL || res < 0) { if (port->allocated) { free(port->buffers); - pw_memblock_free(&port->buffer_mem); + pw_memblock_free(port->buffer_mem); } port->buffers = NULL; port->n_buffers = 0; @@ -426,7 +426,7 @@ int pw_port_use_buffers(struct pw_port *port, struct spa_buffer **buffers, uint3 if (port->allocated) { free(port->buffers); - pw_memblock_free(&port->buffer_mem); + pw_memblock_free(port->buffer_mem); } port->buffers = buffers; port->n_buffers = n_buffers; @@ -459,7 +459,7 @@ int pw_port_alloc_buffers(struct pw_port *port, if (port->allocated) { free(port->buffers); - pw_memblock_free(&port->buffer_mem); + pw_memblock_free(port->buffer_mem); } port->buffers = buffers; port->n_buffers = *n_buffers; diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 9e0d6c82..2f5fa74c 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -195,7 +195,7 @@ struct pw_link { struct spa_hook_list listener_list; void *buffer_owner; - struct pw_memblock buffer_mem; + struct pw_memblock *buffer_mem; struct spa_buffer **buffers; uint32_t n_buffers; @@ -273,7 +273,7 @@ struct pw_port { struct spa_io_buffers io; /**< io area of the port */ bool allocated; /**< if buffers are allocated */ - struct pw_memblock buffer_mem; /**< allocated buffer memory */ + struct pw_memblock *buffer_mem; /**< allocated buffer memory */ struct spa_buffer **buffers; /**< port buffers */ uint32_t n_buffers; /**< number of port buffers */ |