* | | | |
* p=p->ptr->ptr->ptr->ptr p->ptr p->ptr->ptr p->ptr->ptr->ptr
*/
-
-#define MIN_CORE_SIZE 0x80000
-
typedef struct header_t {
size_t size;
struct header_t *ptr;
} header_t;
typedef struct {
+ void *par;
+ size_t min_core_size;
header_t base, *loop_head, *core_head; /* base is a zero-sized block always kept in the loop */
} kmem_t;
abort();
}
-void *km_init(void)
+void *km_init2(void *km_par, size_t min_core_size)
{
- return calloc(1, sizeof(kmem_t));
+ kmem_t *km;
+ km = (kmem_t*)kcalloc(km_par, 1, sizeof(kmem_t));
+ km->par = km_par;
+ if (km_par) km->min_core_size = min_core_size > 0? min_core_size : ((kmem_t*)km_par)->min_core_size - 2;
+ else km->min_core_size = min_core_size > 0? min_core_size : 0x80000;
+ return (void*)km;
}
+void *km_init(void) { return km_init2(0, 0); }
+
void km_destroy(void *_km)
{
kmem_t *km = (kmem_t*)_km;
+ void *km_par;
header_t *p, *q;
if (km == NULL) return;
+ km_par = km->par;
for (p = km->core_head; p != NULL;) {
q = p->ptr;
- free(p);
+ kfree(km_par, p);
p = q;
}
- free(km);
+ kfree(km_par, km);
}
static header_t *morecore(kmem_t *km, size_t nu)
{
header_t *q;
size_t bytes, *p;
- nu = (nu + 1 + (MIN_CORE_SIZE - 1)) / MIN_CORE_SIZE * MIN_CORE_SIZE; /* the first +1 for core header */
+ nu = (nu + 1 + (km->min_core_size - 1)) / km->min_core_size * km->min_core_size; /* the first +1 for core header */
bytes = nu * sizeof(header_t);
- q = (header_t*)malloc(bytes);
+ q = (header_t*)kmalloc(km->par, bytes);
if (!q) panic("[morecore] insufficient memory");
q->ptr = km->core_head, q->size = nu, km->core_head = q;
p = (size_t*)(q + 1);
if (n_bytes == 0) return 0;
if (km == NULL) return malloc(n_bytes);
- n_units = (n_bytes + sizeof(size_t) + sizeof(header_t) - 1) / sizeof(header_t) + 1;
+ n_units = (n_bytes + sizeof(size_t) + sizeof(header_t) - 1) / sizeof(header_t); /* header+n_bytes requires at least this number of units */
if (!(q = km->loop_head)) /* the first time when kmalloc() is called, intialize it */
q = km->loop_head = km->base.ptr = &km->base;
void *krealloc(void *_km, void *ap, size_t n_bytes) // TODO: this can be made more efficient in principle
{
kmem_t *km = (kmem_t*)_km;
- size_t n_units, *p, *q;
+ size_t cap, *p, *q;
if (n_bytes == 0) {
kfree(km, ap); return 0;
}
if (km == NULL) return realloc(ap, n_bytes);
if (ap == NULL) return kmalloc(km, n_bytes);
- n_units = (n_bytes + sizeof(size_t) + sizeof(header_t) - 1) / sizeof(header_t);
p = (size_t*)ap - 1;
- if (*p >= n_units) return ap; /* TODO: this prevents shrinking */
+ cap = (*p) * sizeof(header_t) - sizeof(size_t);
+ if (cap >= n_bytes) return ap; /* TODO: this prevents shrinking */
q = (size_t*)kmalloc(km, n_bytes);
- memcpy(q, ap, (*p - 1) * sizeof(header_t));
+ memcpy(q, ap, cap);
kfree(km, ap);
return q;
}
+void *krelocate(void *km, void *ap, size_t n_bytes)
+{
+ void *p;
+ if (km == 0 || ap == 0) return ap;
+ p = kmalloc(km, n_bytes);
+ memcpy(p, ap, n_bytes);
+ kfree(km, ap);
+ return p;
+}
+
void km_stat(const void *_km, km_stat_t *s)
{
kmem_t *km = (kmem_t*)_km;
s->largest = s->largest > size? s->largest : size;
}
}
+
+void km_stat_print(const void *km)
+{
+ km_stat_t st;
+ km_stat(km, &st);
+ fprintf(stderr, "[km_stat] cap=%ld, avail=%ld, largest=%ld, n_core=%ld, n_block=%ld\n",
+ st.capacity, st.available, st.largest, st.n_blocks, st.n_cores);
+}
void *kmalloc(void *km, size_t size);
void *krealloc(void *km, void *ptr, size_t size);
+void *krelocate(void *km, void *ap, size_t n_bytes);
void *kcalloc(void *km, size_t count, size_t size);
void kfree(void *km, void *ptr);
void *km_init(void);
+void *km_init2(void *km_par, size_t min_core_size);
void km_destroy(void *km);
void km_stat(const void *_km, km_stat_t *s);
+void km_stat_print(const void *km);
#ifdef __cplusplus
}
#endif
+#define Kmalloc(km, type, cnt) ((type*)kmalloc((km), (cnt) * sizeof(type)))
+#define Kcalloc(km, type, cnt) ((type*)kcalloc((km), (cnt), sizeof(type)))
+#define Krealloc(km, type, ptr, cnt) ((type*)krealloc((km), (ptr), (cnt) * sizeof(type)))
+
+#define Kexpand(km, type, a, m) do { \
+ (m) = (m) >= 4? (m) + ((m)>>1) : 16; \
+ (a) = Krealloc(km, type, (a), (m)); \
+ } while (0)
+
+#define KMALLOC(km, ptr, len) ((ptr) = (__typeof__(ptr))kmalloc((km), (len) * sizeof(*(ptr))))
+#define KCALLOC(km, ptr, len) ((ptr) = (__typeof__(ptr))kcalloc((km), (len), sizeof(*(ptr))))
+#define KREALLOC(km, ptr, len) ((ptr) = (__typeof__(ptr))krealloc((km), (ptr), (len) * sizeof(*(ptr))))
+
+#define KEXPAND(km, a, m) do { \
+ (m) = (m) >= 4? (m) + ((m)>>1) : 16; \
+ KREALLOC((km), (a), (m)); \
+ } while (0)
+
+#ifndef klib_unused
+#if (defined __clang__ && __clang_major__ >= 3) || (defined __GNUC__ && __GNUC__ >= 3)
+#define klib_unused __attribute__ ((__unused__))
+#else
+#define klib_unused
+#endif
+#endif /* klib_unused */
+
+#define KALLOC_POOL_INIT2(SCOPE, name, kmptype_t) \
+ typedef struct { \
+ size_t cnt, n, max; \
+ kmptype_t **buf; \
+ void *km; \
+ } kmp_##name##_t; \
+ SCOPE kmp_##name##_t *kmp_init_##name(void *km) { \
+ kmp_##name##_t *mp; \
+ mp = Kcalloc(km, kmp_##name##_t, 1); \
+ mp->km = km; \
+ return mp; \
+ } \
+ SCOPE void kmp_destroy_##name(kmp_##name##_t *mp) { \
+ size_t k; \
+ for (k = 0; k < mp->n; ++k) kfree(mp->km, mp->buf[k]); \
+ kfree(mp->km, mp->buf); kfree(mp->km, mp); \
+ } \
+ SCOPE kmptype_t *kmp_alloc_##name(kmp_##name##_t *mp) { \
+ ++mp->cnt; \
+ if (mp->n == 0) return (kmptype_t*)kcalloc(mp->km, 1, sizeof(kmptype_t)); \
+ return mp->buf[--mp->n]; \
+ } \
+ SCOPE void kmp_free_##name(kmp_##name##_t *mp, kmptype_t *p) { \
+ --mp->cnt; \
+ if (mp->n == mp->max) Kexpand(mp->km, kmptype_t*, mp->buf, mp->max); \
+ mp->buf[mp->n++] = p; \
+ }
+
+#define KALLOC_POOL_INIT(name, kmptype_t) \
+ KALLOC_POOL_INIT2(static inline klib_unused, name, kmptype_t)
+
#endif