summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am54
-rw-r--r--mem.c1816
-rw-r--r--mem.h120
-rw-r--r--mem_malloc.c153
-rw-r--r--mem_malloc.h42
-rw-r--r--phys.c777
-rw-r--r--phys.h66
-rw-r--r--test/test_mem.c57
-rw-r--r--test/test_mem_cache.c145
-rw-r--r--test/test_mem_cache_double_free.c75
-rw-r--r--test/test_mem_cache_invalid_free.c74
-rw-r--r--test/test_mem_cache_write_beyond.c90
-rw-r--r--test/test_mem_cache_write_buftag.c92
-rw-r--r--test/test_mem_cache_write_free.c106
-rw-r--r--test/test_mem_offbyone.c58
-rw-r--r--test/test_phys.c65
-rw-r--r--test/test_xprintf.c298
-rw-r--r--xprintf.c591
-rw-r--r--xprintf.h58
19 files changed, 3 insertions, 4734 deletions
diff --git a/Makefile.am b/Makefile.am
index 55da9a2..d685fce 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,72 +25,24 @@ librbraun_la_SOURCES = \
list.c \
list.h \
macros.h \
- mem.c \
- mem.h \
- mem_malloc.c \
- mem_malloc.h \
- phys.c \
- phys.h \
rbtree.c \
rbtree.h \
rbtree_i.h \
rdxtree.c \
- rdxtree.h \
- xprintf.c \
- xprintf.h
+ rdxtree.h
+
librbraun_la_LIBADD = -lrt -lpthread
bin_PROGRAMS = \
test_avltree \
- test_mem \
- test_mem_cache \
- test_mem_cache_invalid_free \
- test_mem_cache_double_free \
- test_mem_cache_write_free \
- test_mem_cache_write_beyond \
- test_mem_cache_write_buftag \
- test_mem_offbyone \
- test_phys \
test_rbtree \
- test_rdxtree \
- test_xprintf
+ test_rdxtree
test_avltree_SOURCES = test/test_avltree.c
test_avltree_LDADD = librbraun.la
-test_mem_SOURCES = test/test_mem.c
-test_mem_LDADD = librbraun.la
-
-test_mem_cache_SOURCES = test/test_mem_cache.c
-test_mem_cache_LDADD = -lrt -lpthread
-
-test_mem_cache_invalid_free_SOURCES = test/test_mem_cache_invalid_free.c
-test_mem_cache_invalid_free_LDADD = librbraun.la
-
-test_mem_cache_double_free_SOURCES = test/test_mem_cache_double_free.c
-test_mem_cache_double_free_LDADD = librbraun.la
-
-test_mem_cache_write_free_SOURCES = test/test_mem_cache_write_free.c
-test_mem_cache_write_free_LDADD = librbraun.la
-
-test_mem_cache_write_beyond_SOURCES = test/test_mem_cache_write_beyond.c
-test_mem_cache_write_beyond_LDADD = librbraun.la
-
-test_mem_cache_write_buftag_SOURCES = test/test_mem_cache_write_buftag.c
-test_mem_cache_write_buftag_LDADD = librbraun.la
-
-test_mem_offbyone_SOURCES = test/test_mem_offbyone.c
-test_mem_offbyone_LDADD = librbraun.la
-
-test_phys_SOURCES = test/test_phys.c
-test_phys_LDADD = -lrt -lpthread
-
test_rbtree_SOURCES = test/test_rbtree.c
test_rbtree_LDADD = librbraun.la
test_rdxtree_SOURCES = test/test_rdxtree.c
test_rdxtree_LDADD = -lrt -lpthread
-
-test_xprintf_SOURCES = test/test_xprintf.c
-test_xprintf_CFLAGS = $(AM_CFLAGS) -Wno-format
-test_xprintf_LDADD = librbraun.la
diff --git a/mem.c b/mem.c
deleted file mode 100644
index ce71be5..0000000
--- a/mem.c
+++ /dev/null
@@ -1,1816 +0,0 @@
-/*
- * Copyright (c) 2010, 2011 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * Object caching and general purpose memory allocator.
- *
- * This allocator is based on the following works :
- * - "The Slab Allocator: An Object-Caching Kernel Memory Allocator",
- * by Jeff Bonwick.
- *
- * It allows the allocation of objects (i.e. fixed-size typed buffers) from
- * caches and is efficient in both space and time. This implementation follows
- * many of the indications from the paper mentioned. The most notable
- * differences are outlined below.
- *
- * The per-cache self-scaling hash table for buffer-to-bufctl conversion,
- * described in 3.2.3 "Slab Layout for Large Objects", has been replaced by
- * an AVL tree storing slabs, sorted by address. The use of a self-balancing
- * tree for buffer-to-slab conversions provides a few advantages over a hash
- * table. Unlike a hash table, a BST provides a "lookup nearest" operation,
- * so obtaining the slab data (whether it is embedded in the slab or off
- * slab) from a buffer address simply consists of a "lookup nearest towards
- * 0" tree search. Storing slabs instead of buffers also considerably reduces
- * the number of elements to retain. Finally, a self-balancing tree is a true
- * self-scaling data structure, whereas a hash table requires periodic
- * maintenance and complete resizing, which is expensive. The only drawback is
- * that releasing a buffer to the slab layer takes logarithmic time instead of
- * constant time. But as the data set size is kept reasonable (because slabs
- * are stored instead of buffers) and because the CPU pool layer services most
- * requests, avoiding many accesses to the slab layer, it is considered an
- * acceptable tradeoff.
- *
- * This implementation uses per-cpu pools of objects, which service most
- * allocation requests. These pools act as caches (but are named differently
- * to avoid confusion with CPU caches) that reduce contention on multiprocessor
- * systems. When a pool is empty and cannot provide an object, it is filled by
- * transferring multiple objects from the slab layer. The symmetric case is
- * handled likewise.
- */
-
-#include <time.h>
-#include <errno.h>
-#include <sched.h>
-#include <stdio.h>
-#include <assert.h>
-#include <limits.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <pthread.h>
-#include <sys/mman.h>
-
-#include "cpu.h"
-#include "mem.h"
-#include "list.h"
-#include "error.h"
-#include "macros.h"
-#include "avltree.h"
-
-/*
- * The system page size.
- *
- * This macro actually expands to a global variable that is set on
- * initialization.
- */
-#define PAGE_SIZE ((unsigned long)_pagesize)
-
-/*
- * Minimum required alignment.
- */
-#define MEM_ALIGN_MIN 8
-
-/*
- * Minimum number of buffers per slab.
- *
- * This value is ignored when the slab size exceeds a threshold.
- */
-#define MEM_MIN_BUFS_PER_SLAB 8
-
-/*
- * Special slab size beyond which the minimum number of buffers per slab is
- * ignored when computing the slab size of a cache.
- */
-#define MEM_SLAB_SIZE_THRESHOLD (8 * PAGE_SIZE)
-
-/*
- * Special buffer size under which slab data is unconditionnally allocated
- * from its associated slab.
- */
-#define MEM_BUF_SIZE_THRESHOLD (PAGE_SIZE / 8)
-
-/*
- * Time (in seconds) between two garbage collection operations.
- */
-#define MEM_GC_INTERVAL 15
-
-/*
- * The transfer size of a CPU pool is computed by dividing the pool size by
- * this value.
- */
-#define MEM_CPU_POOL_TRANSFER_RATIO 2
-
-/*
- * Shift for the first general cache size.
- */
-#define MEM_CACHES_FIRST_SHIFT 5
-
-/*
- * Number of caches backing general purpose allocations.
- */
-#define MEM_NR_MEM_CACHES 13
-
-/*
- * Per-processor cache of pre-constructed objects.
- *
- * The flags member is a read-only CPU-local copy of the parent cache flags.
- */
-struct mem_cpu_pool {
- pthread_mutex_t lock;
- int flags;
- int size;
- int transfer_size;
- int nr_objs;
- void **array;
-} __aligned(CPU_L1_SIZE);
-
-/*
- * When a cache is created, its CPU pool type is determined from the buffer
- * size. For small buffer sizes, many objects can be cached in a CPU pool.
- * Conversely, for large buffer sizes, this would incur much overhead, so only
- * a few objects are stored in a CPU pool.
- */
-struct mem_cpu_pool_type {
- size_t buf_size;
- int array_size;
- size_t array_align;
- struct mem_cache *array_cache;
-};
-
-/*
- * Buffer descriptor.
- *
- * For normal caches (i.e. without MEM_CF_VERIFY), bufctls are located at the
- * end of (but inside) each buffer. If MEM_CF_VERIFY is set, bufctls are located
- * after each buffer.
- *
- * When an object is allocated to a client, its bufctl isn't used. This memory
- * is instead used for redzoning if cache debugging is in effect.
- */
-union mem_bufctl {
- union mem_bufctl *next;
- unsigned long redzone;
-};
-
-/*
- * Redzone guard word.
- */
-#ifdef __LP64__
-#if _HOST_BIG_ENDIAN
-#define MEM_REDZONE_WORD 0xfeedfacefeedfaceUL
-#else /* _HOST_BIG_ENDIAN */
-#define MEM_REDZONE_WORD 0xcefaedfecefaedfeUL
-#endif /* _HOST_BIG_ENDIAN */
-#else /* __LP64__ */
-#if _HOST_BIG_ENDIAN
-#define MEM_REDZONE_WORD 0xfeedfaceUL
-#else /* _HOST_BIG_ENDIAN */
-#define MEM_REDZONE_WORD 0xcefaedfeUL
-#endif /* _HOST_BIG_ENDIAN */
-#endif /* __LP64__ */
-
-/*
- * Redzone byte for padding.
- */
-#define MEM_REDZONE_BYTE 0xbb
-
-/*
- * Buffer tag.
- *
- * This structure is only used for MEM_CF_VERIFY caches. It is located after
- * the bufctl and includes information about the state of the buffer it
- * describes (allocated or not). It should be thought of as a debugging
- * extension of the bufctl.
- */
-struct mem_buftag {
- unsigned long state;
-};
-
-/*
- * Values the buftag state member can take.
- */
-#ifdef __LP64__
-#if _HOST_BIG_ENDIAN
-#define MEM_BUFTAG_ALLOC 0xa110c8eda110c8edUL
-#define MEM_BUFTAG_FREE 0xf4eeb10cf4eeb10cUL
-#else /* _HOST_BIG_ENDIAN */
-#define MEM_BUFTAG_ALLOC 0xedc810a1edc810a1UL
-#define MEM_BUFTAG_FREE 0x0cb1eef40cb1eef4UL
-#endif /* _HOST_BIG_ENDIAN */
-#else /* __LP64__ */
-#if _HOST_BIG_ENDIAN
-#define MEM_BUFTAG_ALLOC 0xa110c8edUL
-#define MEM_BUFTAG_FREE 0xf4eeb10cUL
-#else /* _HOST_BIG_ENDIAN */
-#define MEM_BUFTAG_ALLOC 0xedc810a1UL
-#define MEM_BUFTAG_FREE 0x0cb1eef4UL
-#endif /* _HOST_BIG_ENDIAN */
-#endif /* __LP64__ */
-
-/*
- * Free and uninitialized patterns.
- *
- * These values are unconditionnally 64-bit wide since buffers are at least
- * 8-byte aligned.
- */
-#if _HOST_BIG_ENDIAN
-#define MEM_FREE_PATTERN 0xdeadbeefdeadbeefULL
-#define MEM_UNINIT_PATTERN 0xbaddcafebaddcafeULL
-#else /* _HOST_BIG_ENDIAN */
-#define MEM_FREE_PATTERN 0xefbeaddeefbeaddeULL
-#define MEM_UNINIT_PATTERN 0xfecaddbafecaddbaULL
-#endif /* _HOST_BIG_ENDIAN */
-
-/*
- * Page-aligned collection of unconstructed buffers.
- */
-struct mem_slab {
- struct list list_node;
- struct avltree_node tree_node;
- unsigned long nr_refs;
- union mem_bufctl *first_free;
- void *addr;
-};
-
-/*
- * Private cache creation flags.
- */
-#define MEM_CREATE_INTERNAL 0x0100 /* Prevent off slab data */
-
-/*
- * Cache name buffer size.
- */
-#define MEM_NAME_SIZE 32
-
-/*
- * Cache flags.
- *
- * The flags don't change once set and can be tested without locking.
- */
-#define MEM_CF_DIRECT 0x0001 /* No buf-to-slab tree lookup */
-#define MEM_CF_SLAB_EXTERNAL 0x0002 /* Slab data is off slab */
-
-/*
- * Debugging flags
- */
-#define MEM_CF_VERIFY 0x0100 /* Use debugging facilities */
-
-/*
- * Cache of objects.
- *
- * Locking order : cpu_pool -> cache. CPU pools locking is ordered by CPU ID.
- *
- * The partial slabs list is sorted by slab references. Slabs with a high
- * number of references are placed first on the list to reduce fragmentation.
- * Sorting occurs at insertion/removal of buffers in a slab. As the list
- * is maintained sorted, and the number of references only changes by one,
- * this is a very cheap operation in the average case and the worst (linear)
- * case is very unlikely.
- */
-struct mem_cache {
- /* CPU pool layer */
- struct mem_cpu_pool cpu_pools[NR_CPUS];
- struct mem_cpu_pool_type *cpu_pool_type;
-
- /* Slab layer */
- pthread_mutex_t lock;
- struct list node; /* Cache list linkage */
- struct list partial_slabs;
- struct list free_slabs;
- struct avltree active_slabs;
- int flags;
- size_t obj_size; /* User-provided size */
- size_t align;
- size_t buf_size; /* Aligned object size */
- size_t bufctl_dist; /* Distance from buffer to bufctl */
- size_t slab_size;
- size_t color;
- size_t color_max;
- unsigned long bufs_per_slab;
- unsigned long nr_objs; /* Number of allocated objects */
- unsigned long nr_bufs; /* Total number of buffers */
- unsigned long nr_slabs;
- unsigned long nr_free_slabs;
- mem_cache_ctor_t ctor;
- struct mem_source source;
- char name[MEM_NAME_SIZE];
- size_t buftag_dist; /* Distance from buffer to buftag */
- size_t redzone_pad; /* Bytes from end of object to redzone word */
-};
-
-/*
- * Options for mem_cache_alloc_verify().
- */
-#define MEM_AV_NOCONSTRUCT 0
-#define MEM_AV_CONSTRUCT 1
-
-/*
- * Error codes for mem_cache_error().
- */
-#define MEM_ERR_INVALID 0 /* Invalid address being freed */
-#define MEM_ERR_DOUBLEFREE 1 /* Freeing already free address */
-#define MEM_ERR_BUFTAG 2 /* Invalid buftag content */
-#define MEM_ERR_MODIFIED 3 /* Buffer modified while free */
-#define MEM_ERR_REDZONE 4 /* Redzone violation */
-
-/*
- * See PAGE_SIZE.
- */
-static long _pagesize;
-
-/*
- * Available CPU pool types.
- *
- * For each entry, the CPU pool size applies from the entry buf_size
- * (excluded) up to (and including) the buf_size of the preceding entry.
- *
- * See struct cpu_pool_type for a description of the values.
- */
-static struct mem_cpu_pool_type mem_cpu_pool_types[] = {
- { 32768, 1, 0, NULL },
- { 4096, 8, CPU_L1_SIZE, NULL },
- { 256, 64, CPU_L1_SIZE, NULL },
- { 0, 128, CPU_L1_SIZE, NULL }
-};
-
-/*
- * Caches where CPU pool arrays are allocated from.
- */
-static struct mem_cache mem_cpu_array_caches[ARRAY_SIZE(mem_cpu_pool_types)];
-
-/*
- * Cache for off slab data.
- */
-static struct mem_cache mem_slab_cache;
-
-/*
- * Cache for dynamically created caches.
- */
-static struct mem_cache mem_cache_cache;
-
-/*
- * General caches array.
- */
-static struct mem_cache mem_caches[MEM_NR_MEM_CACHES];
-
-/*
- * List of all caches managed by the allocator.
- */
-static struct list mem_cache_list;
-static pthread_mutex_t mem_cache_list_lock;
-
-/*
- * Default backend functions.
- */
-static void * mem_default_alloc(size_t size);
-static void mem_default_free(void *ptr, size_t size);
-
-/*
- * Default source of memory.
- */
-static struct mem_source mem_default_source = {
- mem_default_alloc,
- mem_default_free
-};
-
-#define mem_error(format, ...) \
- fprintf(stderr, "mem: error: %s(): " format "\n", __func__, \
- ## __VA_ARGS__)
-
-#define mem_warn(format, ...) \
- fprintf(stderr, "mem: warning: %s(): " format "\n", __func__, \
- ## __VA_ARGS__)
-
-#define mem_print(format, ...) \
- fprintf(stderr, format "\n", ## __VA_ARGS__)
-
-static void mem_cache_error(struct mem_cache *cache, void *buf, int error,
- void *arg);
-static void * mem_cache_alloc_from_slab(struct mem_cache *cache);
-static void mem_cache_free_to_slab(struct mem_cache *cache, void *buf);
-
-#if CONFIG_MEM_USE_PHYS
-#include "phys.h"
-
-static void *
-mem_default_alloc(size_t size)
-{
- return (void *)phys_alloc(size);
-}
-
-static void
-mem_default_free(void *ptr, size_t size)
-{
- phys_free((phys_paddr_t)ptr, size);
-}
-#else /* CONFIG_MEM_USE_PHYS */
-static void *
-mem_default_alloc(size_t size)
-{
- void *addr;
-
- addr = mmap(NULL, size, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-
- if (addr == MAP_FAILED)
- return NULL;
-
- return addr;
-}
-
-static void
-mem_default_free(void *ptr, size_t size)
-{
- munmap(ptr, size);
-}
-#endif /* CONFIG_MEM_USE_PHYS */
-
-static void *
-mem_buf_verify_bytes(void *buf, void *pattern, size_t size)
-{
- char *ptr, *pattern_ptr, *end;
-
- end = buf + size;
-
- for (ptr = buf, pattern_ptr = pattern; ptr < end; ptr++, pattern_ptr++)
- if (*ptr != *pattern_ptr)
- return ptr;
-
- return NULL;
-}
-
-static void *
-mem_buf_verify(void *buf, uint64_t pattern, size_t size)
-{
- uint64_t *ptr, *end;
-
- assert(P2ALIGNED((unsigned long)buf, sizeof(uint64_t)));
- assert(P2ALIGNED(size, sizeof(uint64_t)));
-
- end = buf + size;
-
- for (ptr = buf; ptr < end; ptr++)
- if (*ptr != pattern)
- return mem_buf_verify_bytes(ptr, &pattern, sizeof(pattern));
-
- return NULL;
-}
-
-static void
-mem_buf_fill(void *buf, uint64_t pattern, size_t size)
-{
- uint64_t *ptr, *end;
-
- assert(P2ALIGNED((unsigned long)buf, sizeof(uint64_t)));
- assert(P2ALIGNED(size, sizeof(uint64_t)));
-
- end = buf + size;
-
- for (ptr = buf; ptr < end; ptr++)
- *ptr = pattern;
-}
-
-static void *
-mem_buf_verify_fill(void *buf, uint64_t old, uint64_t new, size_t size)
-{
- uint64_t *ptr, *end;
-
- assert(P2ALIGNED((unsigned long)buf, sizeof(uint64_t)));
- assert(P2ALIGNED(size, sizeof(uint64_t)));
-
- end = buf + size;
-
- for (ptr = buf; ptr < end; ptr++) {
- if (*ptr != old)
- return mem_buf_verify_bytes(ptr, &old, sizeof(old));
-
- *ptr = new;
- }
-
- return NULL;
-}
-
-static inline union mem_bufctl *
-mem_buf_to_bufctl(void *buf, struct mem_cache *cache)
-{
- return (union mem_bufctl *)(buf + cache->bufctl_dist);
-}
-
-static inline struct mem_buftag *
-mem_buf_to_buftag(void *buf, struct mem_cache *cache)
-{
- return (struct mem_buftag *)(buf + cache->buftag_dist);
-}
-
-static inline void *
-mem_bufctl_to_buf(union mem_bufctl *bufctl, struct mem_cache *cache)
-{
- return (void *)bufctl - cache->bufctl_dist;
-}
-
-static void
-mem_slab_create_verify(struct mem_slab *slab, struct mem_cache *cache)
-{
- struct mem_buftag *buftag;
- size_t buf_size;
- unsigned long buffers;
- void *buf;
-
- buf_size = cache->buf_size;
- buf = slab->addr;
- buftag = mem_buf_to_buftag(buf, cache);
-
- for (buffers = cache->bufs_per_slab; buffers != 0; buffers--) {
- mem_buf_fill(buf, MEM_FREE_PATTERN, cache->bufctl_dist);
- buftag->state = MEM_BUFTAG_FREE;
- buf += buf_size;
- buftag = mem_buf_to_buftag(buf, cache);
- }
-}
-
-/*
- * Create an empty slab for a cache.
- *
- * The caller must drop all locks before calling this function.
- */
-static struct mem_slab *
-mem_slab_create(struct mem_cache *cache, size_t color)
-{
- struct mem_slab *slab;
- union mem_bufctl *bufctl;
- size_t buf_size;
- unsigned long buffers;
- void *slab_buf;
-
- slab_buf = cache->source.alloc_fn(cache->slab_size);
-
- if (slab_buf == NULL)
- return NULL;
-
- if (cache->flags & MEM_CF_SLAB_EXTERNAL) {
- slab = mem_cache_alloc(&mem_slab_cache);
-
- if (slab == NULL) {
- cache->source.free_fn(slab_buf, cache->slab_size);
- return NULL;
- }
- } else {
- slab = (struct mem_slab *)(slab_buf + cache->slab_size) - 1;
- }
-
- list_node_init(&slab->list_node);
- avltree_node_init(&slab->tree_node);
- slab->nr_refs = 0;
- slab->first_free = NULL;
- slab->addr = slab_buf + color;
-
- buf_size = cache->buf_size;
- bufctl = mem_buf_to_bufctl(slab->addr, cache);
-
- for (buffers = cache->bufs_per_slab; buffers != 0; buffers--) {
- bufctl->next = slab->first_free;
- slab->first_free = bufctl;
- bufctl = (union mem_bufctl *)((void *)bufctl + buf_size);
- }
-
- if (cache->flags & MEM_CF_VERIFY)
- mem_slab_create_verify(slab, cache);
-
- return slab;
-}
-
-static void
-mem_slab_destroy_verify(struct mem_slab *slab, struct mem_cache *cache)
-{
- struct mem_buftag *buftag;
- size_t buf_size;
- unsigned long buffers;
- void *buf, *addr;
-
- buf_size = cache->buf_size;
- buf = slab->addr;
- buftag = mem_buf_to_buftag(buf, cache);
-
- for (buffers = cache->bufs_per_slab; buffers != 0; buffers--) {
- if (buftag->state != MEM_BUFTAG_FREE)
- mem_cache_error(cache, buf, MEM_ERR_BUFTAG, buftag);
-
- addr = mem_buf_verify(buf, MEM_FREE_PATTERN, cache->bufctl_dist);
-
- if (addr != NULL)
- mem_cache_error(cache, buf, MEM_ERR_MODIFIED, addr);
-
- buf += buf_size;
- buftag = mem_buf_to_buftag(buf, cache);
- }
-}
-
-/*
- * Destroy a slab.
- *
- * The caller must drop all locks before calling this function.
- */
-static void
-mem_slab_destroy(struct mem_slab *slab, struct mem_cache *cache)
-{
- void *slab_buf;
-
- assert(slab->nr_refs == 0);
- assert(slab->first_free != NULL);
-
- if (cache->flags & MEM_CF_VERIFY)
- mem_slab_destroy_verify(slab, cache);
-
- slab_buf = (void *)P2ALIGN((unsigned long)slab->addr, PAGE_SIZE);
- cache->source.free_fn(slab_buf, cache->slab_size);
-
- if (cache->flags & MEM_CF_SLAB_EXTERNAL)
- mem_cache_free(&mem_slab_cache, slab);
-}
-
-static inline int
-mem_slab_use_tree(int flags)
-{
- return !(flags & MEM_CF_DIRECT) || (flags & MEM_CF_VERIFY);
-}
-
-static inline int
-mem_slab_cmp_lookup(const void *addr, const struct avltree_node *node)
-{
- struct mem_slab *slab;
-
- slab = avltree_entry(node, struct mem_slab, tree_node);
-
- if (addr == slab->addr)
- return 0;
- else if (addr < slab->addr)
- return -1;
- else
- return 1;
-}
-
-static inline int
-mem_slab_cmp_insert(const struct avltree_node *a, const struct avltree_node *b)
-{
- struct mem_slab *slab;
-
- slab = avltree_entry(a, struct mem_slab, tree_node);
- return mem_slab_cmp_lookup(slab->addr, b);
-}
-
-static void
-mem_cpu_pool_init(struct mem_cpu_pool *cpu_pool, struct mem_cache *cache)
-{
- pthread_mutex_init(&cpu_pool->lock, NULL);
- cpu_pool->flags = cache->flags;
- cpu_pool->size = 0;
- cpu_pool->transfer_size = 0;
- cpu_pool->nr_objs = 0;
- cpu_pool->array = NULL;
-}
-
-/*
- * Return a CPU pool.
- *
- * This function will generally return the pool matching the CPU running the
- * calling thread. Because of context switches and thread migration, the
- * caller might be running on another processor after this function returns.
- * Although not optimal, this should rarely happen, and it doesn't affect the
- * allocator operations in any other way, as CPU pools are always valid, and
- * their access is serialized by a lock.
- */
-static inline struct mem_cpu_pool *
-mem_cpu_pool_get(struct mem_cache *cache)
-{
- return &cache->cpu_pools[cpu_id()];
-}
-
-static inline void
-mem_cpu_pool_build(struct mem_cpu_pool *cpu_pool, struct mem_cache *cache,
- void **array)
-{
- cpu_pool->size = cache->cpu_pool_type->array_size;
- cpu_pool->transfer_size = (cpu_pool->size + MEM_CPU_POOL_TRANSFER_RATIO - 1)
- / MEM_CPU_POOL_TRANSFER_RATIO;
- cpu_pool->array = array;
-}
-
-static inline void *
-mem_cpu_pool_pop(struct mem_cpu_pool *cpu_pool)
-{
- cpu_pool->nr_objs--;
- return cpu_pool->array[cpu_pool->nr_objs];
-}
-
-static inline void
-mem_cpu_pool_push(struct mem_cpu_pool *cpu_pool, void *obj)
-{
- cpu_pool->array[cpu_pool->nr_objs] = obj;
- cpu_pool->nr_objs++;
-}
-
-static int
-mem_cpu_pool_fill(struct mem_cpu_pool *cpu_pool, struct mem_cache *cache)
-{
- void *obj;
- int i;
-
- pthread_mutex_lock(&cache->lock);
-
- for (i = 0; i < cpu_pool->transfer_size; i++) {
- obj = mem_cache_alloc_from_slab(cache);
-
- if (obj == NULL)
- break;
-
- mem_cpu_pool_push(cpu_pool, obj);
- }
-
- pthread_mutex_unlock(&cache->lock);
-
- return i;
-}
-
-static void
-mem_cpu_pool_drain(struct mem_cpu_pool *cpu_pool, struct mem_cache *cache)
-{
- void *obj;
- int i;
-
- pthread_mutex_lock(&cache->lock);
-
- for (i = cpu_pool->transfer_size; i > 0; i--) {
- obj = mem_cpu_pool_pop(cpu_pool);
- mem_cache_free_to_slab(cache, obj);
- }
-
- pthread_mutex_unlock(&cache->lock);
-}
-
-static void
-mem_cache_error(struct mem_cache *cache, void *buf, int error, void *arg)
-{
- struct mem_buftag *buftag;
-
- mem_error("cache: %s, buffer: %p", cache->name, buf);
-
- switch(error) {
- case MEM_ERR_INVALID:
- mem_error("freeing invalid address");
- break;
- case MEM_ERR_DOUBLEFREE:
- mem_error("attempting to free the same address twice");
- break;
- case MEM_ERR_BUFTAG:
- mem_error("invalid buftag content");
- buftag = arg;
- mem_error("buftag state: %p", (void *)buftag->state);
- break;
- case MEM_ERR_MODIFIED:
- mem_error("free buffer modified");
- mem_error("fault address: %p, offset in buffer: %td", arg, arg - buf);
- break;
- case MEM_ERR_REDZONE:
- mem_error("write beyond end of buffer");
- mem_error("fault address: %p, offset in buffer: %td", arg, arg - buf);
- break;
- default:
- mem_error("unknown error");
- }
-
- error_die(ERR_MEM_CACHE);
-
- /*
- * Never reached.
- */
-}
-
-/*
- * Compute an appropriate slab size for the given cache.
- *
- * Once the slab size is known, this function sets the related properties
- * (buffers per slab and maximum color). It can also set the MEM_CF_DIRECT
- * and/or MEM_CF_SLAB_EXTERNAL flags depending on the resulting layout.
- */
-static void
-mem_cache_compute_sizes(struct mem_cache *cache, int flags)
-{
- size_t i, buffers, buf_size, slab_size, free_slab_size, optimal_size;
- size_t waste, waste_min;
- int embed, optimal_embed;
-
- buf_size = cache->buf_size;
-
- if (buf_size < MEM_BUF_SIZE_THRESHOLD)
- flags |= MEM_CREATE_INTERNAL;
-
- i = 0;
- waste_min = (size_t)-1;
-
- do {
- i++;
- slab_size = P2ROUND(i * buf_size, PAGE_SIZE);
- free_slab_size = slab_size;
-
- if (flags & MEM_CREATE_INTERNAL)
- free_slab_size -= sizeof(struct mem_slab);
-
- buffers = free_slab_size / buf_size;
- waste = free_slab_size % buf_size;
-
- if (buffers > i)
- i = buffers;
-
- if (flags & MEM_CREATE_INTERNAL)
- embed = 1;
- else if (sizeof(struct mem_slab) <= waste) {
- embed = 1;
- waste -= sizeof(struct mem_slab);
- } else {
- embed = 0;
- }
-
- if (waste <= waste_min) {
- waste_min = waste;
- optimal_size = slab_size;
- optimal_embed = embed;
- }
- } while ((buffers < MEM_MIN_BUFS_PER_SLAB)
- && (slab_size < MEM_SLAB_SIZE_THRESHOLD));
-
- assert(!(flags & MEM_CREATE_INTERNAL) || optimal_embed);
-
- cache->slab_size = optimal_size;
- slab_size = cache->slab_size - (optimal_embed
- ? sizeof(struct mem_slab)
- : 0);
- cache->bufs_per_slab = slab_size / buf_size;
- cache->color_max = slab_size % buf_size;
-
- if (cache->color_max >= PAGE_SIZE)
- cache->color_max = PAGE_SIZE - 1;
-
- if (optimal_embed) {
- if (cache->slab_size == PAGE_SIZE)
- cache->flags |= MEM_CF_DIRECT;
- } else {
- cache->flags |= MEM_CF_SLAB_EXTERNAL;
- }
-}
-
-static void
-mem_cache_init(struct mem_cache *cache, const char *name,
- size_t obj_size, size_t align, mem_cache_ctor_t ctor,
- const struct mem_source *source, int flags)
-{
- struct mem_cpu_pool_type *cpu_pool_type;
- size_t i, buf_size;
-
-#if CONFIG_MEM_VERIFY
- cache->flags = MEM_CF_VERIFY;
-#else
- cache->flags = 0;
-#endif
-
- if (flags & MEM_CACHE_VERIFY)
- cache->flags |= MEM_CF_VERIFY;
-
- if (align < MEM_ALIGN_MIN)
- align = MEM_ALIGN_MIN;
-
- assert(obj_size > 0);
- assert(ISP2(align));
- assert(align < PAGE_SIZE);
-
- buf_size = P2ROUND(obj_size, align);
-
- if (source == NULL)
- source = &mem_default_source;
-
- pthread_mutex_init(&cache->lock, NULL);
- list_node_init(&cache->node);
- list_init(&cache->partial_slabs);
- list_init(&cache->free_slabs);
- avltree_init(&cache->active_slabs);
- cache->obj_size = obj_size;
- cache->align = align;
- cache->buf_size = buf_size;
- cache->bufctl_dist = buf_size - sizeof(union mem_bufctl);
- cache->color = 0;
- cache->nr_objs = 0;
- cache->nr_bufs = 0;
- cache->nr_slabs = 0;
- cache->nr_free_slabs = 0;
- cache->ctor = ctor;
- cache->source = *source;
- strncpy(cache->name, name, MEM_NAME_SIZE);
- cache->name[MEM_NAME_SIZE - 1] = '\0';
- cache->buftag_dist = 0;
- cache->redzone_pad = 0;
-
- if (cache->flags & MEM_CF_VERIFY) {
- cache->bufctl_dist = buf_size;
- cache->buftag_dist = cache->bufctl_dist + sizeof(union mem_bufctl);
- cache->redzone_pad = cache->bufctl_dist - cache->obj_size;
- buf_size += sizeof(union mem_bufctl) + sizeof(struct mem_buftag);
- buf_size = P2ROUND(buf_size, align);
- cache->buf_size = buf_size;
- }
-
- mem_cache_compute_sizes(cache, flags);
-
- for (cpu_pool_type = mem_cpu_pool_types;
- buf_size <= cpu_pool_type->buf_size;
- cpu_pool_type++);
-
- cache->cpu_pool_type = cpu_pool_type;
-
- for (i = 0; i < ARRAY_SIZE(cache->cpu_pools); i++)
- mem_cpu_pool_init(&cache->cpu_pools[i], cache);
-
- pthread_mutex_lock(&mem_cache_list_lock);
- list_insert_tail(&mem_cache_list, &cache->node);
- pthread_mutex_unlock(&mem_cache_list_lock);
-}
-
-struct mem_cache *
-mem_cache_create(const char *name, size_t obj_size, size_t align,
- mem_cache_ctor_t ctor, const struct mem_source *source,
- int flags)
-{
- struct mem_cache *cache;
-
- cache = mem_cache_alloc(&mem_cache_cache);
-
- if (cache == NULL)
- return NULL;
-
- mem_cache_init(cache, name, obj_size, align, ctor, source, flags);
-
- return cache;
-}
-
-static inline int
-mem_cache_empty(struct mem_cache *cache)
-{
- return cache->nr_objs == cache->nr_bufs;
-}
-
-static int
-mem_cache_grow(struct mem_cache *cache)
-{
- struct mem_slab *slab;
- size_t color;
- int empty;
-
- pthread_mutex_lock(&cache->lock);
-
- if (!mem_cache_empty(cache)) {
- pthread_mutex_unlock(&cache->lock);
- return 1;
- }
-
- color = cache->color;
- cache->color += cache->align;
-
- if (cache->color > cache->color_max)
- cache->color = 0;
-
- pthread_mutex_unlock(&cache->lock);
-
- slab = mem_slab_create(cache, color);
-
- pthread_mutex_lock(&cache->lock);
-
- if (slab != NULL) {
- list_insert_tail(&cache->free_slabs, &slab->list_node);
- cache->nr_bufs += cache->bufs_per_slab;
- cache->nr_slabs++;
- cache->nr_free_slabs++;
- }
-
- /*
- * Even if our slab creation failed, another thread might have succeeded
- * in growing the cache.
- */
- empty = mem_cache_empty(cache);
-
- pthread_mutex_unlock(&cache->lock);
-
- return !empty;
-}
-
-static void
-mem_cache_reap(struct mem_cache *cache)
-{
- struct mem_slab *slab;
- struct list dead_slabs;
-
- list_init(&dead_slabs);
-
- pthread_mutex_lock(&cache->lock);
-
- while (!list_empty(&cache->free_slabs)) {
- slab = list_first_entry(&cache->free_slabs, struct mem_slab, list_node);
- list_remove(&slab->list_node);
- list_insert(&dead_slabs, &slab->list_node);
- cache->nr_bufs -= cache->bufs_per_slab;
- cache->nr_slabs--;
- cache->nr_free_slabs--;
- }
-
- pthread_mutex_unlock(&cache->lock);
-
- while (!list_empty(&dead_slabs)) {
- slab = list_first_entry(&dead_slabs, struct mem_slab, list_node);
- list_remove(&slab->list_node);
- mem_slab_destroy(slab, cache);
- }
-}
-
-void
-mem_cache_destroy(struct mem_cache *cache)
-{
- struct mem_cpu_pool *cpu_pool;
- void **ptr;
- size_t i;
-
- pthread_mutex_lock(&mem_cache_list_lock);
- list_remove(&cache->node);
- pthread_mutex_unlock(&mem_cache_list_lock);
-
- for (i = 0; i < ARRAY_SIZE(cache->cpu_pools); i++) {
- cpu_pool = &cache->cpu_pools[i];
-
- pthread_mutex_lock(&cpu_pool->lock);
-
- if (cpu_pool->array == NULL) {
- pthread_mutex_unlock(&cpu_pool->lock);
- continue;
- }
-
- pthread_mutex_lock(&cache->lock);
-
- for (ptr = cpu_pool->array + cpu_pool->nr_objs - 1;
- ptr >= cpu_pool->array;
- ptr--)
- mem_cache_free_to_slab(cache, *ptr);
-
- pthread_mutex_unlock(&cache->lock);
-
- ptr = cpu_pool->array;
- cpu_pool->size = 0;
- cpu_pool->nr_objs = 0;
- cpu_pool->array = NULL;
- pthread_mutex_unlock(&cpu_pool->lock);
-
- mem_cache_free(cache->cpu_pool_type->array_cache, ptr);
- }
-
- mem_cache_reap(cache);
-
-#ifndef NDEBUG
- if (cache->nr_objs != 0)
- mem_warn("'%s' not empty", cache->name);
- else {
- assert(list_empty(&cache->partial_slabs));
- assert(list_empty(&cache->free_slabs));
- assert(avltree_empty(&cache->active_slabs));
- assert(cache->nr_bufs == 0);
- assert(cache->nr_slabs == 0);
- }
-#endif /* NDEBUG */
-
- pthread_mutex_destroy(&cache->lock);
-
- for (i = 0; i < ARRAY_SIZE(cache->cpu_pools); i++)
- pthread_mutex_destroy(&cache->cpu_pools[i].lock);
-
- mem_cache_free(&mem_cache_cache, cache);
-}
-
-/*
- * Allocate a raw (unconstructed) buffer from the slab layer of a cache.
- *
- * The cache must be locked before calling this function.
- */
-static void *
-mem_cache_alloc_from_slab(struct mem_cache *cache)
-{
- struct mem_slab *slab;
- union mem_bufctl *bufctl;
-
- if (!list_empty(&cache->partial_slabs))
- slab = list_first_entry(&cache->partial_slabs, struct mem_slab,
- list_node);
- else if (!list_empty(&cache->free_slabs))
- slab = list_first_entry(&cache->free_slabs, struct mem_slab, list_node);
- else
- return NULL;
-
- bufctl = slab->first_free;
- assert(bufctl != NULL);
- slab->first_free = bufctl->next;
- slab->nr_refs++;
- cache->nr_objs++;
-
- /*
- * The slab has become complete.
- */
- if (slab->nr_refs == cache->bufs_per_slab) {
- list_remove(&slab->list_node);
-
- if (slab->nr_refs == 1)
- cache->nr_free_slabs--;
- } else if (slab->nr_refs == 1) {
- /*
- * The slab has become partial.
- */
- list_remove(&slab->list_node);
- list_insert_tail(&cache->partial_slabs, &slab->list_node);
- cache->nr_free_slabs--;
- } else if (!list_singular(&cache->partial_slabs)) {
- struct list *node;
- struct mem_slab *tmp;
-
- /*
- * The slab remains partial. If there are more than one partial slabs,
- * maintain the list sorted.
- */
-
- assert(slab->nr_refs > 1);
-
- for (node = list_prev(&slab->list_node);
- !list_end(&cache->partial_slabs, node);
- node = list_prev(node)) {
- tmp = list_entry(node, struct mem_slab, list_node);
-
- if (tmp->nr_refs >= slab->nr_refs)
- break;
- }
-
- /*
- * If the direct neighbor was found, the list is already sorted.
- * If no slab was found, the slab is inserted at the head of the list.
- */
- if (node != list_prev(&slab->list_node)) {
- list_remove(&slab->list_node);
- list_insert_after(node, &slab->list_node);
- }
- }
-
- if ((slab->nr_refs == 1) && mem_slab_use_tree(cache->flags))
- avltree_insert(&cache->active_slabs, &slab->tree_node,
- mem_slab_cmp_insert);
-
- return mem_bufctl_to_buf(bufctl, cache);
-}
-
-/*
- * Release a buffer to the slab layer of a cache.
- *
- * The cache must be locked before calling this function.
- */
-static void
-mem_cache_free_to_slab(struct mem_cache *cache, void *buf)
-{
- struct mem_slab *slab;
- union mem_bufctl *bufctl;
-
- if (cache->flags & MEM_CF_DIRECT) {
- assert(cache->slab_size == PAGE_SIZE);
- slab = (struct mem_slab *)P2END((unsigned long)buf, cache->slab_size)
- - 1;
- } else {
- struct avltree_node *node;
-
- node = avltree_lookup_nearest(&cache->active_slabs, buf,
- mem_slab_cmp_lookup, AVLTREE_LEFT);
- assert(node != NULL);
- slab = avltree_entry(node, struct mem_slab, tree_node);
- assert((unsigned long)buf < (P2ALIGN((unsigned long)slab->addr
- + cache->slab_size, PAGE_SIZE)));
- }
-
- assert(slab->nr_refs >= 1);
- assert(slab->nr_refs <= cache->bufs_per_slab);
- bufctl = mem_buf_to_bufctl(buf, cache);
- bufctl->next = slab->first_free;
- slab->first_free = bufctl;
- slab->nr_refs--;
- cache->nr_objs--;
-
- /*
- * The slab has become free.
- */
- if (slab->nr_refs == 0) {
- if (mem_slab_use_tree(cache->flags))
- avltree_remove(&cache->active_slabs, &slab->tree_node);
-
- /*
- * The slab was partial.
- */
- if (cache->bufs_per_slab > 1)
- list_remove(&slab->list_node);
-
- list_insert_tail(&cache->free_slabs, &slab->list_node);
- cache->nr_free_slabs++;
- } else if (slab->nr_refs == (cache->bufs_per_slab - 1)) {
- /*
- * The slab has become partial.
- */
- list_insert(&cache->partial_slabs, &slab->list_node);
- } else if (!list_singular(&cache->partial_slabs)) {
- struct list *node;
- struct mem_slab *tmp;
-
- /*
- * The slab remains partial. If there are more than one partial slabs,
- * maintain the list sorted.
- */
-
- assert(slab->nr_refs > 0);
-
- for (node = list_next(&slab->list_node);
- !list_end(&cache->partial_slabs, node);
- node = list_next(node)) {
- tmp = list_entry(node, struct mem_slab, list_node);
-
- if (tmp->nr_refs <= slab->nr_refs)
- break;
- }
-
- /*
- * If the direct neighbor was found, the list is already sorted.
- * If no slab was found, the slab is inserted at the tail of the list.
- */
- if (node != list_next(&slab->list_node)) {
- list_remove(&slab->list_node);
- list_insert_before(node, &slab->list_node);
- }
- }
-}
-
-static void
-mem_cache_alloc_verify(struct mem_cache *cache, void *buf, int construct)
-{
- struct mem_buftag *buftag;
- union mem_bufctl *bufctl;
- void *addr;
-
- buftag = mem_buf_to_buftag(buf, cache);
-
- if (buftag->state != MEM_BUFTAG_FREE)
- mem_cache_error(cache, buf, MEM_ERR_BUFTAG, buftag);
-
- addr = mem_buf_verify_fill(buf, MEM_FREE_PATTERN, MEM_UNINIT_PATTERN,
- cache->bufctl_dist);
-
- if (addr != NULL)
- mem_cache_error(cache, buf, MEM_ERR_MODIFIED, addr);
-
- addr = buf + cache->obj_size;
- memset(addr, MEM_REDZONE_BYTE, cache->redzone_pad);
-
- bufctl = mem_buf_to_bufctl(buf, cache);
- bufctl->redzone = MEM_REDZONE_WORD;
- buftag->state = MEM_BUFTAG_ALLOC;
-
- if (construct && (cache->ctor != NULL))
- cache->ctor(buf);
-}
-
-void *
-mem_cache_alloc(struct mem_cache *cache)
-{
- struct mem_cpu_pool *cpu_pool;
- int filled;
- void *buf;
-
- cpu_pool = mem_cpu_pool_get(cache);
-
- pthread_mutex_lock(&cpu_pool->lock);
-
-fast_alloc_retry:
- if (likely(cpu_pool->nr_objs > 0)) {
- buf = mem_cpu_pool_pop(cpu_pool);
- pthread_mutex_unlock(&cpu_pool->lock);
-
- if (cpu_pool->flags & MEM_CF_VERIFY)
- mem_cache_alloc_verify(cache, buf, MEM_AV_CONSTRUCT);
-
- return buf;
- }
-
- if (cpu_pool->array != NULL) {
- filled = mem_cpu_pool_fill(cpu_pool, cache);
-
- if (!filled) {
- pthread_mutex_unlock(&cpu_pool->lock);
-
- filled = mem_cache_grow(cache);
-
- if (!filled)
- return NULL;
-
- pthread_mutex_lock(&cpu_pool->lock);
- }
-
- goto fast_alloc_retry;
- }
-
- pthread_mutex_unlock(&cpu_pool->lock);
-
-slow_alloc_retry:
- pthread_mutex_lock(&cache->lock);
- buf = mem_cache_alloc_from_slab(cache);
- pthread_mutex_unlock(&cache->lock);
-
- if (buf == NULL) {
- filled = mem_cache_grow(cache);
-
- if (!filled)
- return NULL;
-
- goto slow_alloc_retry;
- }
-
- if (cache->flags & MEM_CF_VERIFY)
- mem_cache_alloc_verify(cache, buf, MEM_AV_NOCONSTRUCT);
-
- if (cache->ctor != NULL)
- cache->ctor(buf);
-
- return buf;
-}
-
-static void
-mem_cache_free_verify(struct mem_cache *cache, void *buf)
-{
- struct avltree_node *node;
- struct mem_buftag *buftag;
- struct mem_slab *slab;
- union mem_bufctl *bufctl;
- unsigned char *redzone_byte;
- unsigned long slabend;
-
- pthread_mutex_lock(&cache->lock);
- node = avltree_lookup_nearest(&cache->active_slabs, buf,
- mem_slab_cmp_lookup, AVLTREE_LEFT);
- pthread_mutex_unlock(&cache->lock);
-
- if (node == NULL)
- mem_cache_error(cache, buf, MEM_ERR_INVALID, NULL);
-
- slab = avltree_entry(node, struct mem_slab, tree_node);
- slabend = P2ALIGN((unsigned long)slab->addr + cache->slab_size, PAGE_SIZE);
-
- if ((unsigned long)buf >= slabend)
- mem_cache_error(cache, buf, MEM_ERR_INVALID, NULL);
-
- if ((((unsigned long)buf - (unsigned long)slab->addr) % cache->buf_size)
- != 0)
- mem_cache_error(cache, buf, MEM_ERR_INVALID, NULL);
-
- /*
- * As the buffer address is valid, accessing its buftag is safe.
- */
- buftag = mem_buf_to_buftag(buf, cache);
-
- if (buftag->state != MEM_BUFTAG_ALLOC) {
- if (buftag->state == MEM_BUFTAG_FREE)
- mem_cache_error(cache, buf, MEM_ERR_DOUBLEFREE, NULL);
- else
- mem_cache_error(cache, buf, MEM_ERR_BUFTAG, buftag);
- }
-
- redzone_byte = buf + cache->obj_size;
- bufctl = mem_buf_to_bufctl(buf, cache);
-
- while (redzone_byte < (unsigned char *)bufctl) {
- if (*redzone_byte != MEM_REDZONE_BYTE)
- mem_cache_error(cache, buf, MEM_ERR_REDZONE, redzone_byte);
-
- redzone_byte++;
- }
-
- if (bufctl->redzone != MEM_REDZONE_WORD) {
- unsigned long word;
-
- word = MEM_REDZONE_WORD;
- redzone_byte = mem_buf_verify_bytes(&bufctl->redzone, &word,
- sizeof(bufctl->redzone));
- mem_cache_error(cache, buf, MEM_ERR_REDZONE, redzone_byte);
- }
-
- mem_buf_fill(buf, MEM_FREE_PATTERN, cache->bufctl_dist);
- buftag->state = MEM_BUFTAG_FREE;
-}
-
-void
-mem_cache_free(struct mem_cache *cache, void *obj)
-{
- struct mem_cpu_pool *cpu_pool;
- void **array;
-
- cpu_pool = mem_cpu_pool_get(cache);
-
- if (cpu_pool->flags & MEM_CF_VERIFY)
- mem_cache_free_verify(cache, obj);
-
- pthread_mutex_lock(&cpu_pool->lock);
-
-fast_free_retry:
- if (likely(cpu_pool->nr_objs < cpu_pool->size)) {
- mem_cpu_pool_push(cpu_pool, obj);
- pthread_mutex_unlock(&cpu_pool->lock);
- return;
- }
-
- if (cpu_pool->array != NULL) {
- mem_cpu_pool_drain(cpu_pool, cache);
- goto fast_free_retry;
- }
-
- pthread_mutex_unlock(&cpu_pool->lock);
-
- array = mem_cache_alloc(cache->cpu_pool_type->array_cache);
-
- if (array != NULL) {
- pthread_mutex_lock(&cpu_pool->lock);
-
- /*
- * Another thread may have built the CPU pool while the lock was
- * dropped.
- */
- if (cpu_pool->array != NULL) {
- pthread_mutex_unlock(&cpu_pool->lock);
- mem_cache_free(cache->cpu_pool_type->array_cache, array);
- pthread_mutex_lock(&cpu_pool->lock);
- goto fast_free_retry;
- }
-
- mem_cpu_pool_build(cpu_pool, cache, array);
- goto fast_free_retry;
- }
-
- pthread_mutex_lock(&cache->lock);
- mem_cache_free_to_slab(cache, obj);
- pthread_mutex_unlock(&cache->lock);
-}
-
-void
-mem_cache_info(struct mem_cache *cache)
-{
- struct mem_cache *cache_stats;
- char flags_str[64];
-
- if (cache == NULL) {
- pthread_mutex_lock(&mem_cache_list_lock);
-
- list_for_each_entry(&mem_cache_list, cache, node)
- mem_cache_info(cache);
-
- pthread_mutex_unlock(&mem_cache_list_lock);
-
- return;
- }
-
- cache_stats = mem_alloc(sizeof(*cache_stats));
-
- if (cache_stats == NULL) {
- mem_warn("unable to allocate memory for cache stats");
- return;
- }
-
- pthread_mutex_lock(&cache->lock);
- cache_stats->flags = cache->flags;
- cache_stats->obj_size = cache->obj_size;
- cache_stats->align = cache->align;
- cache_stats->buf_size = cache->buf_size;
- cache_stats->bufctl_dist = cache->bufctl_dist;
- cache_stats->slab_size = cache->slab_size;
- cache_stats->color_max = cache->color_max;
- cache_stats->bufs_per_slab = cache->bufs_per_slab;
- cache_stats->nr_objs = cache->nr_objs;
- cache_stats->nr_bufs = cache->nr_bufs;
- cache_stats->nr_slabs = cache->nr_slabs;
- cache_stats->nr_free_slabs = cache->nr_free_slabs;
- strcpy(cache_stats->name, cache->name);
- cache_stats->buftag_dist = cache->buftag_dist;
- cache_stats->redzone_pad = cache->redzone_pad;
- cache_stats->cpu_pool_type = cache->cpu_pool_type;
- pthread_mutex_unlock(&cache->lock);
-
- snprintf(flags_str, sizeof(flags_str), "%s%s%s",
- (cache_stats->flags & MEM_CF_DIRECT) ? " DIRECT" : "",
- (cache_stats->flags & MEM_CF_SLAB_EXTERNAL) ? " SLAB_EXTERNAL" : "",
- (cache_stats->flags & MEM_CF_VERIFY) ? " VERIFY" : "");
-
- mem_print("name: %s", cache_stats->name);
- mem_print("flags: 0x%x%s", cache_stats->flags, flags_str);
- mem_print("obj_size: %zu", cache_stats->obj_size);
- mem_print("align: %zu", cache_stats->align);
- mem_print("buf_size: %zu", cache_stats->buf_size);
- mem_print("bufctl_dist: %zu", cache_stats->bufctl_dist);
- mem_print("slab_size: %zu", cache_stats->slab_size);
- mem_print("color_max: %zu", cache_stats->color_max);
- mem_print("bufs_per_slab: %lu", cache_stats->bufs_per_slab);
- mem_print("nr_objs: %lu", cache_stats->nr_objs);
- mem_print("nr_bufs: %lu", cache_stats->nr_bufs);
- mem_print("nr_slabs: %lu", cache_stats->nr_slabs);
- mem_print("nr_free_slabs: %lu", cache_stats->nr_free_slabs);
- mem_print("buftag_dist: %zu", cache_stats->buftag_dist);
- mem_print("redzone_pad: %zu", cache_stats->redzone_pad);
- mem_print("cpu_pool_size: %d", cache_stats->cpu_pool_type->array_size);
- mem_print("--");
-
- mem_free(cache_stats, sizeof(*cache_stats));
-}
-
-static void *
-mem_gc(void *arg)
-{
- struct mem_cache *cache;
- struct timespec ts;
- int error;
-
- (void)arg;
-
- clock_gettime(CLOCK_MONOTONIC, &ts);
-
- for (;;) {
- ts.tv_sec += MEM_GC_INTERVAL;
-
- do
- error = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL);
- while (error == EINTR);
-
- /*
- * EINTR is the only expected error.
- */
- assert(error == 0);
-
-#if 0
- mem_info();
-
-#if CONFIG_MEM_USE_PHYS
- phys_info();
-#endif /* CONFIG_MEM_USE_PHYS */
-#endif
-
- pthread_mutex_lock(&mem_cache_list_lock);
-
- list_for_each_entry(&mem_cache_list, cache, node)
- mem_cache_reap(cache);
-
- pthread_mutex_unlock(&mem_cache_list_lock);
- }
-
- return NULL;
-}
-
-void
-mem_setup(void)
-{
- static int mem_initialized = 0;
- struct mem_cpu_pool_type *cpu_pool_type;
- char name[MEM_NAME_SIZE];
- pthread_t thread;
- size_t i, size;
- int error;
-
- if (mem_initialized)
- return;
-
- mem_initialized = 1;
-
- _pagesize = sysconf(_SC_PAGESIZE);
- assert(ISP2(_pagesize));
-
- /*
- * Make sure a bufctl can always be stored in a buffer.
- */
- assert(sizeof(union mem_bufctl) <= MEM_ALIGN_MIN);
-
-#if CONFIG_MEM_USE_PHYS
- phys_setup();
-#endif /* CONFIG_MEM_USE_PHYS */
-
- list_init(&mem_cache_list);
- pthread_mutex_init(&mem_cache_list_lock, NULL);
-
- for (i = 0; i < ARRAY_SIZE(mem_cpu_pool_types); i++) {
- cpu_pool_type = &mem_cpu_pool_types[i];
- cpu_pool_type->array_cache = &mem_cpu_array_caches[i];
- sprintf(name, "mem_cpu_array_%d", cpu_pool_type->array_size);
- size = sizeof(void *) * cpu_pool_type->array_size;
- mem_cache_init(cpu_pool_type->array_cache, name, size,
- cpu_pool_type->array_align, NULL, NULL, 0);
- }
-
- /*
- * Prevent off slab data for the slab cache to avoid infinite recursion.
- */
- mem_cache_init(&mem_slab_cache, "mem_slab", sizeof(struct mem_slab),
- 0, NULL, NULL, MEM_CREATE_INTERNAL);
- mem_cache_init(&mem_cache_cache, "mem_cache", sizeof(struct mem_cache),
- CPU_L1_SIZE, NULL, NULL, 0);
-
- size = 1 << MEM_CACHES_FIRST_SHIFT;
-
- for (i = 0; i < ARRAY_SIZE(mem_caches); i++) {
- sprintf(name, "mem_%zu", size);
- mem_cache_init(&mem_caches[i], name, size, 0, NULL, NULL, 0);
- size <<= 1;
- }
-
- error = pthread_create(&thread, NULL, mem_gc, NULL);
-
- if (error)
- mem_error("unable to create garbage collection thread: %s",
- strerror(error));
-}
-
-/*
- * Return the mem cache index matching the given allocation size, which
- * must be strictly greater than 0.
- */
-static inline size_t
-mem_get_index(size_t size)
-{
- assert(size != 0);
-
- size = (size - 1) >> MEM_CACHES_FIRST_SHIFT;
-
- if (size == 0)
- return 0;
- else
- return (sizeof(long) * CHAR_BIT) - __builtin_clzl(size);
-}
-
-static void
-mem_alloc_verify(struct mem_cache *cache, void *buf, size_t size)
-{
- size_t redzone_size;
- void *redzone;
-
- assert(size <= cache->obj_size);
-
- redzone = buf + size;
- redzone_size = cache->obj_size - size;
- memset(redzone, MEM_REDZONE_BYTE, redzone_size);
-}
-
-void *
-mem_alloc(size_t size)
-{
- size_t index;
- void *buf;
-
- if (size == 0)
- return NULL;
-
- index = mem_get_index(size);
-
- if (index < ARRAY_SIZE(mem_caches)) {
- struct mem_cache *cache;
-
- cache = &mem_caches[index];
- buf = mem_cache_alloc(cache);
-
- if ((buf != NULL) && (cache->flags & MEM_CF_VERIFY))
- mem_alloc_verify(cache, buf, size);
- } else {
- buf = mem_default_alloc(size);
- }
-
- return buf;
-}
-
-void *
-mem_zalloc(size_t size)
-{
- void *ptr;
-
- ptr = mem_alloc(size);
-
- if (ptr == NULL)
- return NULL;
-
- memset(ptr, 0, size);
- return ptr;
-}
-
-static void
-mem_free_verify(struct mem_cache *cache, void *buf, size_t size)
-{
- unsigned char *redzone_byte, *redzone_end;
-
- assert(size <= cache->obj_size);
-
- redzone_byte = buf + size;
- redzone_end = buf + cache->obj_size;
-
- while (redzone_byte < redzone_end) {
- if (*redzone_byte != MEM_REDZONE_BYTE)
- mem_cache_error(cache, buf, MEM_ERR_REDZONE, redzone_byte);
-
- redzone_byte++;
- }
-}
-
-void
-mem_free(void *ptr, size_t size)
-{
- size_t index;
-
- if ((ptr == NULL) || (size == 0))
- return;
-
- index = mem_get_index(size);
-
- if (index < ARRAY_SIZE(mem_caches)) {
- struct mem_cache *cache;
-
- cache = &mem_caches[index];
-
- if (cache->flags & MEM_CF_VERIFY)
- mem_free_verify(cache, ptr, size);
-
- mem_cache_free(cache, ptr);
- } else {
- mem_default_free(ptr, size);
- }
-}
-
-void
-mem_info(void)
-{
- struct mem_cache *cache, *cache_stats;
- size_t mem_usage, mem_reclaimable;
-
- cache_stats = mem_alloc(sizeof(*cache_stats));
-
- if (cache_stats == NULL) {
- mem_warn("unable to allocate memory for cache stats");
- return;
- }
-
- mem_print("-- cache obj slab bufs objs bufs "
- " total reclaimable");
- mem_print("-- name size size /slab usage count "
- " memory memory");
-
- pthread_mutex_lock(&mem_cache_list_lock);
-
- list_for_each_entry(&mem_cache_list, cache, node) {
- pthread_mutex_lock(&cache->lock);
- cache_stats->obj_size = cache->obj_size;
- cache_stats->slab_size = cache->slab_size;
- cache_stats->bufs_per_slab = cache->bufs_per_slab;
- cache_stats->nr_objs = cache->nr_objs;
- cache_stats->nr_bufs = cache->nr_bufs;
- cache_stats->nr_slabs = cache->nr_slabs;
- cache_stats->nr_free_slabs = cache->nr_free_slabs;
- strcpy(cache_stats->name, cache->name);
- pthread_mutex_unlock(&cache->lock);
-
- mem_usage = (cache_stats->nr_slabs * cache_stats->slab_size) >> 10;
- mem_reclaimable =
- (cache_stats->nr_free_slabs * cache_stats->slab_size) >> 10;
-
- mem_print("%-27s %6zu %3zuk %4lu %6lu %6lu %7zuk %10zuk",
- cache_stats->name, cache_stats->obj_size,
- cache_stats->slab_size >> 10, cache_stats->bufs_per_slab,
- cache_stats->nr_objs, cache_stats->nr_bufs, mem_usage,
- mem_reclaimable);
- }
-
- pthread_mutex_unlock(&mem_cache_list_lock);
-
- mem_free(cache_stats, sizeof(*cache_stats));
-}
diff --git a/mem.h b/mem.h
deleted file mode 100644
index 55f92f7..0000000
--- a/mem.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (c) 2010, 2011 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * Object caching and general purpose memory allocator.
- */
-
-#ifndef _MEM_H
-#define _MEM_H
-
-#include <stddef.h>
-
-/*
- * Backend source of memory for a cache.
- */
-struct mem_source {
- void * (*alloc_fn)(size_t);
- void (*free_fn)(void *, size_t);
-};
-
-/*
- * Object cache opaque declaration.
- */
-struct mem_cache;
-
-/*
- * Type for constructor functions.
- *
- * The pre-constructed state of an object is supposed to include only
- * elements such as e.g. linked lists, locks, reference counters. Therefore
- * constructors are expected to 1) never fail and 2) not need any
- * user-provided data. The first constraint implies that object construction
- * never performs dynamic resource allocation, which also means there is no
- * need for destructors.
- */
-typedef void (*mem_cache_ctor_t)(void *);
-
-/*
- * Cache creation flags.
- */
-#define MEM_CACHE_VERIFY 0x1 /* Use debugging facilities */
-
-/*
- * Create a cache.
- */
-struct mem_cache * mem_cache_create(const char *name, size_t obj_size,
- size_t align, mem_cache_ctor_t ctor,
- const struct mem_source *source, int flags);
-
-/*
- * Destroy a cache.
- */
-void mem_cache_destroy(struct mem_cache *cache);
-
-/*
- * Allocate an object from a cache.
- */
-void * mem_cache_alloc(struct mem_cache *cache);
-
-/*
- * Release an object to its cache.
- */
-void mem_cache_free(struct mem_cache *cache, void *obj);
-
-/*
- * Display internal cache stats on stderr.
- *
- * If cache is NULL, this function displays all managed caches.
- */
-void mem_cache_info(struct mem_cache *cache);
-
-/*
- * Set up the memory allocator module.
- */
-void mem_setup(void);
-
-/*
- * Allocate size bytes of uninitialized memory.
- */
-void * mem_alloc(size_t size);
-
-/*
- * Allocate size bytes of zeroed memory.
- */
-void * mem_zalloc(size_t size);
-
-/*
- * Release memory obtained with mem_alloc() or mem_zalloc().
- *
- * The size argument must strictly match the value given at allocation time.
- */
-void mem_free(void *ptr, size_t size);
-
-/*
- * Display global memory information on stderr.
- */
-void mem_info(void);
-
-#endif /* _MEM_H */
diff --git a/mem_malloc.c b/mem_malloc.c
deleted file mode 100644
index 2f25e0b..0000000
--- a/mem_malloc.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (c) 2010 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * Libc-compatible malloc() functions implementation.
- *
- * Keep in mind this code is mainly used for tests. Also, initialization is
- * not thread-safe.
- */
-
-#include <errno.h>
-#include <stddef.h>
-#include <string.h>
-
-#include "mem.h"
-#include "macros.h"
-#include "mem_malloc.h"
-
-struct btag {
- void *addr;
- size_t size;
-} __aligned(8);
-
-void *
-malloc(size_t size)
-{
- struct btag *btag;
-
- mem_setup();
-
- size += sizeof(*btag);
- btag = mem_alloc(size);
-
- if (btag == NULL) {
- errno = ENOMEM;
- return NULL;
- }
-
- btag->addr = btag;
- btag->size = size;
-
- return btag + 1;
-}
-
-void *
-calloc(size_t nmemb, size_t size)
-{
- size_t bytes;
- void *buf;
-
- mem_setup();
-
- bytes = nmemb * size;
- buf = malloc(bytes);
-
- if (buf == NULL)
- return NULL;
-
- memset(buf, 0, bytes);
-
- return buf;
-}
-
-void *
-realloc(void *ptr, size_t size)
-{
- struct btag *btag;
- size_t old_size;
- char *buf;
-
- mem_setup();
-
- if (ptr == NULL)
- return malloc(size);
- else if (size == 0) {
- free(ptr);
- return NULL;
- }
-
- buf = malloc(size);
-
- if (buf == NULL)
- return NULL;
-
- btag = (struct btag *)ptr - 1;
- old_size = btag->size - sizeof(*btag);
- memcpy(buf, ptr, MIN(old_size, size));
- mem_free(btag->addr, btag->size);
-
- return buf;
-}
-
-int
-posix_memalign(void **ptr, size_t align, size_t size)
-{
- struct btag *btag;
- char *buf;
-
- mem_setup();
-
- if (!ISP2(align))
- return EINVAL;
-
- size += sizeof(*btag);
- size = P2ROUND(size, align * 2);
- buf = mem_alloc(size);
-
- if (buf == NULL)
- return ENOMEM;
-
- btag = (struct btag *)P2ROUND((unsigned long)buf + sizeof(*btag), align)
- - 1;
- btag->addr = buf;
- btag->size = size;
-
- *ptr = btag + 1;
- return 0;
-}
-
-void
-free(void *ptr)
-{
- struct btag *btag;
-
- mem_setup();
-
- if (ptr == NULL)
- return;
-
- btag = (struct btag *)ptr - 1;
- mem_free(btag->addr, btag->size);
-}
diff --git a/mem_malloc.h b/mem_malloc.h
deleted file mode 100644
index 6921c32..0000000
--- a/mem_malloc.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2010 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * Libc-compatible malloc() functions.
- *
- * This code is messy, for testing purposes only, and disabled by default.
- */
-
-#ifndef _MEM_MALLOC_H
-#define _MEM_MALLOC_H
-
-#include <stddef.h>
-
-void * malloc(size_t size);
-void * calloc(size_t nmemb, size_t size);
-void * realloc(void *ptr, size_t size);
-int posix_memalign(void **ptr, size_t align, size_t size);
-void free(void *ptr);
-
-#endif /* _MEM_MALLOC_H */
diff --git a/phys.c b/phys.c
deleted file mode 100644
index 5b6a54b..0000000
--- a/phys.c
+++ /dev/null
@@ -1,777 +0,0 @@
-/*
- * Copyright (c) 2011 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * Page allocator.
- *
- * This implementation uses the binary buddy system to manage its heap.
- * Descriptions of the buddy system can be found in the following works :
- * - "UNIX Internals: The New Frontiers", by Uresh Vahalia.
- * - "Dynamic Storage Allocation: A Survey and Critical Review",
- * by Paul R. Wilson, Mark S. Johnstone, Michael Neely, and David Boles.
- *
- * In addition, this allocator uses per-cpu pools of pages for level 0
- * (i.e. single page) allocations. These pools act as caches (but are named
- * differently to avoid confusion with CPU caches) that reduce contention on
- * multiprocessor systems. When a pool is empty and cannot provide a page,
- * it is filled by transferring multiple pages from the backend buddy system.
- * The symmetric case is handled likewise.
- */
-
-#include <sched.h>
-#include <stdio.h>
-#include <assert.h>
-#include <limits.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <pthread.h>
-#include <sys/mman.h>
-
-#include "cpu.h"
-#include "list.h"
-#include "phys.h"
-#include "error.h"
-#include "macros.h"
-
-/*
- * The system page size.
- *
- * This macro actually expands to a global variable that is set on
- * initialization.
- */
-#define PAGE_SIZE ((unsigned long)_pagesize)
-
-/*
- * Maximum number of segments.
- */
-#define PHYS_MAX_SEGMENTS 2
-
-/*
- * Segment boundaries.
- */
-#define PHYS_ISADMA_LIMIT 0x1000000
-#define PHYS_NORMAL_LIMIT 0x30000000
-
-/*
- * Number of segment lists.
- */
-#define PHYS_NR_SEG_LISTS 2
-
-/*
- * Segment list priorities.
- *
- * Higher priorities have lower numerical values.
- */
-#define PHYS_SEGLIST_NORMAL 1
-#define PHYS_SEGLIST_ISADMA 0
-
-/*
- * Number of free block lists per segment.
- */
-#define PHYS_NR_FREE_LISTS 11
-
-/*
- * The size of a CPU pool is computed by dividing the number of pages in its
- * containing segment by this value.
- */
-#define PHYS_CPU_POOL_RATIO 1024
-
-/*
- * Maximum number of pages in a CPU pool.
- */
-#define PHYS_CPU_POOL_MAX_SIZE 128
-
-/*
- * The transfer size of a CPU pool is computed by dividing the pool size by
- * this value.
- */
-#define PHYS_CPU_POOL_TRANSFER_RATIO 2
-
-/*
- * Per-processor cache of pages.
- */
-struct phys_cpu_pool {
- pthread_mutex_t lock;
- int size;
- int transfer_size;
- int nr_pages;
- struct list pages;
-} __aligned(CPU_L1_SIZE);
-
-/*
- * Special level value.
- *
- * When a page is free, its level is the index of its free list.
- */
-#define PHYS_LEVEL_ALLOCATED PHYS_NR_FREE_LISTS
-
-/*
- * Doubly-linked list of free blocks.
- */
-struct phys_free_list {
- unsigned long size;
- struct list blocks;
-};
-
-/*
- * Segment name buffer size.
- */
-#define PHYS_NAME_SIZE 16
-
-/*
- * Segment of contiguous memory.
- */
-struct phys_seg {
- struct phys_cpu_pool cpu_pools[NR_CPUS];
-
- struct list node;
- phys_paddr_t start;
- phys_paddr_t end;
- struct phys_page *pages;
- struct phys_page *pages_end;
- pthread_mutex_t lock;
- struct phys_free_list free_lists[PHYS_NR_FREE_LISTS];
- unsigned long nr_free_pages;
- char name[PHYS_NAME_SIZE];
-};
-
-/*
- * See PAGE_SIZE.
- */
-static long _pagesize;
-
-/*
- * Segment lists, ordered by priority (higher priority lists have lower
- * numerical priorities).
- */
-static struct list phys_seg_lists[PHYS_NR_SEG_LISTS];
-
-/*
- * Segment table.
- */
-static struct phys_seg phys_segs[PHYS_MAX_SEGMENTS];
-
-/*
- * Number of loaded segments.
- */
-static unsigned int phys_segs_size;
-
-/*
- * Page/address conversion macros.
- */
-#define phys_atop(addr) ((addr) / PAGE_SIZE)
-#define phys_ptoa(pfn) ((pfn) * PAGE_SIZE)
-
-static void
-phys_page_init(struct phys_page *page, struct phys_seg *seg, phys_paddr_t pa)
-{
- page->seg = seg;
- page->phys_addr = pa;
- page->level = PHYS_LEVEL_ALLOCATED;
-}
-
-static inline struct phys_page *
-phys_page_lookup(phys_paddr_t pa)
-{
- struct phys_seg *seg;
- unsigned int i;
-
- for (i = 0; i < phys_segs_size; i++) {
- seg = &phys_segs[i];
-
- if ((pa >= seg->start) && (pa < seg->end))
- return &seg->pages[phys_atop(pa - seg->start)];
- }
-
- return NULL;
-}
-
-static void
-phys_free_list_init(struct phys_free_list *free_list)
-{
- free_list->size = 0;
- list_init(&free_list->blocks);
-}
-
-static inline void
-phys_free_list_insert(struct phys_free_list *free_list, struct phys_page *page)
-{
- assert(page->level == PHYS_LEVEL_ALLOCATED);
-
- free_list->size++;
- list_insert(&free_list->blocks, &page->node);
-}
-
-static inline void
-phys_free_list_remove(struct phys_free_list *free_list, struct phys_page *page)
-{
- assert(free_list->size != 0);
- assert(!list_empty(&free_list->blocks));
- assert(page->level < PHYS_NR_FREE_LISTS);
-
- free_list->size--;
- list_remove(&page->node);
-}
-
-static struct phys_page *
-phys_seg_alloc_from_buddy(struct phys_seg *seg, unsigned int level)
-{
- struct phys_free_list *free_list;
- struct phys_page *page, *buddy;
- unsigned int i;
-
- assert(level < PHYS_NR_FREE_LISTS);
-
- for (i = level; i < PHYS_NR_FREE_LISTS; i++) {
- free_list = &seg->free_lists[i];
-
- if (free_list->size != 0)
- break;
- }
-
- if (i == PHYS_NR_FREE_LISTS)
- return NULL;
-
- page = list_first_entry(&free_list->blocks, struct phys_page, node);
- phys_free_list_remove(free_list, page);
- page->level = PHYS_LEVEL_ALLOCATED;
-
- while (i > level) {
- i--;
- buddy = &page[1 << i];
- phys_free_list_insert(&seg->free_lists[i], buddy);
- buddy->level = i;
- }
-
- seg->nr_free_pages -= (1 << level);
- return page;
-}
-
-static void
-phys_seg_free_to_buddy(struct phys_seg *seg, struct phys_page *page,
- unsigned int level)
-{
- struct phys_page *buddy;
- phys_paddr_t pa, buddy_pa;
- unsigned int nr_pages;
-
- assert(page >= seg->pages);
- assert(page < seg->pages_end);
- assert(page->level == PHYS_LEVEL_ALLOCATED);
- assert(level < PHYS_NR_FREE_LISTS);
-
- nr_pages = (1 << level);
- pa = page->phys_addr;
-
- while (level < (PHYS_NR_FREE_LISTS - 1)) {
- buddy_pa = pa ^ phys_ptoa(1 << level);
-
- if ((buddy_pa < seg->start) || (buddy_pa >= seg->end))
- break;
-
- buddy = &seg->pages[phys_atop(buddy_pa - seg->start)];
-
- if (buddy->level != level)
- break;
-
- phys_free_list_remove(&seg->free_lists[level], buddy);
- buddy->level = PHYS_LEVEL_ALLOCATED;
- level++;
- pa &= -phys_ptoa(1 << level);
- page = &seg->pages[phys_atop(pa - seg->start)];
- }
-
- phys_free_list_insert(&seg->free_lists[level], page);
- page->level = level;
- seg->nr_free_pages += nr_pages;
-}
-
-static void
-phys_cpu_pool_init(struct phys_cpu_pool *cpu_pool, int size)
-{
- pthread_mutex_init(&cpu_pool->lock, NULL);
- cpu_pool->size = size;
- cpu_pool->transfer_size = (size + PHYS_CPU_POOL_TRANSFER_RATIO - 1)
- / PHYS_CPU_POOL_TRANSFER_RATIO;
- cpu_pool->nr_pages = 0;
- list_init(&cpu_pool->pages);
-}
-
-/*
- * Return a CPU pool.
- *
- * This function will generally return the pool matching the CPU running the
- * calling thread. Because of context switches and thread migration, the
- * caller might be running on another processor after this function returns.
- * Although not optimal, this should rarely happen, and it doesn't affect the
- * allocator operations in any other way, as CPU pools are always valid, and
- * their access is serialized by a lock.
- */
-static inline struct phys_cpu_pool *
-phys_cpu_pool_get(struct phys_seg *seg)
-{
- return &seg->cpu_pools[cpu_id()];
-}
-
-static inline struct phys_page *
-phys_cpu_pool_pop(struct phys_cpu_pool *cpu_pool)
-{
- struct phys_page *page;
-
- assert(cpu_pool->nr_pages != 0);
- cpu_pool->nr_pages--;
- page = list_first_entry(&cpu_pool->pages, struct phys_page, node);
- list_remove(&page->node);
- return page;
-}
-
-static inline void
-phys_cpu_pool_push(struct phys_cpu_pool *cpu_pool, struct phys_page *page)
-{
- assert(cpu_pool->nr_pages < cpu_pool->size);
- cpu_pool->nr_pages++;
- list_insert(&cpu_pool->pages, &page->node);
-}
-
-static int
-phys_cpu_pool_fill(struct phys_cpu_pool *cpu_pool, struct phys_seg *seg)
-{
- struct phys_page *page;
- int i;
-
- assert(cpu_pool->nr_pages == 0);
-
- pthread_mutex_lock(&seg->lock);
-
- for (i = 0; i < cpu_pool->transfer_size; i++) {
- page = phys_seg_alloc_from_buddy(seg, 0);
-
- if (page == NULL)
- break;
-
- phys_cpu_pool_push(cpu_pool, page);
- }
-
- pthread_mutex_unlock(&seg->lock);
-
- return i;
-}
-
-static void
-phys_cpu_pool_drain(struct phys_cpu_pool *cpu_pool, struct phys_seg *seg)
-{
- struct phys_page *page;
- int i;
-
- assert(cpu_pool->nr_pages == cpu_pool->size);
-
- pthread_mutex_lock(&seg->lock);
-
- for (i = cpu_pool->transfer_size; i > 0; i--) {
- page = phys_cpu_pool_pop(cpu_pool);
- phys_seg_free_to_buddy(seg, page, 0);
- }
-
- pthread_mutex_unlock(&seg->lock);
-}
-
-static inline phys_paddr_t
-phys_seg_start(struct phys_seg *seg)
-{
- return seg->start;
-}
-
-static inline phys_paddr_t
-phys_seg_end(struct phys_seg *seg)
-{
- return seg->end;
-}
-
-static inline phys_paddr_t
-phys_seg_size(struct phys_seg *seg)
-{
- return phys_seg_end(seg) - phys_seg_start(seg);
-}
-
-static int
-phys_seg_compute_pool_size(struct phys_seg *seg)
-{
- phys_paddr_t size;
-
- size = phys_atop(phys_seg_size(seg)) / PHYS_CPU_POOL_RATIO;
-
- if (size == 0)
- size = 1;
- else if (size > PHYS_CPU_POOL_MAX_SIZE)
- size = PHYS_CPU_POOL_MAX_SIZE;
-
- return size;
-}
-
-static void
-phys_seg_init(struct phys_seg *seg, struct phys_page *pages)
-{
- phys_paddr_t pa;
- int pool_size;
- unsigned int i;
-
- pool_size = phys_seg_compute_pool_size(seg);
-
- for (i = 0; i < ARRAY_SIZE(seg->cpu_pools); i++)
- phys_cpu_pool_init(&seg->cpu_pools[i], pool_size);
-
- seg->pages = pages;
- seg->pages_end = pages + phys_atop(phys_seg_size(seg));
- pthread_mutex_init(&seg->lock, NULL);
-
- for (i = 0; i < ARRAY_SIZE(seg->free_lists); i++)
- phys_free_list_init(&seg->free_lists[i]);
-
- seg->nr_free_pages = 0;
-
- for (pa = phys_seg_start(seg); pa < phys_seg_end(seg); pa += PAGE_SIZE)
- phys_page_init(&pages[phys_atop(pa - phys_seg_start(seg))], seg, pa);
-}
-
-/*
- * Return the level (i.e. the index in the free lists array) matching the
- * given size.
- */
-static inline unsigned int
-phys_get_level(phys_size_t size)
-{
- size = P2ROUND(size, PAGE_SIZE) / PAGE_SIZE;
- assert(size != 0);
- size--;
-
- if (size == 0)
- return 0;
- else
- return (sizeof(size) * CHAR_BIT) - __builtin_clzl(size);
-}
-
-static struct phys_page *
-phys_seg_alloc(struct phys_seg *seg, phys_size_t size)
-{
- struct phys_cpu_pool *cpu_pool;
- struct phys_page *page;
- unsigned int level;
- int filled;
-
- level = phys_get_level(size);
-
- if (level == 0) {
- cpu_pool = phys_cpu_pool_get(seg);
-
- pthread_mutex_lock(&cpu_pool->lock);
-
- if (cpu_pool->nr_pages == 0) {
- filled = phys_cpu_pool_fill(cpu_pool, seg);
-
- if (!filled) {
- pthread_mutex_unlock(&cpu_pool->lock);
- return NULL;
- }
- }
-
- page = phys_cpu_pool_pop(cpu_pool);
- pthread_mutex_unlock(&cpu_pool->lock);
- } else {
- pthread_mutex_lock(&seg->lock);
- page = phys_seg_alloc_from_buddy(seg, level);
- pthread_mutex_unlock(&seg->lock);
- }
-
- return page;
-}
-
-static void
-phys_seg_free(struct phys_seg *seg, struct phys_page *page, phys_size_t size)
-{
- struct phys_cpu_pool *cpu_pool;
- unsigned int level;
-
- level = phys_get_level(size);
-
- if (level == 0) {
- cpu_pool = phys_cpu_pool_get(seg);
-
- pthread_mutex_lock(&cpu_pool->lock);
-
- if (cpu_pool->nr_pages == cpu_pool->size)
- phys_cpu_pool_drain(cpu_pool, seg);
-
- phys_cpu_pool_push(cpu_pool, page);
- pthread_mutex_unlock(&cpu_pool->lock);
- } else {
- pthread_mutex_lock(&seg->lock);
- phys_seg_free_to_buddy(seg, page, level);
- pthread_mutex_unlock(&seg->lock);
- }
-}
-
-/*
- * Load memory during initialization.
- *
- * This function partially initializes a segment.
- */
-static void
-phys_load_segment(const char *name, phys_paddr_t start, phys_paddr_t end,
- unsigned int seg_list_prio)
-{
- static int initialized = 0;
- struct phys_seg *seg;
- struct list *seg_list;
- unsigned int i;
-
- assert(name != NULL);
- assert(start < end);
- assert(seg_list_prio < ARRAY_SIZE(phys_seg_lists));
-
- if (!initialized) {
- for (i = 0; i < ARRAY_SIZE(phys_seg_lists); i++)
- list_init(&phys_seg_lists[i]);
-
- phys_segs_size = 0;
- initialized = 1;
- }
-
- if (phys_segs_size >= ARRAY_SIZE(phys_segs))
- error_die(ERR_NORES);
-
- seg_list = &phys_seg_lists[seg_list_prio];
- seg = &phys_segs[phys_segs_size];
-
- list_insert_tail(seg_list, &seg->node);
- seg->start = start;
- seg->end = end;
- strncpy(seg->name, name, PHYS_NAME_SIZE);
- seg->name[sizeof(seg->name) - 1] = '\0';
-
- phys_segs_size++;
-}
-
-/*
- * Loading segments is normally done by architecture-specific code. In
- * this implementation, an Intel machine with two segments of RAM is
- * virtualized.
- */
-static void
-phys_load_segments(void)
-{
- phys_paddr_t start, end;
- size_t size;
- void *addr;
-
- /*
- * Load the ISADMA segment.
- */
- size = PHYS_ISADMA_LIMIT;
- addr = mmap(NULL, size, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-
- if (addr == MAP_FAILED)
- error_die(ERR_NOMEM);
-
- start = (phys_paddr_t)addr;
- end = start + size;
- phys_load_segment("isadma", start, end, PHYS_SEGLIST_ISADMA);
-
- /*
- * Load the normal segment.
- */
- size = PHYS_NORMAL_LIMIT - PHYS_ISADMA_LIMIT;
- addr = mmap(NULL, size, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-
- if (addr == MAP_FAILED)
- error_die(ERR_NOMEM);
-
- start = (phys_paddr_t)addr;
- end = start + size;
- phys_load_segment("normal", start, end, PHYS_SEGLIST_NORMAL);
-}
-
-void
-phys_setup(void)
-{
- struct phys_seg *seg, *map_seg;
- struct phys_page *page, *map;
- struct list *seg_list;
- phys_paddr_t map_size;
- unsigned int i;
-
- _pagesize = sysconf(_SC_PAGESIZE);
- assert(ISP2(_pagesize));
-
- phys_load_segments();
-
- /*
- * Compute the memory map size.
- */
- map_size = 0;
-
- for (i = 0; i < phys_segs_size; i++)
- map_size += phys_atop(phys_seg_size(&phys_segs[i]));
-
- map_size = P2ROUND(map_size * sizeof(struct phys_page), PAGE_SIZE);
-
- /*
- * Find a segment from which to allocate the memory map.
- */
- for (seg_list = &phys_seg_lists[ARRAY_SIZE(phys_seg_lists) - 1];
- seg_list >= phys_seg_lists;
- seg_list--)
- list_for_each_entry(seg_list, map_seg, node)
- if (map_size <= phys_seg_size(map_seg))
- goto found;
-
- error_die(ERR_NOMEM);
-
-found:
- /*
- * Allocate the memory map.
- */
- map = (struct phys_page *)phys_seg_start(map_seg);
-
- /*
- * Initialize the segments, associating them to the memory map. When
- * the segments are initialized, all their pages are set allocated,
- * with a block size of one (level 0). They are then released, which
- * populates the free lists.
- */
- for (i = 0; i < phys_segs_size; i++) {
- seg = &phys_segs[i];
- phys_seg_init(seg, map);
-
- /*
- * Don't release the memory map pages.
- *
- * XXX The memory map pages normally don't need descriptors, as they
- * are never released. This implementation however can be used in
- * cases where some memory is reserved at the start of all segments.
- * In order not to require descriptors for the memory map, the segment
- * where the map resides should be split. As it is quite cumbersome,
- * no effort is made here to avoid wasting descriptors and the pages
- * containing them.
- */
- if (seg == map_seg)
- page = seg->pages + phys_atop(map_size);
- else
- page = seg->pages;
-
- while (page < seg->pages_end) {
- phys_seg_free_to_buddy(seg, page, 0);
- page++;
- }
-
- map += phys_atop(phys_seg_size(seg));
- }
-}
-
-struct phys_page *
-phys_alloc_pages(phys_size_t size)
-{
- struct list *seg_list;
- struct phys_seg *seg;
- struct phys_page *page;
-
- for (seg_list = &phys_seg_lists[ARRAY_SIZE(phys_seg_lists) - 1];
- seg_list >= phys_seg_lists;
- seg_list--)
- list_for_each_entry(seg_list, seg, node) {
- page = phys_seg_alloc(seg, size);
-
- if (page != NULL)
- return page;
- }
-
- return NULL;
-}
-
-void
-phys_free_pages(struct phys_page *page, phys_size_t size)
-{
- phys_seg_free(page->seg, page, size);
-}
-
-phys_paddr_t
-phys_alloc(phys_size_t size)
-{
- struct phys_page *page;
-
- page = phys_alloc_pages(size);
-
- /*
- * XXX Rely on the system to never provide a virtual memory area
- * starting at 0.
- */
- if (page == NULL)
- return 0;
-
- return page->phys_addr;
-}
-
-void
-phys_free(phys_paddr_t pa, phys_size_t size)
-{
- struct phys_page *page;
-
- page = phys_page_lookup(pa);
- assert(page != NULL);
- phys_free_pages(page, size);
-}
-
-void
-phys_info(void)
-{
- struct phys_seg *seg;
- unsigned int i, j;
- char name[16];
-
- printf(" name");
-
- for (i = 0; i < PHYS_NR_FREE_LISTS; i++) {
- snprintf(name, sizeof(name), "#%u", (1 << i));
- printf(" %5s", name);
- }
-
- printf("\n");
-
- for (i = 0; i < phys_segs_size; i++) {
- seg = &phys_segs[i];
-
- printf("%8s", seg->name);
-
- pthread_mutex_lock(&seg->lock);
-
- for (j = 0; j < ARRAY_SIZE(seg->free_lists); j++)
- printf(" %5lu", seg->free_lists[j].size);
-
- pthread_mutex_unlock(&seg->lock);
-
- printf("\n");
- }
-}
diff --git a/phys.h b/phys.h
deleted file mode 100644
index 50efe1c..0000000
--- a/phys.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2011 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * Page allocator.
- */
-
-#ifndef _PHYS_H
-#define _PHYS_H
-
-#include "list.h"
-
-/*
- * Physical address.
- */
-typedef unsigned long phys_paddr_t;
-
-/*
- * Memory range size.
- */
-typedef unsigned long phys_size_t;
-
-/*
- * Page descriptor.
- */
-struct phys_page {
- struct list node;
- struct phys_seg *seg;
- phys_paddr_t phys_addr;
- unsigned int level;
-};
-
-void phys_setup(void);
-
-struct phys_page * phys_alloc_pages(phys_size_t size);
-
-void phys_free_pages(struct phys_page *page, phys_size_t size);
-
-phys_paddr_t phys_alloc(phys_size_t size);
-
-void phys_free(phys_paddr_t pa, phys_size_t size);
-
-void phys_info(void);
-
-#endif /* _PHYS_H */
diff --git a/test/test_mem.c b/test/test_mem.c
deleted file mode 100644
index eb7a56c..0000000
--- a/test/test_mem.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2010 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include "../mem.h"
-#include "../macros.h"
-
-#define STRING "This is a test string."
-#define STRING_SIZE (STRLEN(STRING) + 1)
-
-int
-main(int argc, char *argv[])
-{
- char *s;
-
- (void)argc;
- (void)argv;
-
- mem_setup();
-
- s = mem_alloc(STRING_SIZE);
-
- if (s == NULL) {
- fprintf(stderr, "unable to allocate memory\n");
- return 1;
- }
-
- strcpy(s, STRING);
- printf("string: '%s'\n", s);
- mem_free(s, STRING_SIZE);
-
- return 0;
-}
diff --git a/test/test_mem_cache.c b/test/test_mem_cache.c
deleted file mode 100644
index eaa043a..0000000
--- a/test/test_mem_cache.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (c) 2010, 2011 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <assert.h>
-#include <stddef.h>
-#include <pthread.h>
-
-#include <stdio.h>
-
-#include "../cpu.h"
-#include "../mem.c"
-#include "../error.c"
-#include "../avltree.c"
-
-#if CONFIG_MEM_USE_PHYS
-#include "../phys.c"
-#endif /* CONFIG_MEM_USE_PHYS */
-
-#define NTHREADS 4
-#define TEST_TIME 60
-#define OBJSPERLOOP 100
-
-struct result {
- unsigned long allocs;
- unsigned long frees;
-} __aligned(CPU_L1_SIZE);
-
-struct obj {
- unsigned long nr_refs;
- char name[16];
-};
-
-static void
-obj_ctor(void *ptr)
-{
- struct obj *obj;
-
- obj = ptr;
- obj->nr_refs = 0;
-}
-
-static struct mem_cache *obj_cache;
-static volatile int work;
-static struct result results[NTHREADS];
-
-static void *
-run(void *arg)
-{
- struct obj *objs[OBJSPERLOOP];
- struct result *result;
- int i, id;
-
- result = arg;
- id = result - results;
-
- mem_print("started");
-
- while (work) {
- for (i = 0; i < OBJSPERLOOP; i++) {
- objs[i] = mem_cache_alloc(obj_cache);
- result->allocs++;
- }
-
- for (i = 0; i < OBJSPERLOOP; i++) {
- mem_cache_free(obj_cache, objs[i]);
- result->frees++;
- }
- }
-
- return NULL;
-}
-
-int
-main(int argc, char *argv[])
-{
- pthread_t threads[NTHREADS];
- unsigned long ops;
- int i;
-
- (void)argc;
- (void)argv;
-
- mem_setup();
-
- mem_info();
-
- mem_print("Selected cache line size: %u", CPU_L1_SIZE);
- mem_print("sizeof(pthread_mutex_t): %zu", sizeof(pthread_mutex_t));
- mem_print("sizeof(struct mem_cpu_pool): %zu", sizeof(struct mem_cpu_pool));
- mem_print("sizeof(union mem_bufctl): %zu", sizeof(union mem_bufctl));
- mem_print("sizeof(struct mem_buftag): %zu", sizeof(struct mem_buftag));
- mem_print("sizeof(struct mem_slab): %zu", sizeof(struct mem_slab));
- mem_print("sizeof(struct mem_cache): %zu", sizeof(struct mem_cache));
- mem_print("sizeof(struct obj): %zu", sizeof(struct obj));
-
- obj_cache = mem_cache_create("obj", sizeof(struct obj), 0,
- obj_ctor, NULL, 0);
-
- memset(results, 0, sizeof(results));
- work = 1;
-
- for (i = 0; i < NTHREADS; i++)
- pthread_create(&threads[i], NULL, run, &results[i]);
-
- sleep(TEST_TIME);
- work = 0;
-
- for (i = 0; i < NTHREADS; i++)
- pthread_join(threads[i], NULL);
-
- ops = 0;
-
- for (i = 0; i < NTHREADS; i++)
- ops += results[i].allocs + results[i].frees;
-
- mem_info();
- mem_cache_info(obj_cache);
- mem_print("total: %lu ops in %d secs", ops, TEST_TIME);
-
- mem_cache_destroy(obj_cache);
-
- return 0;
-}
diff --git a/test/test_mem_cache_double_free.c b/test/test_mem_cache_double_free.c
deleted file mode 100644
index de356a3..0000000
--- a/test/test_mem_cache_double_free.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2010 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-
-#include "../mem.h"
-#include "../macros.h"
-
-struct obj {
- unsigned long nr_refs;
- char name[16];
-};
-
-static void
-obj_ctor(void *ptr)
-{
- struct obj *obj;
-
- obj = ptr;
- obj->nr_refs = 0;
-}
-
-int
-main(int argc, char *argv[])
-{
- struct mem_cache *obj_cache;
- struct obj *obj;
-
- (void)argc;
- (void)argv;
-
- mem_setup();
-
- obj_cache = mem_cache_create("obj", sizeof(struct obj), 0,
- obj_ctor, NULL, MEM_CACHE_VERIFY);
-
- printf("trying normal alloc+free:\n");
- obj = mem_cache_alloc(obj_cache);
- mem_cache_free(obj_cache, obj);
-
- mem_cache_info(obj_cache);
-
- printf("trying alloc+double free:\n");
- obj = mem_cache_alloc(obj_cache);
- mem_cache_free(obj_cache, obj);
- mem_cache_free(obj_cache, obj);
-
- printf("done\n");
-
- return 0;
-}
diff --git a/test/test_mem_cache_invalid_free.c b/test/test_mem_cache_invalid_free.c
deleted file mode 100644
index 767ee6b..0000000
--- a/test/test_mem_cache_invalid_free.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2010 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-
-#include "../mem.h"
-#include "../macros.h"
-
-struct obj {
- unsigned long nr_refs;
- char name[16];
-};
-
-static void
-obj_ctor(void *ptr)
-{
- struct obj *obj;
-
- obj = ptr;
- obj->nr_refs = 0;
-}
-
-int
-main(int argc, char *argv[])
-{
- struct mem_cache *obj_cache;
- struct obj *obj;
-
- (void)argc;
- (void)argv;
-
- mem_setup();
-
- obj_cache = mem_cache_create("obj", sizeof(struct obj), 0,
- obj_ctor, NULL, MEM_CACHE_VERIFY);
-
- printf("trying normal alloc+free:\n");
- obj = mem_cache_alloc(obj_cache);
- mem_cache_free(obj_cache, obj);
-
- mem_cache_info(obj_cache);
-
- printf("trying alloc+invalid free:\n");
- obj = mem_cache_alloc(obj_cache);
- mem_cache_free(obj_cache, (char *)obj + 1);
-
- printf("done\n");
-
- return 0;
-}
diff --git a/test/test_mem_cache_write_beyond.c b/test/test_mem_cache_write_beyond.c
deleted file mode 100644
index 05bea2e..0000000
--- a/test/test_mem_cache_write_beyond.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2010 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-
-#include "../mem.h"
-#include "../macros.h"
-
-struct obj {
- unsigned long nr_refs;
- char name[16];
-};
-
-static void
-obj_ctor(void *ptr)
-{
- struct obj *obj;
-
- obj = ptr;
- obj->nr_refs = 0;
-}
-
-static void
-obj_print(struct obj *obj, size_t size)
-{
- unsigned char *ptr, *end;
-
- printf("buffer content: ");
-
- for (ptr = (unsigned char *)obj, end = ptr + size; ptr < end; ptr++)
- printf("%02x", *ptr);
-
- printf("\n");
-}
-
-int
-main(int argc, char *argv[])
-{
- struct mem_cache *obj_cache;
- struct obj *obj;
- size_t buf_size;
-
- (void)argc;
- (void)argv;
-
- mem_setup();
-
- obj_cache = mem_cache_create("obj", sizeof(struct obj), 0,
- obj_ctor, NULL, MEM_CACHE_VERIFY);
- mem_cache_info(obj_cache);
-
- printf("doing normal alloc:\n");
- obj = mem_cache_alloc(obj_cache);
-
- printf("writing beyond object boundary:\n");
- strcpy(obj->name, "invalid write 000000");
- buf_size = P2ROUND(sizeof(*obj), 8);
- obj_print(obj, buf_size + (sizeof(unsigned long) * 2));
-
- printf("doing normal free:\n");
- mem_cache_free(obj_cache, obj);
-
- printf("done\n");
-
- return 0;
-}
diff --git a/test/test_mem_cache_write_buftag.c b/test/test_mem_cache_write_buftag.c
deleted file mode 100644
index 539d399..0000000
--- a/test/test_mem_cache_write_buftag.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2010 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-
-#include "../mem.h"
-#include "../macros.h"
-
-struct obj {
- unsigned long nr_refs;
- char name[16];
-};
-
-static void
-obj_ctor(void *ptr)
-{
- struct obj *obj;
-
- obj = ptr;
- obj->nr_refs = 0;
-}
-
-static void
-obj_print(struct obj *obj, size_t size)
-{
- unsigned char *ptr, *end;
-
- printf("buffer content: ");
-
- for (ptr = (unsigned char *)obj, end = ptr + size; ptr < end; ptr++)
- printf("%02x", *ptr);
-
- printf("\n");
-}
-
-int
-main(int argc, char *argv[])
-{
- struct mem_cache *obj_cache;
- struct obj *obj;
- unsigned long *ptr;
- size_t buf_size;
-
- (void)argc;
- (void)argv;
-
- mem_setup();
-
- obj_cache = mem_cache_create("obj", sizeof(struct obj), 0,
- obj_ctor, NULL, MEM_CACHE_VERIFY);
- mem_cache_info(obj_cache);
-
- printf("doing normal alloc:\n");
- obj = mem_cache_alloc(obj_cache);
-
- printf("writing garbage in buftag:\n");
- buf_size = P2ROUND(sizeof(*obj), 8);
- ptr = (void *)obj + buf_size + sizeof(unsigned long);
- *ptr = 0xed0000a1;
- obj_print(obj, buf_size + (sizeof(unsigned long) * 2));
-
- printf("doing normal free:\n");
- mem_cache_free(obj_cache, obj);
-
- printf("done\n");
-
- return 0;
-}
diff --git a/test/test_mem_cache_write_free.c b/test/test_mem_cache_write_free.c
deleted file mode 100644
index fd1c9db..0000000
--- a/test/test_mem_cache_write_free.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (c) 2010 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define _GNU_SOURCE
-#include <sched.h>
-
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-
-#include "../mem.h"
-#include "../macros.h"
-
-struct obj {
- unsigned long nr_refs;
- char name[16];
-};
-
-static void
-obj_ctor(void *ptr)
-{
- struct obj *obj;
-
- obj = ptr;
- obj->nr_refs = 0;
-}
-
-static void
-obj_print(struct obj *obj)
-{
- unsigned char *ptr, *end;
-
- printf("buffer content: ");
-
- for (ptr = (unsigned char *)obj, end = ptr + sizeof(*obj);
- ptr < end;
- ptr++)
- printf("%02x", *ptr);
-
- printf("\n");
-}
-
-int
-main(int argc, char *argv[])
-{
- struct mem_cache *obj_cache;
- struct obj *obj;
- cpu_set_t cpu_set;
-
- (void)argc;
- (void)argv;
-
- printf("binding to CPU 0\n");
- CPU_ZERO(&cpu_set);
- CPU_SET(0, &cpu_set);
- sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
-
- mem_setup();
-
- obj_cache = mem_cache_create("obj", sizeof(struct obj), 0,
- obj_ctor, NULL, MEM_CACHE_VERIFY);
-
- printf("doing normal alloc+free:\n");
- obj = mem_cache_alloc(obj_cache);
- mem_cache_free(obj_cache, obj);
-
- mem_cache_info(obj_cache);
-
- obj_print(obj);
-
- printf("doing write on free object:\n");
- memset((void *)obj + 3, 0x89, 5);
-
- obj_print(obj);
-
- printf("trying normal alloc+free on same CPU (should fail):\n");
-
- obj = mem_cache_alloc(obj_cache);
- mem_cache_free(obj_cache, obj);
-
- printf("done\n");
-
- return 0;
-}
diff --git a/test/test_mem_offbyone.c b/test/test_mem_offbyone.c
deleted file mode 100644
index b9e7d75..0000000
--- a/test/test_mem_offbyone.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2010 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include "../mem.h"
-
-#define BUFSIZE 200
-
-int
-main(int argc, char *argv[])
-{
- char *s;
-
- (void)argc;
- (void)argv;
-
- mem_setup();
-
- printf("allocating memory:\n");
- s = mem_alloc(BUFSIZE);
-
- if (s == NULL) {
- fprintf(stderr, "unable to allocate memory\n");
- return 1;
- }
-
- printf("writing beyond end of buffer:\n");
- memset(s, 'a', BUFSIZE + 1);
-
- printf("releasing buffer, should fail if CONFIG_MEM_VERIFY defined\n");
- mem_free(s, BUFSIZE);
-
- return 0;
-}
diff --git a/test/test_phys.c b/test/test_phys.c
deleted file mode 100644
index 5ded8d5..0000000
--- a/test/test_phys.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2011 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stddef.h>
-#include <string.h>
-
-#include "../error.c"
-#include "../phys.c"
-
-int
-main(int argc, char *argv[])
-{
- struct phys_page *page;
-
- (void)argc;
- (void)argv;
-
- phys_setup();
-
- phys_info();
- printf("sizeof(struct phys_cpu_pool) = %zu\n",
- sizeof(struct phys_cpu_pool));
- printf("sizeof(struct phys_free_list) = %zu\n",
- sizeof(struct phys_free_list));
- printf("sizeof(struct phys_page): %zu\n", sizeof(struct phys_page));
- printf("sizeof(struct phys_seg): %zu\n", sizeof(struct phys_seg));
- printf("allocating two pages\n");
- page = phys_alloc_pages(PAGE_SIZE * 2);
-
- if (page == NULL) {
- fprintf(stderr, "unable to allocate memory\n");
- return 1;
- }
-
- phys_info();
-
- printf("freeing the allocated pages\n");
- phys_free_pages(page, PAGE_SIZE * 2);
- phys_info();
-
- return 0;
-}
diff --git a/test/test_xprintf.c b/test/test_xprintf.c
deleted file mode 100644
index ff157b8..0000000
--- a/test/test_xprintf.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (c) 2010 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <assert.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include "../macros.h"
-#include "../xprintf.h"
-
-#define TEST_PRINTF(format, ...) \
-MACRO_BEGIN \
- char stra[256], strb[256]; \
- int la, lb; \
- la = snprintf(stra, 256, format, ## __VA_ARGS__); \
- printf(" printf: %s", stra); \
- lb = xsnprintf(strb, 256, format, ## __VA_ARGS__); \
- xprintf("xprintf: %s", stra); \
- assert(la == lb); \
- assert(strcmp(stra, strb) == 0); \
-MACRO_END
-
-int
-main(int argc, char *argv[])
-{
- (void)argc;
- (void)argv;
-
-#define FORMAT "%c"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 'a');
-#undef FORMAT
-
-#define FORMAT "%8c"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 'a');
-#undef FORMAT
-
-#define FORMAT "%-8c"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 'a');
-#undef FORMAT
-
-#define FORMAT "%.s"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, "12345");
-#undef FORMAT
-
-#define FORMAT "%.3s"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, "12345");
-#undef FORMAT
-
-#define FORMAT "%4.3s"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, "12345");
-#undef FORMAT
-
-#define FORMAT "%-4.3s"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, "12345");
-#undef FORMAT
-
-#define FORMAT "%3.4s"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, "12345");
-#undef FORMAT
-
-#define FORMAT "%-3.4s"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, "12345");
-#undef FORMAT
-
-#define FORMAT "%#o"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%#x"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%#X"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%08d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%-8d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%-08d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%0-8d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "% d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%+d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%+ d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%12d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%*d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 12, 123);
-#undef FORMAT
-
-#define FORMAT "%.12d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%.012d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%.*d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 12, 123);
-#undef FORMAT
-
-#define FORMAT "%.d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%.*d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, -12, 123);
-#undef FORMAT
-
-#define FORMAT "%.4d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%5.4d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%4.5d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 0);
-#undef FORMAT
-
-#define FORMAT "%.0d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 0);
-#undef FORMAT
-
-#define FORMAT "%.0o"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 0);
-#undef FORMAT
-
-#define FORMAT "%.0x"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 0);
-#undef FORMAT
-
-#define FORMAT "%1.0d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 0);
-#undef FORMAT
-
-#define FORMAT "%08.0d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, -123);
-#undef FORMAT
-
-#define FORMAT "%08d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, -123);
-#undef FORMAT
-
-#define FORMAT "%08d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%8d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%8d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, -123);
-#undef FORMAT
-
-#define FORMAT "%.8d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, -123);
-#undef FORMAT
-
-#define FORMAT "%.80d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, -123);
-#undef FORMAT
-
-#define FORMAT "%-80d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, -123);
-#undef FORMAT
-
-#define FORMAT "%80d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, -123);
-#undef FORMAT
-
-#define FORMAT "%80.40d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, -123);
-#undef FORMAT
-
-#define FORMAT "%-+80.40d"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%+x"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, -123);
-#undef FORMAT
-
-#define FORMAT "%#x"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%#o"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 123);
-#undef FORMAT
-
-#define FORMAT "%p"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, "123");
-#undef FORMAT
-
-#define FORMAT "%#lx"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 0xdeadbeefL);
-#undef FORMAT
-
-#define FORMAT "%zd"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, (size_t)-123);
-#undef FORMAT
-
-#define FORMAT "%#llx"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 0xdeadbeefbadcafeLL);
-#undef FORMAT
-
-#define FORMAT "%llo"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT, 0xffffffffffffffffLL);
-#undef FORMAT
-
-#define FORMAT "%%"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT);
-#undef FORMAT
-
-#define FORMAT "%y"
- TEST_PRINTF("%s: '" FORMAT "'\n", FORMAT);
-#undef FORMAT
-
- char stra[10], strb[10];
- int la, lb;
- la = snprintf(stra, sizeof(stra), "%s", "123456789a");
- printf(" printf: %s\n", stra);
- lb = xsnprintf(strb, sizeof(strb), "%s", "123456789a");
- xprintf("xprintf: %s\n", stra);
- assert(la == lb);
- assert(strncmp(stra, strb, 10) == 0);
-
-#define FORMAT "12%n3%#08x4%n5"
- int lc, ld;
- sprintf(stra, FORMAT, &la, 123, &lb);
- printf(" printf: la: %d, lb: %d\n", la, lb);
- xsprintf(strb, FORMAT, &lc, 123, &ld);
- xprintf("xprintf: lc: %d, ld: %d\n", lc, ld);
- assert(la == lc);
- assert(lb == ld);
-#undef FORMAT
-
- la = snprintf(NULL, 0, "%s", "123");
- printf(" printf: %d\n", la);
- lb = xsnprintf(NULL, 0, "%s", "123");
- xprintf("xprintf: %d\n", lb);
- assert(la == lb);
-
- return 0;
-}
diff --git a/xprintf.c b/xprintf.c
deleted file mode 100644
index 7efb786..0000000
--- a/xprintf.c
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- * Copyright (c) 2010 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <pthread.h>
-
-#include "xprintf.h"
-
-/*
- * Formatting flags.
- *
- * FORMAT_LOWER must be 0x20 as it is OR'd with digits, eg.
- * '0': 0x30 | 0x20 => 0x30 ('0')
- * 'A': 0x41 | 0x20 => 0x61 ('a')
- */
-#define FORMAT_ALT_FORM 0x01 /* "Alternate form" */
-#define FORMAT_ZERO_PAD 0x02 /* Zero padding on the left */
-#define FORMAT_LEFT_JUSTIFY 0x04 /* Align text on the left */
-#define FORMAT_BLANK 0x08 /* Blank space before positive number */
-#define FORMAT_SIGN 0x10 /* Always place a sign (either + or -) */
-#define FORMAT_LOWER 0x20 /* To lowercase (for %x) */
-#define FORMAT_CONV_SIGNED 0x40 /* Format specifies signed conversion */
-
-enum {
- MODIFIER_NONE,
- MODIFIER_CHAR,
- MODIFIER_SHORT,
- MODIFIER_LONG,
- MODIFIER_LONGLONG,
- MODIFIER_PTR, /* Used only for %p */
- MODIFIER_SIZE,
- MODIFIER_PTRDIFF
-};
-
-enum {
- SPECIFIER_INVALID,
- SPECIFIER_INT,
- SPECIFIER_CHAR,
- SPECIFIER_STR,
- SPECIFIER_NRCHARS,
- SPECIFIER_PERCENT
-};
-
-/*
- * Size for the temporary number buffer. The minimum base is 8 so 3 bits
- * are consumed per digit. Add one to round up. The conversion algorithm
- * doesn't use the null byte.
- */
-#define MAX_NUM_SIZE (((sizeof(unsigned long long) * CHAR_BIT) / 3) + 1)
-
-/*
- * Special size for xvsnprintf(), used by xsprintf()/xvsprintf() when the
- * buffer size is unknown.
- */
-#define XPRINT_NOLIMIT ((size_t)-1)
-
-/*
- * Size of the static buffer used by xprintf()/xvprintf().
- */
-#define XPRINT_BUFSIZE 1024
-
-static char xprint_buffer[XPRINT_BUFSIZE];
-static pthread_mutex_t xprint_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static const char digits[] = "0123456789ABCDEF";
-
-static inline char *
-xputchar(char *str, char *end, char c)
-{
- if (str < end)
- *str = c;
-
- str++;
-
- return str;
-}
-
-static inline int
-xisdigit(char c)
-{
- return (c >= '0') && (c <= '9');
-}
-
-int
-xprintf(const char *format, ...)
-{
- va_list ap;
- int length;
-
- va_start(ap, format);
- length = xvprintf(format, ap);
- va_end(ap);
-
- return length;
-}
-
-int
-xvprintf(const char *format, va_list ap)
-{
- size_t size;
- int length;
-
- pthread_mutex_lock(&xprint_mutex);
- length = xvsnprintf(xprint_buffer, sizeof(xprint_buffer), format, ap);
- size = ((unsigned int)length >= sizeof(xprint_buffer))
- ? sizeof(xprint_buffer) - 1
- : (unsigned int)length;
- fwrite(xprint_buffer, 1, size, stdout);
- pthread_mutex_unlock(&xprint_mutex);
-
- return length;
-}
-
-int
-xsprintf(char *str, const char *format, ...)
-{
- va_list ap;
- int length;
-
- va_start(ap, format);
- length = xvsprintf(str, format, ap);
- va_end(ap);
-
- return length;
-}
-
-int
-xvsprintf(char *str, const char *format, va_list ap)
-{
- return xvsnprintf(str, XPRINT_NOLIMIT, format, ap);
-}
-
-int
-xsnprintf(char *str, size_t size, const char *format, ...)
-{
- va_list ap;
- int length;
-
- va_start(ap, format);
- length = xvsnprintf(str, size, format, ap);
- va_end(ap);
-
- return length;
-}
-
-int
-xvsnprintf(char *str, size_t size, const char *format, va_list ap)
-{
- unsigned long long n;
- int i, len, found, flags, width, precision, modifier, specifier, shift;
- unsigned char r, base, mask;
- char c, *s, *start, *end, sign, tmp[MAX_NUM_SIZE];
-
- start = str;
-
- if (size == 0)
- end = NULL;
- else if (size == XPRINT_NOLIMIT)
- end = (char *)-1;
- else
- end = start + size - 1;
-
- while ((c = *format) != '\0') {
- if (c != '%') {
- str = xputchar(str, end, c);
- format++;
- continue;
- }
-
- /* Flags */
-
- found = 1;
- flags = 0;
-
- do {
- format++;
- c = *format;
-
- switch (c) {
- case '#':
- flags |= FORMAT_ALT_FORM;
- break;
- case '0':
- flags |= FORMAT_ZERO_PAD;
- break;
- case '-':
- flags |= FORMAT_LEFT_JUSTIFY;
- break;
- case ' ':
- flags |= FORMAT_BLANK;
- break;
- case '+':
- flags |= FORMAT_SIGN;
- break;
- default:
- found = 0;
- break;
- }
- } while (found);
-
- /* Width */
-
- if (xisdigit(c)) {
- width = 0;
-
- while (xisdigit(c)) {
- width = width * 10 + (c - '0');
- format++;
- c = *format;
- }
- } else if (c == '*') {
- width = va_arg(ap, int);
-
- if (width < 0) {
- flags |= FORMAT_LEFT_JUSTIFY;
- width = -width;
- }
-
- format++;
- c = *format;
- } else {
- width = 0;
- }
-
- /* Precision */
-
- if (c == '.') {
- format++;
- c = *format;
-
- if (xisdigit(c)) {
- precision = 0;
-
- while (xisdigit(c)) {
- precision = precision * 10 + (c - '0');
- format++;
- c = *format;
- }
- } else if (c == '*') {
- precision = va_arg(ap, int);
-
- if (precision < 0)
- precision = 0;
-
- format++;
- c = *format;
- } else {
- precision = 0;
- }
- } else {
- /* precision is >= 0 only if explicit */
- precision = -1;
- }
-
- /* Length modifier */
-
- switch (c) {
- case 'h':
- case 'l':
- format++;
-
- if (c == *format) {
- modifier = (c == 'h') ? MODIFIER_CHAR : MODIFIER_LONGLONG;
- goto skip_modifier;
- } else {
- modifier = (c == 'h') ? MODIFIER_SHORT : MODIFIER_LONG;
- c = *format;
- }
-
- break;
- case 'z':
- modifier = MODIFIER_SIZE;
- goto skip_modifier;
- case 't':
- modifier = MODIFIER_PTRDIFF;
-skip_modifier:
- format++;
- c = *format;
- break;
- default:
- modifier = MODIFIER_NONE;
- break;
- }
-
- /* Specifier */
-
- switch (c) {
- case 'd':
- case 'i':
- flags |= FORMAT_CONV_SIGNED;
- case 'u':
- base = 10;
- goto integer;
- case 'o':
- base = 8;
- goto integer;
- case 'p':
- flags |= FORMAT_ALT_FORM;
- modifier = MODIFIER_PTR;
- case 'x':
- flags |= FORMAT_LOWER;
- case 'X':
- base = 16;
-integer:
- specifier = SPECIFIER_INT;
- break;
- case 'c':
- specifier = SPECIFIER_CHAR;
- break;
- case 's':
- specifier = SPECIFIER_STR;
- break;
- case 'n':
- specifier = SPECIFIER_NRCHARS;
- break;
- case '%':
- specifier = SPECIFIER_PERCENT;
- break;
- default:
- specifier = SPECIFIER_INVALID;
- break;
- }
-
- /* Output */
-
- switch (specifier) {
- case SPECIFIER_INT:
- switch (modifier) {
- case MODIFIER_CHAR:
- if (flags & FORMAT_CONV_SIGNED)
- n = (signed char)va_arg(ap, int);
- else
- n = (unsigned char)va_arg(ap, int);
- break;
- case MODIFIER_SHORT:
- if (flags & FORMAT_CONV_SIGNED)
- n = (short)va_arg(ap, int);
- else
- n = (unsigned short)va_arg(ap, int);
- break;
- case MODIFIER_LONG:
- if (flags & FORMAT_CONV_SIGNED)
- n = va_arg(ap, long);
- else
- n = va_arg(ap, unsigned long);
- break;
- case MODIFIER_LONGLONG:
- if (flags & FORMAT_CONV_SIGNED)
- n = va_arg(ap, long long);
- else
- n = va_arg(ap, unsigned long long);
- break;
- case MODIFIER_PTR:
- n = (unsigned long)va_arg(ap, void *);
- break;
- case MODIFIER_SIZE:
- if (flags & FORMAT_CONV_SIGNED)
- n = va_arg(ap, ssize_t);
- else
- n = va_arg(ap, size_t);
- break;
- case MODIFIER_PTRDIFF:
- n = va_arg(ap, ptrdiff_t);
- break;
- default:
- if (flags & FORMAT_CONV_SIGNED)
- n = va_arg(ap, int);
- else
- n = va_arg(ap, unsigned int);
- break;
- }
-
- if ((flags & FORMAT_LEFT_JUSTIFY) || (precision >= 0))
- flags &= ~FORMAT_ZERO_PAD;
-
- sign = 0;
-
- if (flags & FORMAT_ALT_FORM) {
- /* '0' for octal */
- width--;
-
- /* '0x' or '0X' for hexadecimal */
- if (base == 16)
- width--;
- } else if (flags & FORMAT_CONV_SIGNED) {
- if ((long long)n < 0) {
- sign = '-';
- width--;
- n = -(long long)n;
- } else if (flags & FORMAT_SIGN) {
- /* FORMAT_SIGN must precede FORMAT_BLANK. */
- sign = '+';
- width--;
- } else if (flags & FORMAT_BLANK) {
- sign = ' ';
- width--;
- }
- }
-
- /* Conversion, in reverse order */
-
- i = 0;
-
- if (n == 0) {
- if (precision != 0)
- tmp[i++] = '0';
- } else if (base == 10) {
- /*
- * Try to avoid 64 bits operations if the processor doesn't
- * support them. Note that even when using modulus and
- * division operators close to each other, the compiler may
- * forge two calls to __udivdi3() and __umoddi3() instead of
- * one to __udivmoddi3(), whereas processor instructions are
- * generally correctly used once, giving both the remainder
- * and the quotient, through plain or reciprocal division.
- */
-#ifndef __LP64__
- if (modifier == MODIFIER_LONGLONG) {
-#endif /* __LP64__ */
- do {
- r = n % 10;
- n /= 10;
- tmp[i++] = digits[r];
- } while (n != 0);
-#ifndef __LP64__
- } else {
- unsigned long m;
-
- m = (unsigned long)n;
-
- do {
- r = m % 10;
- m /= 10;
- tmp[i++] = digits[r];
- } while (m != 0);
- }
-#endif /* __LP64__ */
- } else {
- mask = base - 1;
- shift = (base == 8) ? 3 : 4;
-
- do {
- r = (unsigned char)n & mask;
- n >>= shift;
- tmp[i++] = digits[r] | (flags & FORMAT_LOWER);
- } while (n != 0);
- }
-
- if (i > precision)
- precision = i;
-
- width -= precision;
-
- if (!(flags & (FORMAT_LEFT_JUSTIFY | FORMAT_ZERO_PAD)))
- while (width-- > 0)
- str = xputchar(str, end, ' ');
-
- if (flags & FORMAT_ALT_FORM) {
- str = xputchar(str, end, '0');
-
- if (base == 16)
- str = xputchar(str, end, 'X' | (flags & FORMAT_LOWER));
- } else if (sign) {
- str = xputchar(str, end, sign);
- }
-
- if (!(flags & FORMAT_LEFT_JUSTIFY)) {
- c = (flags & FORMAT_ZERO_PAD) ? '0' : ' ';
-
- while (width-- > 0)
- str = xputchar(str, end, c);
- }
-
- while (i < precision--)
- str = xputchar(str, end, '0');
-
- while (i-- > 0)
- str = xputchar(str, end, tmp[i]);
-
- while (width-- > 0)
- str = xputchar(str, end, ' ');
-
- break;
- case SPECIFIER_CHAR:
- c = (unsigned char)va_arg(ap, int);
-
- if (!(flags & FORMAT_LEFT_JUSTIFY))
- while (--width > 0)
- str = xputchar(str, end, ' ');
-
- str = xputchar(str, end, c);
-
- while (--width > 0)
- str = xputchar(str, end, ' ');
-
- break;
- case SPECIFIER_STR:
- s = va_arg(ap, char *);
-
- if (s == NULL)
- s = "(null)";
-
- len = 0;
-
- for (len = 0; s[len] != '\0'; len++)
- if (len == precision)
- break;
-
- if (!(flags & FORMAT_LEFT_JUSTIFY))
- while (len < width--)
- str = xputchar(str, end, ' ');
-
- for (i = 0; i < len; i++) {
- str = xputchar(str, end, *s);
- s++;
- }
-
- while (len < width--)
- str = xputchar(str, end, ' ');
-
- break;
- case SPECIFIER_NRCHARS:
- if (modifier == MODIFIER_CHAR) {
- signed char *ptr = va_arg(ap, signed char *);
- *ptr = str - start;
- } else if (modifier == MODIFIER_SHORT) {
- short *ptr = va_arg(ap, short *);
- *ptr = str - start;
- } else if (modifier == MODIFIER_LONG) {
- long *ptr = va_arg(ap, long *);
- *ptr = str - start;
- } else if (modifier == MODIFIER_LONGLONG) {
- long long *ptr = va_arg(ap, long long *);
- *ptr = str - start;
- } else if (modifier == MODIFIER_SIZE) {
- ssize_t *ptr = va_arg(ap, ssize_t *);
- *ptr = str - start;
- } else if (modifier == MODIFIER_PTRDIFF) {
- ptrdiff_t *ptr = va_arg(ap, ptrdiff_t *);
- *ptr = str - start;
- } else {
- int *ptr = va_arg(ap, int *);
- *ptr = str - start;
- }
-
- break;
- case SPECIFIER_PERCENT:
- case SPECIFIER_INVALID:
- str = xputchar(str, end, '%');
- break;
- default:
- break;
- }
-
- if (specifier != SPECIFIER_INVALID)
- format++;
- }
-
- if (str < end)
- *str = '\0';
- else if (end != NULL)
- *end = '\0';
-
- return str - start;
-}
diff --git a/xprintf.h b/xprintf.h
deleted file mode 100644
index 7634a9f..0000000
--- a/xprintf.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2010 Richard Braun.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * Formatted output functions.
- *
- * The functions provided by this module implement a subset of the C99
- * printf() like functions, mostly centered around character, string, and
- * integer conversions.
- *
- * The supported specifiers are: d i o u x X c s p n %
- * The supported length modifiers are: hh h l ll z t
- *
- * The xprintf() and xvprintf() functions internally use a statically
- * allocated buffer. Although they are thread-safe, they won't produce
- * output larger than 1 KiB.
- */
-
-#ifndef _XPRINTF_H
-#define _XPRINTF_H
-
-#include <stdarg.h>
-
-#include "macros.h"
-
-int xprintf(const char *format, ...) __format_printf(1, 2);
-int xvprintf(const char *format, va_list ap) __format_printf(1, 0);
-
-int xsprintf(char *str, const char *format, ...) __format_printf(2, 3);
-int xvsprintf(char *str, const char *format, va_list ap) __format_printf(2, 0);
-
-int xsnprintf(char *str, size_t size, const char *format, ...)
- __format_printf(3, 4);
-int xvsnprintf(char *str, size_t size, const char *format, va_list ap)
- __format_printf(3, 0);
-
-#endif /* _XPRINTF_H */