Skip to content

Commit 426ac32

Browse files
madmajestronikic
authored andcommitted
Fix minimum block size used by sma layer
The minimum allocation size previously used by the sma layer was too small. This could lead to small free blocks that could not be used for any allocation. To keep separation of layers, the expected minimum allocation size is now passed to apc_sma_init().
1 parent 3c23c47 commit 426ac32

File tree

4 files changed

+16
-13
lines changed

4 files changed

+16
-13
lines changed

apc_cache.h

+2
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ static inline void apc_cache_runlock(apc_cache_t *cache) {
299299
}
300300
}
301301

302+
#define APC_ENTRY_MIN_ALLOC_SIZE (ZEND_MM_ALIGNED_SIZE(sizeof(apc_cache_entry_t)) + ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(1)))
303+
302304
#endif
303305

304306
/*

apc_sma.c

+11-11
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,15 @@ static inline block_t *find_block(sma_header_t *header, size_t realsize) {
152152
}
153153

154154
/* {{{ sma_allocate: tries to allocate at least size bytes in a segment */
155-
static APC_HOTSPOT size_t sma_allocate(sma_header_t *header, size_t size, size_t fragment, size_t *allocated)
155+
static APC_HOTSPOT size_t sma_allocate(sma_header_t *header, size_t size, size_t min_block_size, size_t *allocated)
156156
{
157157
void* shmaddr; /* header of shared memory segment */
158158
block_t* prv; /* block prior to working block */
159159
block_t* cur; /* working block in list */
160160
size_t realsize; /* actual size of block needed, including header */
161-
size_t block_size = ALIGNWORD(sizeof(struct block_t));
161+
size_t block_header_size = ALIGNWORD(sizeof(struct block_t));
162162

163-
realsize = ALIGNWORD(size + block_size);
163+
realsize = ALIGNWORD(size + block_header_size);
164164

165165
/*
166166
* First, insure that the segment contains at least realsize free bytes,
@@ -178,9 +178,9 @@ static APC_HOTSPOT size_t sma_allocate(sma_header_t *header, size_t size, size_t
178178
return SIZE_MAX;
179179
}
180180

181-
if (cur->size == realsize || (cur->size > realsize && cur->size < (realsize + (MINBLOCKSIZE + fragment)))) {
181+
if (cur->size >= realsize && cur->size < (realsize + min_block_size)) {
182182
/* cur is big enough for realsize, but too small to split - unlink it */
183-
*(allocated) = cur->size - block_size;
183+
*(allocated) = cur->size - block_header_size;
184184
prv = BLOCKAT(cur->fprev);
185185
prv->fnext = cur->fnext;
186186
BLOCKAT(cur->fnext)->fprev = OFFSET(prv);
@@ -192,7 +192,7 @@ static APC_HOTSPOT size_t sma_allocate(sma_header_t *header, size_t size, size_t
192192

193193
oldsize = cur->size;
194194
cur->size = realsize;
195-
*(allocated) = cur->size - block_size;
195+
*(allocated) = cur->size - block_header_size;
196196
nxt = NEXT_SBLOCK(cur);
197197
nxt->prev_size = 0; /* block is alloc'd */
198198
nxt->size = oldsize - realsize; /* and fix the size */
@@ -221,7 +221,7 @@ static APC_HOTSPOT size_t sma_allocate(sma_header_t *header, size_t size, size_t
221221
fprintf(stderr, "allocate(realsize=%d,size=%d,id=%d)\n", (int)(size), (int)(cur->size), cur->id);
222222
#endif
223223

224-
return OFFSET(cur) + block_size;
224+
return OFFSET(cur) + block_header_size;
225225
}
226226
/* }}} */
227227

@@ -288,7 +288,7 @@ static APC_HOTSPOT size_t sma_deallocate(void* shmaddr, size_t offset)
288288
/* }}} */
289289

290290
/* {{{ APC SMA API */
291-
PHP_APCU_API void apc_sma_init(apc_sma_t* sma, void** data, apc_sma_expunge_f expunge, int32_t num, size_t size, char *mask) {
291+
PHP_APCU_API void apc_sma_init(apc_sma_t* sma, void** data, apc_sma_expunge_f expunge, int32_t num, size_t size, size_t min_alloc_size, char *mask) {
292292
int32_t i;
293293

294294
if (sma->initialized) {
@@ -298,6 +298,7 @@ PHP_APCU_API void apc_sma_init(apc_sma_t* sma, void** data, apc_sma_expunge_f ex
298298
sma->initialized = 1;
299299
sma->expunge = expunge;
300300
sma->data = data;
301+
sma->min_block_size = min_alloc_size > 0 ? ALIGNWORD(min_alloc_size + ALIGNWORD(sizeof(struct block_t))) : MINBLOCKSIZE;
301302

302303
#ifdef APC_MMAP
303304
/*
@@ -399,7 +400,6 @@ PHP_APCU_API void apc_sma_detach(apc_sma_t* sma) {
399400
}
400401

401402
PHP_APCU_API void *apc_sma_malloc_ex(apc_sma_t *sma, size_t n, size_t *allocated) {
402-
size_t fragment = MINBLOCKSIZE;
403403
size_t off;
404404
int32_t i;
405405
zend_bool nuked = 0;
@@ -412,7 +412,7 @@ PHP_APCU_API void *apc_sma_malloc_ex(apc_sma_t *sma, size_t n, size_t *allocated
412412
return NULL;
413413
}
414414

415-
off = sma_allocate(SMA_HDR(sma, last), n, fragment, allocated);
415+
off = sma_allocate(SMA_HDR(sma, last), n, sma->min_block_size, allocated);
416416

417417
if (off != SIZE_MAX) {
418418
void* p = (void *)(SMA_ADDR(sma, last) + off);
@@ -434,7 +434,7 @@ PHP_APCU_API void *apc_sma_malloc_ex(apc_sma_t *sma, size_t n, size_t *allocated
434434
return NULL;
435435
}
436436

437-
off = sma_allocate(SMA_HDR(sma, i), n, fragment, allocated);
437+
off = sma_allocate(SMA_HDR(sma, i), n, sma->min_block_size, allocated);
438438
if (off != SIZE_MAX) {
439439
void* p = (void *)(SMA_ADDR(sma, i) + off);
440440
sma->last = i;

apc_sma.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ typedef struct _apc_sma_t {
7676
int32_t num; /* number of segments */
7777
size_t size; /* segment size */
7878
int32_t last; /* last segment */
79+
size_t min_block_size; /* expected minimum size of allocated blocks */
7980

8081
/* segments */
8182
apc_segment_t *segs; /* segments */
@@ -88,7 +89,7 @@ typedef struct _apc_sma_t {
8889
*/
8990
PHP_APCU_API void apc_sma_init(
9091
apc_sma_t* sma, void** data, apc_sma_expunge_f expunge,
91-
int32_t num, size_t size, char *mask);
92+
int32_t num, size_t size, size_t min_alloc_size, char *mask);
9293

9394
/*
9495
* apc_sma_detach will detach from shared memory and cleanup local allocations.

php_apc.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ static PHP_MINIT_FUNCTION(apcu)
247247
/* initialize shared memory allocator */
248248
apc_sma_init(
249249
&apc_sma, (void **) &apc_user_cache, (apc_sma_expunge_f) apc_cache_default_expunge,
250-
APCG(shm_segments), APCG(shm_size), mmap_file_mask);
250+
APCG(shm_segments), APCG(shm_size), APC_ENTRY_MIN_ALLOC_SIZE, mmap_file_mask);
251251

252252
REGISTER_LONG_CONSTANT(APC_SERIALIZER_CONSTANT, (zend_long)&_apc_register_serializer, CONST_PERSISTENT | CONST_CS);
253253

0 commit comments

Comments
 (0)