1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/*
2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Copyright 2010 Marek Olšák <maraeo@gmail.com>
3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Permission is hereby granted, free of charge, to any person obtaining a
5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * copy of this software and associated documentation files (the "Software"),
6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * to deal in the Software without restriction, including without limitation
7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * on the rights to use, copy, modify, merge, publish, distribute, sub
8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * license, and/or sell copies of the Software, and to permit persons to whom
9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * the Software is furnished to do so, subject to the following conditions:
10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * The above copyright notice and this permission notice (including the next
12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * paragraph) shall be included in all copies or substantial portions of the
13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Software.
14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_slab.h"
24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_math.h"
26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_memory.h"
27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_simple_list.h"
28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <stdio.h>
30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define UTIL_SLAB_MAGIC 0xcafe4321
32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/* The block is either allocated memory or free space. */
34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct util_slab_block {
35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   /* The header. */
36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   /* The first next free block. */
37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct util_slab_block *next_free;
38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   intptr_t magic;
40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   /* Memory after the last member is dedicated to the block itself.
42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    * The allocated size is always larger than this structure. */
43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic struct util_slab_block *
46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgutil_slab_get_block(struct util_slab_mempool *pool,
47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    struct util_slab_page *page, unsigned index)
48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return (struct util_slab_block*)
50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org          ((uint8_t*)page + sizeof(struct util_slab_page) +
51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org           (pool->block_size * index));
52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void util_slab_add_new_page(struct util_slab_mempool *pool)
55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct util_slab_page *page;
57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct util_slab_block *block;
58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int i;
59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   page = MALLOC(pool->page_size);
61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   insert_at_tail(&pool->list, page);
62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   /* Mark all blocks as free. */
64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   for (i = 0; i < pool->num_blocks-1; i++) {
65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      block = util_slab_get_block(pool, page, i);
66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      block->next_free = util_slab_get_block(pool, page, i+1);
67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      block->magic = UTIL_SLAB_MAGIC;
68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   block = util_slab_get_block(pool, page, pool->num_blocks-1);
71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   block->next_free = pool->first_free;
72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   block->magic = UTIL_SLAB_MAGIC;
73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pool->first_free = util_slab_get_block(pool, page, 0);
74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pool->num_pages++;
75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#if 0
77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   fprintf(stderr, "New page! Num of pages: %i\n", pool->num_pages);
78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#endif
79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void *util_slab_alloc_st(struct util_slab_mempool *pool)
82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct util_slab_block *block;
84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!pool->first_free)
86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      util_slab_add_new_page(pool);
87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   block = pool->first_free;
89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   assert(block->magic == UTIL_SLAB_MAGIC);
90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pool->first_free = block->next_free;
91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return (uint8_t*)block + sizeof(struct util_slab_block);
93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void util_slab_free_st(struct util_slab_mempool *pool, void *ptr)
96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct util_slab_block *block =
98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         (struct util_slab_block*)
99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         ((uint8_t*)ptr - sizeof(struct util_slab_block));
100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   assert(block->magic == UTIL_SLAB_MAGIC);
102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   block->next_free = pool->first_free;
103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pool->first_free = block;
104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void *util_slab_alloc_mt(struct util_slab_mempool *pool)
107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   void *mem;
109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pipe_mutex_lock(pool->mutex);
111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   mem = util_slab_alloc_st(pool);
112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pipe_mutex_unlock(pool->mutex);
113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return mem;
114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void util_slab_free_mt(struct util_slab_mempool *pool, void *ptr)
117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pipe_mutex_lock(pool->mutex);
119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   util_slab_free_st(pool, ptr);
120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pipe_mutex_unlock(pool->mutex);
121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid util_slab_set_thread_safety(struct util_slab_mempool *pool,
124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                    enum util_slab_threading threading)
125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pool->threading = threading;
127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (threading) {
129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      pool->alloc = util_slab_alloc_mt;
130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      pool->free = util_slab_free_mt;
131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   } else {
132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      pool->alloc = util_slab_alloc_st;
133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      pool->free = util_slab_free_st;
134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid util_slab_create(struct util_slab_mempool *pool,
138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                      unsigned item_size,
139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                      unsigned num_blocks,
140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                      enum util_slab_threading threading)
141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   item_size = align(item_size, sizeof(intptr_t));
143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pool->num_pages = 0;
145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pool->num_blocks = num_blocks;
146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pool->block_size = sizeof(struct util_slab_block) + item_size;
147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pool->block_size = align(pool->block_size, sizeof(intptr_t));
148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pool->page_size = sizeof(struct util_slab_page) +
149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                     num_blocks * pool->block_size;
150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pool->first_free = NULL;
151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   make_empty_list(&pool->list);
153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pipe_mutex_init(pool->mutex);
155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   util_slab_set_thread_safety(pool, threading);
157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid util_slab_destroy(struct util_slab_mempool *pool)
160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct util_slab_page *page, *temp;
162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (pool->list.next) {
164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      foreach_s(page, temp, &pool->list) {
165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         remove_from_list(page);
166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         FREE(page);
167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
169f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
170f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   pipe_mutex_destroy(pool->mutex);
171f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
172