kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

pool.c (4685B)



      1 /*
      2  * Copyright (c) 2013-2022 Joris Vink <joris@coders.se>
      3  *
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #include <sys/types.h>
     18 #include <sys/mman.h>
     19 #include <sys/queue.h>
     20 
     21 #include <stdint.h>
     22 
     23 #include "kore.h"
     24 
     25 #define POOL_MIN_ELEMENTS		16
     26 
     27 #define POOL_ELEMENT_BUSY		0
     28 #define POOL_ELEMENT_FREE		1
     29 
     30 #if defined(KORE_USE_TASKS)
     31 static void		pool_lock(struct kore_pool *);
     32 static void		pool_unlock(struct kore_pool *);
     33 #endif
     34 
     35 static void		pool_region_create(struct kore_pool *, size_t);
     36 static void		pool_region_destroy(struct kore_pool *);
     37 
     38 void
     39 kore_pool_init(struct kore_pool *pool, const char *name,
     40     size_t len, size_t elm)
     41 {
     42 	if (elm < POOL_MIN_ELEMENTS)
     43 		elm = POOL_MIN_ELEMENTS;
     44 
     45 	if ((pool->name = strdup(name)) == NULL)
     46 		fatal("kore_pool_init: strdup %s", errno_s);
     47 
     48 	len = (len + (8 - 1)) & ~(8 - 1);
     49 
     50 	pool->lock = 0;
     51 	pool->elms = 0;
     52 	pool->inuse = 0;
     53 	pool->elen = len;
     54 	pool->growth = elm * 0.25f;
     55 	pool->slen = pool->elen + sizeof(struct kore_pool_entry);
     56 
     57 	LIST_INIT(&(pool->regions));
     58 	LIST_INIT(&(pool->freelist));
     59 
     60 	pool_region_create(pool, elm);
     61 }
     62 
     63 void
     64 kore_pool_cleanup(struct kore_pool *pool)
     65 {
     66 	pool->lock = 0;
     67 	pool->elms = 0;
     68 	pool->inuse = 0;
     69 	pool->elen = 0;
     70 	pool->slen = 0;
     71 
     72 	free(pool->name);
     73 	pool->name = NULL;
     74 
     75 	pool_region_destroy(pool);
     76 }
     77 
     78 void *
     79 kore_pool_get(struct kore_pool *pool)
     80 {
     81 	u_int8_t			*ptr;
     82 	struct kore_pool_entry		*entry;
     83 
     84 #if defined(KORE_USE_TASKS)
     85 	pool_lock(pool);
     86 #endif
     87 
     88 	if (LIST_EMPTY(&(pool->freelist)))
     89 		pool_region_create(pool, pool->growth);
     90 
     91 	entry = LIST_FIRST(&(pool->freelist));
     92 	if (entry->state != POOL_ELEMENT_FREE)
     93 		fatal("%s: element %p was not free", pool->name, (void *)entry);
     94 	LIST_REMOVE(entry, list);
     95 
     96 	entry->state = POOL_ELEMENT_BUSY;
     97 	ptr = (u_int8_t *)entry + sizeof(struct kore_pool_entry);
     98 
     99 	pool->inuse++;
    100 
    101 #if defined(KORE_USE_TASKS)
    102 	pool_unlock(pool);
    103 #endif
    104 
    105 	return (ptr);
    106 }
    107 
    108 void
    109 kore_pool_put(struct kore_pool *pool, void *ptr)
    110 {
    111 	struct kore_pool_entry		*entry;
    112 
    113 #if defined(KORE_USE_TASKS)
    114 	pool_lock(pool);
    115 #endif
    116 
    117 	entry = (struct kore_pool_entry *)
    118 	    ((u_int8_t *)ptr - sizeof(struct kore_pool_entry));
    119 
    120 	if (entry->state != POOL_ELEMENT_BUSY)
    121 		fatal("%s: element %p was not busy", pool->name, ptr);
    122 
    123 	entry->state = POOL_ELEMENT_FREE;
    124 	LIST_INSERT_HEAD(&(pool->freelist), entry, list);
    125 
    126 	pool->inuse--;
    127 
    128 #if defined(KORE_USE_TASKS)
    129 	pool_unlock(pool);
    130 #endif
    131 }
    132 
    133 static void
    134 pool_region_create(struct kore_pool *pool, size_t elms)
    135 {
    136 	size_t				i;
    137 	u_int8_t			*p;
    138 	struct kore_pool_region		*reg;
    139 	struct kore_pool_entry		*entry;
    140 
    141 	if ((reg = calloc(1, sizeof(struct kore_pool_region))) == NULL)
    142 		fatal("pool_region_create: calloc: %s", errno_s);
    143 
    144 	LIST_INSERT_HEAD(&(pool->regions), reg, list);
    145 
    146 	if (SIZE_MAX / elms < pool->slen)
    147 		fatal("pool_region_create: overflow");
    148 
    149 	reg->length = elms * pool->slen;
    150 	reg->start = mmap(NULL, reg->length, PROT_READ | PROT_WRITE,
    151 	    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
    152 	if (reg->start == MAP_FAILED)
    153 		fatal("mmap: %s", errno_s);
    154 
    155 	p = (u_int8_t *)reg->start;
    156 
    157 	for (i = 0; i < elms; i++) {
    158 		entry = (struct kore_pool_entry *)p;
    159 		entry->region = reg;
    160 		entry->state = POOL_ELEMENT_FREE;
    161 		LIST_INSERT_HEAD(&(pool->freelist), entry, list);
    162 
    163 		p = p + pool->slen;
    164 	}
    165 
    166 	pool->elms += elms;
    167 }
    168 
    169 static void
    170 pool_region_destroy(struct kore_pool *pool)
    171 {
    172 	struct kore_pool_region		*reg;
    173 
    174 	/* Take care iterating when modifying list contents */
    175 	while (!LIST_EMPTY(&pool->regions)) {
    176 		reg = LIST_FIRST(&pool->regions);
    177 		LIST_REMOVE(reg, list);
    178 		(void)munmap(reg->start, reg->length);
    179 		free(reg);
    180 	}
    181 
    182 	/* Freelist references into the regions memory allocations */
    183 	LIST_INIT(&pool->freelist);
    184 	pool->elms = 0;
    185 }
    186 
    187 #if defined(KORE_USE_TASKS)
    188 static void
    189 pool_lock(struct kore_pool *pool)
    190 {
    191 	for (;;) {
    192 		if (__sync_bool_compare_and_swap(&pool->lock, 0, 1))
    193 			break;
    194 	}
    195 }
    196 
    197 static void
    198 pool_unlock(struct kore_pool *pool)
    199 {
    200 	if (!__sync_bool_compare_and_swap(&pool->lock, 1, 0))
    201 		fatal("pool_unlock: failed to release %s", pool->name);
    202 }
    203 #endif