src/core/ngx_slab.c - nginx-1.7.10

Global variables defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */

  5. #include <ngx_config.h>
  6. #include <ngx_core.h>


  7. #define NGX_SLAB_PAGE_MASK   3
  8. #define NGX_SLAB_PAGE        0
  9. #define NGX_SLAB_BIG         1
  10. #define NGX_SLAB_EXACT       2
  11. #define NGX_SLAB_SMALL       3

  12. #if (NGX_PTR_SIZE == 4)

  13. #define NGX_SLAB_PAGE_FREE   0
  14. #define NGX_SLAB_PAGE_BUSY   0xffffffff
  15. #define NGX_SLAB_PAGE_START  0x80000000

  16. #define NGX_SLAB_SHIFT_MASK  0x0000000f
  17. #define NGX_SLAB_MAP_MASK    0xffff0000
  18. #define NGX_SLAB_MAP_SHIFT   16

  19. #define NGX_SLAB_BUSY        0xffffffff

  20. #else /* (NGX_PTR_SIZE == 8) */

  21. #define NGX_SLAB_PAGE_FREE   0
  22. #define NGX_SLAB_PAGE_BUSY   0xffffffffffffffff
  23. #define NGX_SLAB_PAGE_START  0x8000000000000000

  24. #define NGX_SLAB_SHIFT_MASK  0x000000000000000f
  25. #define NGX_SLAB_MAP_MASK    0xffffffff00000000
  26. #define NGX_SLAB_MAP_SHIFT   32

  27. #define NGX_SLAB_BUSY        0xffffffffffffffff

  28. #endif


  29. #if (NGX_DEBUG_MALLOC)

  30. #define ngx_slab_junk(p, size)     ngx_memset(p, 0xA5, size)

  31. #elif (NGX_HAVE_DEBUG_MALLOC)

  32. #define ngx_slab_junk(p, size)                                                \
  33.     if (ngx_debug_malloc)          ngx_memset(p, 0xA5, size)

  34. #else

  35. #define ngx_slab_junk(p, size)

  36. #endif

  37. static ngx_slab_page_t *ngx_slab_alloc_pages(ngx_slab_pool_t *pool,
  38.     ngx_uint_t pages);
  39. static void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
  40.     ngx_uint_t pages);
  41. static void ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level,
  42.     char *text);


  43. static ngx_uint_t  ngx_slab_max_size;
  44. static ngx_uint_t  ngx_slab_exact_size;
  45. static ngx_uint_t  ngx_slab_exact_shift;


  46. void
  47. ngx_slab_init(ngx_slab_pool_t *pool)
  48. {
  49.     u_char           *p;
  50.     size_t            size;
  51.     ngx_int_t         m;
  52.     ngx_uint_t        i, n, pages;
  53.     ngx_slab_page_t  *slots;

  54.     /* STUB */
  55.     if (ngx_slab_max_size == 0) {
  56.         ngx_slab_max_size = ngx_pagesize / 2;
  57.         ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t));
  58.         for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) {
  59.             /* void */
  60.         }
  61.     }
  62.     /**/

  63.     pool->min_size = 1 << pool->min_shift;

  64.     p = (u_char *) pool + sizeof(ngx_slab_pool_t);
  65.     size = pool->end - p;

  66.     ngx_slab_junk(p, size);

  67.     slots = (ngx_slab_page_t *) p;
  68.     n = ngx_pagesize_shift - pool->min_shift;

  69.     for (i = 0; i < n; i++) {
  70.         slots[i].slab = 0;
  71.         slots[i].next = &slots[i];
  72.         slots[i].prev = 0;
  73.     }

  74.     p += n * sizeof(ngx_slab_page_t);

  75.     pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t)));

  76.     ngx_memzero(p, pages * sizeof(ngx_slab_page_t));

  77.     pool->pages = (ngx_slab_page_t *) p;

  78.     pool->free.prev = 0;
  79.     pool->free.next = (ngx_slab_page_t *) p;

  80.     pool->pages->slab = pages;
  81.     pool->pages->next = &pool->free;
  82.     pool->pages->prev = (uintptr_t) &pool->free;

  83.     pool->start = (u_char *)
  84.                   ngx_align_ptr((uintptr_t) p + pages * sizeof(ngx_slab_page_t),
  85.                                  ngx_pagesize);

  86.     m = pages - (pool->end - pool->start) / ngx_pagesize;
  87.     if (m > 0) {
  88.         pages -= m;
  89.         pool->pages->slab = pages;
  90.     }

  91.     pool->last = pool->pages + pages;

  92.     pool->log_nomem = 1;
  93.     pool->log_ctx = &pool->zero;
  94.     pool->zero = '\0';
  95. }


  96. void *
  97. ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
  98. {
  99.     void  *p;

  100.     ngx_shmtx_lock(&pool->mutex);

  101.     p = ngx_slab_alloc_locked(pool, size);

  102.     ngx_shmtx_unlock(&pool->mutex);

  103.     return p;
  104. }


  105. void *
  106. ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size)
  107. {
  108.     size_t            s;
  109.     uintptr_t         p, n, m, mask, *bitmap;
  110.     ngx_uint_t        i, slot, shift, map;
  111.     ngx_slab_page_t  *page, *prev, *slots;

  112.     if (size > ngx_slab_max_size) {

  113.         ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
  114.                        "slab alloc: %uz", size);

  115.         page = ngx_slab_alloc_pages(pool, (size >> ngx_pagesize_shift)
  116.                                           + ((size % ngx_pagesize) ? 1 : 0));
  117.         if (page) {
  118.             p = (page - pool->pages) << ngx_pagesize_shift;
  119.             p += (uintptr_t) pool->start;

  120.         } else {
  121.             p = 0;
  122.         }

  123.         goto done;
  124.     }

  125.     if (size > pool->min_size) {
  126.         shift = 1;
  127.         for (s = size - 1; s >>= 1; shift++) { /* void */ }
  128.         slot = shift - pool->min_shift;

  129.     } else {
  130.         size = pool->min_size;
  131.         shift = pool->min_shift;
  132.         slot = 0;
  133.     }

  134.     ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
  135.                    "slab alloc: %uz slot: %ui", size, slot);

  136.     slots = (ngx_slab_page_t *) ((u_char *) pool + sizeof(ngx_slab_pool_t));
  137.     page = slots[slot].next;

  138.     if (page->next != page) {

  139.         if (shift < ngx_slab_exact_shift) {

  140.             do {
  141.                 p = (page - pool->pages) << ngx_pagesize_shift;
  142.                 bitmap = (uintptr_t *) (pool->start + p);

  143.                 map = (1 << (ngx_pagesize_shift - shift))
  144.                           / (sizeof(uintptr_t) * 8);

  145.                 for (n = 0; n < map; n++) {

  146.                     if (bitmap[n] != NGX_SLAB_BUSY) {

  147.                         for (m = 1, i = 0; m; m <<= 1, i++) {
  148.                             if ((bitmap[n] & m)) {
  149.                                 continue;
  150.                             }

  151.                             bitmap[n] |= m;

  152.                             i = ((n * sizeof(uintptr_t) * 8) << shift)
  153.                                 + (i << shift);

  154.                             if (bitmap[n] == NGX_SLAB_BUSY) {
  155.                                 for (n = n + 1; n < map; n++) {
  156.                                      if (bitmap[n] != NGX_SLAB_BUSY) {
  157.                                          p = (uintptr_t) bitmap + i;

  158.                                          goto done;
  159.                                      }
  160.                                 }

  161.                                 prev = (ngx_slab_page_t *)
  162.                                             (page->prev & ~NGX_SLAB_PAGE_MASK);
  163.                                 prev->next = page->next;
  164.                                 page->next->prev = page->prev;

  165.                                 page->next = NULL;
  166.                                 page->prev = NGX_SLAB_SMALL;
  167.                             }

  168.                             p = (uintptr_t) bitmap + i;

  169.                             goto done;
  170.                         }
  171.                     }
  172.                 }

  173.                 page = page->next;

  174.             } while (page);

  175.         } else if (shift == ngx_slab_exact_shift) {

  176.             do {
  177.                 if (page->slab != NGX_SLAB_BUSY) {

  178.                     for (m = 1, i = 0; m; m <<= 1, i++) {
  179.                         if ((page->slab & m)) {
  180.                             continue;
  181.                         }

  182.                         page->slab |= m;

  183.                         if (page->slab == NGX_SLAB_BUSY) {
  184.                             prev = (ngx_slab_page_t *)
  185.                                             (page->prev & ~NGX_SLAB_PAGE_MASK);
  186.                             prev->next = page->next;
  187.                             page->next->prev = page->prev;

  188.                             page->next = NULL;
  189.                             page->prev = NGX_SLAB_EXACT;
  190.                         }

  191.                         p = (page - pool->pages) << ngx_pagesize_shift;
  192.                         p += i << shift;
  193.                         p += (uintptr_t) pool->start;

  194.                         goto done;
  195.                     }
  196.                 }

  197.                 page = page->next;

  198.             } while (page);

  199.         } else { /* shift > ngx_slab_exact_shift */

  200.             n = ngx_pagesize_shift - (page->slab & NGX_SLAB_SHIFT_MASK);
  201.             n = 1 << n;
  202.             n = ((uintptr_t) 1 << n) - 1;
  203.             mask = n << NGX_SLAB_MAP_SHIFT;

  204.             do {
  205.                 if ((page->slab & NGX_SLAB_MAP_MASK) != mask) {

  206.                     for (m = (uintptr_t) 1 << NGX_SLAB_MAP_SHIFT, i = 0;
  207.                          m & mask;
  208.                          m <<= 1, i++)
  209.                     {
  210.                         if ((page->slab & m)) {
  211.                             continue;
  212.                         }

  213.                         page->slab |= m;

  214.                         if ((page->slab & NGX_SLAB_MAP_MASK) == mask) {
  215.                             prev = (ngx_slab_page_t *)
  216.                                             (page->prev & ~NGX_SLAB_PAGE_MASK);
  217.                             prev->next = page->next;
  218.                             page->next->prev = page->prev;

  219.                             page->next = NULL;
  220.                             page->prev = NGX_SLAB_BIG;
  221.                         }

  222.                         p = (page - pool->pages) << ngx_pagesize_shift;
  223.                         p += i << shift;
  224.                         p += (uintptr_t) pool->start;

  225.                         goto done;
  226.                     }
  227.                 }

  228.                 page = page->next;

  229.             } while (page);
  230.         }
  231.     }

  232.     page = ngx_slab_alloc_pages(pool, 1);

  233.     if (page) {
  234.         if (shift < ngx_slab_exact_shift) {
  235.             p = (page - pool->pages) << ngx_pagesize_shift;
  236.             bitmap = (uintptr_t *) (pool->start + p);

  237.             s = 1 << shift;
  238.             n = (1 << (ngx_pagesize_shift - shift)) / 8 / s;

  239.             if (n == 0) {
  240.                 n = 1;
  241.             }

  242.             bitmap[0] = (2 << n) - 1;

  243.             map = (1 << (ngx_pagesize_shift - shift)) / (sizeof(uintptr_t) * 8);

  244.             for (i = 1; i < map; i++) {
  245.                 bitmap[i] = 0;
  246.             }

  247.             page->slab = shift;
  248.             page->next = &slots[slot];
  249.             page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_SMALL;

  250.             slots[slot].next = page;

  251.             p = ((page - pool->pages) << ngx_pagesize_shift) + s * n;
  252.             p += (uintptr_t) pool->start;

  253.             goto done;

  254.         } else if (shift == ngx_slab_exact_shift) {

  255.             page->slab = 1;
  256.             page->next = &slots[slot];
  257.             page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_EXACT;

  258.             slots[slot].next = page;

  259.             p = (page - pool->pages) << ngx_pagesize_shift;
  260.             p += (uintptr_t) pool->start;

  261.             goto done;

  262.         } else { /* shift > ngx_slab_exact_shift */

  263.             page->slab = ((uintptr_t) 1 << NGX_SLAB_MAP_SHIFT) | shift;
  264.             page->next = &slots[slot];
  265.             page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_BIG;

  266.             slots[slot].next = page;

  267.             p = (page - pool->pages) << ngx_pagesize_shift;
  268.             p += (uintptr_t) pool->start;

  269.             goto done;
  270.         }
  271.     }

  272.     p = 0;

  273. done:

  274.     ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab alloc: %p", p);

  275.     return (void *) p;
  276. }


  277. void *
  278. ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size)
  279. {
  280.     void  *p;

  281.     ngx_shmtx_lock(&pool->mutex);

  282.     p = ngx_slab_calloc_locked(pool, size);

  283.     ngx_shmtx_unlock(&pool->mutex);

  284.     return p;
  285. }


  286. void *
  287. ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size)
  288. {
  289.     void  *p;

  290.     p = ngx_slab_alloc_locked(pool, size);
  291.     if (p) {
  292.         ngx_memzero(p, size);
  293.     }

  294.     return p;
  295. }


  296. void
  297. ngx_slab_free(ngx_slab_pool_t *pool, void *p)
  298. {
  299.     ngx_shmtx_lock(&pool->mutex);

  300.     ngx_slab_free_locked(pool, p);

  301.     ngx_shmtx_unlock(&pool->mutex);
  302. }


  303. void
  304. ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p)
  305. {
  306.     size_t            size;
  307.     uintptr_t         slab, m, *bitmap;
  308.     ngx_uint_t        n, type, slot, shift, map;
  309.     ngx_slab_page_t  *slots, *page;

  310.     ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab free: %p", p);

  311.     if ((u_char *) p < pool->start || (u_char *) p > pool->end) {
  312.         ngx_slab_error(pool, NGX_LOG_ALERT, "ngx_slab_free(): outside of pool");
  313.         goto fail;
  314.     }

  315.     n = ((u_char *) p - pool->start) >> ngx_pagesize_shift;
  316.     page = &pool->pages[n];
  317.     slab = page->slab;
  318.     type = page->prev & NGX_SLAB_PAGE_MASK;

  319.     switch (type) {

  320.     case NGX_SLAB_SMALL:

  321.         shift = slab & NGX_SLAB_SHIFT_MASK;
  322.         size = 1 << shift;

  323.         if ((uintptr_t) p & (size - 1)) {
  324.             goto wrong_chunk;
  325.         }

  326.         n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift;
  327.         m = (uintptr_t) 1 << (n & (sizeof(uintptr_t) * 8 - 1));
  328.         n /= (sizeof(uintptr_t) * 8);
  329.         bitmap = (uintptr_t *)
  330.                              ((uintptr_t) p & ~((uintptr_t) ngx_pagesize - 1));

  331.         if (bitmap[n] & m) {

  332.             if (page->next == NULL) {
  333.                 slots = (ngx_slab_page_t *)
  334.                                    ((u_char *) pool + sizeof(ngx_slab_pool_t));
  335.                 slot = shift - pool->min_shift;

  336.                 page->next = slots[slot].next;
  337.                 slots[slot].next = page;

  338.                 page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_SMALL;
  339.                 page->next->prev = (uintptr_t) page | NGX_SLAB_SMALL;
  340.             }

  341.             bitmap[n] &= ~m;

  342.             n = (1 << (ngx_pagesize_shift - shift)) / 8 / (1 << shift);

  343.             if (n == 0) {
  344.                 n = 1;
  345.             }

  346.             if (bitmap[0] & ~(((uintptr_t) 1 << n) - 1)) {
  347.                 goto done;
  348.             }

  349.             map = (1 << (ngx_pagesize_shift - shift)) / (sizeof(uintptr_t) * 8);

  350.             for (n = 1; n < map; n++) {
  351.                 if (bitmap[n]) {
  352.                     goto done;
  353.                 }
  354.             }

  355.             ngx_slab_free_pages(pool, page, 1);

  356.             goto done;
  357.         }

  358.         goto chunk_already_free;

  359.     case NGX_SLAB_EXACT:

  360.         m = (uintptr_t) 1 <<
  361.                 (((uintptr_t) p & (ngx_pagesize - 1)) >> ngx_slab_exact_shift);
  362.         size = ngx_slab_exact_size;

  363.         if ((uintptr_t) p & (size - 1)) {
  364.             goto wrong_chunk;
  365.         }

  366.         if (slab & m) {
  367.             if (slab == NGX_SLAB_BUSY) {
  368.                 slots = (ngx_slab_page_t *)
  369.                                    ((u_char *) pool + sizeof(ngx_slab_pool_t));
  370.                 slot = ngx_slab_exact_shift - pool->min_shift;

  371.                 page->next = slots[slot].next;
  372.                 slots[slot].next = page;

  373.                 page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_EXACT;
  374.                 page->next->prev = (uintptr_t) page | NGX_SLAB_EXACT;
  375.             }

  376.             page->slab &= ~m;

  377.             if (page->slab) {
  378.                 goto done;
  379.             }

  380.             ngx_slab_free_pages(pool, page, 1);

  381.             goto done;
  382.         }

  383.         goto chunk_already_free;

  384.     case NGX_SLAB_BIG:

  385.         shift = slab & NGX_SLAB_SHIFT_MASK;
  386.         size = 1 << shift;

  387.         if ((uintptr_t) p & (size - 1)) {
  388.             goto wrong_chunk;
  389.         }

  390.         m = (uintptr_t) 1 << ((((uintptr_t) p & (ngx_pagesize - 1)) >> shift)
  391.                               + NGX_SLAB_MAP_SHIFT);

  392.         if (slab & m) {

  393.             if (page->next == NULL) {
  394.                 slots = (ngx_slab_page_t *)
  395.                                    ((u_char *) pool + sizeof(ngx_slab_pool_t));
  396.                 slot = shift - pool->min_shift;

  397.                 page->next = slots[slot].next;
  398.                 slots[slot].next = page;

  399.                 page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_BIG;
  400.                 page->next->prev = (uintptr_t) page | NGX_SLAB_BIG;
  401.             }

  402.             page->slab &= ~m;

  403.             if (page->slab & NGX_SLAB_MAP_MASK) {
  404.                 goto done;
  405.             }

  406.             ngx_slab_free_pages(pool, page, 1);

  407.             goto done;
  408.         }

  409.         goto chunk_already_free;

  410.     case NGX_SLAB_PAGE:

  411.         if ((uintptr_t) p & (ngx_pagesize - 1)) {
  412.             goto wrong_chunk;
  413.         }

  414.         if (slab == NGX_SLAB_PAGE_FREE) {
  415.             ngx_slab_error(pool, NGX_LOG_ALERT,
  416.                            "ngx_slab_free(): page is already free");
  417.             goto fail;
  418.         }

  419.         if (slab == NGX_SLAB_PAGE_BUSY) {
  420.             ngx_slab_error(pool, NGX_LOG_ALERT,
  421.                            "ngx_slab_free(): pointer to wrong page");
  422.             goto fail;
  423.         }

  424.         n = ((u_char *) p - pool->start) >> ngx_pagesize_shift;
  425.         size = slab & ~NGX_SLAB_PAGE_START;

  426.         ngx_slab_free_pages(pool, &pool->pages[n], size);

  427.         ngx_slab_junk(p, size << ngx_pagesize_shift);

  428.         return;
  429.     }

  430.     /* not reached */

  431.     return;

  432. done:

  433.     ngx_slab_junk(p, size);

  434.     return;

  435. wrong_chunk:

  436.     ngx_slab_error(pool, NGX_LOG_ALERT,
  437.                    "ngx_slab_free(): pointer to wrong chunk");

  438.     goto fail;

  439. chunk_already_free:

  440.     ngx_slab_error(pool, NGX_LOG_ALERT,
  441.                    "ngx_slab_free(): chunk is already free");

  442. fail:

  443.     return;
  444. }


  445. static ngx_slab_page_t *
  446. ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages)
  447. {
  448.     ngx_slab_page_t  *page, *p;

  449.     for (page = pool->free.next; page != &pool->free; page = page->next) {

  450.         if (page->slab >= pages) {

  451.             if (page->slab > pages) {
  452.                 page[page->slab - 1].prev = (uintptr_t) &page[pages];

  453.                 page[pages].slab = page->slab - pages;
  454.                 page[pages].next = page->next;
  455.                 page[pages].prev = page->prev;

  456.                 p = (ngx_slab_page_t *) page->prev;
  457.                 p->next = &page[pages];
  458.                 page->next->prev = (uintptr_t) &page[pages];

  459.             } else {
  460.                 p = (ngx_slab_page_t *) page->prev;
  461.                 p->next = page->next;
  462.                 page->next->prev = page->prev;
  463.             }

  464.             page->slab = pages | NGX_SLAB_PAGE_START;
  465.             page->next = NULL;
  466.             page->prev = NGX_SLAB_PAGE;

  467.             if (--pages == 0) {
  468.                 return page;
  469.             }

  470.             for (p = page + 1; pages; pages--) {
  471.                 p->slab = NGX_SLAB_PAGE_BUSY;
  472.                 p->next = NULL;
  473.                 p->prev = NGX_SLAB_PAGE;
  474.                 p++;
  475.             }

  476.             return page;
  477.         }
  478.     }

  479.     if (pool->log_nomem) {
  480.         ngx_slab_error(pool, NGX_LOG_CRIT,
  481.                        "ngx_slab_alloc() failed: no memory");
  482.     }

  483.     return NULL;
  484. }


  485. static void
  486. ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
  487.     ngx_uint_t pages)
  488. {
  489.     ngx_uint_t        type;
  490.     ngx_slab_page_t  *prev, *join;

  491.     page->slab = pages--;

  492.     if (pages) {
  493.         ngx_memzero(&page[1], pages * sizeof(ngx_slab_page_t));
  494.     }

  495.     if (page->next) {
  496.         prev = (ngx_slab_page_t *) (page->prev & ~NGX_SLAB_PAGE_MASK);
  497.         prev->next = page->next;
  498.         page->next->prev = page->prev;
  499.     }

  500.     join = page + page->slab;

  501.     if (join < pool->last) {
  502.         type = join->prev & NGX_SLAB_PAGE_MASK;

  503.         if (type == NGX_SLAB_PAGE) {

  504.             if (join->next != NULL) {
  505.                 pages += join->slab;
  506.                 page->slab += join->slab;

  507.                 prev = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK);
  508.                 prev->next = join->next;
  509.                 join->next->prev = join->prev;

  510.                 join->slab = NGX_SLAB_PAGE_FREE;
  511.                 join->next = NULL;
  512.                 join->prev = NGX_SLAB_PAGE;
  513.             }
  514.         }
  515.     }

  516.     if (page > pool->pages) {
  517.         join = page - 1;
  518.         type = join->prev & NGX_SLAB_PAGE_MASK;

  519.         if (type == NGX_SLAB_PAGE) {

  520.             if (join->slab == NGX_SLAB_PAGE_FREE) {
  521.                 join = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK);
  522.             }

  523.             if (join->next != NULL) {
  524.                 pages += join->slab;
  525.                 join->slab += page->slab;

  526.                 prev = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK);
  527.                 prev->next = join->next;
  528.                 join->next->prev = join->prev;

  529.                 page->slab = NGX_SLAB_PAGE_FREE;
  530.                 page->next = NULL;
  531.                 page->prev = NGX_SLAB_PAGE;

  532.                 page = join;
  533.             }
  534.         }
  535.     }

  536.     if (pages) {
  537.         page[pages].prev = (uintptr_t) page;
  538.     }

  539.     page->prev = (uintptr_t) &pool->free;
  540.     page->next = pool->free.next;

  541.     page->next->prev = (uintptr_t) page;

  542.     pool->free.next = page;
  543. }


  544. static void
  545. ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level, char *text)
  546. {
  547.     ngx_log_error(level, ngx_cycle->log, 0, "%s%s", text, pool->log_ctx);
  548. }