#include <string.h>
#include "memblock.h"
+#include "xmalloc.h"
-static unsigned memblock_count = 0, memblock_total = 0;
+static void stat_add(struct pa_memblock*m, struct pa_memblock_stat *s) {
+ assert(m);
-struct pa_memblock *pa_memblock_new(size_t length) {
- struct pa_memblock *b = malloc(sizeof(struct pa_memblock)+length);
+ m->stat = pa_memblock_stat_ref(s);
+ s->total++;
+ s->allocated++;
+ s->total_size += m->length;
+ s->allocated_size += m->length;
+}
+
+static void stat_remove(struct pa_memblock *m) {
+ assert(m);
+
+ if (!m->stat)
+ return;
+
+ m->stat->total--;
+ m->stat->total_size -= m->length;
+
+ pa_memblock_stat_unref(m->stat);
+ m->stat = NULL;
+}
+
+struct pa_memblock *pa_memblock_new(size_t length, struct pa_memblock_stat*s) {
+ struct pa_memblock *b = pa_xmalloc(sizeof(struct pa_memblock)+length);
b->type = PA_MEMBLOCK_APPENDED;
b->ref = 1;
b->length = length;
b->data = b+1;
- memblock_count++;
- memblock_total += length;
+ b->free_cb = NULL;
+ stat_add(b, s);
return b;
}
-struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length) {
- struct pa_memblock *b = malloc(sizeof(struct pa_memblock));
+struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length, struct pa_memblock_stat*s) {
+ struct pa_memblock *b = pa_xmalloc(sizeof(struct pa_memblock));
b->type = PA_MEMBLOCK_FIXED;
b->ref = 1;
b->length = length;
b->data = d;
- memblock_count++;
- memblock_total += length;
+ b->free_cb = NULL;
+ stat_add(b, s);
return b;
}
-struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length) {
- struct pa_memblock *b = malloc(sizeof(struct pa_memblock));
+struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length, struct pa_memblock_stat*s) {
+ struct pa_memblock *b = pa_xmalloc(sizeof(struct pa_memblock));
b->type = PA_MEMBLOCK_DYNAMIC;
b->ref = 1;
b->length = length;
b->data = d;
- memblock_count++;
- memblock_total += length;
+ b->free_cb = NULL;
+ stat_add(b, s);
+ return b;
+}
+
+struct pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p), struct pa_memblock_stat*s) {
+ struct pa_memblock *b;
+ assert(d && length && free_cb);
+ b = pa_xmalloc(sizeof(struct pa_memblock));
+ b->type = PA_MEMBLOCK_USER;
+ b->ref = 1;
+ b->length = length;
+ b->data = d;
+ b->free_cb = free_cb;
+ stat_add(b, s);
return b;
}
void pa_memblock_unref(struct pa_memblock*b) {
assert(b && b->ref >= 1);
- b->ref--;
- if (b->ref == 0) {
- if (b->type == PA_MEMBLOCK_DYNAMIC)
- free(b->data);
+ if ((--(b->ref)) == 0) {
+ stat_remove(b);
- memblock_count--;
- memblock_total -= b->length;
+ if (b->type == PA_MEMBLOCK_USER) {
+ assert(b->free_cb);
+ b->free_cb(b->data);
+ } else if (b->type == PA_MEMBLOCK_DYNAMIC)
+ pa_xfree(b->data);
- free(b);
+ pa_xfree(b);
}
}
void pa_memblock_unref_fixed(struct pa_memblock *b) {
- void *d;
-
- assert(b && b->ref >= 1);
+ assert(b && b->ref >= 1 && b->type == PA_MEMBLOCK_FIXED);
- if (b->ref == 1) {
+ if (b->ref == 1)
pa_memblock_unref(b);
- return;
- } else {
- d = malloc(b->length);
- assert(d);
- memcpy(d, b->data, b->length);
- b->data = d;
+ else {
+ b->data = pa_xmemdup(b->data, b->length);
b->type = PA_MEMBLOCK_DYNAMIC;
b->ref--;
}
}
-unsigned pa_memblock_get_count(void) {
- return memblock_count;
+struct pa_memblock_stat* pa_memblock_stat_new(void) {
+ struct pa_memblock_stat *s;
+
+ s = pa_xmalloc(sizeof(struct pa_memblock_stat));
+ s->ref = 1;
+ s->total = s->total_size = s->allocated = s->allocated_size = 0;
+
+ return s;
+}
+
+void pa_memblock_stat_unref(struct pa_memblock_stat *s) {
+ assert(s && s->ref >= 1);
+
+ if (!(--(s->ref))) {
+ assert(!s->total);
+ pa_xfree(s);
+ }
}
-unsigned pa_memblock_get_total(void) {
- return memblock_total;
+struct pa_memblock_stat * pa_memblock_stat_ref(struct pa_memblock_stat *s) {
+ assert(s);
+ s->ref++;
+ return s;
}