Annotation of embedaddon/nginx/src/core/ngx_slab.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (C) Igor Sysoev
4: * Copyright (C) Nginx, Inc.
5: */
6:
7: #include <ngx_config.h>
8: #include <ngx_core.h>
9:
10:
11: #define NGX_SLAB_PAGE_MASK 3
12: #define NGX_SLAB_PAGE 0
13: #define NGX_SLAB_BIG 1
14: #define NGX_SLAB_EXACT 2
15: #define NGX_SLAB_SMALL 3
16:
17: #if (NGX_PTR_SIZE == 4)
18:
19: #define NGX_SLAB_PAGE_FREE 0
20: #define NGX_SLAB_PAGE_BUSY 0xffffffff
21: #define NGX_SLAB_PAGE_START 0x80000000
22:
23: #define NGX_SLAB_SHIFT_MASK 0x0000000f
24: #define NGX_SLAB_MAP_MASK 0xffff0000
25: #define NGX_SLAB_MAP_SHIFT 16
26:
27: #define NGX_SLAB_BUSY 0xffffffff
28:
29: #else /* (NGX_PTR_SIZE == 8) */
30:
31: #define NGX_SLAB_PAGE_FREE 0
32: #define NGX_SLAB_PAGE_BUSY 0xffffffffffffffff
33: #define NGX_SLAB_PAGE_START 0x8000000000000000
34:
35: #define NGX_SLAB_SHIFT_MASK 0x000000000000000f
36: #define NGX_SLAB_MAP_MASK 0xffffffff00000000
37: #define NGX_SLAB_MAP_SHIFT 32
38:
39: #define NGX_SLAB_BUSY 0xffffffffffffffff
40:
41: #endif
42:
43:
44: #if (NGX_DEBUG_MALLOC)
45:
46: #define ngx_slab_junk(p, size) ngx_memset(p, 0xA5, size)
47:
48: #elif (NGX_HAVE_DEBUG_MALLOC)
49:
50: #define ngx_slab_junk(p, size) \
51: if (ngx_debug_malloc) ngx_memset(p, 0xA5, size)
52:
53: #else
54:
55: #define ngx_slab_junk(p, size)
56:
57: #endif
58:
59: static ngx_slab_page_t *ngx_slab_alloc_pages(ngx_slab_pool_t *pool,
60: ngx_uint_t pages);
61: static void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
62: ngx_uint_t pages);
63: static void ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level,
64: char *text);
65:
66:
67: static ngx_uint_t ngx_slab_max_size;
68: static ngx_uint_t ngx_slab_exact_size;
69: static ngx_uint_t ngx_slab_exact_shift;
70:
71:
72: void
73: ngx_slab_init(ngx_slab_pool_t *pool)
74: {
75: u_char *p;
76: size_t size;
77: ngx_int_t m;
78: ngx_uint_t i, n, pages;
79: ngx_slab_page_t *slots;
80:
81: /* STUB */
82: if (ngx_slab_max_size == 0) {
83: ngx_slab_max_size = ngx_pagesize / 2;
84: ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t));
85: for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) {
86: /* void */
87: }
88: }
89: /**/
90:
91: pool->min_size = 1 << pool->min_shift;
92:
93: p = (u_char *) pool + sizeof(ngx_slab_pool_t);
94: size = pool->end - p;
95:
96: ngx_slab_junk(p, size);
97:
98: slots = (ngx_slab_page_t *) p;
99: n = ngx_pagesize_shift - pool->min_shift;
100:
101: for (i = 0; i < n; i++) {
102: slots[i].slab = 0;
103: slots[i].next = &slots[i];
104: slots[i].prev = 0;
105: }
106:
107: p += n * sizeof(ngx_slab_page_t);
108:
109: pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t)));
110:
111: ngx_memzero(p, pages * sizeof(ngx_slab_page_t));
112:
113: pool->pages = (ngx_slab_page_t *) p;
114:
115: pool->free.prev = 0;
116: pool->free.next = (ngx_slab_page_t *) p;
117:
118: pool->pages->slab = pages;
119: pool->pages->next = &pool->free;
120: pool->pages->prev = (uintptr_t) &pool->free;
121:
122: pool->start = (u_char *)
123: ngx_align_ptr((uintptr_t) p + pages * sizeof(ngx_slab_page_t),
124: ngx_pagesize);
125:
126: m = pages - (pool->end - pool->start) / ngx_pagesize;
127: if (m > 0) {
128: pages -= m;
129: pool->pages->slab = pages;
130: }
131:
132: pool->log_ctx = &pool->zero;
133: pool->zero = '\0';
134: }
135:
136:
137: void *
138: ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
139: {
140: void *p;
141:
142: ngx_shmtx_lock(&pool->mutex);
143:
144: p = ngx_slab_alloc_locked(pool, size);
145:
146: ngx_shmtx_unlock(&pool->mutex);
147:
148: return p;
149: }
150:
151:
152: void *
153: ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size)
154: {
155: size_t s;
156: uintptr_t p, n, m, mask, *bitmap;
157: ngx_uint_t i, slot, shift, map;
158: ngx_slab_page_t *page, *prev, *slots;
159:
160: if (size >= ngx_slab_max_size) {
161:
162: ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
163: "slab alloc: %uz", size);
164:
165: page = ngx_slab_alloc_pages(pool, (size >> ngx_pagesize_shift)
166: + ((size % ngx_pagesize) ? 1 : 0));
167: if (page) {
168: p = (page - pool->pages) << ngx_pagesize_shift;
169: p += (uintptr_t) pool->start;
170:
171: } else {
172: p = 0;
173: }
174:
175: goto done;
176: }
177:
178: if (size > pool->min_size) {
179: shift = 1;
180: for (s = size - 1; s >>= 1; shift++) { /* void */ }
181: slot = shift - pool->min_shift;
182:
183: } else {
184: size = pool->min_size;
185: shift = pool->min_shift;
186: slot = 0;
187: }
188:
189: ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
190: "slab alloc: %uz slot: %ui", size, slot);
191:
192: slots = (ngx_slab_page_t *) ((u_char *) pool + sizeof(ngx_slab_pool_t));
193: page = slots[slot].next;
194:
195: if (page->next != page) {
196:
197: if (shift < ngx_slab_exact_shift) {
198:
199: do {
200: p = (page - pool->pages) << ngx_pagesize_shift;
201: bitmap = (uintptr_t *) (pool->start + p);
202:
203: map = (1 << (ngx_pagesize_shift - shift))
204: / (sizeof(uintptr_t) * 8);
205:
206: for (n = 0; n < map; n++) {
207:
208: if (bitmap[n] != NGX_SLAB_BUSY) {
209:
210: for (m = 1, i = 0; m; m <<= 1, i++) {
211: if ((bitmap[n] & m)) {
212: continue;
213: }
214:
215: bitmap[n] |= m;
216:
217: i = ((n * sizeof(uintptr_t) * 8) << shift)
218: + (i << shift);
219:
220: if (bitmap[n] == NGX_SLAB_BUSY) {
221: for (n = n + 1; n < map; n++) {
222: if (bitmap[n] != NGX_SLAB_BUSY) {
223: p = (uintptr_t) bitmap + i;
224:
225: goto done;
226: }
227: }
228:
229: prev = (ngx_slab_page_t *)
230: (page->prev & ~NGX_SLAB_PAGE_MASK);
231: prev->next = page->next;
232: page->next->prev = page->prev;
233:
234: page->next = NULL;
235: page->prev = NGX_SLAB_SMALL;
236: }
237:
238: p = (uintptr_t) bitmap + i;
239:
240: goto done;
241: }
242: }
243: }
244:
245: page = page->next;
246:
247: } while (page);
248:
249: } else if (shift == ngx_slab_exact_shift) {
250:
251: do {
252: if (page->slab != NGX_SLAB_BUSY) {
253:
254: for (m = 1, i = 0; m; m <<= 1, i++) {
255: if ((page->slab & m)) {
256: continue;
257: }
258:
259: page->slab |= m;
260:
261: if (page->slab == NGX_SLAB_BUSY) {
262: prev = (ngx_slab_page_t *)
263: (page->prev & ~NGX_SLAB_PAGE_MASK);
264: prev->next = page->next;
265: page->next->prev = page->prev;
266:
267: page->next = NULL;
268: page->prev = NGX_SLAB_EXACT;
269: }
270:
271: p = (page - pool->pages) << ngx_pagesize_shift;
272: p += i << shift;
273: p += (uintptr_t) pool->start;
274:
275: goto done;
276: }
277: }
278:
279: page = page->next;
280:
281: } while (page);
282:
283: } else { /* shift > ngx_slab_exact_shift */
284:
285: n = ngx_pagesize_shift - (page->slab & NGX_SLAB_SHIFT_MASK);
286: n = 1 << n;
287: n = ((uintptr_t) 1 << n) - 1;
288: mask = n << NGX_SLAB_MAP_SHIFT;
289:
290: do {
291: if ((page->slab & NGX_SLAB_MAP_MASK) != mask) {
292:
293: for (m = (uintptr_t) 1 << NGX_SLAB_MAP_SHIFT, i = 0;
294: m & mask;
295: m <<= 1, i++)
296: {
297: if ((page->slab & m)) {
298: continue;
299: }
300:
301: page->slab |= m;
302:
303: if ((page->slab & NGX_SLAB_MAP_MASK) == mask) {
304: prev = (ngx_slab_page_t *)
305: (page->prev & ~NGX_SLAB_PAGE_MASK);
306: prev->next = page->next;
307: page->next->prev = page->prev;
308:
309: page->next = NULL;
310: page->prev = NGX_SLAB_BIG;
311: }
312:
313: p = (page - pool->pages) << ngx_pagesize_shift;
314: p += i << shift;
315: p += (uintptr_t) pool->start;
316:
317: goto done;
318: }
319: }
320:
321: page = page->next;
322:
323: } while (page);
324: }
325: }
326:
327: page = ngx_slab_alloc_pages(pool, 1);
328:
329: if (page) {
330: if (shift < ngx_slab_exact_shift) {
331: p = (page - pool->pages) << ngx_pagesize_shift;
332: bitmap = (uintptr_t *) (pool->start + p);
333:
334: s = 1 << shift;
335: n = (1 << (ngx_pagesize_shift - shift)) / 8 / s;
336:
337: if (n == 0) {
338: n = 1;
339: }
340:
341: bitmap[0] = (2 << n) - 1;
342:
343: map = (1 << (ngx_pagesize_shift - shift)) / (sizeof(uintptr_t) * 8);
344:
345: for (i = 1; i < map; i++) {
346: bitmap[i] = 0;
347: }
348:
349: page->slab = shift;
350: page->next = &slots[slot];
351: page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_SMALL;
352:
353: slots[slot].next = page;
354:
355: p = ((page - pool->pages) << ngx_pagesize_shift) + s * n;
356: p += (uintptr_t) pool->start;
357:
358: goto done;
359:
360: } else if (shift == ngx_slab_exact_shift) {
361:
362: page->slab = 1;
363: page->next = &slots[slot];
364: page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_EXACT;
365:
366: slots[slot].next = page;
367:
368: p = (page - pool->pages) << ngx_pagesize_shift;
369: p += (uintptr_t) pool->start;
370:
371: goto done;
372:
373: } else { /* shift > ngx_slab_exact_shift */
374:
375: page->slab = ((uintptr_t) 1 << NGX_SLAB_MAP_SHIFT) | shift;
376: page->next = &slots[slot];
377: page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_BIG;
378:
379: slots[slot].next = page;
380:
381: p = (page - pool->pages) << ngx_pagesize_shift;
382: p += (uintptr_t) pool->start;
383:
384: goto done;
385: }
386: }
387:
388: p = 0;
389:
390: done:
391:
392: ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab alloc: %p", p);
393:
394: return (void *) p;
395: }
396:
397:
398: void
399: ngx_slab_free(ngx_slab_pool_t *pool, void *p)
400: {
401: ngx_shmtx_lock(&pool->mutex);
402:
403: ngx_slab_free_locked(pool, p);
404:
405: ngx_shmtx_unlock(&pool->mutex);
406: }
407:
408:
409: void
410: ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p)
411: {
412: size_t size;
413: uintptr_t slab, m, *bitmap;
414: ngx_uint_t n, type, slot, shift, map;
415: ngx_slab_page_t *slots, *page;
416:
417: ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab free: %p", p);
418:
419: if ((u_char *) p < pool->start || (u_char *) p > pool->end) {
420: ngx_slab_error(pool, NGX_LOG_ALERT, "ngx_slab_free(): outside of pool");
421: goto fail;
422: }
423:
424: n = ((u_char *) p - pool->start) >> ngx_pagesize_shift;
425: page = &pool->pages[n];
426: slab = page->slab;
427: type = page->prev & NGX_SLAB_PAGE_MASK;
428:
429: switch (type) {
430:
431: case NGX_SLAB_SMALL:
432:
433: shift = slab & NGX_SLAB_SHIFT_MASK;
434: size = 1 << shift;
435:
436: if ((uintptr_t) p & (size - 1)) {
437: goto wrong_chunk;
438: }
439:
440: n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift;
441: m = (uintptr_t) 1 << (n & (sizeof(uintptr_t) * 8 - 1));
442: n /= (sizeof(uintptr_t) * 8);
443: bitmap = (uintptr_t *) ((uintptr_t) p & ~(ngx_pagesize - 1));
444:
445: if (bitmap[n] & m) {
446:
447: if (page->next == NULL) {
448: slots = (ngx_slab_page_t *)
449: ((u_char *) pool + sizeof(ngx_slab_pool_t));
450: slot = shift - pool->min_shift;
451:
452: page->next = slots[slot].next;
453: slots[slot].next = page;
454:
455: page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_SMALL;
456: page->next->prev = (uintptr_t) page | NGX_SLAB_SMALL;
457: }
458:
459: bitmap[n] &= ~m;
460:
461: n = (1 << (ngx_pagesize_shift - shift)) / 8 / (1 << shift);
462:
463: if (n == 0) {
464: n = 1;
465: }
466:
467: if (bitmap[0] & ~(((uintptr_t) 1 << n) - 1)) {
468: goto done;
469: }
470:
471: map = (1 << (ngx_pagesize_shift - shift)) / (sizeof(uintptr_t) * 8);
472:
473: for (n = 1; n < map; n++) {
474: if (bitmap[n]) {
475: goto done;
476: }
477: }
478:
479: ngx_slab_free_pages(pool, page, 1);
480:
481: goto done;
482: }
483:
484: goto chunk_already_free;
485:
486: case NGX_SLAB_EXACT:
487:
488: m = (uintptr_t) 1 <<
489: (((uintptr_t) p & (ngx_pagesize - 1)) >> ngx_slab_exact_shift);
490: size = ngx_slab_exact_size;
491:
492: if ((uintptr_t) p & (size - 1)) {
493: goto wrong_chunk;
494: }
495:
496: if (slab & m) {
497: if (slab == NGX_SLAB_BUSY) {
498: slots = (ngx_slab_page_t *)
499: ((u_char *) pool + sizeof(ngx_slab_pool_t));
500: slot = ngx_slab_exact_shift - pool->min_shift;
501:
502: page->next = slots[slot].next;
503: slots[slot].next = page;
504:
505: page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_EXACT;
506: page->next->prev = (uintptr_t) page | NGX_SLAB_EXACT;
507: }
508:
509: page->slab &= ~m;
510:
511: if (page->slab) {
512: goto done;
513: }
514:
515: ngx_slab_free_pages(pool, page, 1);
516:
517: goto done;
518: }
519:
520: goto chunk_already_free;
521:
522: case NGX_SLAB_BIG:
523:
524: shift = slab & NGX_SLAB_SHIFT_MASK;
525: size = 1 << shift;
526:
527: if ((uintptr_t) p & (size - 1)) {
528: goto wrong_chunk;
529: }
530:
531: m = (uintptr_t) 1 << ((((uintptr_t) p & (ngx_pagesize - 1)) >> shift)
532: + NGX_SLAB_MAP_SHIFT);
533:
534: if (slab & m) {
535:
536: if (page->next == NULL) {
537: slots = (ngx_slab_page_t *)
538: ((u_char *) pool + sizeof(ngx_slab_pool_t));
539: slot = shift - pool->min_shift;
540:
541: page->next = slots[slot].next;
542: slots[slot].next = page;
543:
544: page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_BIG;
545: page->next->prev = (uintptr_t) page | NGX_SLAB_BIG;
546: }
547:
548: page->slab &= ~m;
549:
550: if (page->slab & NGX_SLAB_MAP_MASK) {
551: goto done;
552: }
553:
554: ngx_slab_free_pages(pool, page, 1);
555:
556: goto done;
557: }
558:
559: goto chunk_already_free;
560:
561: case NGX_SLAB_PAGE:
562:
563: if ((uintptr_t) p & (ngx_pagesize - 1)) {
564: goto wrong_chunk;
565: }
566:
567: if (slab == NGX_SLAB_PAGE_FREE) {
568: ngx_slab_error(pool, NGX_LOG_ALERT,
569: "ngx_slab_free(): page is already free");
570: goto fail;
571: }
572:
573: if (slab == NGX_SLAB_PAGE_BUSY) {
574: ngx_slab_error(pool, NGX_LOG_ALERT,
575: "ngx_slab_free(): pointer to wrong page");
576: goto fail;
577: }
578:
579: n = ((u_char *) p - pool->start) >> ngx_pagesize_shift;
580: size = slab & ~NGX_SLAB_PAGE_START;
581:
582: ngx_slab_free_pages(pool, &pool->pages[n], size);
583:
584: ngx_slab_junk(p, size << ngx_pagesize_shift);
585:
586: return;
587: }
588:
589: /* not reached */
590:
591: return;
592:
593: done:
594:
595: ngx_slab_junk(p, size);
596:
597: return;
598:
599: wrong_chunk:
600:
601: ngx_slab_error(pool, NGX_LOG_ALERT,
602: "ngx_slab_free(): pointer to wrong chunk");
603:
604: goto fail;
605:
606: chunk_already_free:
607:
608: ngx_slab_error(pool, NGX_LOG_ALERT,
609: "ngx_slab_free(): chunk is already free");
610:
611: fail:
612:
613: return;
614: }
615:
616:
617: static ngx_slab_page_t *
618: ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages)
619: {
620: ngx_slab_page_t *page, *p;
621:
622: for (page = pool->free.next; page != &pool->free; page = page->next) {
623:
624: if (page->slab >= pages) {
625:
626: if (page->slab > pages) {
627: page[pages].slab = page->slab - pages;
628: page[pages].next = page->next;
629: page[pages].prev = page->prev;
630:
631: p = (ngx_slab_page_t *) page->prev;
632: p->next = &page[pages];
633: page->next->prev = (uintptr_t) &page[pages];
634:
635: } else {
636: p = (ngx_slab_page_t *) page->prev;
637: p->next = page->next;
638: page->next->prev = page->prev;
639: }
640:
641: page->slab = pages | NGX_SLAB_PAGE_START;
642: page->next = NULL;
643: page->prev = NGX_SLAB_PAGE;
644:
645: if (--pages == 0) {
646: return page;
647: }
648:
649: for (p = page + 1; pages; pages--) {
650: p->slab = NGX_SLAB_PAGE_BUSY;
651: p->next = NULL;
652: p->prev = NGX_SLAB_PAGE;
653: p++;
654: }
655:
656: return page;
657: }
658: }
659:
660: ngx_slab_error(pool, NGX_LOG_CRIT, "ngx_slab_alloc() failed: no memory");
661:
662: return NULL;
663: }
664:
665:
666: static void
667: ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
668: ngx_uint_t pages)
669: {
670: ngx_slab_page_t *prev;
671:
672: page->slab = pages--;
673:
674: if (pages) {
675: ngx_memzero(&page[1], pages * sizeof(ngx_slab_page_t));
676: }
677:
678: if (page->next) {
679: prev = (ngx_slab_page_t *) (page->prev & ~NGX_SLAB_PAGE_MASK);
680: prev->next = page->next;
681: page->next->prev = page->prev;
682: }
683:
684: page->prev = (uintptr_t) &pool->free;
685: page->next = pool->free.next;
686:
687: page->next->prev = (uintptr_t) page;
688:
689: pool->free.next = page;
690: }
691:
692:
693: static void
694: ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level, char *text)
695: {
696: ngx_log_error(level, ngx_cycle->log, 0, "%s%s", text, pool->log_ctx);
697: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>