diff --git a/utils.c b/utils.c index 91dd71e..e59002e 100644 --- a/utils.c +++ b/utils.c @@ -16,10 +16,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "utils.h" +#include #include #include #include +#include "utils.h" #define foreach_arg(_arg, _addr, _len, _first_addr, _first_len) \ for (_addr = (_first_addr), _len = (_first_len); \ @@ -103,3 +104,48 @@ out: } #endif + +void *cbuf_alloc(unsigned int order) +{ + char path[] = "/tmp/cbuf-XXXXXX"; + unsigned long size = cbuf_size(order); + void *ret = NULL; + int fd; + + fd = mkstemp(path); + if (fd < 0) + return NULL; + + if (unlink(path)) + goto close; + + if (ftruncate(fd, cbuf_size(order))) + goto close; + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + + ret = mmap(NULL, size * 2, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (ret == MAP_FAILED) { + ret = NULL; + goto close; + } + + if (mmap(ret, size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, + fd, 0) != ret || + mmap(ret + size, size, PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_SHARED, fd, 0) != ret + size) { + munmap(ret, size * 2); + ret = NULL; + } + +close: + close(fd); + return ret; +} + +void cbuf_free(void *ptr, unsigned int order) +{ + munmap(ptr, cbuf_size(order) * 2); +} diff --git a/utils.h b/utils.h index d00e76b..803150b 100644 --- a/utils.h +++ b/utils.h @@ -23,6 +23,7 @@ #include #include #include +#include #include /* @@ -192,4 +193,23 @@ int b64_decode(const void *src, void *dest, size_t dest_len); #define B64_ENCODE_LEN(_len) ((((_len) + 2) / 3) * 4 + 1) #define B64_DECODE_LEN(_len) (((_len) / 4) * 3 + 1) +static inline unsigned int cbuf_order(unsigned int x) +{ + return 32 - __builtin_clz(x - 1); +} + +static inline unsigned long cbuf_size(int order) +{ + unsigned long page_size = sysconf(_SC_PAGESIZE); + unsigned long ret = 1ULL << order; + + if (ret < page_size) + ret = page_size; + + return ret; +} + +void *cbuf_alloc(unsigned int order); +void cbuf_free(void *ptr, unsigned int order); + #endif