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

mem.c (6094B)



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