void * tfw_pool_alloc(TfwPool *p, size_t n) { void *a; n = TFW_POOL_ALIGN_SZ(n); if (unlikely(p->off + n > TFW_POOL_CHUNK_SZ(p))) { TfwPoolChunk *c, *curr = p->curr; unsigned int off = TFW_POOL_ALIGN_SZ(sizeof(TfwPoolChunk)) + n; unsigned int order = get_order(off); c = (TfwPoolChunk *)tfw_pool_alloc_pages(order); if (!c) return NULL; c->next = curr; c->order = order; curr->off = p->off; p->order = order; p->off = off; p->curr = c; return (void *)TFW_POOL_ALIGN_SZ((unsigned long)(c + 1)); } a = (char *)TFW_POOL_CHUNK_END(p); p->off += n; return a; }
void tfw_pool_free(TfwPool *p, void *ptr, size_t n) { TfwPoolChunk *c = p->curr; n = TFW_POOL_ALIGN_SZ(n); /* Stack-like usage is expected. */ if (likely((char *)ptr + n == (char *)TFW_POOL_CHUNK_END(c))) c->off -= n; /* Free empty chunk which doesn't contain the pool header. */ if (unlikely(c != tfw_pool_chunk_first(p) && c->off == TFW_POOL_ALIGN_SZ(sizeof(*c)))) { p->curr = c->next; tfw_pool_free_pages(TFW_POOL_CHUNK_BASE(c), c->order); } }
/** * It's good to call the function against just allocated chunk in stack-manner. * Consequent free calls can empty the whole pool but the first chunk with * the pool header. */ void tfw_pool_free(TfwPool *p, void *ptr, size_t n) { n = TFW_POOL_ALIGN_SZ(n); /* Stack-like usage is expected. */ if (unlikely((char *)ptr + n != (char *)TFW_POOL_CHUNK_END(p))) return; p->off -= n; /* Free empty chunk which doesn't contain the pool header. */ if (unlikely(p->off == TFW_POOL_ALIGN_SZ(sizeof(TfwPoolChunk)))) { TfwPoolChunk *next = p->curr->next; tfw_pool_free_pages(TFW_POOL_CHUNK_BASE(p->curr), p->order); p->curr = next; p->order = next->order; p->off = next->off; } }
/** * Allocate bit more pages than we need. */ TfwPool * __tfw_pool_new(size_t n) { TfwPool *p; TfwPoolChunk *c; unsigned int order; order = get_order(TFW_POOL_ALIGN_SZ(n) + TFW_POOL_HEAD_OFF); c = (TfwPoolChunk *)tfw_pool_alloc_pages(order); if (unlikely(!c)) return NULL; p = (TfwPool *)((char *)c + TFW_POOL_ALIGN_SZ(sizeof(*c))); c->next = NULL; p->order = c->order = order; p->off = c->off = TFW_POOL_HEAD_OFF; p->curr = c; return p; }
TfwPool * __tfw_pool_new(size_t n) { TfwPool *p; TfwPoolChunk *c; unsigned int order; order = get_order(TFW_POOL_ALIGN_SZ(n) + TFW_POOL_HEAD_OFF); p = (TfwPool *)tfw_pool_alloc_pages(order); if (!p) return NULL; c = tfw_pool_chunk_first(p); c->next = NULL; c->order = order; c->off = TFW_POOL_ALIGN_SZ((char *)(c + 1) - (char *)p); p->curr = c; return p; }
void * tfw_pool_realloc(TfwPool *p, void *ptr, size_t old_n, size_t new_n) { void *a; BUG_ON(new_n < old_n); old_n = TFW_POOL_ALIGN_SZ(old_n); new_n = TFW_POOL_ALIGN_SZ(new_n); if ((char *)ptr + old_n == (char *)TFW_POOL_CHUNK_END(p) && p->off - old_n + new_n <= TFW_POOL_CHUNK_SZ(p)) { p->off += new_n - old_n; return ptr; } a = tfw_pool_alloc(p, new_n); if (likely(a)) memcpy(a, ptr, old_n); return a; }
static inline TfwPoolChunk * tfw_pool_chunk_first(TfwPool *p) { return (TfwPoolChunk *)TFW_POOL_ALIGN_SZ((unsigned long)(p + 1)); }