pb_bufmgr_slab.c File Reference

S-lab pool implementation. More...

Include dependency graph for pb_bufmgr_slab.c:

Go to the source code of this file.

Data Structures

struct  pb_slab_buffer
 Buffer in a slab. More...
struct  pb_slab
 Slab -- a contiguous piece of memory. More...
struct  pb_slab_manager
 It adds/removes slabs as needed in order to meet the allocation/destruction of individual buffers. More...
struct  pb_slab_range_manager
 Wrapper around several slabs, therefore capable of handling buffers of multiple sizes. More...

Functions

static struct pb_slab_bufferpb_slab_buffer (struct pb_buffer *buf)
static struct pb_slab_managerpb_slab_manager (struct pb_manager *mgr)
static struct
pb_slab_range_manager
pb_slab_range_manager (struct pb_manager *mgr)
static void pb_slab_buffer_destroy (struct pb_buffer *_buf)
 Delete a buffer from the slab delayed list and put it on the slab FREE list.
static void * pb_slab_buffer_map (struct pb_buffer *_buf, unsigned flags)
static void pb_slab_buffer_unmap (struct pb_buffer *_buf)
static void pb_slab_buffer_get_base_buffer (struct pb_buffer *_buf, struct pb_buffer **base_buf, unsigned *offset)
static enum pipe_error pb_slab_create (struct pb_slab_manager *mgr)
 Create a new slab.
static struct pb_bufferpb_slab_manager_create_buffer (struct pb_manager *_mgr, size_t size, const struct pb_desc *desc)
static void pb_slab_manager_flush (struct pb_manager *_mgr)
static void pb_slab_manager_destroy (struct pb_manager *_mgr)
struct pb_managerpb_slab_manager_create (struct pb_manager *provider, size_t bufSize, size_t slabSize, const struct pb_desc *desc)
 Slab sub-allocator.
static struct pb_bufferpb_slab_range_manager_create_buffer (struct pb_manager *_mgr, size_t size, const struct pb_desc *desc)
static void pb_slab_range_manager_flush (struct pb_manager *_mgr)
static void pb_slab_range_manager_destroy (struct pb_manager *_mgr)
struct pb_managerpb_slab_range_manager_create (struct pb_manager *provider, size_t minBufSize, size_t maxBufSize, size_t slabSize, const struct pb_desc *desc)
 Allow a range of buffer size, by aggregating multiple slabs sub-allocators with different bucket sizes.

Variables

static struct pb_vtbl pb_slab_buffer_vtbl


Detailed Description

S-lab pool implementation.

See also:
http://en.wikipedia.org/wiki/Slab_allocation
Author:
Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>

Jose Fonseca <jrfonseca@tungstengraphics.com>

Definition in file pb_bufmgr_slab.c.


Function Documentation

static struct pb_slab_buffer* pb_slab_buffer ( struct pb_buffer buf  )  [static, read]

Definition at line 168 of file pb_bufmgr_slab.c.

References assert.

00169 {
00170    assert(buf);
00171    return (struct pb_slab_buffer *)buf;
00172 }

static void pb_slab_buffer_destroy ( struct pb_buffer _buf  )  [static]

Delete a buffer from the slab delayed list and put it on the slab FREE list.

Definition at line 196 of file pb_bufmgr_slab.c.

References assert, pb_buffer::base, pb_slab_buffer::base, pb_slab::bo, pb_slab::buffers, FREE, pb_slab::freeBuffers, pb_slab::head, pb_slab_buffer::head, list, LIST_ADDTAIL, LIST_DEL, LIST_DELINIT, pb_slab_buffer::mapCount, pb_slab::mgr, pb_slab_manager::mutex, list_head::next, pb_slab::numBuffers, pb_slab::numFree, pb_reference(), pb_slab_buffer(), pipe_mutex_lock, pipe_mutex_unlock, pipe_buffer::refcount, pb_slab_buffer::slab, and pb_slab_manager::slabs.

00197 {
00198    struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
00199    struct pb_slab *slab = buf->slab;
00200    struct pb_slab_manager *mgr = slab->mgr;
00201    struct list_head *list = &buf->head;
00202 
00203    pipe_mutex_lock(mgr->mutex);
00204    
00205    assert(buf->base.base.refcount == 0);
00206    
00207    buf->mapCount = 0;
00208 
00209    LIST_DEL(list);
00210    LIST_ADDTAIL(list, &slab->freeBuffers);
00211    slab->numFree++;
00212 
00213    if (slab->head.next == &slab->head)
00214       LIST_ADDTAIL(&slab->head, &mgr->slabs);
00215 
00216    /* If the slab becomes totally empty, free it */
00217    if (slab->numFree == slab->numBuffers) {
00218       list = &slab->head;
00219       LIST_DELINIT(list);
00220       pb_reference(&slab->bo, NULL);
00221       FREE(slab->buffers);
00222       FREE(slab);
00223    }
00224 
00225    pipe_mutex_unlock(mgr->mutex);
00226 }

static void pb_slab_buffer_get_base_buffer ( struct pb_buffer _buf,
struct pb_buffer **  base_buf,
unsigned *  offset 
) [static]

Definition at line 252 of file pb_bufmgr_slab.c.

References pb_slab::bo, pb_get_base_buffer(), pb_slab_buffer(), pb_slab_buffer::slab, and pb_slab_buffer::start.

00255 {
00256    struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
00257    pb_get_base_buffer(buf->slab->bo, base_buf, offset);
00258    *offset += buf->start;
00259 }

static void* pb_slab_buffer_map ( struct pb_buffer _buf,
unsigned  flags 
) [static]

Definition at line 230 of file pb_bufmgr_slab.c.

References pb_slab_buffer::mapCount, pb_slab_buffer(), pb_slab_buffer::slab, pb_slab_buffer::start, and pb_slab::virtual.

00232 {
00233    struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
00234 
00235    ++buf->mapCount;
00236    return (void *) ((uint8_t *) buf->slab->virtual + buf->start);
00237 }

static void pb_slab_buffer_unmap ( struct pb_buffer _buf  )  [static]

Definition at line 241 of file pb_bufmgr_slab.c.

References pb_slab_buffer::event, pb_slab_buffer::mapCount, pb_slab_buffer(), and pipe_condvar_broadcast.

00242 {
00243    struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
00244 
00245    --buf->mapCount;
00246    if (buf->mapCount == 0) 
00247        pipe_condvar_broadcast(buf->event);
00248 }

static enum pipe_error pb_slab_create ( struct pb_slab_manager mgr  )  [static]

Create a new slab.

Called when we ran out of free slabs.

Definition at line 277 of file pb_bufmgr_slab.c.

References pipe_buffer::alignment, pb_slab_buffer::base, pb_buffer::base, pb_slab::bo, pb_slab::buffers, pb_slab_manager::bufSize, CALLOC, CALLOC_STRUCT, pb_manager::create_buffer, pb_slab_manager::desc, pb_slab_buffer::event, FREE, pb_slab::freeBuffers, pb_slab_buffer::head, pb_slab::head, LIST_ADDTAIL, LIST_INITHEAD, pb_slab_buffer::mapCount, pb_slab::mgr, pb_slab::numBuffers, pb_slab::numFree, pb_map(), pb_reference(), pb_unmap(), PIPE_BUFFER_USAGE_CPU_READ, PIPE_BUFFER_USAGE_CPU_WRITE, pipe_condvar_init, PIPE_ERROR_OUT_OF_MEMORY, PIPE_OK, pb_slab_manager::provider, pipe_buffer::refcount, pipe_buffer::size, pb_slab_buffer::slab, pb_slab_manager::slabs, pb_slab_manager::slabSize, pb_slab_buffer::start, pipe_buffer::usage, pb_slab::virtual, and pb_buffer::vtbl.

00278 {
00279    struct pb_slab *slab;
00280    struct pb_slab_buffer *buf;
00281    unsigned numBuffers;
00282    unsigned i;
00283    enum pipe_error ret;
00284 
00285    slab = CALLOC_STRUCT(pb_slab);
00286    if (!slab)
00287       return PIPE_ERROR_OUT_OF_MEMORY;
00288 
00289    slab->bo = mgr->provider->create_buffer(mgr->provider, mgr->slabSize, &mgr->desc);
00290    if(!slab->bo) {
00291       ret = PIPE_ERROR_OUT_OF_MEMORY;
00292       goto out_err0;
00293    }
00294 
00295    /* Note down the slab virtual address. All mappings are accessed directly 
00296     * through this address so it is required that the buffer is pinned. */
00297    slab->virtual = pb_map(slab->bo, 
00298                           PIPE_BUFFER_USAGE_CPU_READ |
00299                           PIPE_BUFFER_USAGE_CPU_WRITE);
00300    if(!slab->virtual) {
00301       ret = PIPE_ERROR_OUT_OF_MEMORY;
00302       goto out_err1;
00303    }
00304    pb_unmap(slab->bo);
00305 
00306    numBuffers = slab->bo->base.size / mgr->bufSize;
00307 
00308    slab->buffers = CALLOC(numBuffers, sizeof(*slab->buffers));
00309    if (!slab->buffers) {
00310       ret = PIPE_ERROR_OUT_OF_MEMORY;
00311       goto out_err1;
00312    }
00313 
00314    LIST_INITHEAD(&slab->head);
00315    LIST_INITHEAD(&slab->freeBuffers);
00316    slab->numBuffers = numBuffers;
00317    slab->numFree = 0;
00318    slab->mgr = mgr;
00319 
00320    buf = slab->buffers;
00321    for (i=0; i < numBuffers; ++i) {
00322       buf->base.base.refcount = 0;
00323       buf->base.base.size = mgr->bufSize;
00324       buf->base.base.alignment = 0;
00325       buf->base.base.usage = 0;
00326       buf->base.vtbl = &pb_slab_buffer_vtbl;
00327       buf->slab = slab;
00328       buf->start = i* mgr->bufSize;
00329       buf->mapCount = 0;
00330       pipe_condvar_init(buf->event);
00331       LIST_ADDTAIL(&buf->head, &slab->freeBuffers);
00332       slab->numFree++;
00333       buf++;
00334    }
00335 
00336    /* Add this slab to the list of partial slabs */
00337    LIST_ADDTAIL(&slab->head, &mgr->slabs);
00338 
00339    return PIPE_OK;
00340 
00341 out_err1: 
00342    pb_reference(&slab->bo, NULL);
00343 out_err0: 
00344    FREE(slab);
00345    return ret;
00346 }

static struct pb_slab_manager* pb_slab_manager ( struct pb_manager mgr  )  [static, read]

Definition at line 176 of file pb_bufmgr_slab.c.

References assert.

00177 {
00178    assert(mgr);
00179    return (struct pb_slab_manager *)mgr;
00180 }

struct pb_manager* pb_slab_manager_create ( struct pb_manager provider,
size_t  bufSize,
size_t  slabSize,
const struct pb_desc desc 
) [read]

Slab sub-allocator.

Definition at line 431 of file pb_bufmgr_slab.c.

References pb_slab_manager::base, pb_slab_manager::bufSize, CALLOC_STRUCT, pb_manager::create_buffer, pb_slab_manager::desc, pb_manager::destroy, pb_manager::flush, LIST_INITHEAD, pb_slab_manager::mutex, pb_slab_manager_create_buffer(), pb_slab_manager_destroy(), pb_slab_manager_flush(), pipe_mutex_init, pb_slab_manager::provider, pb_slab_manager::slabs, and pb_slab_manager::slabSize.

00435 {
00436    struct pb_slab_manager *mgr;
00437 
00438    mgr = CALLOC_STRUCT(pb_slab_manager);
00439    if (!mgr)
00440       return NULL;
00441 
00442    mgr->base.destroy = pb_slab_manager_destroy;
00443    mgr->base.create_buffer = pb_slab_manager_create_buffer;
00444    mgr->base.flush = pb_slab_manager_flush;
00445 
00446    mgr->provider = provider;
00447    mgr->bufSize = bufSize;
00448    mgr->slabSize = slabSize;
00449    mgr->desc = *desc;
00450 
00451    LIST_INITHEAD(&mgr->slabs);
00452    
00453    pipe_mutex_init(mgr->mutex);
00454 
00455    return &mgr->base;
00456 }

static struct pb_buffer* pb_slab_manager_create_buffer ( struct pb_manager _mgr,
size_t  size,
const struct pb_desc desc 
) [static, read]

Definition at line 350 of file pb_bufmgr_slab.c.

References pipe_buffer::alignment, pb_desc::alignment, assert, pb_buffer::base, pb_slab_buffer::base, pb_slab_manager::bufSize, pb_slab_manager::desc, pb_slab::freeBuffers, list, LIST_DELINIT, LIST_ENTRY, pb_slab_manager::mutex, list_head::next, pb_slab::numFree, pb_check_alignment(), pb_check_usage(), pb_slab_create(), pb_slab_manager(), pipe_mutex_lock, pipe_mutex_unlock, pipe_buffer::refcount, pb_slab_manager::slabs, pipe_buffer::usage, and pb_desc::usage.

00353 {
00354    struct pb_slab_manager *mgr = pb_slab_manager(_mgr);
00355    static struct pb_slab_buffer *buf;
00356    struct pb_slab *slab;
00357    struct list_head *list;
00358 
00359    /* check size */
00360    assert(size <= mgr->bufSize);
00361    if(size > mgr->bufSize)
00362       return NULL;
00363    
00364    /* check if we can provide the requested alignment */
00365    assert(pb_check_alignment(desc->alignment, mgr->desc.alignment));
00366    if(!pb_check_alignment(desc->alignment, mgr->desc.alignment))
00367       return NULL;
00368    assert(pb_check_alignment(desc->alignment, mgr->bufSize));
00369    if(!pb_check_alignment(desc->alignment, mgr->bufSize))
00370       return NULL;
00371 
00372    assert(pb_check_usage(desc->usage, mgr->desc.usage));
00373    if(!pb_check_usage(desc->usage, mgr->desc.usage))
00374       return NULL;
00375 
00376    pipe_mutex_lock(mgr->mutex);
00377    
00378    /* Create a new slab, if we run out of partial slabs */
00379    if (mgr->slabs.next == &mgr->slabs) {
00380       (void) pb_slab_create(mgr);
00381       if (mgr->slabs.next == &mgr->slabs) {
00382          pipe_mutex_unlock(mgr->mutex);
00383          return NULL;
00384       }
00385    }
00386    
00387    /* Allocate the buffer from a partial (or just created) slab */
00388    list = mgr->slabs.next;
00389    slab = LIST_ENTRY(struct pb_slab, list, head);
00390    
00391    /* If totally full remove from the partial slab list */
00392    if (--slab->numFree == 0)
00393       LIST_DELINIT(list);
00394 
00395    list = slab->freeBuffers.next;
00396    LIST_DELINIT(list);
00397 
00398    pipe_mutex_unlock(mgr->mutex);
00399    buf = LIST_ENTRY(struct pb_slab_buffer, list, head);
00400    
00401    ++buf->base.base.refcount;
00402    buf->base.base.alignment = desc->alignment;
00403    buf->base.base.usage = desc->usage;
00404    
00405    return &buf->base;
00406 }

static void pb_slab_manager_destroy ( struct pb_manager _mgr  )  [static]

Definition at line 421 of file pb_bufmgr_slab.c.

References FREE, and pb_slab_manager().

00422 {
00423    struct pb_slab_manager *mgr = pb_slab_manager(_mgr);
00424 
00425    /* TODO: cleanup all allocated buffers */
00426    FREE(mgr);
00427 }

static void pb_slab_manager_flush ( struct pb_manager _mgr  )  [static]

Definition at line 410 of file pb_bufmgr_slab.c.

References assert, pb_manager::flush, pb_slab_manager(), and pb_slab_manager::provider.

00411 {
00412    struct pb_slab_manager *mgr = pb_slab_manager(_mgr);
00413 
00414    assert(mgr->provider->flush);
00415    if(mgr->provider->flush)
00416       mgr->provider->flush(mgr->provider);
00417 }

static struct pb_slab_range_manager* pb_slab_range_manager ( struct pb_manager mgr  )  [static, read]

Definition at line 184 of file pb_bufmgr_slab.c.

References assert.

00185 {
00186    assert(mgr);
00187    return (struct pb_slab_range_manager *)mgr;
00188 }

struct pb_manager* pb_slab_range_manager_create ( struct pb_manager provider,
size_t  minBufSize,
size_t  maxBufSize,
size_t  slabSize,
const struct pb_desc desc 
) [read]

Allow a range of buffer size, by aggregating multiple slabs sub-allocators with different bucket sizes.

Definition at line 508 of file pb_bufmgr_slab.c.

References pb_slab_range_manager::base, pb_slab_range_manager::buckets, CALLOC, CALLOC_STRUCT, pb_manager::create_buffer, pb_manager::destroy, pb_manager::flush, FREE, pb_slab_range_manager::maxBufSize, pb_slab_range_manager::minBufSize, pb_slab_range_manager::numBuckets, pb_slab_manager_create(), pb_slab_range_manager_create_buffer(), pb_slab_range_manager_destroy(), pb_slab_range_manager_flush(), and pb_slab_range_manager::provider.

00513 {
00514    struct pb_slab_range_manager *mgr;
00515    size_t bufSize;
00516    unsigned i;
00517 
00518    if(!provider)
00519       return NULL;
00520    
00521    mgr = CALLOC_STRUCT(pb_slab_range_manager);
00522    if (!mgr)
00523       goto out_err0;
00524 
00525    mgr->base.destroy = pb_slab_range_manager_destroy;
00526    mgr->base.create_buffer = pb_slab_range_manager_create_buffer;
00527    mgr->base.flush = pb_slab_range_manager_flush;
00528 
00529    mgr->provider = provider;
00530    mgr->minBufSize = minBufSize;
00531    mgr->maxBufSize = maxBufSize;
00532 
00533    mgr->numBuckets = 1;
00534    bufSize = minBufSize;
00535    while(bufSize < maxBufSize) {
00536       bufSize *= 2;
00537       ++mgr->numBuckets;
00538    }
00539    
00540    mgr->buckets = CALLOC(mgr->numBuckets, sizeof(*mgr->buckets));
00541    if (!mgr->buckets)
00542       goto out_err1;
00543 
00544    bufSize = minBufSize;
00545    for (i = 0; i < mgr->numBuckets; ++i) {
00546       mgr->buckets[i] = pb_slab_manager_create(provider, bufSize, slabSize, desc);
00547       if(!mgr->buckets[i])
00548          goto out_err2;
00549       bufSize *= 2;
00550    }
00551 
00552    return &mgr->base;
00553 
00554 out_err2: 
00555    for (i = 0; i < mgr->numBuckets; ++i)
00556       if(mgr->buckets[i])
00557             mgr->buckets[i]->destroy(mgr->buckets[i]);
00558    FREE(mgr->buckets);
00559 out_err1: 
00560    FREE(mgr);
00561 out_err0:
00562    return NULL;
00563 }

static struct pb_buffer* pb_slab_range_manager_create_buffer ( struct pb_manager _mgr,
size_t  size,
const struct pb_desc desc 
) [static, read]

Definition at line 460 of file pb_bufmgr_slab.c.

References pb_slab_range_manager::buckets, pb_manager::create_buffer, pb_slab_range_manager::minBufSize, pb_slab_range_manager::numBuckets, pb_slab_range_manager(), and pb_slab_range_manager::provider.

00463 {
00464    struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr);
00465    size_t bufSize;
00466    unsigned i;
00467 
00468    bufSize = mgr->minBufSize;
00469    for (i = 0; i < mgr->numBuckets; ++i) {
00470       if(bufSize >= size)
00471          return mgr->buckets[i]->create_buffer(mgr->buckets[i], size, desc);
00472       bufSize *= 2;
00473    }
00474 
00475    /* Fall back to allocate a buffer object directly from the provider. */
00476    return mgr->provider->create_buffer(mgr->provider, size, desc);
00477 }

static void pb_slab_range_manager_destroy ( struct pb_manager _mgr  )  [static]

Definition at line 494 of file pb_bufmgr_slab.c.

References pb_slab_range_manager::buckets, pb_slab_range_manager::bucketSizes, pb_manager::destroy, FREE, pb_slab_range_manager::numBuckets, and pb_slab_range_manager().

00495 {
00496    struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr);
00497    unsigned i;
00498    
00499    for (i = 0; i < mgr->numBuckets; ++i)
00500       mgr->buckets[i]->destroy(mgr->buckets[i]);
00501    FREE(mgr->buckets);
00502    FREE(mgr->bucketSizes);
00503    FREE(mgr);
00504 }

static void pb_slab_range_manager_flush ( struct pb_manager _mgr  )  [static]

Definition at line 481 of file pb_bufmgr_slab.c.

References assert, pb_manager::flush, pb_slab_range_manager(), and pb_slab_range_manager::provider.

00482 {
00483    struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr);
00484 
00485    /* Individual slabs don't hold any temporary buffers so no need to call them */
00486    
00487    assert(mgr->provider->flush);
00488    if(mgr->provider->flush)
00489       mgr->provider->flush(mgr->provider);
00490 }


Variable Documentation

struct pb_vtbl pb_slab_buffer_vtbl [static]

Initial value:

Definition at line 263 of file pb_bufmgr_slab.c.


Generated on Tue Sep 29 06:25:24 2009 for Gallium3D by  doxygen 1.5.4