1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev#include <ngx_config.h>
8e18a033bSKonstantin Ananyev#include <ngx_core.h>
9e18a033bSKonstantin Ananyev
10e18a033bSKonstantin Ananyev
11e18a033bSKonstantin Ananyev#define NGX_SLAB_PAGE_MASK   3
12e18a033bSKonstantin Ananyev#define NGX_SLAB_PAGE        0
13e18a033bSKonstantin Ananyev#define NGX_SLAB_BIG         1
14e18a033bSKonstantin Ananyev#define NGX_SLAB_EXACT       2
15e18a033bSKonstantin Ananyev#define NGX_SLAB_SMALL       3
16e18a033bSKonstantin Ananyev
17e18a033bSKonstantin Ananyev#if (NGX_PTR_SIZE == 4)
18e18a033bSKonstantin Ananyev
19e18a033bSKonstantin Ananyev#define NGX_SLAB_PAGE_FREE   0
20e18a033bSKonstantin Ananyev#define NGX_SLAB_PAGE_BUSY   0xffffffff
21e18a033bSKonstantin Ananyev#define NGX_SLAB_PAGE_START  0x80000000
22e18a033bSKonstantin Ananyev
23e18a033bSKonstantin Ananyev#define NGX_SLAB_SHIFT_MASK  0x0000000f
24e18a033bSKonstantin Ananyev#define NGX_SLAB_MAP_MASK    0xffff0000
25e18a033bSKonstantin Ananyev#define NGX_SLAB_MAP_SHIFT   16
26e18a033bSKonstantin Ananyev
27e18a033bSKonstantin Ananyev#define NGX_SLAB_BUSY        0xffffffff
28e18a033bSKonstantin Ananyev
29e18a033bSKonstantin Ananyev#else /* (NGX_PTR_SIZE == 8) */
30e18a033bSKonstantin Ananyev
31e18a033bSKonstantin Ananyev#define NGX_SLAB_PAGE_FREE   0
32e18a033bSKonstantin Ananyev#define NGX_SLAB_PAGE_BUSY   0xffffffffffffffff
33e18a033bSKonstantin Ananyev#define NGX_SLAB_PAGE_START  0x8000000000000000
34e18a033bSKonstantin Ananyev
35e18a033bSKonstantin Ananyev#define NGX_SLAB_SHIFT_MASK  0x000000000000000f
36e18a033bSKonstantin Ananyev#define NGX_SLAB_MAP_MASK    0xffffffff00000000
37e18a033bSKonstantin Ananyev#define NGX_SLAB_MAP_SHIFT   32
38e18a033bSKonstantin Ananyev
39e18a033bSKonstantin Ananyev#define NGX_SLAB_BUSY        0xffffffffffffffff
40e18a033bSKonstantin Ananyev
41e18a033bSKonstantin Ananyev#endif
42e18a033bSKonstantin Ananyev
43e18a033bSKonstantin Ananyev
44e18a033bSKonstantin Ananyev#define ngx_slab_slots(pool)                                                  \
45e18a033bSKonstantin Ananyev    (ngx_slab_page_t *) ((u_char *) (pool) + sizeof(ngx_slab_pool_t))
46e18a033bSKonstantin Ananyev
47e18a033bSKonstantin Ananyev#define ngx_slab_page_type(page)   ((page)->prev & NGX_SLAB_PAGE_MASK)
48e18a033bSKonstantin Ananyev
49e18a033bSKonstantin Ananyev#define ngx_slab_page_prev(page)                                              \
50e18a033bSKonstantin Ananyev    (ngx_slab_page_t *) ((page)->prev & ~NGX_SLAB_PAGE_MASK)
51e18a033bSKonstantin Ananyev
52e18a033bSKonstantin Ananyev#define ngx_slab_page_addr(pool, page)                                        \
53e18a033bSKonstantin Ananyev    ((((page) - (pool)->pages) << ngx_pagesize_shift)                         \
54e18a033bSKonstantin Ananyev     + (uintptr_t) (pool)->start)
55e18a033bSKonstantin Ananyev
56e18a033bSKonstantin Ananyev
57e18a033bSKonstantin Ananyev#if (NGX_DEBUG_MALLOC)
58e18a033bSKonstantin Ananyev
59e18a033bSKonstantin Ananyev#define ngx_slab_junk(p, size)     ngx_memset(p, 0xA5, size)
60e18a033bSKonstantin Ananyev
61e18a033bSKonstantin Ananyev#elif (NGX_HAVE_DEBUG_MALLOC)
62e18a033bSKonstantin Ananyev
63e18a033bSKonstantin Ananyev#define ngx_slab_junk(p, size)                                                \
64e18a033bSKonstantin Ananyev    if (ngx_debug_malloc)          ngx_memset(p, 0xA5, size)
65e18a033bSKonstantin Ananyev
66e18a033bSKonstantin Ananyev#else
67e18a033bSKonstantin Ananyev
68e18a033bSKonstantin Ananyev#define ngx_slab_junk(p, size)
69e18a033bSKonstantin Ananyev
70e18a033bSKonstantin Ananyev#endif
71e18a033bSKonstantin Ananyev
72e18a033bSKonstantin Ananyevstatic ngx_slab_page_t *ngx_slab_alloc_pages(ngx_slab_pool_t *pool,
73e18a033bSKonstantin Ananyev    ngx_uint_t pages);
74e18a033bSKonstantin Ananyevstatic void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
75e18a033bSKonstantin Ananyev    ngx_uint_t pages);
76e18a033bSKonstantin Ananyevstatic void ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level,
77e18a033bSKonstantin Ananyev    char *text);
78e18a033bSKonstantin Ananyev
79e18a033bSKonstantin Ananyev
80e18a033bSKonstantin Ananyevstatic ngx_uint_t  ngx_slab_max_size;
81e18a033bSKonstantin Ananyevstatic ngx_uint_t  ngx_slab_exact_size;
82e18a033bSKonstantin Ananyevstatic ngx_uint_t  ngx_slab_exact_shift;
83e18a033bSKonstantin Ananyev
84e18a033bSKonstantin Ananyev
85e18a033bSKonstantin Ananyevvoid
86e18a033bSKonstantin Ananyevngx_slab_init(ngx_slab_pool_t *pool)
87e18a033bSKonstantin Ananyev{
88e18a033bSKonstantin Ananyev    u_char           *p;
89e18a033bSKonstantin Ananyev    size_t            size;
90e18a033bSKonstantin Ananyev    ngx_int_t         m;
91e18a033bSKonstantin Ananyev    ngx_uint_t        i, n, pages;
92e18a033bSKonstantin Ananyev    ngx_slab_page_t  *slots, *page;
93e18a033bSKonstantin Ananyev
94e18a033bSKonstantin Ananyev    /* STUB */
95e18a033bSKonstantin Ananyev    if (ngx_slab_max_size == 0) {
96e18a033bSKonstantin Ananyev        ngx_slab_max_size = ngx_pagesize / 2;
97e18a033bSKonstantin Ananyev        ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t));
98e18a033bSKonstantin Ananyev        for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) {
99e18a033bSKonstantin Ananyev            /* void */
100e18a033bSKonstantin Ananyev        }
101e18a033bSKonstantin Ananyev    }
102e18a033bSKonstantin Ananyev    /**/
103e18a033bSKonstantin Ananyev
104e18a033bSKonstantin Ananyev    pool->min_size = (size_t) 1 << pool->min_shift;
105e18a033bSKonstantin Ananyev
106e18a033bSKonstantin Ananyev    slots = ngx_slab_slots(pool);
107e18a033bSKonstantin Ananyev
108e18a033bSKonstantin Ananyev    p = (u_char *) slots;
109e18a033bSKonstantin Ananyev    size = pool->end - p;
110e18a033bSKonstantin Ananyev
111e18a033bSKonstantin Ananyev    ngx_slab_junk(p, size);
112e18a033bSKonstantin Ananyev
113e18a033bSKonstantin Ananyev    n = ngx_pagesize_shift - pool->min_shift;
114e18a033bSKonstantin Ananyev
115e18a033bSKonstantin Ananyev    for (i = 0; i < n; i++) {
116e18a033bSKonstantin Ananyev        /* only "next" is used in list head */
117e18a033bSKonstantin Ananyev        slots[i].slab = 0;
118e18a033bSKonstantin Ananyev        slots[i].next = &slots[i];
119e18a033bSKonstantin Ananyev        slots[i].prev = 0;
120e18a033bSKonstantin Ananyev    }
121e18a033bSKonstantin Ananyev
122e18a033bSKonstantin Ananyev    p += n * sizeof(ngx_slab_page_t);
123e18a033bSKonstantin Ananyev
124e18a033bSKonstantin Ananyev    pool->stats = (ngx_slab_stat_t *) p;
125e18a033bSKonstantin Ananyev    ngx_memzero(pool->stats, n * sizeof(ngx_slab_stat_t));
126e18a033bSKonstantin Ananyev
127e18a033bSKonstantin Ananyev    p += n * sizeof(ngx_slab_stat_t);
128e18a033bSKonstantin Ananyev
129e18a033bSKonstantin Ananyev    size -= n * (sizeof(ngx_slab_page_t) + sizeof(ngx_slab_stat_t));
130e18a033bSKonstantin Ananyev
131e18a033bSKonstantin Ananyev    pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t)));
132e18a033bSKonstantin Ananyev
133e18a033bSKonstantin Ananyev    pool->pages = (ngx_slab_page_t *) p;
134e18a033bSKonstantin Ananyev    ngx_memzero(pool->pages, pages * sizeof(ngx_slab_page_t));
135e18a033bSKonstantin Ananyev
136e18a033bSKonstantin Ananyev    page = pool->pages;
137e18a033bSKonstantin Ananyev
138e18a033bSKonstantin Ananyev    /* only "next" is used in list head */
139e18a033bSKonstantin Ananyev    pool->free.slab = 0;
140e18a033bSKonstantin Ananyev    pool->free.next = page;
141e18a033bSKonstantin Ananyev    pool->free.prev = 0;
142e18a033bSKonstantin Ananyev
143e18a033bSKonstantin Ananyev    page->slab = pages;
144e18a033bSKonstantin Ananyev    page->next = &pool->free;
145e18a033bSKonstantin Ananyev    page->prev = (uintptr_t) &pool->free;
146e18a033bSKonstantin Ananyev
147e18a033bSKonstantin Ananyev    pool->start = ngx_align_ptr(p + pages * sizeof(ngx_slab_page_t),
148e18a033bSKonstantin Ananyev                                ngx_pagesize);
149e18a033bSKonstantin Ananyev
150e18a033bSKonstantin Ananyev    m = pages - (pool->end - pool->start) / ngx_pagesize;
151e18a033bSKonstantin Ananyev    if (m > 0) {
152e18a033bSKonstantin Ananyev        pages -= m;
153e18a033bSKonstantin Ananyev        page->slab = pages;
154e18a033bSKonstantin Ananyev    }
155e18a033bSKonstantin Ananyev
156e18a033bSKonstantin Ananyev    pool->last = pool->pages + pages;
157e18a033bSKonstantin Ananyev    pool->pfree = pages;
158e18a033bSKonstantin Ananyev
159e18a033bSKonstantin Ananyev    pool->log_nomem = 1;
160e18a033bSKonstantin Ananyev    pool->log_ctx = &pool->zero;
161e18a033bSKonstantin Ananyev    pool->zero = '\0';
162e18a033bSKonstantin Ananyev}
163e18a033bSKonstantin Ananyev
164e18a033bSKonstantin Ananyev
165e18a033bSKonstantin Ananyevvoid *
166e18a033bSKonstantin Ananyevngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
167e18a033bSKonstantin Ananyev{
168e18a033bSKonstantin Ananyev    void  *p;
169e18a033bSKonstantin Ananyev
170e18a033bSKonstantin Ananyev    ngx_shmtx_lock(&pool->mutex);
171e18a033bSKonstantin Ananyev
172e18a033bSKonstantin Ananyev    p = ngx_slab_alloc_locked(pool, size);
173e18a033bSKonstantin Ananyev
174e18a033bSKonstantin Ananyev    ngx_shmtx_unlock(&pool->mutex);
175e18a033bSKonstantin Ananyev
176e18a033bSKonstantin Ananyev    return p;
177e18a033bSKonstantin Ananyev}
178e18a033bSKonstantin Ananyev
179e18a033bSKonstantin Ananyev
180e18a033bSKonstantin Ananyevvoid *
181e18a033bSKonstantin Ananyevngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size)
182e18a033bSKonstantin Ananyev{
183e18a033bSKonstantin Ananyev    size_t            s;
184e18a033bSKonstantin Ananyev    uintptr_t         p, n, m, mask, *bitmap;
185e18a033bSKonstantin Ananyev    ngx_uint_t        i, slot, shift, map;
186e18a033bSKonstantin Ananyev    ngx_slab_page_t  *page, *prev, *slots;
187e18a033bSKonstantin Ananyev
188e18a033bSKonstantin Ananyev    if (size > ngx_slab_max_size) {
189e18a033bSKonstantin Ananyev
190e18a033bSKonstantin Ananyev        ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
191e18a033bSKonstantin Ananyev                       "slab alloc: %uz", size);
192e18a033bSKonstantin Ananyev
193e18a033bSKonstantin Ananyev        page = ngx_slab_alloc_pages(pool, (size >> ngx_pagesize_shift)
194e18a033bSKonstantin Ananyev                                          + ((size % ngx_pagesize) ? 1 : 0));
195e18a033bSKonstantin Ananyev        if (page) {
196e18a033bSKonstantin Ananyev            p = ngx_slab_page_addr(pool, page);
197e18a033bSKonstantin Ananyev
198e18a033bSKonstantin Ananyev        } else {
199e18a033bSKonstantin Ananyev            p = 0;
200e18a033bSKonstantin Ananyev        }
201e18a033bSKonstantin Ananyev
202e18a033bSKonstantin Ananyev        goto done;
203e18a033bSKonstantin Ananyev    }
204e18a033bSKonstantin Ananyev
205e18a033bSKonstantin Ananyev    if (size > pool->min_size) {
206e18a033bSKonstantin Ananyev        shift = 1;
207e18a033bSKonstantin Ananyev        for (s = size - 1; s >>= 1; shift++) { /* void */ }
208e18a033bSKonstantin Ananyev        slot = shift - pool->min_shift;
209e18a033bSKonstantin Ananyev
210e18a033bSKonstantin Ananyev    } else {
211e18a033bSKonstantin Ananyev        shift = pool->min_shift;
212e18a033bSKonstantin Ananyev        slot = 0;
213e18a033bSKonstantin Ananyev    }
214e18a033bSKonstantin Ananyev
215e18a033bSKonstantin Ananyev    pool->stats[slot].reqs++;
216e18a033bSKonstantin Ananyev
217e18a033bSKonstantin Ananyev    ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
218e18a033bSKonstantin Ananyev                   "slab alloc: %uz slot: %ui", size, slot);
219e18a033bSKonstantin Ananyev
220e18a033bSKonstantin Ananyev    slots = ngx_slab_slots(pool);
221e18a033bSKonstantin Ananyev    page = slots[slot].next;
222e18a033bSKonstantin Ananyev
223e18a033bSKonstantin Ananyev    if (page->next != page) {
224e18a033bSKonstantin Ananyev
225e18a033bSKonstantin Ananyev        if (shift < ngx_slab_exact_shift) {
226e18a033bSKonstantin Ananyev
227e18a033bSKonstantin Ananyev            bitmap = (uintptr_t *) ngx_slab_page_addr(pool, page);
228e18a033bSKonstantin Ananyev
229e18a033bSKonstantin Ananyev            map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8);
230e18a033bSKonstantin Ananyev
231e18a033bSKonstantin Ananyev            for (n = 0; n < map; n++) {
232e18a033bSKonstantin Ananyev
233e18a033bSKonstantin Ananyev                if (bitmap[n] != NGX_SLAB_BUSY) {
234e18a033bSKonstantin Ananyev
235e18a033bSKonstantin Ananyev                    for (m = 1, i = 0; m; m <<= 1, i++) {
236e18a033bSKonstantin Ananyev                        if (bitmap[n] & m) {
237e18a033bSKonstantin Ananyev                            continue;
238e18a033bSKonstantin Ananyev                        }
239e18a033bSKonstantin Ananyev
240e18a033bSKonstantin Ananyev                        bitmap[n] |= m;
241e18a033bSKonstantin Ananyev
242e18a033bSKonstantin Ananyev                        i = (n * sizeof(uintptr_t) * 8 + i) << shift;
243e18a033bSKonstantin Ananyev
244e18a033bSKonstantin Ananyev                        p = (uintptr_t) bitmap + i;
245e18a033bSKonstantin Ananyev
246e18a033bSKonstantin Ananyev                        pool->stats[slot].used++;
247e18a033bSKonstantin Ananyev
248e18a033bSKonstantin Ananyev                        if (bitmap[n] == NGX_SLAB_BUSY) {
249e18a033bSKonstantin Ananyev                            for (n = n + 1; n < map; n++) {
250e18a033bSKonstantin Ananyev                                if (bitmap[n] != NGX_SLAB_BUSY) {
251e18a033bSKonstantin Ananyev                                    goto done;
252e18a033bSKonstantin Ananyev                                }
253e18a033bSKonstantin Ananyev                            }
254e18a033bSKonstantin Ananyev
255e18a033bSKonstantin Ananyev                            prev = ngx_slab_page_prev(page);
256e18a033bSKonstantin Ananyev                            prev->next = page->next;
257e18a033bSKonstantin Ananyev                            page->next->prev = page->prev;
258e18a033bSKonstantin Ananyev
259e18a033bSKonstantin Ananyev                            page->next = NULL;
260e18a033bSKonstantin Ananyev                            page->prev = NGX_SLAB_SMALL;
261e18a033bSKonstantin Ananyev                        }
262e18a033bSKonstantin Ananyev
263e18a033bSKonstantin Ananyev                        goto done;
264e18a033bSKonstantin Ananyev                    }
265e18a033bSKonstantin Ananyev                }
266e18a033bSKonstantin Ananyev            }
267e18a033bSKonstantin Ananyev
268e18a033bSKonstantin Ananyev        } else if (shift == ngx_slab_exact_shift) {
269e18a033bSKonstantin Ananyev
270e18a033bSKonstantin Ananyev            for (m = 1, i = 0; m; m <<= 1, i++) {
271e18a033bSKonstantin Ananyev                if (page->slab & m) {
272e18a033bSKonstantin Ananyev                    continue;
273e18a033bSKonstantin Ananyev                }
274e18a033bSKonstantin Ananyev
275e18a033bSKonstantin Ananyev                page->slab |= m;
276e18a033bSKonstantin Ananyev
277e18a033bSKonstantin Ananyev                if (page->slab == NGX_SLAB_BUSY) {
278e18a033bSKonstantin Ananyev                    prev = ngx_slab_page_prev(page);
279e18a033bSKonstantin Ananyev                    prev->next = page->next;
280e18a033bSKonstantin Ananyev                    page->next->prev = page->prev;
281e18a033bSKonstantin Ananyev
282e18a033bSKonstantin Ananyev                    page->next = NULL;
283e18a033bSKonstantin Ananyev                    page->prev = NGX_SLAB_EXACT;
284e18a033bSKonstantin Ananyev                }
285e18a033bSKonstantin Ananyev
286e18a033bSKonstantin Ananyev                p = ngx_slab_page_addr(pool, page) + (i << shift);
287e18a033bSKonstantin Ananyev
288e18a033bSKonstantin Ananyev                pool->stats[slot].used++;
289e18a033bSKonstantin Ananyev
290e18a033bSKonstantin Ananyev                goto done;
291e18a033bSKonstantin Ananyev            }
292e18a033bSKonstantin Ananyev
293e18a033bSKonstantin Ananyev        } else { /* shift > ngx_slab_exact_shift */
294e18a033bSKonstantin Ananyev
295e18a033bSKonstantin Ananyev            mask = ((uintptr_t) 1 << (ngx_pagesize >> shift)) - 1;
296e18a033bSKonstantin Ananyev            mask <<= NGX_SLAB_MAP_SHIFT;
297e18a033bSKonstantin Ananyev
298e18a033bSKonstantin Ananyev            for (m = (uintptr_t) 1 << NGX_SLAB_MAP_SHIFT, i = 0;
299e18a033bSKonstantin Ananyev                 m & mask;
300e18a033bSKonstantin Ananyev                 m <<= 1, i++)
301e18a033bSKonstantin Ananyev            {
302e18a033bSKonstantin Ananyev                if (page->slab & m) {
303e18a033bSKonstantin Ananyev                    continue;
304e18a033bSKonstantin Ananyev                }
305e18a033bSKonstantin Ananyev
306e18a033bSKonstantin Ananyev                page->slab |= m;
307e18a033bSKonstantin Ananyev
308e18a033bSKonstantin Ananyev                if ((page->slab & NGX_SLAB_MAP_MASK) == mask) {
309e18a033bSKonstantin Ananyev                    prev = ngx_slab_page_prev(page);
310e18a033bSKonstantin Ananyev                    prev->next = page->next;
311e18a033bSKonstantin Ananyev                    page->next->prev = page->prev;
312e18a033bSKonstantin Ananyev
313e18a033bSKonstantin Ananyev                    page->next = NULL;
314e18a033bSKonstantin Ananyev                    page->prev = NGX_SLAB_BIG;
315e18a033bSKonstantin Ananyev                }
316e18a033bSKonstantin Ananyev
317e18a033bSKonstantin Ananyev                p = ngx_slab_page_addr(pool, page) + (i << shift);
318e18a033bSKonstantin Ananyev
319e18a033bSKonstantin Ananyev                pool->stats[slot].used++;
320e18a033bSKonstantin Ananyev
321e18a033bSKonstantin Ananyev                goto done;
322e18a033bSKonstantin Ananyev            }
323e18a033bSKonstantin Ananyev        }
324e18a033bSKonstantin Ananyev
325e18a033bSKonstantin Ananyev        ngx_slab_error(pool, NGX_LOG_ALERT, "ngx_slab_alloc(): page is busy");
326e18a033bSKonstantin Ananyev        ngx_debug_point();
327e18a033bSKonstantin Ananyev    }
328e18a033bSKonstantin Ananyev
329e18a033bSKonstantin Ananyev    page = ngx_slab_alloc_pages(pool, 1);
330e18a033bSKonstantin Ananyev
331e18a033bSKonstantin Ananyev    if (page) {
332e18a033bSKonstantin Ananyev        if (shift < ngx_slab_exact_shift) {
333e18a033bSKonstantin Ananyev            bitmap = (uintptr_t *) ngx_slab_page_addr(pool, page);
334e18a033bSKonstantin Ananyev
335e18a033bSKonstantin Ananyev            n = (ngx_pagesize >> shift) / ((1 << shift) * 8);
336e18a033bSKonstantin Ananyev
337e18a033bSKonstantin Ananyev            if (n == 0) {
338e18a033bSKonstantin Ananyev                n = 1;
339e18a033bSKonstantin Ananyev            }
340e18a033bSKonstantin Ananyev
341e18a033bSKonstantin Ananyev            /* "n" elements for bitmap, plus one requested */
342e18a033bSKonstantin Ananyev            bitmap[0] = ((uintptr_t) 2 << n) - 1;
343e18a033bSKonstantin Ananyev
344e18a033bSKonstantin Ananyev            map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8);
345e18a033bSKonstantin Ananyev
346e18a033bSKonstantin Ananyev            for (i = 1; i < map; i++) {
347e18a033bSKonstantin Ananyev                bitmap[i] = 0;
348e18a033bSKonstantin Ananyev            }
349e18a033bSKonstantin Ananyev
350e18a033bSKonstantin Ananyev            page->slab = shift;
351e18a033bSKonstantin Ananyev            page->next = &slots[slot];
352e18a033bSKonstantin Ananyev            page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_SMALL;
353e18a033bSKonstantin Ananyev
354e18a033bSKonstantin Ananyev            slots[slot].next = page;
355e18a033bSKonstantin Ananyev
356e18a033bSKonstantin Ananyev            pool->stats[slot].total += (ngx_pagesize >> shift) - n;
357e18a033bSKonstantin Ananyev
358e18a033bSKonstantin Ananyev            p = ngx_slab_page_addr(pool, page) + (n << shift);
359e18a033bSKonstantin Ananyev
360e18a033bSKonstantin Ananyev            pool->stats[slot].used++;
361e18a033bSKonstantin Ananyev
362e18a033bSKonstantin Ananyev            goto done;
363e18a033bSKonstantin Ananyev
364e18a033bSKonstantin Ananyev        } else if (shift == ngx_slab_exact_shift) {
365e18a033bSKonstantin Ananyev
366e18a033bSKonstantin Ananyev            page->slab = 1;
367e18a033bSKonstantin Ananyev            page->next = &slots[slot];
368e18a033bSKonstantin Ananyev            page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_EXACT;
369e18a033bSKonstantin Ananyev
370e18a033bSKonstantin Ananyev            slots[slot].next = page;
371e18a033bSKonstantin Ananyev
372e18a033bSKonstantin Ananyev            pool->stats[slot].total += sizeof(uintptr_t) * 8;
373e18a033bSKonstantin Ananyev
374e18a033bSKonstantin Ananyev            p = ngx_slab_page_addr(pool, page);
375e18a033bSKonstantin Ananyev
376e18a033bSKonstantin Ananyev            pool->stats[slot].used++;
377e18a033bSKonstantin Ananyev
378e18a033bSKonstantin Ananyev            goto done;
379e18a033bSKonstantin Ananyev
380e18a033bSKonstantin Ananyev        } else { /* shift > ngx_slab_exact_shift */
381e18a033bSKonstantin Ananyev
382e18a033bSKonstantin Ananyev            page->slab = ((uintptr_t) 1 << NGX_SLAB_MAP_SHIFT) | shift;
383e18a033bSKonstantin Ananyev            page->next = &slots[slot];
384e18a033bSKonstantin Ananyev            page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_BIG;
385e18a033bSKonstantin Ananyev
386e18a033bSKonstantin Ananyev            slots[slot].next = page;
387e18a033bSKonstantin Ananyev
388e18a033bSKonstantin Ananyev            pool->stats[slot].total += ngx_pagesize >> shift;
389e18a033bSKonstantin Ananyev
390e18a033bSKonstantin Ananyev            p = ngx_slab_page_addr(pool, page);
391e18a033bSKonstantin Ananyev
392e18a033bSKonstantin Ananyev            pool->stats[slot].used++;
393e18a033bSKonstantin Ananyev
394e18a033bSKonstantin Ananyev            goto done;
395e18a033bSKonstantin Ananyev        }
396e18a033bSKonstantin Ananyev    }
397e18a033bSKonstantin Ananyev
398e18a033bSKonstantin Ananyev    p = 0;
399e18a033bSKonstantin Ananyev
400e18a033bSKonstantin Ananyev    pool->stats[slot].fails++;
401e18a033bSKonstantin Ananyev
402e18a033bSKonstantin Ananyevdone:
403e18a033bSKonstantin Ananyev
404e18a033bSKonstantin Ananyev    ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
405e18a033bSKonstantin Ananyev                   "slab alloc: %p", (void *) p);
406e18a033bSKonstantin Ananyev
407e18a033bSKonstantin Ananyev    return (void *) p;
408e18a033bSKonstantin Ananyev}
409e18a033bSKonstantin Ananyev
410e18a033bSKonstantin Ananyev
411e18a033bSKonstantin Ananyevvoid *
412e18a033bSKonstantin Ananyevngx_slab_calloc(ngx_slab_pool_t *pool, size_t size)
413e18a033bSKonstantin Ananyev{
414e18a033bSKonstantin Ananyev    void  *p;
415e18a033bSKonstantin Ananyev
416e18a033bSKonstantin Ananyev    ngx_shmtx_lock(&pool->mutex);
417e18a033bSKonstantin Ananyev
418e18a033bSKonstantin Ananyev    p = ngx_slab_calloc_locked(pool, size);
419