Importing memory cache pool changes from nJScript.
This commit is contained in:
@@ -13,21 +13,20 @@
|
|||||||
* size. Page size must be a power of 2. A page can be used entirely or
|
* size. Page size must be a power of 2. A page can be used entirely or
|
||||||
* can be divided on chunks of equal size. Chunk size must be a power of 2.
|
* can be divided on chunks of equal size. Chunk size must be a power of 2.
|
||||||
* A cluster can contains pages with different chunk sizes. Cluster size
|
* A cluster can contains pages with different chunk sizes. Cluster size
|
||||||
* must be multiple of page size and may be not a power of 2. Allocations
|
* must be a multiple of page size and may be not a power of 2. Allocations
|
||||||
* greater than page are allocated outside clusters. Start addresses and
|
* greater than page are allocated outside clusters. Start addresses and
|
||||||
* sizes of clusters and large allocations are stored in rbtree to find
|
* sizes of the clusters and large allocations are stored in rbtree blocks
|
||||||
* them on free operations. The rbtree nodes are sorted by start addresses.
|
* to find them on free operations. The rbtree nodes are sorted by start
|
||||||
|
* addresses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
typedef struct nxt_mem_cache_page_s nxt_mem_cache_page_t;
|
typedef struct {
|
||||||
|
/*
|
||||||
struct nxt_mem_cache_page_s {
|
* Used to link pages with free chunks in pool chunk slot list
|
||||||
/* Chunk bitmap. There can be no more than 32 chunks in a page. */
|
* or to link free pages in clusters.
|
||||||
uint8_t map[4];
|
*/
|
||||||
|
nxt_queue_link_t link;
|
||||||
/* Number of free chunks of a chunked page. */
|
|
||||||
uint8_t chunks;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Size of chunks or page shifted by pool->chunk_size_shift.
|
* Size of chunks or page shifted by pool->chunk_size_shift.
|
||||||
@@ -37,21 +36,41 @@ struct nxt_mem_cache_page_s {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Page number in page cluster.
|
* Page number in page cluster.
|
||||||
* There can be no more than 65536 pages in a cluster.
|
* There can be no more than 256 pages in a cluster.
|
||||||
*/
|
*/
|
||||||
uint16_t number;
|
uint8_t number;
|
||||||
|
|
||||||
|
/* Number of free chunks of a chunked page. */
|
||||||
|
uint8_t chunks;
|
||||||
|
|
||||||
|
uint8_t _unused;
|
||||||
|
|
||||||
|
/* Chunk bitmap. There can be no more than 32 chunks in a page. */
|
||||||
|
uint8_t map[4];
|
||||||
|
} nxt_mem_cache_page_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* Block of cluster. The block is allocated apart of the cluster. */
|
||||||
|
NXT_MEM_CACHE_CLUSTER_BLOCK = 0,
|
||||||
/*
|
/*
|
||||||
* Used to link pages with free chunks in pool chunk slot list
|
* Block of large allocation.
|
||||||
* or to link free pages in clusters.
|
* The block is allocated apart of the allocation.
|
||||||
*/
|
*/
|
||||||
nxt_queue_link_t link;
|
NXT_MEM_CACHE_DISCRETE_BLOCK,
|
||||||
};
|
/*
|
||||||
|
* Block of large allocation.
|
||||||
|
* The block is allocated just after of the allocation.
|
||||||
|
*/
|
||||||
|
NXT_MEM_CACHE_EMBEDDED_BLOCK,
|
||||||
|
} nxt_mem_cache_block_type_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
NXT_RBTREE_NODE (node);
|
NXT_RBTREE_NODE (node);
|
||||||
uint8_t type;
|
nxt_mem_cache_block_type_t type:8;
|
||||||
|
|
||||||
|
/* Block size must be less than 4G. */
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
|
|
||||||
u_char *start;
|
u_char *start;
|
||||||
@@ -61,19 +80,22 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
nxt_queue_t pages;
|
nxt_queue_t pages;
|
||||||
|
|
||||||
|
/* Size of page chunks. */
|
||||||
#if (NXT_64BIT)
|
#if (NXT_64BIT)
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t chunks;
|
|
||||||
#else
|
#else
|
||||||
uint16_t size;
|
uint16_t size;
|
||||||
uint16_t chunks;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Maximum number of free chunks in chunked page. */
|
||||||
|
uint8_t chunks;
|
||||||
} nxt_mem_cache_slot_t;
|
} nxt_mem_cache_slot_t;
|
||||||
|
|
||||||
|
|
||||||
struct nxt_mem_cache_pool_s {
|
struct nxt_mem_cache_pool_s {
|
||||||
/* rbtree of nxt_mem_cache_block_t. */
|
/* rbtree of nxt_mem_cache_block_t. */
|
||||||
nxt_rbtree_t pages;
|
nxt_rbtree_t blocks;
|
||||||
|
|
||||||
nxt_queue_t free_pages;
|
nxt_queue_t free_pages;
|
||||||
|
|
||||||
@@ -87,40 +109,31 @@ struct nxt_mem_cache_pool_s {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* A cluster cache block. */
|
#define nxt_mem_cache_chunk_is_free(map, chunk) \
|
||||||
#define NXT_MEM_CACHE_CLUSTER_BLOCK 0
|
|
||||||
|
|
||||||
/* A discrete cache block of large allocation. */
|
|
||||||
#define NXT_MEM_CACHE_DISCRETE_BLOCK 1
|
|
||||||
/*
|
|
||||||
* An embedded cache block allocated together with large allocation
|
|
||||||
* just after the allocation.
|
|
||||||
*/
|
|
||||||
#define NXT_MEM_CACHE_EMBEDDED_BLOCK 2
|
|
||||||
|
|
||||||
|
|
||||||
#define \
|
|
||||||
nxt_mem_cache_chunk_is_free(map, chunk) \
|
|
||||||
((map[chunk / 8] & (0x80 >> (chunk & 7))) == 0)
|
((map[chunk / 8] & (0x80 >> (chunk & 7))) == 0)
|
||||||
|
|
||||||
|
|
||||||
#define \
|
#define nxt_mem_cache_chunk_set_free(map, chunk) \
|
||||||
nxt_mem_cache_chunk_set_free(map, chunk) \
|
|
||||||
map[chunk / 8] &= ~(0x80 >> (chunk & 7))
|
map[chunk / 8] &= ~(0x80 >> (chunk & 7))
|
||||||
|
|
||||||
|
|
||||||
#define \
|
#define nxt_mem_cache_free_junk(p, size) \
|
||||||
nxt_mem_cache_free_junk(p, size) \
|
memset((p), 0x5A, size)
|
||||||
nxt_memset((p), 0x5A, size)
|
|
||||||
|
|
||||||
|
#define nxt_is_power_of_two(value) \
|
||||||
|
((((value) - 1) & (value)) == 0)
|
||||||
|
|
||||||
|
|
||||||
static nxt_uint_t nxt_mem_cache_shift(nxt_uint_t n);
|
static nxt_uint_t nxt_mem_cache_shift(nxt_uint_t n);
|
||||||
|
#if !(NXT_DEBUG_MEMORY)
|
||||||
static void *nxt_mem_cache_alloc_small(nxt_mem_cache_pool_t *pool, size_t size);
|
static void *nxt_mem_cache_alloc_small(nxt_mem_cache_pool_t *pool, size_t size);
|
||||||
static nxt_uint_t nxt_mem_cache_alloc_chunk(u_char *map, nxt_uint_t size);
|
static nxt_uint_t nxt_mem_cache_alloc_chunk(u_char *map, nxt_uint_t size);
|
||||||
static nxt_mem_cache_page_t *
|
static nxt_mem_cache_page_t *
|
||||||
nxt_mem_cache_alloc_page(nxt_mem_cache_pool_t *pool);
|
nxt_mem_cache_alloc_page(nxt_mem_cache_pool_t *pool);
|
||||||
static nxt_mem_cache_block_t *
|
static nxt_mem_cache_block_t *
|
||||||
nxt_mem_cache_alloc_cluster(nxt_mem_cache_pool_t *pool);
|
nxt_mem_cache_alloc_cluster(nxt_mem_cache_pool_t *pool);
|
||||||
|
#endif
|
||||||
static void *nxt_mem_cache_alloc_large(nxt_mem_cache_pool_t *pool,
|
static void *nxt_mem_cache_alloc_large(nxt_mem_cache_pool_t *pool,
|
||||||
size_t alignment, size_t size);
|
size_t alignment, size_t size);
|
||||||
static intptr_t nxt_mem_cache_rbtree_compare(nxt_rbtree_node_t *node1,
|
static intptr_t nxt_mem_cache_rbtree_compare(nxt_rbtree_node_t *node1,
|
||||||
@@ -137,9 +150,9 @@ nxt_mem_cache_pool_create(size_t cluster_size, size_t page_alignment,
|
|||||||
{
|
{
|
||||||
/* Alignment and sizes must be a power of 2. */
|
/* Alignment and sizes must be a power of 2. */
|
||||||
|
|
||||||
if (nxt_slow_path((page_alignment & (page_alignment - 1)) != 0
|
if (nxt_slow_path(!nxt_is_power_of_two(page_alignment)
|
||||||
|| (page_size & (page_size - 1)) != 0
|
|| !nxt_is_power_of_two(page_size)
|
||||||
|| (min_chunk_size & (min_chunk_size - 1)) != 0))
|
|| !nxt_is_power_of_two(min_chunk_size)))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -151,6 +164,7 @@ nxt_mem_cache_pool_create(size_t cluster_size, size_t page_alignment,
|
|||||||
|| page_size < min_chunk_size
|
|| page_size < min_chunk_size
|
||||||
|| min_chunk_size * 32 < page_size
|
|| min_chunk_size * 32 < page_size
|
||||||
|| cluster_size < page_size
|
|| cluster_size < page_size
|
||||||
|
|| cluster_size / page_size > 256
|
||||||
|| cluster_size % page_size != 0))
|
|| cluster_size % page_size != 0))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -181,7 +195,6 @@ nxt_mem_cache_pool_fast_create(size_t cluster_size, size_t page_alignment,
|
|||||||
+ slots * sizeof(nxt_mem_cache_slot_t));
|
+ slots * sizeof(nxt_mem_cache_slot_t));
|
||||||
|
|
||||||
if (nxt_fast_path(pool != NULL)) {
|
if (nxt_fast_path(pool != NULL)) {
|
||||||
|
|
||||||
pool->page_size = page_size;
|
pool->page_size = page_size;
|
||||||
pool->page_alignment = nxt_max(page_alignment, NXT_MAX_ALIGNMENT);
|
pool->page_alignment = nxt_max(page_alignment, NXT_MAX_ALIGNMENT);
|
||||||
pool->cluster_size = cluster_size;
|
pool->cluster_size = cluster_size;
|
||||||
@@ -202,7 +215,7 @@ nxt_mem_cache_pool_fast_create(size_t cluster_size, size_t page_alignment,
|
|||||||
pool->chunk_size_shift = nxt_mem_cache_shift(min_chunk_size);
|
pool->chunk_size_shift = nxt_mem_cache_shift(min_chunk_size);
|
||||||
pool->page_size_shift = nxt_mem_cache_shift(page_size);
|
pool->page_size_shift = nxt_mem_cache_shift(page_size);
|
||||||
|
|
||||||
nxt_rbtree_init(&pool->pages, nxt_mem_cache_rbtree_compare);
|
nxt_rbtree_init(&pool->blocks, nxt_mem_cache_rbtree_compare);
|
||||||
|
|
||||||
nxt_queue_init(&pool->free_pages);
|
nxt_queue_init(&pool->free_pages);
|
||||||
}
|
}
|
||||||
@@ -231,7 +244,7 @@ nxt_mem_cache_shift(nxt_uint_t n)
|
|||||||
nxt_bool_t
|
nxt_bool_t
|
||||||
nxt_mem_cache_pool_is_empty(nxt_mem_cache_pool_t *pool)
|
nxt_mem_cache_pool_is_empty(nxt_mem_cache_pool_t *pool)
|
||||||
{
|
{
|
||||||
return (nxt_rbtree_is_empty(&pool->pages)
|
return (nxt_rbtree_is_empty(&pool->blocks)
|
||||||
&& nxt_queue_is_empty(&pool->free_pages));
|
&& nxt_queue_is_empty(&pool->free_pages));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,16 +256,13 @@ nxt_mem_cache_pool_destroy(nxt_mem_cache_pool_t *pool)
|
|||||||
nxt_rbtree_node_t *node, *next;
|
nxt_rbtree_node_t *node, *next;
|
||||||
nxt_mem_cache_block_t *block;
|
nxt_mem_cache_block_t *block;
|
||||||
|
|
||||||
for (node = nxt_rbtree_min(&pool->pages);
|
next = nxt_rbtree_root(&pool->blocks);
|
||||||
nxt_rbtree_is_there_successor(&pool->pages, node);
|
|
||||||
node = next)
|
|
||||||
{
|
|
||||||
next = nxt_rbtree_node_successor(&pool->pages, node);
|
|
||||||
|
|
||||||
|
while (next != nxt_rbtree_sentinel(&pool->blocks)) {
|
||||||
|
|
||||||
|
node = nxt_rbtree_destroy_next(&pool->blocks, &next);
|
||||||
block = (nxt_mem_cache_block_t *) node;
|
block = (nxt_mem_cache_block_t *) node;
|
||||||
|
|
||||||
nxt_rbtree_delete(&pool->pages, &block->node);
|
|
||||||
|
|
||||||
p = block->start;
|
p = block->start;
|
||||||
|
|
||||||
if (block->type != NXT_MEM_CACHE_EMBEDDED_BLOCK) {
|
if (block->type != NXT_MEM_CACHE_EMBEDDED_BLOCK) {
|
||||||
@@ -266,28 +276,19 @@ nxt_mem_cache_pool_destroy(nxt_mem_cache_pool_t *pool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
nxt_inline u_char *
|
|
||||||
nxt_mem_cache_page_addr(nxt_mem_cache_pool_t *pool, nxt_mem_cache_page_t *page)
|
|
||||||
{
|
|
||||||
nxt_mem_cache_block_t *block;
|
|
||||||
|
|
||||||
block = (nxt_mem_cache_block_t *)
|
|
||||||
((u_char *) page - page->number * sizeof(nxt_mem_cache_page_t)
|
|
||||||
- offsetof(nxt_mem_cache_block_t, pages));
|
|
||||||
|
|
||||||
return block->start + (page->number << pool->page_size_shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
nxt_mem_cache_alloc(nxt_mem_cache_pool_t *pool, size_t size)
|
nxt_mem_cache_alloc(nxt_mem_cache_pool_t *pool, size_t size)
|
||||||
{
|
{
|
||||||
nxt_thread_log_debug("mem cache alloc: %uz", size);
|
// nxt_debug(task, "mem cache alloc: %zd", size);
|
||||||
|
|
||||||
|
#if !(NXT_DEBUG_MEMORY)
|
||||||
|
|
||||||
if (size <= pool->page_size) {
|
if (size <= pool->page_size) {
|
||||||
return nxt_mem_cache_alloc_small(pool, size);
|
return nxt_mem_cache_alloc_small(pool, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
return nxt_mem_cache_alloc_large(pool, NXT_MAX_ALIGNMENT, size);
|
return nxt_mem_cache_alloc_large(pool, NXT_MAX_ALIGNMENT, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,7 +301,7 @@ nxt_mem_cache_zalloc(nxt_mem_cache_pool_t *pool, size_t size)
|
|||||||
p = nxt_mem_cache_alloc(pool, size);
|
p = nxt_mem_cache_alloc(pool, size);
|
||||||
|
|
||||||
if (nxt_fast_path(p != NULL)) {
|
if (nxt_fast_path(p != NULL)) {
|
||||||
nxt_memzero(p, size);
|
memset(p, 0, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
@@ -310,11 +311,13 @@ nxt_mem_cache_zalloc(nxt_mem_cache_pool_t *pool, size_t size)
|
|||||||
void *
|
void *
|
||||||
nxt_mem_cache_align(nxt_mem_cache_pool_t *pool, size_t alignment, size_t size)
|
nxt_mem_cache_align(nxt_mem_cache_pool_t *pool, size_t alignment, size_t size)
|
||||||
{
|
{
|
||||||
nxt_thread_log_debug("mem cache align: @%uz:%uz", alignment, size);
|
// nxt_debug(task, "mem cache align: @%zd:%zd", alignment, size);
|
||||||
|
|
||||||
/* Alignment must be a power of 2. */
|
/* Alignment must be a power of 2. */
|
||||||
|
|
||||||
if (nxt_fast_path((alignment - 1) & alignment) == 0) {
|
if (nxt_fast_path(nxt_is_power_of_two(alignment))) {
|
||||||
|
|
||||||
|
#if !(NXT_DEBUG_MEMORY)
|
||||||
|
|
||||||
if (size <= pool->page_size && alignment <= pool->page_alignment) {
|
if (size <= pool->page_size && alignment <= pool->page_alignment) {
|
||||||
size = nxt_max(size, alignment);
|
size = nxt_max(size, alignment);
|
||||||
@@ -324,6 +327,8 @@ nxt_mem_cache_align(nxt_mem_cache_pool_t *pool, size_t alignment, size_t size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
return nxt_mem_cache_alloc_large(pool, alignment, size);
|
return nxt_mem_cache_alloc_large(pool, alignment, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,13 +344,28 @@ nxt_mem_cache_zalign(nxt_mem_cache_pool_t *pool, size_t alignment, size_t size)
|
|||||||
p = nxt_mem_cache_align(pool, alignment, size);
|
p = nxt_mem_cache_align(pool, alignment, size);
|
||||||
|
|
||||||
if (nxt_fast_path(p != NULL)) {
|
if (nxt_fast_path(p != NULL)) {
|
||||||
nxt_memzero(p, size);
|
memset(p, 0, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !(NXT_DEBUG_MEMORY)
|
||||||
|
|
||||||
|
nxt_inline u_char *
|
||||||
|
nxt_mem_cache_page_addr(nxt_mem_cache_pool_t *pool, nxt_mem_cache_page_t *page)
|
||||||
|
{
|
||||||
|
nxt_mem_cache_block_t *block;
|
||||||
|
|
||||||
|
block = (nxt_mem_cache_block_t *)
|
||||||
|
((u_char *) page - page->number * sizeof(nxt_mem_cache_page_t)
|
||||||
|
- offsetof(nxt_mem_cache_block_t, pages));
|
||||||
|
|
||||||
|
return block->start + (page->number << pool->page_size_shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
nxt_mem_cache_alloc_small(nxt_mem_cache_pool_t *pool, size_t size)
|
nxt_mem_cache_alloc_small(nxt_mem_cache_pool_t *pool, size_t size)
|
||||||
{
|
{
|
||||||
@@ -416,7 +436,7 @@ nxt_mem_cache_alloc_small(nxt_mem_cache_pool_t *pool, size_t size)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
nxt_thread_log_debug("mem cache chunk:%uz alloc: %p", size, p);
|
// nxt_debug(task, "mem cache chunk:%uz alloc: %p", size, p);
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@@ -519,11 +539,13 @@ nxt_mem_cache_alloc_cluster(nxt_mem_cache_pool_t *pool)
|
|||||||
&cluster->pages[n].link);
|
&cluster->pages[n].link);
|
||||||
}
|
}
|
||||||
|
|
||||||
nxt_rbtree_insert(&pool->pages, &cluster->node);
|
nxt_rbtree_insert(&pool->blocks, &cluster->node);
|
||||||
|
|
||||||
return cluster;
|
return cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
nxt_mem_cache_alloc_large(nxt_mem_cache_pool_t *pool, size_t alignment,
|
nxt_mem_cache_alloc_large(nxt_mem_cache_pool_t *pool, size_t alignment,
|
||||||
@@ -534,39 +556,43 @@ nxt_mem_cache_alloc_large(nxt_mem_cache_pool_t *pool, size_t alignment,
|
|||||||
uint8_t type;
|
uint8_t type;
|
||||||
nxt_mem_cache_block_t *block;
|
nxt_mem_cache_block_t *block;
|
||||||
|
|
||||||
if (nxt_slow_path((size - 1) & size) != 0) {
|
/* Allocation must be less than 4G. */
|
||||||
|
if (nxt_slow_path(size >= 0xffffffff)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nxt_is_power_of_two(size)) {
|
||||||
|
block = nxt_malloc(sizeof(nxt_mem_cache_block_t));
|
||||||
|
if (nxt_slow_path(block == NULL)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = nxt_memalign(alignment, size);
|
||||||
|
if (nxt_slow_path(p == NULL)) {
|
||||||
|
nxt_free(block);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = NXT_MEM_CACHE_DISCRETE_BLOCK;
|
||||||
|
|
||||||
|
} else {
|
||||||
aligned_size = nxt_align_size(size, sizeof(uintptr_t));
|
aligned_size = nxt_align_size(size, sizeof(uintptr_t));
|
||||||
|
|
||||||
p = nxt_memalign(alignment,
|
p = nxt_memalign(alignment,
|
||||||
aligned_size + sizeof(nxt_mem_cache_block_t));
|
aligned_size + sizeof(nxt_mem_cache_block_t));
|
||||||
|
|
||||||
if (nxt_slow_path(p == NULL)) {
|
if (nxt_slow_path(p == NULL)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
block = (nxt_mem_cache_block_t *) (p + aligned_size);
|
block = (nxt_mem_cache_block_t *) (p + aligned_size);
|
||||||
type = NXT_MEM_CACHE_EMBEDDED_BLOCK;
|
type = NXT_MEM_CACHE_EMBEDDED_BLOCK;
|
||||||
|
|
||||||
} else {
|
|
||||||
block = nxt_malloc(sizeof(nxt_mem_cache_block_t));
|
|
||||||
if (nxt_slow_path(block == NULL)) {
|
|
||||||
nxt_free(block);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = nxt_memalign(alignment, size);
|
|
||||||
if (nxt_slow_path(p == NULL)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
type = NXT_MEM_CACHE_DISCRETE_BLOCK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
block->type = type;
|
block->type = type;
|
||||||
block->size = size;
|
block->size = size;
|
||||||
block->start = p;
|
block->start = p;
|
||||||
|
|
||||||
nxt_rbtree_insert(&pool->pages, &block->node);
|
nxt_rbtree_insert(&pool->blocks, &block->node);
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@@ -590,17 +616,21 @@ nxt_mem_cache_free(nxt_mem_cache_pool_t *pool, void *p)
|
|||||||
const char *err;
|
const char *err;
|
||||||
nxt_mem_cache_block_t *block;
|
nxt_mem_cache_block_t *block;
|
||||||
|
|
||||||
nxt_thread_log_debug("mem cache free %p", p);
|
// nxt_debug(task, "mem cache free %p", p);
|
||||||
|
|
||||||
block = nxt_mem_cache_find_block(&pool->pages, p);
|
block = nxt_mem_cache_find_block(&pool->blocks, p);
|
||||||
|
|
||||||
if (nxt_fast_path(block != NULL)) {
|
if (nxt_fast_path(block != NULL)) {
|
||||||
|
|
||||||
if (block->type == NXT_MEM_CACHE_CLUSTER_BLOCK) {
|
if (block->type == NXT_MEM_CACHE_CLUSTER_BLOCK) {
|
||||||
err = nxt_mem_cache_chunk_free(pool, block, p);
|
err = nxt_mem_cache_chunk_free(pool, block, p);
|
||||||
|
|
||||||
|
if (nxt_fast_path(err == NULL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (nxt_fast_path(p == block->start)) {
|
} else if (nxt_fast_path(p == block->start)) {
|
||||||
nxt_rbtree_delete(&pool->pages, &block->node);
|
nxt_rbtree_delete(&pool->blocks, &block->node);
|
||||||
|
|
||||||
if (block->type == NXT_MEM_CACHE_DISCRETE_BLOCK) {
|
if (block->type == NXT_MEM_CACHE_DISCRETE_BLOCK) {
|
||||||
nxt_free(block);
|
nxt_free(block);
|
||||||
@@ -608,19 +638,17 @@ nxt_mem_cache_free(nxt_mem_cache_pool_t *pool, void *p)
|
|||||||
|
|
||||||
nxt_free(p);
|
nxt_free(p);
|
||||||
|
|
||||||
err = NULL;
|
return;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
err = "pointer to wrong page";
|
err = "freed pointer points to middle of block: %p";
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
err = "pointer is out of pool";
|
err = "freed pointer is out of pool: %p";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nxt_slow_path(err != NULL)) {
|
// nxt_log(task, NXT_LOG_CRIT, err, p);
|
||||||
nxt_thread_log_alert("nxt_mem_cache_pool_free(%p): %s", p, err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -668,7 +696,7 @@ nxt_mem_cache_chunk_free(nxt_mem_cache_pool_t *pool,
|
|||||||
page = &cluster->pages[n];
|
page = &cluster->pages[n];
|
||||||
|
|
||||||
if (page->size == 0) {
|
if (page->size == 0) {
|
||||||
return "page is already free";
|
return "freed pointer points to already free page: %p";
|
||||||
}
|
}
|
||||||
|
|
||||||
size = page->size << pool->chunk_size_shift;
|
size = page->size << pool->chunk_size_shift;
|
||||||
@@ -679,11 +707,11 @@ nxt_mem_cache_chunk_free(nxt_mem_cache_pool_t *pool,
|
|||||||
chunk = offset / size;
|
chunk = offset / size;
|
||||||
|
|
||||||
if (nxt_slow_path(offset != chunk * size)) {
|
if (nxt_slow_path(offset != chunk * size)) {
|
||||||
return "pointer to wrong chunk";
|
return "freed pointer points to wrong chunk: %p";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nxt_slow_path(nxt_mem_cache_chunk_is_free(page->map, chunk))) {
|
if (nxt_slow_path(nxt_mem_cache_chunk_is_free(page->map, chunk))) {
|
||||||
return "chunk is already free";
|
return "freed pointer points to already free chunk: %p";
|
||||||
}
|
}
|
||||||
|
|
||||||
nxt_mem_cache_chunk_set_free(page->map, chunk);
|
nxt_mem_cache_chunk_set_free(page->map, chunk);
|
||||||
@@ -715,7 +743,7 @@ nxt_mem_cache_chunk_free(nxt_mem_cache_pool_t *pool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (nxt_slow_path(p != start)) {
|
} else if (nxt_slow_path(p != start)) {
|
||||||
return "invalid pointer to chunk";
|
return "invalid pointer to chunk: %p";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add the free page to the pool's free pages tree. */
|
/* Add the free page to the pool's free pages tree. */
|
||||||
@@ -750,7 +778,7 @@ nxt_mem_cache_chunk_free(nxt_mem_cache_pool_t *pool,
|
|||||||
n--;
|
n--;
|
||||||
} while (n != 0);
|
} while (n != 0);
|
||||||
|
|
||||||
nxt_rbtree_delete(&pool->pages, &cluster->node);
|
nxt_rbtree_delete(&pool->blocks, &cluster->node);
|
||||||
|
|
||||||
p = cluster->start;
|
p = cluster->start;
|
||||||
|
|
||||||
@@ -759,9 +787,3 @@ nxt_mem_cache_chunk_free(nxt_mem_cache_pool_t *pool,
|
|||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const nxt_mem_proto_t nxt_mem_cache_proto = {
|
|
||||||
(nxt_mem_proto_alloc_t) nxt_mem_cache_alloc,
|
|
||||||
(nxt_mem_proto_free_t) nxt_mem_cache_free,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -492,3 +492,37 @@ nxt_rbtree_parent_relink(nxt_rbtree_node_t *subst, nxt_rbtree_node_t *node)
|
|||||||
link = (node == parent->left) ? &parent->left : &parent->right;
|
link = (node == parent->left) ? &parent->left : &parent->right;
|
||||||
*link = subst;
|
*link = subst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
nxt_rbtree_node_t *
|
||||||
|
nxt_rbtree_destroy_next(nxt_rbtree_t *tree, nxt_rbtree_node_t **next)
|
||||||
|
{
|
||||||
|
nxt_rbtree_node_t *node, *subst, *parent, *sentinel;
|
||||||
|
|
||||||
|
sentinel = nxt_rbtree_sentinel(tree);
|
||||||
|
|
||||||
|
/* Find the leftmost node. */
|
||||||
|
for (node = *next; node->left != sentinel; node = node->left);
|
||||||
|
|
||||||
|
/* Replace the leftmost node with its right child. */
|
||||||
|
subst = node->right;
|
||||||
|
parent = node->parent;
|
||||||
|
|
||||||
|
parent->left = subst;
|
||||||
|
subst->parent = parent;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The right child is used as the next start node. If the right child
|
||||||
|
* is the sentinel then parent of the leftmost node is used as the next
|
||||||
|
* start node. The parent of the root node is the sentinel so after
|
||||||
|
* the single root node will be replaced with the sentinel, the next
|
||||||
|
* start node will be equal to the sentinel and iteration will stop.
|
||||||
|
*/
|
||||||
|
if (subst == sentinel) {
|
||||||
|
subst = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
*next = subst;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|||||||
@@ -116,5 +116,16 @@ NXT_EXPORT nxt_rbtree_node_t
|
|||||||
nxt_rbtree_part_t *node);
|
nxt_rbtree_part_t *node);
|
||||||
NXT_EXPORT void nxt_rbtree_delete(nxt_rbtree_t *tree, nxt_rbtree_part_t *node);
|
NXT_EXPORT void nxt_rbtree_delete(nxt_rbtree_t *tree, nxt_rbtree_part_t *node);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nxt_rbtree_destroy_next() is iterator to use only while rbtree destruction.
|
||||||
|
* It deletes a node from rbtree and returns the node. The rbtree is not
|
||||||
|
* rebalanced after deletion. At the beginning the "next" parameter should
|
||||||
|
* be equal to rbtree root. The iterator should be called in loop until
|
||||||
|
* the "next" parameter will be equal to the rbtree sentinel. No other
|
||||||
|
* operations must be performed on the rbtree while destruction.
|
||||||
|
*/
|
||||||
|
NXT_EXPORT nxt_rbtree_node_t *nxt_rbtree_destroy_next(nxt_rbtree_t *tree,
|
||||||
|
nxt_rbtree_node_t **next);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _NXT_RBTREE_H_INCLUDED_ */
|
#endif /* _NXT_RBTREE_H_INCLUDED_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user