forked from liexusong/php-beast
-
Notifications
You must be signed in to change notification settings - Fork 1
/
beast_mm.c
376 lines (305 loc) · 9.53 KB
/
beast_mm.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| [email protected] so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Liexusong <[email protected]> |
+----------------------------------------------------------------------+
*/
/*
* The simple share memory manager algorithm
*/
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/types.h>
#ifdef PHP_WIN32
#include <Windows.h>
#else
#include <sys/mman.h>
#endif
#include "spinlock.h"
#include "beast_log.h"
#include "shm.h"
#define BEAST_SEGMENT_DEFAULT_SIZE (256 * 1024)
#define BLOCKAT(addr, offset) ((beast_block_t *)((char *)(addr) + (offset)))
#ifdef max
#undef max
#endif
#define max(a, b) ((a) > (b) ? (a) : (b))
typedef struct beast_header_s {
int segsize; /* size of entire segment */
int avail; /* bytes available memorys */
} beast_header_t;
typedef struct beast_block_s {
int size; /* size of this block */
int next; /* offset in segment of next free block */
} beast_block_t;
static int beast_mm_initialized = 0;
static void *beast_mm_block = NULL;
static int beast_mm_block_size = 0;
static beast_atomic_t *mm_lock;
extern int beast_pid;
void beast_mm_lock()
{
beast_spinlock(mm_lock, beast_pid);
}
void beast_mm_unlock()
{
beast_spinunlock(mm_lock, beast_pid);
}
/*
* memory align function
* @param bits, align bits
*/
static inline int beast_mm_alignmem(int bits)
{
typedef union {
void* p;
int i;
long l;
double d;
void (*f)();
} beast_word_t; /* may be 8 bits */
return sizeof(beast_word_t) * (1 + ((bits - 1) / sizeof(beast_word_t)));
}
static int beast_mm_allocate(void *shmaddr, int size)
{
beast_header_t *header; /* header of shared memory segment */
beast_block_t *prv; /* block prior to working block */
beast_block_t *cur; /* working block in list */
beast_block_t *prvbestfit; /* block before best fit */
int realsize; /* actual size of block needed, including header */
int minsize; /* for finding best fit */
int offset;
/* Realsize must be aligned to a word boundary on some architectures. */
realsize = size + beast_mm_alignmem(sizeof(int));
realsize = beast_mm_alignmem(max(realsize, sizeof(beast_block_t)));
/*
* First, insure that the segment contains at least realsize free bytes,
* even if they are not contiguous.
*/
header = (beast_header_t *)shmaddr;
if (header->avail < realsize) {
beast_write_log(beast_log_error,
"Not enough memory for beast_mm_alloc()");
return -1;
}
prvbestfit = 0; /* Best block prev's node */
minsize = INT_MAX;
prv = BLOCKAT(shmaddr, sizeof(beast_header_t)); /* Free list header */
while (prv->next != 0) {
cur = BLOCKAT(shmaddr, prv->next); /* Current active block */
if (cur->size == realsize) {
prvbestfit = prv;
break;
}
else if (cur->size > (sizeof(beast_block_t) + realsize)
&& cur->size < minsize)
{
prvbestfit = prv;
minsize = cur->size;
}
prv = cur;
}
if (prvbestfit == 0) { /* Not found best block */
return -1;
}
prv = prvbestfit;
cur = BLOCKAT(shmaddr, prv->next);
/* update the block header */
header->avail -= realsize;
if (cur->size == realsize) {
prv->next = cur->next;
} else {
beast_block_t *nxt; /* The new block (chopped part of cur) */
int nxtoffset; /* Offset of the block currently after cur */
int oldsize; /* Size of cur before split */
/* bestfit is too big; split it into two smaller blocks */
nxtoffset = cur->next;
oldsize = cur->size;
prv->next += realsize;
cur->size = realsize;
nxt = BLOCKAT(shmaddr, prv->next);
nxt->next = nxtoffset;
nxt->size = oldsize - realsize;
}
/* skip size field */
offset = (char *)cur - (char *)shmaddr;
return offset + beast_mm_alignmem(sizeof(int));
}
static int beast_mm_deallocate(void *shmaddr, int offset)
{
beast_header_t *header; /* Header of shared memory segment */
beast_block_t *cur; /* The new block to insert */
beast_block_t *prv; /* The block before cur */
beast_block_t *nxt; /* The block after cur */
int size; /* Size of deallocated block */
offset -= beast_mm_alignmem(sizeof(int)); /* Really offset */
/* Find position of new block in free list */
prv = BLOCKAT(shmaddr, sizeof(beast_header_t));
while (prv->next != 0 && prv->next < offset) {
prv = BLOCKAT(shmaddr, prv->next);
}
/* Insert new block after prv */
cur = BLOCKAT(shmaddr, offset);
cur->next = prv->next;
prv->next = offset;
/* Update the block header */
header = (beast_header_t *)shmaddr;
header->avail += cur->size;
size = cur->size;
if (((char *)prv) + prv->size == (char *) cur) {
/* cur and prv share an edge, combine them */
prv->size += cur->size;
prv->next = cur->next;
cur = prv;
}
nxt = BLOCKAT(shmaddr, cur->next);
if (((char *)cur) + cur->size == (char *) nxt) {
/* cur and nxt shared an edge, combine them */
cur->size += nxt->size;
cur->next = nxt->next;
}
return size;
}
void beast_mm_reinit()
{
beast_header_t *header;
beast_block_t *block;
header = (beast_header_t *)beast_mm_block;
header->segsize = beast_mm_block_size;
header->avail = beast_mm_block_size
- sizeof(beast_header_t)
- sizeof(beast_block_t)
- beast_mm_alignmem(sizeof(int));
/* The free list head block node */
block = BLOCKAT(beast_mm_block, sizeof(beast_header_t));
block->size = 0;
block->next = sizeof(beast_header_t) + sizeof(beast_block_t);
/* The avail block */
block = BLOCKAT(beast_mm_block, block->next);
block->size = header->avail;
block->next = 0;
}
/*
* Init memory manager
*/
int beast_mm_init(int block_size)
{
if (beast_mm_initialized) {
return 0;
}
/* Init memory manager lock */
mm_lock = (int *)beast_shm_alloc(sizeof(beast_atomic_t));
if (!mm_lock) {
beast_write_log(beast_log_error,
"Unable alloc share memory for memory manager lock");
return -1;
}
*mm_lock = 0;
/* Init share memory for beast */
if (block_size < BEAST_SEGMENT_DEFAULT_SIZE) {
beast_mm_block_size = BEAST_SEGMENT_DEFAULT_SIZE;
} else {
beast_mm_block_size = block_size;
}
beast_mm_block = (void *)beast_shm_alloc(beast_mm_block_size);
if (!beast_mm_block) {
beast_write_log(beast_log_error,
"Unable alloc share memory for beast");
beast_shm_free((void *)mm_lock, sizeof(beast_atomic_t));
return -1;
}
beast_mm_reinit();
beast_mm_initialized = 1;
return 0;
}
void *beast_mm_malloc(int size)
{
int offset;
void *p = NULL;
beast_mm_lock();
offset = beast_mm_allocate(beast_mm_block, size);
if (offset != -1) {
p = (void *)(((char *)beast_mm_block) + offset);
}
beast_mm_unlock();
return p;
}
void *beast_mm_calloc(int size)
{
int offset;
void *p = NULL;
beast_mm_lock();
offset = beast_mm_allocate(beast_mm_block, size);
if (offset != -1) {
p = (void *)(((char *)beast_mm_block) + offset);
}
beast_mm_unlock();
if (NULL != p) {
memset(p, 0, size);
}
return p;
}
void beast_mm_free(void *p)
{
int offset;
offset = (unsigned int)((char *)p - (char *)beast_mm_block);
if (offset <= 0) {
return;
}
beast_mm_lock();
beast_mm_deallocate(beast_mm_block, offset);
beast_mm_unlock();
}
void beast_mm_flush()
{
beast_mm_lock();
beast_mm_reinit();
beast_mm_unlock();
}
/*
* Get the avail's memory space
*/
int beast_mm_availspace()
{
int size;
beast_header_t *header = (beast_header_t *)beast_mm_block;
beast_mm_lock();
size = header->avail;
beast_mm_unlock();
return size;
}
/*
* Don't locked here, because the segsize not change forever
*/
int beast_mm_realspace()
{
int size;
beast_mm_lock();
size = ((beast_header_t *)beast_mm_block)->segsize;
beast_mm_unlock();
return size;
}
/*
* Destroy memory's manager
*/
void beast_mm_destroy()
{
if (beast_mm_initialized) {
beast_shm_free((void *)beast_mm_block, beast_mm_block_size);
beast_shm_free((void *)mm_lock, sizeof(beast_atomic_t));
beast_mm_initialized = 0;
}
}