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:
Wim Taymans 2017-04-26 10:56:00 +02:00
parent edb21a0ff8
commit ed273ec465
3 changed files with 87 additions and 35 deletions

View file

@ -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

View file

@ -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

View file

@ -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,19 +81,24 @@ 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);
}
if (reset) { static void
for (i = 0; i < a->max_inputs; i++) { transport_reset_area (PinosTransport *trans)
trans->inputs[i].status = SPA_RESULT_OK; {
trans->inputs[i].buffer_id = SPA_ID_INVALID; int i;
} PinosTransportArea *a = trans->area;
for (i = 0; i < a->max_outputs; i++) {
trans->outputs[i].status = SPA_RESULT_OK; for (i = 0; i < a->max_inputs; i++) {
trans->outputs[i].buffer_id = SPA_ID_INVALID; trans->inputs[i].status = SPA_RESULT_OK;
} trans->inputs[i].buffer_id = SPA_ID_INVALID;
spa_ringbuffer_init (trans->input_buffer, INPUT_BUFFER_SIZE);
spa_ringbuffer_init (trans->output_buffer, OUTPUT_BUFFER_SIZE);
} }
for (i = 0; i < a->max_outputs; i++) {
trans->outputs[i].status = SPA_RESULT_OK;
trans->outputs[i].buffer_id = SPA_ID_INVALID;
}
spa_ringbuffer_init (trans->input_buffer, INPUT_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;