1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2006-2008 VMware, Inc., USA 4bf215546Sopenharmony_ci * All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, FREE of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 17bf215546Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 18bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 21bf215546Sopenharmony_ci * 22bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 23bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 24bf215546Sopenharmony_ci * of the Software. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci * 27bf215546Sopenharmony_ci **************************************************************************/ 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci/** 30bf215546Sopenharmony_ci * @file 31bf215546Sopenharmony_ci * S-lab pool implementation. 32bf215546Sopenharmony_ci * 33bf215546Sopenharmony_ci * @sa http://en.wikipedia.org/wiki/Slab_allocation 34bf215546Sopenharmony_ci * 35bf215546Sopenharmony_ci * @author Thomas Hellstrom <thellstrom-at-vmware-dot-com> 36bf215546Sopenharmony_ci * @author Jose Fonseca <jfonseca@vmware.com> 37bf215546Sopenharmony_ci */ 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci#include "pipe/p_compiler.h" 40bf215546Sopenharmony_ci#include "util/u_debug.h" 41bf215546Sopenharmony_ci#include "os/os_thread.h" 42bf215546Sopenharmony_ci#include "pipe/p_defines.h" 43bf215546Sopenharmony_ci#include "util/u_memory.h" 44bf215546Sopenharmony_ci#include "util/list.h" 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci#include "pb_buffer.h" 47bf215546Sopenharmony_ci#include "pb_bufmgr.h" 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_cistruct pb_slab; 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_ci/** 54bf215546Sopenharmony_ci * Buffer in a slab. 55bf215546Sopenharmony_ci * 56bf215546Sopenharmony_ci * Sub-allocation of a contiguous buffer. 57bf215546Sopenharmony_ci */ 58bf215546Sopenharmony_cistruct pb_slab_buffer 59bf215546Sopenharmony_ci{ 60bf215546Sopenharmony_ci struct pb_buffer base; 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci struct pb_slab *slab; 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci struct list_head head; 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci unsigned mapCount; 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci /** Offset relative to the start of the slab buffer. */ 69bf215546Sopenharmony_ci pb_size start; 70bf215546Sopenharmony_ci}; 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci/** 74bf215546Sopenharmony_ci * Slab -- a contiguous piece of memory. 75bf215546Sopenharmony_ci */ 76bf215546Sopenharmony_cistruct pb_slab 77bf215546Sopenharmony_ci{ 78bf215546Sopenharmony_ci struct list_head head; 79bf215546Sopenharmony_ci struct list_head freeBuffers; 80bf215546Sopenharmony_ci pb_size numBuffers; 81bf215546Sopenharmony_ci pb_size numFree; 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci struct pb_slab_buffer *buffers; 84bf215546Sopenharmony_ci struct pb_slab_manager *mgr; 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci /** Buffer from the provider */ 87bf215546Sopenharmony_ci struct pb_buffer *bo; 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci void *virtual; 90bf215546Sopenharmony_ci}; 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci/** 94bf215546Sopenharmony_ci * It adds/removes slabs as needed in order to meet the allocation/destruction 95bf215546Sopenharmony_ci * of individual buffers. 96bf215546Sopenharmony_ci */ 97bf215546Sopenharmony_cistruct pb_slab_manager 98bf215546Sopenharmony_ci{ 99bf215546Sopenharmony_ci struct pb_manager base; 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci /** From where we get our buffers */ 102bf215546Sopenharmony_ci struct pb_manager *provider; 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_ci /** Size of the buffers we hand on downstream */ 105bf215546Sopenharmony_ci pb_size bufSize; 106bf215546Sopenharmony_ci 107bf215546Sopenharmony_ci /** Size of the buffers we request upstream */ 108bf215546Sopenharmony_ci pb_size slabSize; 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci /** 111bf215546Sopenharmony_ci * Alignment, usage to be used to allocate the slab buffers. 112bf215546Sopenharmony_ci * 113bf215546Sopenharmony_ci * We can only provide buffers which are consistent (in alignment, usage) 114bf215546Sopenharmony_ci * with this description. 115bf215546Sopenharmony_ci */ 116bf215546Sopenharmony_ci struct pb_desc desc; 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci /** 119bf215546Sopenharmony_ci * Partial slabs 120bf215546Sopenharmony_ci * 121bf215546Sopenharmony_ci * Full slabs are not stored in any list. Empty slabs are destroyed 122bf215546Sopenharmony_ci * immediatly. 123bf215546Sopenharmony_ci */ 124bf215546Sopenharmony_ci struct list_head slabs; 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci mtx_t mutex; 127bf215546Sopenharmony_ci}; 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci/** 131bf215546Sopenharmony_ci * Wrapper around several slabs, therefore capable of handling buffers of 132bf215546Sopenharmony_ci * multiple sizes. 133bf215546Sopenharmony_ci * 134bf215546Sopenharmony_ci * This buffer manager just dispatches buffer allocations to the appropriate slab 135bf215546Sopenharmony_ci * manager, according to the requested buffer size, or by passes the slab 136bf215546Sopenharmony_ci * managers altogether for even greater sizes. 137bf215546Sopenharmony_ci * 138bf215546Sopenharmony_ci * The data of this structure remains constant after 139bf215546Sopenharmony_ci * initialization and thus needs no mutex protection. 140bf215546Sopenharmony_ci */ 141bf215546Sopenharmony_cistruct pb_slab_range_manager 142bf215546Sopenharmony_ci{ 143bf215546Sopenharmony_ci struct pb_manager base; 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci struct pb_manager *provider; 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci pb_size minBufSize; 148bf215546Sopenharmony_ci pb_size maxBufSize; 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci /** @sa pb_slab_manager::desc */ 151bf215546Sopenharmony_ci struct pb_desc desc; 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci unsigned numBuckets; 154bf215546Sopenharmony_ci pb_size *bucketSizes; 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci /** Array of pb_slab_manager, one for each bucket size */ 157bf215546Sopenharmony_ci struct pb_manager **buckets; 158bf215546Sopenharmony_ci}; 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_cistatic inline struct pb_slab_buffer * 162bf215546Sopenharmony_cipb_slab_buffer(struct pb_buffer *buf) 163bf215546Sopenharmony_ci{ 164bf215546Sopenharmony_ci assert(buf); 165bf215546Sopenharmony_ci return (struct pb_slab_buffer *)buf; 166bf215546Sopenharmony_ci} 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_cistatic inline struct pb_slab_manager * 170bf215546Sopenharmony_cipb_slab_manager(struct pb_manager *mgr) 171bf215546Sopenharmony_ci{ 172bf215546Sopenharmony_ci assert(mgr); 173bf215546Sopenharmony_ci return (struct pb_slab_manager *)mgr; 174bf215546Sopenharmony_ci} 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_cistatic inline struct pb_slab_range_manager * 178bf215546Sopenharmony_cipb_slab_range_manager(struct pb_manager *mgr) 179bf215546Sopenharmony_ci{ 180bf215546Sopenharmony_ci assert(mgr); 181bf215546Sopenharmony_ci return (struct pb_slab_range_manager *)mgr; 182bf215546Sopenharmony_ci} 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci/** 186bf215546Sopenharmony_ci * Delete a buffer from the slab delayed list and put 187bf215546Sopenharmony_ci * it on the slab FREE list. 188bf215546Sopenharmony_ci */ 189bf215546Sopenharmony_cistatic void 190bf215546Sopenharmony_cipb_slab_buffer_destroy(void *winsys, struct pb_buffer *_buf) 191bf215546Sopenharmony_ci{ 192bf215546Sopenharmony_ci struct pb_slab_buffer *buf = pb_slab_buffer(_buf); 193bf215546Sopenharmony_ci struct pb_slab *slab = buf->slab; 194bf215546Sopenharmony_ci struct pb_slab_manager *mgr = slab->mgr; 195bf215546Sopenharmony_ci struct list_head *list = &buf->head; 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci mtx_lock(&mgr->mutex); 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci assert(!pipe_is_referenced(&buf->base.reference)); 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci buf->mapCount = 0; 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci list_del(list); 204bf215546Sopenharmony_ci list_addtail(list, &slab->freeBuffers); 205bf215546Sopenharmony_ci slab->numFree++; 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_ci if (slab->head.next == &slab->head) 208bf215546Sopenharmony_ci list_addtail(&slab->head, &mgr->slabs); 209bf215546Sopenharmony_ci 210bf215546Sopenharmony_ci /* If the slab becomes totally empty, free it */ 211bf215546Sopenharmony_ci if (slab->numFree == slab->numBuffers) { 212bf215546Sopenharmony_ci list = &slab->head; 213bf215546Sopenharmony_ci list_delinit(list); 214bf215546Sopenharmony_ci pb_unmap(slab->bo); 215bf215546Sopenharmony_ci pb_reference(&slab->bo, NULL); 216bf215546Sopenharmony_ci FREE(slab->buffers); 217bf215546Sopenharmony_ci FREE(slab); 218bf215546Sopenharmony_ci } 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci mtx_unlock(&mgr->mutex); 221bf215546Sopenharmony_ci} 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_cistatic void * 225bf215546Sopenharmony_cipb_slab_buffer_map(struct pb_buffer *_buf, 226bf215546Sopenharmony_ci enum pb_usage_flags flags, 227bf215546Sopenharmony_ci void *flush_ctx) 228bf215546Sopenharmony_ci{ 229bf215546Sopenharmony_ci struct pb_slab_buffer *buf = pb_slab_buffer(_buf); 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci /* XXX: it will be necessary to remap here to propagate flush_ctx */ 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci ++buf->mapCount; 234bf215546Sopenharmony_ci return (void *) ((uint8_t *) buf->slab->virtual + buf->start); 235bf215546Sopenharmony_ci} 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_cistatic void 239bf215546Sopenharmony_cipb_slab_buffer_unmap(struct pb_buffer *_buf) 240bf215546Sopenharmony_ci{ 241bf215546Sopenharmony_ci struct pb_slab_buffer *buf = pb_slab_buffer(_buf); 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci --buf->mapCount; 244bf215546Sopenharmony_ci} 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_cistatic enum pipe_error 248bf215546Sopenharmony_cipb_slab_buffer_validate(struct pb_buffer *_buf, 249bf215546Sopenharmony_ci struct pb_validate *vl, 250bf215546Sopenharmony_ci enum pb_usage_flags flags) 251bf215546Sopenharmony_ci{ 252bf215546Sopenharmony_ci struct pb_slab_buffer *buf = pb_slab_buffer(_buf); 253bf215546Sopenharmony_ci return pb_validate(buf->slab->bo, vl, flags); 254bf215546Sopenharmony_ci} 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_cistatic void 258bf215546Sopenharmony_cipb_slab_buffer_fence(struct pb_buffer *_buf, 259bf215546Sopenharmony_ci struct pipe_fence_handle *fence) 260bf215546Sopenharmony_ci{ 261bf215546Sopenharmony_ci struct pb_slab_buffer *buf = pb_slab_buffer(_buf); 262bf215546Sopenharmony_ci pb_fence(buf->slab->bo, fence); 263bf215546Sopenharmony_ci} 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_cistatic void 267bf215546Sopenharmony_cipb_slab_buffer_get_base_buffer(struct pb_buffer *_buf, 268bf215546Sopenharmony_ci struct pb_buffer **base_buf, 269bf215546Sopenharmony_ci pb_size *offset) 270bf215546Sopenharmony_ci{ 271bf215546Sopenharmony_ci struct pb_slab_buffer *buf = pb_slab_buffer(_buf); 272bf215546Sopenharmony_ci pb_get_base_buffer(buf->slab->bo, base_buf, offset); 273bf215546Sopenharmony_ci *offset += buf->start; 274bf215546Sopenharmony_ci} 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_cistatic const struct pb_vtbl 278bf215546Sopenharmony_cipb_slab_buffer_vtbl = { 279bf215546Sopenharmony_ci pb_slab_buffer_destroy, 280bf215546Sopenharmony_ci pb_slab_buffer_map, 281bf215546Sopenharmony_ci pb_slab_buffer_unmap, 282bf215546Sopenharmony_ci pb_slab_buffer_validate, 283bf215546Sopenharmony_ci pb_slab_buffer_fence, 284bf215546Sopenharmony_ci pb_slab_buffer_get_base_buffer 285bf215546Sopenharmony_ci}; 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci 288bf215546Sopenharmony_ci/** 289bf215546Sopenharmony_ci * Create a new slab. 290bf215546Sopenharmony_ci * 291bf215546Sopenharmony_ci * Called when we ran out of free slabs. 292bf215546Sopenharmony_ci */ 293bf215546Sopenharmony_cistatic enum pipe_error 294bf215546Sopenharmony_cipb_slab_create(struct pb_slab_manager *mgr) 295bf215546Sopenharmony_ci{ 296bf215546Sopenharmony_ci struct pb_slab *slab; 297bf215546Sopenharmony_ci struct pb_slab_buffer *buf; 298bf215546Sopenharmony_ci unsigned numBuffers; 299bf215546Sopenharmony_ci unsigned i; 300bf215546Sopenharmony_ci enum pipe_error ret; 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_ci slab = CALLOC_STRUCT(pb_slab); 303bf215546Sopenharmony_ci if (!slab) 304bf215546Sopenharmony_ci return PIPE_ERROR_OUT_OF_MEMORY; 305bf215546Sopenharmony_ci 306bf215546Sopenharmony_ci slab->bo = mgr->provider->create_buffer(mgr->provider, mgr->slabSize, &mgr->desc); 307bf215546Sopenharmony_ci if(!slab->bo) { 308bf215546Sopenharmony_ci ret = PIPE_ERROR_OUT_OF_MEMORY; 309bf215546Sopenharmony_ci goto out_err0; 310bf215546Sopenharmony_ci } 311bf215546Sopenharmony_ci 312bf215546Sopenharmony_ci /* Note down the slab virtual address. All mappings are accessed directly 313bf215546Sopenharmony_ci * through this address so it is required that the buffer is mapped 314bf215546Sopenharmony_ci * persistent */ 315bf215546Sopenharmony_ci slab->virtual = pb_map(slab->bo, 316bf215546Sopenharmony_ci PB_USAGE_CPU_READ | 317bf215546Sopenharmony_ci PB_USAGE_CPU_WRITE | 318bf215546Sopenharmony_ci PB_USAGE_PERSISTENT, NULL); 319bf215546Sopenharmony_ci if(!slab->virtual) { 320bf215546Sopenharmony_ci ret = PIPE_ERROR_OUT_OF_MEMORY; 321bf215546Sopenharmony_ci goto out_err1; 322bf215546Sopenharmony_ci } 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_ci numBuffers = slab->bo->size / mgr->bufSize; 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_ci slab->buffers = CALLOC(numBuffers, sizeof(*slab->buffers)); 327bf215546Sopenharmony_ci if (!slab->buffers) { 328bf215546Sopenharmony_ci ret = PIPE_ERROR_OUT_OF_MEMORY; 329bf215546Sopenharmony_ci goto out_err1; 330bf215546Sopenharmony_ci } 331bf215546Sopenharmony_ci 332bf215546Sopenharmony_ci list_inithead(&slab->head); 333bf215546Sopenharmony_ci list_inithead(&slab->freeBuffers); 334bf215546Sopenharmony_ci slab->numBuffers = numBuffers; 335bf215546Sopenharmony_ci slab->numFree = 0; 336bf215546Sopenharmony_ci slab->mgr = mgr; 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci buf = slab->buffers; 339bf215546Sopenharmony_ci for (i=0; i < numBuffers; ++i) { 340bf215546Sopenharmony_ci pipe_reference_init(&buf->base.reference, 0); 341bf215546Sopenharmony_ci buf->base.size = mgr->bufSize; 342bf215546Sopenharmony_ci buf->base.alignment_log2 = 0; 343bf215546Sopenharmony_ci buf->base.usage = 0; 344bf215546Sopenharmony_ci buf->base.vtbl = &pb_slab_buffer_vtbl; 345bf215546Sopenharmony_ci buf->slab = slab; 346bf215546Sopenharmony_ci buf->start = i* mgr->bufSize; 347bf215546Sopenharmony_ci buf->mapCount = 0; 348bf215546Sopenharmony_ci list_addtail(&buf->head, &slab->freeBuffers); 349bf215546Sopenharmony_ci slab->numFree++; 350bf215546Sopenharmony_ci buf++; 351bf215546Sopenharmony_ci } 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_ci /* Add this slab to the list of partial slabs */ 354bf215546Sopenharmony_ci list_addtail(&slab->head, &mgr->slabs); 355bf215546Sopenharmony_ci 356bf215546Sopenharmony_ci return PIPE_OK; 357bf215546Sopenharmony_ci 358bf215546Sopenharmony_ciout_err1: 359bf215546Sopenharmony_ci pb_reference(&slab->bo, NULL); 360bf215546Sopenharmony_ciout_err0: 361bf215546Sopenharmony_ci FREE(slab); 362bf215546Sopenharmony_ci return ret; 363bf215546Sopenharmony_ci} 364bf215546Sopenharmony_ci 365bf215546Sopenharmony_ci 366bf215546Sopenharmony_cistatic struct pb_buffer * 367bf215546Sopenharmony_cipb_slab_manager_create_buffer(struct pb_manager *_mgr, 368bf215546Sopenharmony_ci pb_size size, 369bf215546Sopenharmony_ci const struct pb_desc *desc) 370bf215546Sopenharmony_ci{ 371bf215546Sopenharmony_ci struct pb_slab_manager *mgr = pb_slab_manager(_mgr); 372bf215546Sopenharmony_ci static struct pb_slab_buffer *buf; 373bf215546Sopenharmony_ci struct pb_slab *slab; 374bf215546Sopenharmony_ci struct list_head *list; 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_ci /* check size */ 377bf215546Sopenharmony_ci assert(size <= mgr->bufSize); 378bf215546Sopenharmony_ci if(size > mgr->bufSize) 379bf215546Sopenharmony_ci return NULL; 380bf215546Sopenharmony_ci 381bf215546Sopenharmony_ci /* check if we can provide the requested alignment */ 382bf215546Sopenharmony_ci assert(pb_check_alignment(desc->alignment, mgr->desc.alignment)); 383bf215546Sopenharmony_ci if(!pb_check_alignment(desc->alignment, mgr->desc.alignment)) 384bf215546Sopenharmony_ci return NULL; 385bf215546Sopenharmony_ci assert(pb_check_alignment(desc->alignment, mgr->bufSize)); 386bf215546Sopenharmony_ci if(!pb_check_alignment(desc->alignment, mgr->bufSize)) 387bf215546Sopenharmony_ci return NULL; 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci assert(pb_check_usage(desc->usage, mgr->desc.usage)); 390bf215546Sopenharmony_ci if(!pb_check_usage(desc->usage, mgr->desc.usage)) 391bf215546Sopenharmony_ci return NULL; 392bf215546Sopenharmony_ci 393bf215546Sopenharmony_ci mtx_lock(&mgr->mutex); 394bf215546Sopenharmony_ci 395bf215546Sopenharmony_ci /* Create a new slab, if we run out of partial slabs */ 396bf215546Sopenharmony_ci if (mgr->slabs.next == &mgr->slabs) { 397bf215546Sopenharmony_ci (void) pb_slab_create(mgr); 398bf215546Sopenharmony_ci if (mgr->slabs.next == &mgr->slabs) { 399bf215546Sopenharmony_ci mtx_unlock(&mgr->mutex); 400bf215546Sopenharmony_ci return NULL; 401bf215546Sopenharmony_ci } 402bf215546Sopenharmony_ci } 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ci /* Allocate the buffer from a partial (or just created) slab */ 405bf215546Sopenharmony_ci list = mgr->slabs.next; 406bf215546Sopenharmony_ci slab = list_entry(list, struct pb_slab, head); 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci /* If totally full remove from the partial slab list */ 409bf215546Sopenharmony_ci if (--slab->numFree == 0) 410bf215546Sopenharmony_ci list_delinit(list); 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_ci list = slab->freeBuffers.next; 413bf215546Sopenharmony_ci list_delinit(list); 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci mtx_unlock(&mgr->mutex); 416bf215546Sopenharmony_ci buf = list_entry(list, struct pb_slab_buffer, head); 417bf215546Sopenharmony_ci 418bf215546Sopenharmony_ci pipe_reference_init(&buf->base.reference, 1); 419bf215546Sopenharmony_ci buf->base.alignment_log2 = util_logbase2(desc->alignment); 420bf215546Sopenharmony_ci buf->base.usage = desc->usage; 421bf215546Sopenharmony_ci 422bf215546Sopenharmony_ci return &buf->base; 423bf215546Sopenharmony_ci} 424bf215546Sopenharmony_ci 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_cistatic void 427bf215546Sopenharmony_cipb_slab_manager_flush(struct pb_manager *_mgr) 428bf215546Sopenharmony_ci{ 429bf215546Sopenharmony_ci struct pb_slab_manager *mgr = pb_slab_manager(_mgr); 430bf215546Sopenharmony_ci 431bf215546Sopenharmony_ci assert(mgr->provider->flush); 432bf215546Sopenharmony_ci if(mgr->provider->flush) 433bf215546Sopenharmony_ci mgr->provider->flush(mgr->provider); 434bf215546Sopenharmony_ci} 435bf215546Sopenharmony_ci 436bf215546Sopenharmony_ci 437bf215546Sopenharmony_cistatic void 438bf215546Sopenharmony_cipb_slab_manager_destroy(struct pb_manager *_mgr) 439bf215546Sopenharmony_ci{ 440bf215546Sopenharmony_ci struct pb_slab_manager *mgr = pb_slab_manager(_mgr); 441bf215546Sopenharmony_ci 442bf215546Sopenharmony_ci /* TODO: cleanup all allocated buffers */ 443bf215546Sopenharmony_ci FREE(mgr); 444bf215546Sopenharmony_ci} 445bf215546Sopenharmony_ci 446bf215546Sopenharmony_ci 447bf215546Sopenharmony_cistruct pb_manager * 448bf215546Sopenharmony_cipb_slab_manager_create(struct pb_manager *provider, 449bf215546Sopenharmony_ci pb_size bufSize, 450bf215546Sopenharmony_ci pb_size slabSize, 451bf215546Sopenharmony_ci const struct pb_desc *desc) 452bf215546Sopenharmony_ci{ 453bf215546Sopenharmony_ci struct pb_slab_manager *mgr; 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_ci mgr = CALLOC_STRUCT(pb_slab_manager); 456bf215546Sopenharmony_ci if (!mgr) 457bf215546Sopenharmony_ci return NULL; 458bf215546Sopenharmony_ci 459bf215546Sopenharmony_ci mgr->base.destroy = pb_slab_manager_destroy; 460bf215546Sopenharmony_ci mgr->base.create_buffer = pb_slab_manager_create_buffer; 461bf215546Sopenharmony_ci mgr->base.flush = pb_slab_manager_flush; 462bf215546Sopenharmony_ci 463bf215546Sopenharmony_ci mgr->provider = provider; 464bf215546Sopenharmony_ci mgr->bufSize = bufSize; 465bf215546Sopenharmony_ci mgr->slabSize = slabSize; 466bf215546Sopenharmony_ci mgr->desc = *desc; 467bf215546Sopenharmony_ci 468bf215546Sopenharmony_ci list_inithead(&mgr->slabs); 469bf215546Sopenharmony_ci 470bf215546Sopenharmony_ci (void) mtx_init(&mgr->mutex, mtx_plain); 471bf215546Sopenharmony_ci 472bf215546Sopenharmony_ci return &mgr->base; 473bf215546Sopenharmony_ci} 474bf215546Sopenharmony_ci 475bf215546Sopenharmony_ci 476bf215546Sopenharmony_cistatic struct pb_buffer * 477bf215546Sopenharmony_cipb_slab_range_manager_create_buffer(struct pb_manager *_mgr, 478bf215546Sopenharmony_ci pb_size size, 479bf215546Sopenharmony_ci const struct pb_desc *desc) 480bf215546Sopenharmony_ci{ 481bf215546Sopenharmony_ci struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr); 482bf215546Sopenharmony_ci pb_size bufSize; 483bf215546Sopenharmony_ci pb_size reqSize = size; 484bf215546Sopenharmony_ci enum pb_usage_flags i; 485bf215546Sopenharmony_ci 486bf215546Sopenharmony_ci if(desc->alignment > reqSize) 487bf215546Sopenharmony_ci reqSize = desc->alignment; 488bf215546Sopenharmony_ci 489bf215546Sopenharmony_ci bufSize = mgr->minBufSize; 490bf215546Sopenharmony_ci for (i = 0; i < mgr->numBuckets; ++i) { 491bf215546Sopenharmony_ci if(bufSize >= reqSize) 492bf215546Sopenharmony_ci return mgr->buckets[i]->create_buffer(mgr->buckets[i], size, desc); 493bf215546Sopenharmony_ci bufSize *= 2; 494bf215546Sopenharmony_ci } 495bf215546Sopenharmony_ci 496bf215546Sopenharmony_ci /* Fall back to allocate a buffer object directly from the provider. */ 497bf215546Sopenharmony_ci return mgr->provider->create_buffer(mgr->provider, size, desc); 498bf215546Sopenharmony_ci} 499bf215546Sopenharmony_ci 500bf215546Sopenharmony_ci 501bf215546Sopenharmony_cistatic void 502bf215546Sopenharmony_cipb_slab_range_manager_flush(struct pb_manager *_mgr) 503bf215546Sopenharmony_ci{ 504bf215546Sopenharmony_ci struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr); 505bf215546Sopenharmony_ci 506bf215546Sopenharmony_ci /* Individual slabs don't hold any temporary buffers so no need to call them */ 507bf215546Sopenharmony_ci 508bf215546Sopenharmony_ci assert(mgr->provider->flush); 509bf215546Sopenharmony_ci if(mgr->provider->flush) 510bf215546Sopenharmony_ci mgr->provider->flush(mgr->provider); 511bf215546Sopenharmony_ci} 512bf215546Sopenharmony_ci 513bf215546Sopenharmony_ci 514bf215546Sopenharmony_cistatic void 515bf215546Sopenharmony_cipb_slab_range_manager_destroy(struct pb_manager *_mgr) 516bf215546Sopenharmony_ci{ 517bf215546Sopenharmony_ci struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr); 518bf215546Sopenharmony_ci unsigned i; 519bf215546Sopenharmony_ci 520bf215546Sopenharmony_ci for (i = 0; i < mgr->numBuckets; ++i) 521bf215546Sopenharmony_ci mgr->buckets[i]->destroy(mgr->buckets[i]); 522bf215546Sopenharmony_ci FREE(mgr->buckets); 523bf215546Sopenharmony_ci FREE(mgr->bucketSizes); 524bf215546Sopenharmony_ci FREE(mgr); 525bf215546Sopenharmony_ci} 526bf215546Sopenharmony_ci 527bf215546Sopenharmony_ci 528bf215546Sopenharmony_cistruct pb_manager * 529bf215546Sopenharmony_cipb_slab_range_manager_create(struct pb_manager *provider, 530bf215546Sopenharmony_ci pb_size minBufSize, 531bf215546Sopenharmony_ci pb_size maxBufSize, 532bf215546Sopenharmony_ci pb_size slabSize, 533bf215546Sopenharmony_ci const struct pb_desc *desc) 534bf215546Sopenharmony_ci{ 535bf215546Sopenharmony_ci struct pb_slab_range_manager *mgr; 536bf215546Sopenharmony_ci pb_size bufSize; 537bf215546Sopenharmony_ci unsigned i; 538bf215546Sopenharmony_ci 539bf215546Sopenharmony_ci if (!provider) 540bf215546Sopenharmony_ci return NULL; 541bf215546Sopenharmony_ci 542bf215546Sopenharmony_ci mgr = CALLOC_STRUCT(pb_slab_range_manager); 543bf215546Sopenharmony_ci if (!mgr) 544bf215546Sopenharmony_ci goto out_err0; 545bf215546Sopenharmony_ci 546bf215546Sopenharmony_ci mgr->base.destroy = pb_slab_range_manager_destroy; 547bf215546Sopenharmony_ci mgr->base.create_buffer = pb_slab_range_manager_create_buffer; 548bf215546Sopenharmony_ci mgr->base.flush = pb_slab_range_manager_flush; 549bf215546Sopenharmony_ci 550bf215546Sopenharmony_ci mgr->provider = provider; 551bf215546Sopenharmony_ci mgr->minBufSize = minBufSize; 552bf215546Sopenharmony_ci mgr->maxBufSize = maxBufSize; 553bf215546Sopenharmony_ci 554bf215546Sopenharmony_ci mgr->numBuckets = 1; 555bf215546Sopenharmony_ci bufSize = minBufSize; 556bf215546Sopenharmony_ci while(bufSize < maxBufSize) { 557bf215546Sopenharmony_ci bufSize *= 2; 558bf215546Sopenharmony_ci ++mgr->numBuckets; 559bf215546Sopenharmony_ci } 560bf215546Sopenharmony_ci 561bf215546Sopenharmony_ci mgr->buckets = CALLOC(mgr->numBuckets, sizeof(*mgr->buckets)); 562bf215546Sopenharmony_ci if (!mgr->buckets) 563bf215546Sopenharmony_ci goto out_err1; 564bf215546Sopenharmony_ci 565bf215546Sopenharmony_ci bufSize = minBufSize; 566bf215546Sopenharmony_ci for (i = 0; i < mgr->numBuckets; ++i) { 567bf215546Sopenharmony_ci mgr->buckets[i] = pb_slab_manager_create(provider, bufSize, slabSize, desc); 568bf215546Sopenharmony_ci if(!mgr->buckets[i]) 569bf215546Sopenharmony_ci goto out_err2; 570bf215546Sopenharmony_ci bufSize *= 2; 571bf215546Sopenharmony_ci } 572bf215546Sopenharmony_ci 573bf215546Sopenharmony_ci return &mgr->base; 574bf215546Sopenharmony_ci 575bf215546Sopenharmony_ciout_err2: 576bf215546Sopenharmony_ci for (i = 0; i < mgr->numBuckets; ++i) 577bf215546Sopenharmony_ci if(mgr->buckets[i]) 578bf215546Sopenharmony_ci mgr->buckets[i]->destroy(mgr->buckets[i]); 579bf215546Sopenharmony_ci FREE(mgr->buckets); 580bf215546Sopenharmony_ciout_err1: 581bf215546Sopenharmony_ci FREE(mgr); 582bf215546Sopenharmony_ciout_err0: 583bf215546Sopenharmony_ci return NULL; 584bf215546Sopenharmony_ci} 585