mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-06 13:30:01 -05:00
mem: add support for ringbuffers
Add an option to map the memory twice in contigious memory to make it easier to deal with ringbuffers.
This commit is contained in:
parent
edb21a0ff8
commit
ed273ec465
3 changed files with 87 additions and 35 deletions
|
|
@ -75,18 +75,66 @@ static inline int memfd_create(const char *name, unsigned int flags) {
|
||||||
|
|
||||||
#undef USE_MEMFD
|
#undef USE_MEMFD
|
||||||
|
|
||||||
|
SpaResult
|
||||||
|
pinos_memblock_map (PinosMemblock *mem)
|
||||||
|
{
|
||||||
|
if (mem->ptr != NULL)
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
|
||||||
|
if (mem->flags & PINOS_MEMBLOCK_FLAG_MAP_READWRITE) {
|
||||||
|
int prot = 0;
|
||||||
|
|
||||||
|
if (mem->flags & PINOS_MEMBLOCK_FLAG_MAP_READ)
|
||||||
|
prot |= PROT_READ;
|
||||||
|
if (mem->flags & PINOS_MEMBLOCK_FLAG_MAP_WRITE)
|
||||||
|
prot |= PROT_WRITE;
|
||||||
|
|
||||||
|
if (mem->flags & PINOS_MEMBLOCK_FLAG_MAP_TWICE) {
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
mem->ptr = mmap (NULL, mem->size << 1, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||||
|
if (mem->ptr == MAP_FAILED)
|
||||||
|
return SPA_RESULT_NO_MEMORY;
|
||||||
|
|
||||||
|
ptr = mmap (mem->ptr, mem->size, prot, MAP_FIXED | MAP_SHARED, mem->fd, mem->offset);
|
||||||
|
if (ptr != mem->ptr) {
|
||||||
|
munmap (mem->ptr, mem->size << 1);
|
||||||
|
return SPA_RESULT_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = mmap (mem->ptr + mem->size, mem->size, prot, MAP_FIXED | MAP_SHARED, mem->fd, mem->offset);
|
||||||
|
if (ptr != mem->ptr + mem->size) {
|
||||||
|
munmap (mem->ptr, mem->size << 1);
|
||||||
|
return SPA_RESULT_NO_MEMORY;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mem->ptr = mmap (NULL, mem->size, prot, MAP_SHARED, mem->fd, 0);
|
||||||
|
if (mem->ptr == MAP_FAILED)
|
||||||
|
return SPA_RESULT_NO_MEMORY;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mem->ptr = NULL;
|
||||||
|
}
|
||||||
|
return SPA_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
SpaResult
|
SpaResult
|
||||||
pinos_memblock_alloc (PinosMemblockFlags flags,
|
pinos_memblock_alloc (PinosMemblockFlags flags,
|
||||||
size_t size,
|
size_t size,
|
||||||
PinosMemblock *mem)
|
PinosMemblock *mem)
|
||||||
{
|
{
|
||||||
|
bool use_fd;
|
||||||
|
|
||||||
if (mem == NULL || size == 0)
|
if (mem == NULL || size == 0)
|
||||||
return SPA_RESULT_INVALID_ARGUMENTS;
|
return SPA_RESULT_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
mem->offset = 0;
|
||||||
mem->flags = flags;
|
mem->flags = flags;
|
||||||
mem->size = size;
|
mem->size = size;
|
||||||
|
|
||||||
if (flags & PINOS_MEMBLOCK_FLAG_WITH_FD) {
|
use_fd = !!(flags & (PINOS_MEMBLOCK_FLAG_MAP_TWICE | PINOS_MEMBLOCK_FLAG_WITH_FD));
|
||||||
|
|
||||||
|
if (use_fd) {
|
||||||
#ifdef USE_MEMFD
|
#ifdef USE_MEMFD
|
||||||
mem->fd = memfd_create ("pinos-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
mem->fd = memfd_create ("pinos-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
||||||
if (mem->fd == -1) {
|
if (mem->fd == -1) {
|
||||||
|
|
@ -116,27 +164,23 @@ pinos_memblock_alloc (PinosMemblockFlags flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (flags & PINOS_MEMBLOCK_FLAG_MAP_READWRITE) {
|
if (pinos_memblock_map (mem) != SPA_RESULT_OK)
|
||||||
int prot = 0;
|
goto mmap_failed;
|
||||||
|
|
||||||
if (flags & PINOS_MEMBLOCK_FLAG_MAP_READ)
|
|
||||||
prot |= PROT_READ;
|
|
||||||
if (flags & PINOS_MEMBLOCK_FLAG_MAP_WRITE)
|
|
||||||
prot |= PROT_WRITE;
|
|
||||||
|
|
||||||
mem->ptr = mmap (NULL, size, prot, MAP_SHARED, mem->fd, 0);
|
|
||||||
if (mem->ptr == MAP_FAILED)
|
|
||||||
return SPA_RESULT_NO_MEMORY;
|
|
||||||
} else {
|
|
||||||
mem->ptr = NULL;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
mem->ptr = malloc (size);
|
mem->ptr = malloc (size);
|
||||||
if (mem->ptr == NULL)
|
if (mem->ptr == NULL)
|
||||||
return SPA_RESULT_NO_MEMORY;
|
return SPA_RESULT_NO_MEMORY;
|
||||||
mem->fd = -1;
|
mem->fd = -1;
|
||||||
}
|
}
|
||||||
|
if (!(flags & PINOS_MEMBLOCK_FLAG_WITH_FD) && mem->fd != -1) {
|
||||||
|
close (mem->fd);
|
||||||
|
mem->fd = -1;
|
||||||
|
}
|
||||||
return SPA_RESULT_OK;
|
return SPA_RESULT_OK;
|
||||||
|
|
||||||
|
mmap_failed:
|
||||||
|
close (mem->fd);
|
||||||
|
return SPA_RESULT_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,10 @@ typedef struct _PinosMemblock PinosMemblock;
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PINOS_MEMBLOCK_FLAG_NONE = 0,
|
PINOS_MEMBLOCK_FLAG_NONE = 0,
|
||||||
PINOS_MEMBLOCK_FLAG_WITH_FD = (1 << 0),
|
PINOS_MEMBLOCK_FLAG_WITH_FD = (1 << 0),
|
||||||
PINOS_MEMBLOCK_FLAG_MAP_READ = (1 << 1),
|
PINOS_MEMBLOCK_FLAG_SEAL = (1 << 1),
|
||||||
PINOS_MEMBLOCK_FLAG_MAP_WRITE = (1 << 2),
|
PINOS_MEMBLOCK_FLAG_MAP_READ = (1 << 2),
|
||||||
PINOS_MEMBLOCK_FLAG_SEAL = (1 << 3),
|
PINOS_MEMBLOCK_FLAG_MAP_WRITE = (1 << 3),
|
||||||
|
PINOS_MEMBLOCK_FLAG_MAP_TWICE = (1 << 4),
|
||||||
} PinosMemblockFlags;
|
} PinosMemblockFlags;
|
||||||
|
|
||||||
#define PINOS_MEMBLOCK_FLAG_MAP_READWRITE (PINOS_MEMBLOCK_FLAG_MAP_READ | PINOS_MEMBLOCK_FLAG_MAP_WRITE)
|
#define PINOS_MEMBLOCK_FLAG_MAP_READWRITE (PINOS_MEMBLOCK_FLAG_MAP_READ | PINOS_MEMBLOCK_FLAG_MAP_WRITE)
|
||||||
|
|
@ -41,6 +42,7 @@ typedef enum {
|
||||||
struct _PinosMemblock {
|
struct _PinosMemblock {
|
||||||
PinosMemblockFlags flags;
|
PinosMemblockFlags flags;
|
||||||
int fd;
|
int fd;
|
||||||
|
off_t offset;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
size_t size;
|
size_t size;
|
||||||
};
|
};
|
||||||
|
|
@ -48,6 +50,7 @@ struct _PinosMemblock {
|
||||||
SpaResult pinos_memblock_alloc (PinosMemblockFlags flags,
|
SpaResult pinos_memblock_alloc (PinosMemblockFlags flags,
|
||||||
size_t size,
|
size_t size,
|
||||||
PinosMemblock *mem);
|
PinosMemblock *mem);
|
||||||
|
SpaResult pinos_memblock_map (PinosMemblock *mem);
|
||||||
void pinos_memblock_free (PinosMemblock *mem);
|
void pinos_memblock_free (PinosMemblock *mem);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,9 @@ transport_area_get_size (PinosTransportArea *area)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
transport_setup_area (void *p, PinosTransport *trans, bool reset)
|
transport_setup_area (void *p, PinosTransport *trans)
|
||||||
{
|
{
|
||||||
PinosTransportArea *a;
|
PinosTransportArea *a;
|
||||||
int i;
|
|
||||||
|
|
||||||
trans->area = a = p;
|
trans->area = a = p;
|
||||||
p = SPA_MEMBER (p, sizeof (PinosTransportArea), SpaPortIO);
|
p = SPA_MEMBER (p, sizeof (PinosTransportArea), SpaPortIO);
|
||||||
|
|
@ -82,8 +81,14 @@ transport_setup_area (void *p, PinosTransport *trans, bool reset)
|
||||||
|
|
||||||
trans->output_data = p;
|
trans->output_data = p;
|
||||||
p = SPA_MEMBER (p, OUTPUT_BUFFER_SIZE, void);
|
p = SPA_MEMBER (p, OUTPUT_BUFFER_SIZE, void);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
transport_reset_area (PinosTransport *trans)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
PinosTransportArea *a = trans->area;
|
||||||
|
|
||||||
if (reset) {
|
|
||||||
for (i = 0; i < a->max_inputs; i++) {
|
for (i = 0; i < a->max_inputs; i++) {
|
||||||
trans->inputs[i].status = SPA_RESULT_OK;
|
trans->inputs[i].status = SPA_RESULT_OK;
|
||||||
trans->inputs[i].buffer_id = SPA_ID_INVALID;
|
trans->inputs[i].buffer_id = SPA_ID_INVALID;
|
||||||
|
|
@ -94,7 +99,6 @@ transport_setup_area (void *p, PinosTransport *trans, bool reset)
|
||||||
}
|
}
|
||||||
spa_ringbuffer_init (trans->input_buffer, INPUT_BUFFER_SIZE);
|
spa_ringbuffer_init (trans->input_buffer, INPUT_BUFFER_SIZE);
|
||||||
spa_ringbuffer_init (trans->output_buffer, OUTPUT_BUFFER_SIZE);
|
spa_ringbuffer_init (trans->output_buffer, OUTPUT_BUFFER_SIZE);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PinosTransport *
|
PinosTransport *
|
||||||
|
|
@ -126,7 +130,8 @@ pinos_transport_new (uint32_t max_inputs,
|
||||||
&impl->mem);
|
&impl->mem);
|
||||||
|
|
||||||
memcpy (impl->mem.ptr, &area, sizeof (PinosTransportArea));
|
memcpy (impl->mem.ptr, &area, sizeof (PinosTransportArea));
|
||||||
transport_setup_area (impl->mem.ptr, trans, true);
|
transport_setup_area (impl->mem.ptr, trans);
|
||||||
|
transport_reset_area (trans);
|
||||||
|
|
||||||
return trans;
|
return trans;
|
||||||
}
|
}
|
||||||
|
|
@ -148,16 +153,16 @@ pinos_transport_new_from_info (PinosTransportInfo *info)
|
||||||
impl->mem.flags = PINOS_MEMBLOCK_FLAG_MAP_READWRITE |
|
impl->mem.flags = PINOS_MEMBLOCK_FLAG_MAP_READWRITE |
|
||||||
PINOS_MEMBLOCK_FLAG_WITH_FD;
|
PINOS_MEMBLOCK_FLAG_WITH_FD;
|
||||||
impl->mem.fd = info->memfd;
|
impl->mem.fd = info->memfd;
|
||||||
|
impl->mem.offset = info->offset;
|
||||||
impl->mem.size = info->size;
|
impl->mem.size = info->size;
|
||||||
impl->mem.ptr = mmap (NULL, info->size, PROT_READ | PROT_WRITE, MAP_SHARED, info->memfd, info->offset);
|
if (pinos_memblock_map (&impl->mem) != SPA_RESULT_OK) {
|
||||||
if (impl->mem.ptr == MAP_FAILED) {
|
|
||||||
pinos_log_warn ("transport %p: failed to map fd %d: %s", impl, info->memfd, strerror (errno));
|
pinos_log_warn ("transport %p: failed to map fd %d: %s", impl, info->memfd, strerror (errno));
|
||||||
goto mmap_failed;
|
goto mmap_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl->offset = info->offset;
|
impl->offset = info->offset;
|
||||||
|
|
||||||
transport_setup_area (impl->mem.ptr, trans, false);
|
transport_setup_area (impl->mem.ptr, trans);
|
||||||
|
|
||||||
tmp = trans->output_buffer;
|
tmp = trans->output_buffer;
|
||||||
trans->output_buffer = trans->input_buffer;
|
trans->output_buffer = trans->input_buffer;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue