kore

Kore is a web application platform for writing scalable, concurrent web based processes in C or Python.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

mem.c (5978B)



      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 /*
     18  * The memory facitilies such as kore_malloc / kore_calloc are all
     19  * based on the kore pool system as long as the allocations are
     20  * below 8192 bytes.
     21  *
     22  * Anything over 8192 bytes will get an mmap() allocation instead
     23  * that does not benefit from the protections offered by the kore_pool API.
     24  */
     25 
     26 #include <sys/types.h>
     27 #include <sys/mman.h>
     28 
     29 #include <stdlib.h>
     30 #include <stdint.h>
     31 
     32 #include "kore.h"
     33 
     34 #define KORE_MEM_POOLS			11
     35 #define KORE_MEM_POOLS_PREALLOC		32
     36 #define KORE_MEM_POOLS_SIZE_MAX		8192
     37 
     38 #define KORE_MEM_TAGGED			0x0001
     39 
     40 struct meminfo {
     41 	size_t			len;
     42 	u_int16_t		flags;
     43 };
     44 
     45 struct tag {
     46 	void			*ptr;
     47 	u_int32_t		id;
     48 	TAILQ_ENTRY(tag)	list;
     49 };
     50 
     51 static inline struct meminfo	*meminfo(void *);
     52 static void			*mem_alloc(size_t);
     53 static size_t			mem_index(size_t);
     54 
     55 static TAILQ_HEAD(, tag)	tags;
     56 static struct kore_pool		tag_pool;
     57 static struct kore_pool		mempools[KORE_MEM_POOLS];
     58 
     59 void
     60 kore_mem_init(void)
     61 {
     62 	const char	*opt;
     63 	int		i, len;
     64 	char		name[32];
     65 	size_t		size, elm, mlen;
     66 
     67 	if ((opt = getenv("KORE_MEM_GUARD")) != NULL && !strcmp(opt, "1"))
     68 		kore_mem_guard = 1;
     69 
     70 	size = 8;
     71 	TAILQ_INIT(&tags);
     72 	kore_pool_init(&tag_pool, "tag_pool", sizeof(struct tag), 4);
     73 
     74 	for (i = 0; i < KORE_MEM_POOLS; i++) {
     75 		len = snprintf(name, sizeof(name), "block-%zu", size);
     76 		if (len == -1 || (size_t)len >= sizeof(name))
     77 			fatal("kore_mem_init: snprintf");
     78 
     79 		elm = (KORE_MEM_POOLS_PREALLOC * 1024) / size;
     80 		mlen = sizeof(struct meminfo) + size;
     81 
     82 		kore_pool_init(&mempools[i], name, mlen, elm);
     83 
     84 		size = size << 1;
     85 	}
     86 }
     87 
     88 void
     89 kore_mem_cleanup(void)
     90 {
     91 	int		i;
     92 
     93 	for (i = 0; i < KORE_MEM_POOLS; i++) {
     94 		kore_pool_cleanup(&mempools[i]);
     95 	}
     96 }
     97 
     98 void *
     99 kore_mmap_region(size_t len)
    100 {
    101 	void		*ptr;
    102 
    103 	if ((ptr = mmap(NULL, len, PROT_READ | PROT_WRITE,
    104 	    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) == MAP_FAILED)
    105 		fatal("%s: mmap: %s", __func__, errno_s);
    106 
    107 	return (ptr);
    108 }
    109 
    110 void *
    111 kore_malloc(size_t len)
    112 {
    113 	return (mem_alloc(len));
    114 }
    115 
    116 void *
    117 kore_realloc(void *ptr, size_t len)
    118 {
    119 	struct meminfo		*mem;
    120 	void			*nptr;
    121 
    122 	if (ptr == NULL) {
    123 		nptr = mem_alloc(len);
    124 	} else {
    125 		mem = meminfo(ptr);
    126 		if (len == mem->len)
    127 			return (ptr);
    128 		nptr = mem_alloc(len);
    129 		memcpy(nptr, ptr, MIN(len, mem->len));
    130 		kore_free_zero(ptr);
    131 	}
    132 
    133 	return (nptr);
    134 }
    135 
    136 void *
    137 kore_calloc(size_t memb, size_t len)
    138 {
    139 	void		*ptr;
    140 	size_t		total;
    141 
    142 	if (SIZE_MAX / memb < len)
    143 		fatal("kore_calloc(): memb * len > SIZE_MAX");
    144 
    145 	total = memb * len;
    146 	ptr = mem_alloc(total);
    147 	memset(ptr, 0, total);
    148 
    149 	return (ptr);
    150 }
    151 
    152 void
    153 kore_free_zero(void *ptr)
    154 {
    155 	struct meminfo		*mem;
    156 
    157 	if (ptr == NULL)
    158 		return;
    159 
    160 	mem = meminfo(ptr);
    161 	kore_mem_zero(ptr, mem->len);
    162 
    163 	kore_free(ptr);
    164 }
    165 
    166 void
    167 kore_free(void *ptr)
    168 {
    169 	size_t			idx;
    170 	struct meminfo		*mem;
    171 	u_int8_t		*addr;
    172 
    173 	if (ptr == NULL)
    174 		return;
    175 
    176 	mem = meminfo(ptr);
    177 	if (mem->flags & KORE_MEM_TAGGED) {
    178 		kore_mem_untag(ptr);
    179 		mem->flags &= ~KORE_MEM_TAGGED;
    180 	}
    181 
    182 	addr = (u_int8_t *)ptr - sizeof(struct meminfo);
    183 
    184 	if (mem->len <= KORE_MEM_POOLS_SIZE_MAX) {
    185 		idx = mem_index(mem->len);
    186 		kore_pool_put(&mempools[idx], addr);
    187 	} else {
    188 		if (munmap(addr, sizeof(*mem) + mem->len) == -1)
    189 			fatal("%s: munmap: %s", __func__, errno_s);
    190 	}
    191 }
    192 
    193 char *
    194 kore_strdup(const char *str)
    195 {
    196 	size_t		len;
    197 	char		*nstr;
    198 
    199 	len = strlen(str) + 1;
    200 	nstr = mem_alloc(len);
    201 	(void)kore_strlcpy(nstr, str, len);
    202 
    203 	return (nstr);
    204 }
    205 
    206 void *
    207 kore_malloc_tagged(size_t len, u_int32_t tag)
    208 {
    209 	void		*ptr;
    210 
    211 	ptr = mem_alloc(len);
    212 	kore_mem_tag(ptr, tag);
    213 
    214 	return (ptr);
    215 }
    216 
    217 void
    218 kore_mem_tag(void *ptr, u_int32_t id)
    219 {
    220 	struct tag		*tag;
    221 	struct meminfo		*mem;
    222 
    223 	if (kore_mem_lookup(id) != NULL)
    224 		fatal("kore_mem_tag: tag %u taken", id);
    225 
    226 	mem = meminfo(ptr);
    227 	mem->flags |= KORE_MEM_TAGGED;
    228 
    229 	tag = kore_pool_get(&tag_pool);
    230 	tag->id = id;
    231 	tag->ptr = ptr;
    232 
    233 	TAILQ_INSERT_TAIL(&tags, tag, list);
    234 }
    235 
    236 void
    237 kore_mem_untag(void *ptr)
    238 {
    239 	struct tag		*tag;
    240 
    241 	TAILQ_FOREACH(tag, &tags, list) {
    242 		if (tag->ptr == ptr) {
    243 			TAILQ_REMOVE(&tags, tag, list);
    244 			kore_pool_put(&tag_pool, tag);
    245 			break;
    246 		}
    247 	}
    248 }
    249 
    250 void *
    251 kore_mem_lookup(u_int32_t id)
    252 {
    253 	struct tag		*tag;
    254 
    255 	TAILQ_FOREACH(tag, &tags, list) {
    256 		if (tag->id == id)
    257 			return (tag->ptr);
    258 	}
    259 
    260 	return (NULL);
    261 }
    262 
    263 /* Best effort to try and let the compiler not optimize this call away. */
    264 void
    265 kore_mem_zero(void *ptr, size_t len)
    266 {
    267 	volatile char	*p;
    268 
    269 	p = (volatile char *)ptr;
    270 
    271 	if (p != NULL) {
    272 		while (len-- > 0)
    273 			*(p)++ = 0x00;
    274 	}
    275 }
    276 
    277 static void *
    278 mem_alloc(size_t len)
    279 {
    280 	void			*ptr;
    281 	struct meminfo		*mem;
    282 	size_t			mlen, idx;
    283 
    284 	if (len == 0)
    285 		len = 8;
    286 
    287 	if (len <= KORE_MEM_POOLS_SIZE_MAX) {
    288 		idx = mem_index(len);
    289 		ptr = kore_pool_get(&mempools[idx]);
    290 	} else {
    291 		mlen = sizeof(struct meminfo) + len;
    292 		ptr = kore_mmap_region(mlen);
    293 	}
    294 
    295 	mem = (struct meminfo *)ptr;
    296 	mem->len = len;
    297 	mem->flags = 0;
    298 
    299 	return ((u_int8_t *)ptr + sizeof(struct meminfo));
    300 }
    301 
    302 static size_t
    303 mem_index(size_t len)
    304 {
    305 	size_t		mlen, idx;
    306 
    307 	idx = 0;
    308 	mlen = 8;
    309 	while (mlen < len) {
    310 		idx++;
    311 		mlen = mlen << 1;
    312 	}
    313 
    314 	if (idx > (KORE_MEM_POOLS - 1))
    315 		fatal("mem_index: idx too high");
    316 
    317 	return (idx);
    318 }
    319 
    320 static inline struct meminfo *
    321 meminfo(void *ptr)
    322 {
    323 	return ((struct meminfo *)((u_int8_t *)ptr - sizeof(struct meminfo)));
    324 }