From ed273ec465ea8ee51a4a044c12b15a0f0b56f4a6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 26 Apr 2017 10:56:00 +0200 Subject: [PATCH] mem: add support for ringbuffers Add an option to map the memory twice in contigious memory to make it easier to deal with ringbuffers. --- pinos/client/mem.c | 74 ++++++++++++++++++++++++++++++++-------- pinos/client/mem.h | 9 +++-- pinos/client/transport.c | 39 ++++++++++++--------- 3 files changed, 87 insertions(+), 35 deletions(-) diff --git a/pinos/client/mem.c b/pinos/client/mem.c index f1dbe8425..b84edf728 100644 --- a/pinos/client/mem.c +++ b/pinos/client/mem.c @@ -75,18 +75,66 @@ static inline int memfd_create(const char *name, unsigned int flags) { #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 pinos_memblock_alloc (PinosMemblockFlags flags, size_t size, PinosMemblock *mem) { + bool use_fd; + if (mem == NULL || size == 0) return SPA_RESULT_INVALID_ARGUMENTS; + mem->offset = 0; mem->flags = flags; 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 mem->fd = memfd_create ("pinos-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING); if (mem->fd == -1) { @@ -116,27 +164,23 @@ pinos_memblock_alloc (PinosMemblockFlags flags, } } #endif - if (flags & PINOS_MEMBLOCK_FLAG_MAP_READWRITE) { - int prot = 0; - - 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; - } + if (pinos_memblock_map (mem) != SPA_RESULT_OK) + goto mmap_failed; } else { mem->ptr = malloc (size); if (mem->ptr == NULL) return SPA_RESULT_NO_MEMORY; mem->fd = -1; } + if (!(flags & PINOS_MEMBLOCK_FLAG_WITH_FD) && mem->fd != -1) { + close (mem->fd); + mem->fd = -1; + } return SPA_RESULT_OK; + +mmap_failed: + close (mem->fd); + return SPA_RESULT_NO_MEMORY; } void diff --git a/pinos/client/mem.h b/pinos/client/mem.h index 431e7bc29..88032dc13 100644 --- a/pinos/client/mem.h +++ b/pinos/client/mem.h @@ -31,9 +31,10 @@ typedef struct _PinosMemblock PinosMemblock; typedef enum { PINOS_MEMBLOCK_FLAG_NONE = 0, PINOS_MEMBLOCK_FLAG_WITH_FD = (1 << 0), - PINOS_MEMBLOCK_FLAG_MAP_READ = (1 << 1), - PINOS_MEMBLOCK_FLAG_MAP_WRITE = (1 << 2), - PINOS_MEMBLOCK_FLAG_SEAL = (1 << 3), + PINOS_MEMBLOCK_FLAG_SEAL = (1 << 1), + PINOS_MEMBLOCK_FLAG_MAP_READ = (1 << 2), + PINOS_MEMBLOCK_FLAG_MAP_WRITE = (1 << 3), + PINOS_MEMBLOCK_FLAG_MAP_TWICE = (1 << 4), } PinosMemblockFlags; #define PINOS_MEMBLOCK_FLAG_MAP_READWRITE (PINOS_MEMBLOCK_FLAG_MAP_READ | PINOS_MEMBLOCK_FLAG_MAP_WRITE) @@ -41,6 +42,7 @@ typedef enum { struct _PinosMemblock { PinosMemblockFlags flags; int fd; + off_t offset; void *ptr; size_t size; }; @@ -48,6 +50,7 @@ struct _PinosMemblock { SpaResult pinos_memblock_alloc (PinosMemblockFlags flags, size_t size, PinosMemblock *mem); +SpaResult pinos_memblock_map (PinosMemblock *mem); void pinos_memblock_free (PinosMemblock *mem); #ifdef __cplusplus diff --git a/pinos/client/transport.c b/pinos/client/transport.c index b118357bd..e143e0db9 100644 --- a/pinos/client/transport.c +++ b/pinos/client/transport.c @@ -57,10 +57,9 @@ transport_area_get_size (PinosTransportArea *area) } static void -transport_setup_area (void *p, PinosTransport *trans, bool reset) +transport_setup_area (void *p, PinosTransport *trans) { PinosTransportArea *a; - int i; trans->area = a = p; p = SPA_MEMBER (p, sizeof (PinosTransportArea), SpaPortIO); @@ -82,19 +81,24 @@ transport_setup_area (void *p, PinosTransport *trans, bool reset) trans->output_data = p; p = SPA_MEMBER (p, OUTPUT_BUFFER_SIZE, void); +} - if (reset) { - for (i = 0; i < a->max_inputs; i++) { - trans->inputs[i].status = SPA_RESULT_OK; - trans->inputs[i].buffer_id = SPA_ID_INVALID; - } - 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); +static void +transport_reset_area (PinosTransport *trans) +{ + int i; + PinosTransportArea *a = trans->area; + + for (i = 0; i < a->max_inputs; i++) { + trans->inputs[i].status = SPA_RESULT_OK; + trans->inputs[i].buffer_id = SPA_ID_INVALID; } + 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 * @@ -126,7 +130,8 @@ pinos_transport_new (uint32_t max_inputs, &impl->mem); 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; } @@ -148,16 +153,16 @@ pinos_transport_new_from_info (PinosTransportInfo *info) impl->mem.flags = PINOS_MEMBLOCK_FLAG_MAP_READWRITE | PINOS_MEMBLOCK_FLAG_WITH_FD; impl->mem.fd = info->memfd; + impl->mem.offset = info->offset; impl->mem.size = info->size; - impl->mem.ptr = mmap (NULL, info->size, PROT_READ | PROT_WRITE, MAP_SHARED, info->memfd, info->offset); - if (impl->mem.ptr == MAP_FAILED) { + if (pinos_memblock_map (&impl->mem) != SPA_RESULT_OK) { pinos_log_warn ("transport %p: failed to map fd %d: %s", impl, info->memfd, strerror (errno)); goto mmap_failed; } impl->offset = info->offset; - transport_setup_area (impl->mem.ptr, trans, false); + transport_setup_area (impl->mem.ptr, trans); tmp = trans->output_buffer; trans->output_buffer = trans->input_buffer;