6fcaa63a6cb8ca5551c784496b46469f38eea21a
[samba.git] / source4 / lib / appweb / ejs-2.0 / mpr / mprAlloc.c
1 /**
2  *      @file mprAlloc.c 
3  *      @brief Memory Allocation
4  *      @overview 
5  */
6
7 /*
8  *      @copy   default
9  *      
10  *      Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
11  *      
12  *      This software is distributed under commercial and open source licenses.
13  *      You may use the GPL open source license described below or you may acquire 
14  *      a commercial license from Mbedthis Software. You agree to be fully bound 
15  *      by the terms of either license. Consult the LICENSE.TXT distributed with 
16  *      this software for full details.
17  *      
18  *      This software is open source; you can redistribute it and/or modify it 
19  *      under the terms of the GNU General Public License as published by the 
20  *      Free Software Foundation; either version 2 of the License, or (at your 
21  *      option) any later version. See the GNU General Public License for more 
22  *      details at: http://www.mbedthis.com/downloads/gplLicense.html
23  *      
24  *      This program is distributed WITHOUT ANY WARRANTY; without even the 
25  *      implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
26  *      
27  *      This GPL license does NOT permit incorporating this software into 
28  *      proprietary programs. If you are unable to comply with the GPL, you must
29  *      acquire a commercial license to use this software. Commercial licenses 
30  *      for this software and support services are available from Mbedthis 
31  *      Software at http://www.mbedthis.com 
32  *      
33  *      @end
34  */
35
36 /********************************* Includes ***********************************/
37
38 #define         UNSAFE_FUNCTIONS_OK 1
39
40 #include        "mpr.h"
41
42 /******************************* Local Defines ********************************/
43 /*
44  *      Set to 1 to disable slab based allocations
45  */
46 #define NO_SLAB                                 0
47
48 /*
49  *      Validation mode is quite slow
50  */
51 #define VALIDATE_ALLOC                  0
52 #if VALIDATE_ALLOC
53 #define VALIDATE_BLOCK(ptr)             mprValidateBlock(ptr)
54 #else
55 #define VALIDATE_BLOCK(ptr)                     
56 #endif
57
58 /*
59  *      Align on 4 bytes if squeeze, Otherwize on 16 bytes.
60  */
61 #define HDR_SIZE                                MPR_BLK_HDR_SIZE
62
63 #define APP_MAGIC                               0xa571cb80
64 #define ALLOC_MAGIC                     0xe814ecc0
65
66 /*
67  *      This must be at least one word to ensure that the smallest allocation is
68  *      4 bytes. Slab allocations need at least one word to store their next ptr.
69  */
70 #define ALLOC_ALIGN(x)                  (((x)+3)&~3)
71 #define GET_HDR(ptr)                    ((MprBlk*) (((char*) (ptr)) - HDR_SIZE))
72 #define GET_PTR(bp)                     ((void*) (((char*) (bp)) + HDR_SIZE))
73 #define VALID_HDR(bp)                   (((bp)->flags & ~0x3F) == ALLOC_MAGIC)
74 #define VALID_BLK(ptr)                  (VALID_HDR(GET_HDR(ptr)))
75
76 /*
77  *      In production releases, mprAssert will compile out (not be included)
78  *      but CHECK_HDR will remain even in production builds.
79  */
80 #define CHECK_HDR(bp) \
81         if (1) { if (! VALID_HDR(bp)) { mprAllocAbort(); } } else
82
83 /*
84  *      Chunk the slabs into 32 byte increments.
85  *      This allows for allocations up to 512 bytes via slabs and maximizes
86  *      sharing of slab allocations.
87  *
88  *      Index map:
89  *               0 ==  32  bytes
90  *               1 ==  64  bytes
91  *               2 ==  96  bytes
92  *               3 ==  128 bytes
93  *               4 ==  160 bytes
94  *               5 ==  192 bytes
95  *               6 ==  224 bytes
96  *               7 ==  256 bytes
97  *               8 ==  288 bytes
98  *               9 ==  320 bytes
99  *              10 ==  352 bytes
100  *              11 ==  384 bytes
101  *              12 ==  416 bytes
102  *              13 ==  448 bytes
103  *              14 ==  480 bytes
104  *              15 ==  512 bytes
105  */
106 #define SLAB_ALIGN(size)                ((size + 31) & ~31)
107 #define GET_SLAB(size)                  (size >> 6)
108
109 /*
110  *      Block flags
111  */
112 #define ALLOC_FLAGS_FREE                        0x1             /* Block is free */
113 #define ALLOC_FLAGS_FREEING                     0x2             /* Block is being freed */
114 #define ALLOC_FLAGS_SLAB_BLOCK          0x4             /* Block was allocated from slab */
115 #define ALLOC_FLAGS_REQUIRED            0x8             /* Block is required by alloc */
116 #define ALLOC_FLAGS_KEEP                        0x10    /* Keep block - don't mprFree */
117 #define ALLOC_FLAGS_DONT_OS_FREE        0x20    /* Don't return mem to O/S */
118 #define ALLOC_FLAGS_IS_SLAB                     0x40    /* Block is a slab */
119
120 #if BLD_DEBUG && !BREW
121 /*
122  *      Set this address to break when this address is allocated or freed. This is
123  *      a block address (not a user ptr).
124  */
125 static MprBlk *stopAlloc;
126 #endif
127
128 #if !BREW
129 static MprCtx rootCtx;                                          /* Root context if none supplied */
130 #endif
131
132 /***************************** Forward Declarations ***************************/
133
134 static int mprAllocException(MPR_LOC_DEC(ptr, loc), uint size, bool granted);
135 static void slabFree(MprBlk *bp);
136 static int      growSlab(MPR_LOC_DEC(ctx, loc), MprSlab *slab, uint size, uint inc);
137
138 /******************************************************************************/
139 /*
140  *      Put first in file so it is easy to locate in a debugger
141  */
142
143 void mprBreakpoint(const char *loc, const char *msg)
144 {
145 }
146
147 /******************************************************************************/
148 #if (WIN || BREW_SIMULATOR) && BLD_DEBUG
149
150 int crtReportHook(int type, char *msg, int *retval)
151 {
152         printf("%s\n", msg);
153         *retval = 0;
154         return TRUE;
155 }
156
157 #endif
158 /******************************************************************************/
159 /*
160  *      Initialize the memory subsystem
161  */
162
163 MprApp *mprAllocInit(MprAllocCback cback)
164 {
165         MprAllocStats   *stats;
166         MprApp                  *app;
167         MprSlab                 *slab;
168         MprBlk                  *bp, *sp;
169         int                             i;
170
171         bp = malloc(sizeof(MprApp) + HDR_SIZE);
172         mprAssert(bp);
173         if (bp == 0) {
174                 if (cback) {
175                         (*cback)(0, sizeof(MprApp), 0, 0);
176                 }
177                 return 0;
178         }
179         memset(bp, 0, sizeof(MprApp) + HDR_SIZE);
180
181         bp->parent = bp;
182         bp->size = sizeof(MprApp);
183         bp->flags = ALLOC_MAGIC;
184         bp->next = bp->prev = bp;
185
186 #if BLD_FEATURE_ALLOC_LEAK_TRACK
187         bp->location = MPR_LOC;
188 #endif
189
190         app = (MprApp*) GET_PTR(bp);
191         app->magic = APP_MAGIC;
192
193         app->alloc.cback = cback;
194         app->stackStart = (void*) &app;
195
196         bp->app = app;
197
198         app->alloc.slabs = mprAllocZeroedBlock(MPR_LOC_PASS(app, MPR_LOC), 
199                 sizeof(MprSlab) * MPR_MAX_SLAB);
200         if (app->alloc.slabs == 0) {
201                 mprFree(app);
202                 return 0;
203         }
204
205         /*
206          *      The slab control structures must not be freed. Set keep to safeguard
207          *      against accidents.
208          */
209         sp = GET_HDR(app->alloc.slabs);
210         sp->flags |= ALLOC_FLAGS_KEEP;
211
212         for (i = 0; i < MPR_MAX_SLAB; i++) {
213                 /*
214                  *      This is overriden by requestors calling slabAlloc
215                  */
216                 slab = &app->alloc.slabs[i];
217                 slab->preAllocateIncr = MPR_SLAB_DEFAULT_INC;
218         }
219
220         /*
221          *      Keep aggregated stats even in production code
222          */
223         stats = &app->alloc.stats;
224         stats->bytesAllocated += sizeof(MprApp);
225         if (stats->bytesAllocated > stats->peakAllocated) {
226                 stats->peakAllocated = stats->bytesAllocated;
227         }
228         stats->allocCount++;
229
230 #if !BREW
231         rootCtx = app;
232 #endif
233 #if (WIN || BREW_SIMULATOR) && BLD_DEBUG
234         _CrtSetReportHook(crtReportHook);
235 #endif
236         return app;
237 }
238
239 /******************************************************************************/
240 /*
241  *      Terminate the alloc module
242  */
243
244 void mprAllocTerm(MprApp *app)
245 {
246         MprSlab         *slabs;
247         MprBlk          *appBlk, *slabBlk;
248
249         /*
250          *      Must do a carefully ordered cleanup. Need to free all children blocks
251          *      before freeing the slab memory. Save a local pointer to the slabs.
252          */
253         slabs = app->alloc.slabs;
254
255         /*
256          *      Free the app and all children. Set DONT_OS_FREE to prevent free() being
257          *      called on app itself. We need that so we can free the slabs below.
258          */
259         appBlk = GET_HDR(app);
260         appBlk->flags |= ALLOC_FLAGS_DONT_OS_FREE;
261         mprFree(app);
262
263         /*
264          *      Slabs are initially marked don't free. We must preserve them while all
265          *      other blocks are freed. Then we clear the don't free flag and free.
266          *      Now we don't have an app structure which is used by mprFree. We must
267          *      fake it.
268          */
269         slabBlk = GET_HDR(slabs);
270         slabBlk->flags &= ~ALLOC_FLAGS_KEEP;
271         mprFree(slabs);
272
273         /*
274          *      Now we can finally free the memory for the app structure
275          */
276         free(appBlk);
277 }
278
279 /******************************************************************************/
280 /*
281  *      Allocate a block
282  */
283
284 void *mprAllocBlock(MPR_LOC_DEC(ctx, loc), uint size)
285 {
286         MprAllocStats   *stats;
287         MprBlk                  *bp, *parent;
288         MprApp                  *app;
289         int                             diff;
290
291         mprAssert(size > 0);
292
293         if (ctx == 0) {
294 #if BREW
295                 mprAssert(ctx);
296                 return 0;
297 #else
298                 ctx = rootCtx;
299 #endif
300         }
301         if (size == 0) {
302                 size = 1;
303         }
304
305         mprAssert(VALID_BLK(ctx));
306         parent = GET_HDR(ctx);
307         mprAssert(VALID_HDR(parent));
308
309         CHECK_HDR(parent);
310
311         size = ALLOC_ALIGN(size);
312
313         app = parent->app;
314
315         stats = &app->alloc.stats;
316
317         mprLock(app->allocLock);
318
319         stats->bytesAllocated += size + HDR_SIZE;
320         if (stats->bytesAllocated > stats->peakAllocated) {
321                 stats->peakAllocated = stats->bytesAllocated;
322         }
323
324         /*
325          *      Prevent allocation if over the maximum
326          */
327         if (stats->maxMemory && stats->bytesAllocated > stats->maxMemory) {
328                 stats->bytesAllocated -= (size + HDR_SIZE);
329                 mprUnlock(app->allocLock);
330                 if (mprAllocException(MPR_LOC_PASS(ctx, loc), size, 0) < 0) {
331                         return 0;
332                 }
333                 mprLock(app->allocLock);
334         }
335
336         if ((bp = malloc(size + HDR_SIZE)) == 0) {
337                 mprAssert(bp);
338                 stats->errors++;
339                 mprUnlock(app->allocLock);
340                 mprAllocException(MPR_LOC_PASS(ctx, loc), size, 0);
341                 return 0;
342         }
343
344 #if BLD_DEBUG
345         memset(bp, 0xf7, size + HDR_SIZE);
346 #endif
347
348 #if BLD_DEBUG && !BREW
349         if (bp == stopAlloc) {
350                 mprBreakpoint(MPR_LOC, "breakOnAddr");
351         }
352 #endif
353
354         /*
355          *      Warn if allocation puts us over the red line
356          */
357         if (stats->redLine && stats->bytesAllocated > stats->redLine) {
358                 mprUnlock(app->allocLock);
359                 if (mprAllocException(MPR_LOC_PASS(ctx, loc), size, 1) < 0) {
360                         return 0;
361                 }
362                 mprLock(app->allocLock);
363         }
364
365         bp->size = size;
366         bp->flags = ALLOC_MAGIC;
367         bp->destructor = 0;
368
369         bp->parent = parent;
370
371         if (parent->children == 0) {
372                 parent->children = bp;
373                 bp->next = bp->prev = bp;
374
375         } else {
376                 /*
377                  *      Append to the end of the list. Preserve alloc order
378                  */
379                 bp->next = parent->children;
380                 bp->prev = parent->children->prev;
381                 parent->children->prev->next = bp;
382                 parent->children->prev = bp;
383         }
384
385         bp->children = 0;
386
387 #if BLD_FEATURE_ALLOC_LEAK_TRACK
388         bp->location = loc;
389 #endif
390
391         bp->app = parent->app;
392
393         VALIDATE_BLOCK(GET_PTR(bp));
394
395         stats->allocCount++;
396
397         /*
398          *      Monitor stack usage
399          */
400         diff = (int) bp->app->stackStart - (int) &stats;
401         if (diff < 0) {
402                 app->maxStack -= diff;
403                 app->stackStart = (void*) &stats;
404                 diff = 0;
405         }
406
407         if ((uint) diff > app->maxStack) {
408                 app->maxStack = diff;
409         }
410         mprUnlock(app->allocLock);
411
412         return GET_PTR(bp);
413 }
414
415 /******************************************************************************/
416 /*
417  *      Allocate and zero a block
418  */
419
420 void *mprAllocZeroedBlock(MPR_LOC_DEC(ctx, loc), uint size)
421 {
422         void    *newBlock;
423
424         MprBlk  *bp;
425
426         bp = GET_HDR(ctx);
427         mprAssert(VALID_BLK(ctx));
428
429         newBlock = mprAllocBlock(MPR_LOC_PASS(ctx, loc), size);
430         if (newBlock) {
431                 memset(newBlock, 0, size);
432         }
433         return newBlock;
434 }
435
436 /******************************************************************************/
437 /*
438  *      Free a block of memory. Free all children recursively.
439  */
440
441 int mprFree(void *ptr)
442 {
443         MprAllocStats   *stats;
444         MprBlk                  *bp, *parent, *cp, *firstChild, *prev;
445         MprApp                  *app;
446
447         if (ptr == 0) {
448                 return 0;
449         }
450
451         mprAssert(VALID_BLK(ptr));
452         VALIDATE_BLOCK(ptr);
453
454         bp = GET_HDR(ptr);
455
456 #if BLD_DEBUG && !BREW
457         if (bp == stopAlloc) {
458                 mprBreakpoint(MPR_LOC, "breakOnAddr");
459         }
460 #endif
461
462         mprAssert(bp);
463         mprAssert(VALID_HDR(bp));
464
465         CHECK_HDR(bp);
466
467         /*
468          *      Test if already freed
469          */
470         mprAssert(! (bp->flags & ALLOC_FLAGS_FREE));
471         if (bp->flags & ALLOC_FLAGS_FREE) {
472                 return 0;
473         }
474
475         /*
476          *      Return if recursive freeing or this is a permanent block
477          */
478         app = bp->app;
479         mprLock(app->allocLock);
480         if (bp->flags & (ALLOC_FLAGS_FREEING | ALLOC_FLAGS_KEEP)) {
481                 mprUnlock(app->allocLock);
482                 return 0;
483         }
484         bp->flags |= ALLOC_FLAGS_FREEING;
485
486
487         /*
488          *      Call any destructors
489          */
490         if (bp->destructor) {
491                 mprUnlock(app->allocLock);
492                 if ((bp->destructor)(ptr) < 0) {
493                         return -1;
494                 }
495                 mprLock(app->allocLock);
496                 bp->destructor = 0;
497         }
498
499         /*
500          *      Free the children. Free in reverse order so firstChild is preserved
501          *      during the list scan as an end of list marker.
502          */
503         if ((firstChild = bp->children) != 0) {
504                 cp = firstChild->prev;
505                 while (cp != firstChild) {
506
507                         mprAssert(VALID_HDR(cp));
508                         VALIDATE_BLOCK(GET_PTR(cp));
509
510                         prev = cp->prev;
511
512                         /*
513                          *      FUTURE - OPT. Make this inline 
514                          */
515                         mprFree(GET_PTR(cp));
516
517                         cp = prev;
518                 }
519
520                 mprFree(GET_PTR(firstChild));
521
522                 /*
523                  *      Just for clarity
524                  */
525                 bp->children = 0;
526         }
527
528         parent = bp->parent;
529
530         mprAssert(VALID_HDR(parent));
531
532         /*
533          *      Unlink from the parent
534          */
535         if (parent->children == bp) {
536                 if (bp->next == bp) {
537                         parent->children = 0;
538                 } else {
539                         parent->children = bp->next;
540                 }
541         }
542
543         /*
544          *      Remove from the sibling chain
545          */
546         bp->prev->next = bp->next;
547         bp->next->prev = bp->prev;
548
549         bp->flags |= ALLOC_FLAGS_FREE;
550
551         /*
552          *      Release the memory. If from a slab, return to the slab. Otherwise, 
553          *      return to the O/S.
554          */
555         if (bp->flags & ALLOC_FLAGS_SLAB_BLOCK) {
556                 slabFree(bp);
557
558         } else {
559                 mprAssert(bp);
560
561                 /*
562                  *      Update the stats
563                  */
564                 stats = &bp->app->alloc.stats;
565                 stats->bytesAllocated -= (bp->size + HDR_SIZE);
566                 mprAssert(stats->bytesAllocated >= 0);
567
568                 stats->allocCount--;
569                 mprAssert(stats->allocCount >= 0);
570
571 #if BLD_DEBUG && !BREW
572                 if (bp == stopAlloc) {
573                         mprBreakpoint(MPR_LOC, "breakOnAddr");
574                 }
575 #endif
576
577                 /*
578                  *      Return to the O/S
579                  */
580                 if (! (bp->flags & ALLOC_FLAGS_DONT_OS_FREE)) {
581                         free(bp);
582                 }
583         }
584         /* OPT */
585         if (app != ptr) {
586                 mprUnlock(app->allocLock);
587         }
588
589         return 0;
590 }
591
592 /******************************************************************************/
593 /*
594  *      Rallocate a block
595  */
596
597 void *mprReallocBlock(MPR_LOC_DEC(ctx, loc), void *ptr, uint size)
598 {
599         MprBlk  *bp, *newbp, *firstChild, *cp;
600         MprApp  *app;
601         void    *newPtr;
602
603         mprAssert(VALID_BLK(ctx));
604         mprAssert(size > 0);
605
606         if (ptr == 0) {
607                 return mprAllocBlock(MPR_LOC_PASS(ctx, loc), size);
608         }
609         
610         mprAssert(VALID_BLK(ptr));
611         bp = GET_HDR(ptr);
612         mprAssert(bp);
613         mprAssert(VALID_HDR(bp));
614
615         CHECK_HDR(bp);
616
617         if (size < bp->size) {
618                 return ptr;
619         }
620
621         newPtr = mprAllocBlock(MPR_LOC_PASS(ctx, loc), size);
622         if (newPtr == 0) {
623                 bp->flags &= ~ALLOC_FLAGS_FREE;
624                 free(bp);
625                 return 0;
626         }
627
628         newbp = GET_HDR(newPtr);
629         mprAssert(newbp->size >= size);
630         memcpy((char*) newbp + HDR_SIZE, (char*) bp + HDR_SIZE, bp->size);
631         mprAssert(newbp->size >= size);
632
633         /* 
634          *      Fix the next / prev pointers
635          */
636         app = bp->app;
637         mprLock(app->allocLock);
638         newbp->next->prev = newbp;
639         newbp->prev->next = newbp;
640
641         /*
642          *      Need to fix the parent pointer of all children
643          */
644         if ((firstChild = newbp->children) != 0) {
645                 cp = firstChild;
646                 do {
647                         cp->parent = newbp;
648                         cp = cp->next;
649                 } while (cp != firstChild);
650         }
651
652         /*
653          *      May need to set the children pointer of our parent
654          */
655         if (newbp->parent->children == bp) {
656                 newbp->parent->children = newbp;
657         }
658
659         /*
660          *      Free the original block
661          */
662         mprFree(ptr);
663
664         mprUnlock(app->allocLock);
665
666         return GET_PTR(newbp);
667 }
668
669 /******************************************************************************/
670 /*
671  *      Allocate a block from a slab
672  */
673
674 void *mprSlabAllocBlock(MPR_LOC_DEC(ctx, loc), uint size, uint inc)
675 {
676
677 #if NO_SLAB
678         return mprAllocBlock(MPR_LOC_PASS(ctx, loc), size);
679 #else
680
681         MprBlk                  *parent, *bp;
682         MprSlabBlock    *sb;
683         MprApp                  *app;
684         MprSlab                 *slab;
685         int                             slabIndex;
686
687         if (ctx == 0) {
688                 mprAssert(ctx);
689                 return 0;
690         }
691
692         mprAssert(size > 0);
693         mprAssert(VALID_BLK(ctx));
694
695         parent = GET_HDR(ctx);
696         mprAssert(VALID_HDR(parent));
697
698         CHECK_HDR(parent);
699
700         size = SLAB_ALIGN(size);
701
702         app = parent->app;
703         mprAssert(app);
704
705         slabIndex = GET_SLAB(size);
706
707         if (slabIndex < 0 || slabIndex >= MPR_MAX_SLAB) {
708                 return mprAllocBlock(MPR_LOC_PASS(ctx, loc), size);
709         }
710
711         /*
712          *      Dequeue a block from the slab. "sb" will point to the user data
713          *      portion of the block (i.e. after the MprBlk header). Slabs must be 
714          *      allocated off the "slabs" context to ensure they don't get freed 
715          *      until after all other blocks are freed.
716          */
717         mprLock(app->allocLock);
718         slab = &app->alloc.slabs[slabIndex];
719         if ((sb = slab->next) == 0) {
720                 if (growSlab(MPR_LOC_ARGS(parent->app->alloc.slabs), 
721                                 slab, size, inc) < 0) {
722                         mprUnlock(app->allocLock);
723                         return 0;
724                 }
725                 sb = slab->next;
726         }
727         mprAssert(sb);
728
729         /*
730          *      Dequeue the block
731          */
732         slab->next = sb->next;
733
734 #if BLD_FEATURE_ALLOC_STATS
735 {
736         MprSlabStats    *slabStats;
737         /*
738          *      Update the slab stats
739          */
740         slabStats = &slab->stats;
741         slabStats->totalAllocCount++;
742         slabStats->freeCount--;
743         slabStats->allocCount++;
744         if (slabStats->allocCount > slabStats->peakAllocCount) {
745                 slabStats->peakAllocCount = slabStats->allocCount;
746         }
747 }
748 #endif /* BLD_FEATURE_ALLOC_STATS */
749
750         bp = GET_HDR(sb);
751
752 #if BLD_DEBUG && !BREW
753         if (bp == stopAlloc) {
754                 mprBreakpoint(MPR_LOC, "breakOnAddr");
755         }
756 #endif
757
758         bp->size = size;
759         bp->flags = ALLOC_MAGIC | ALLOC_FLAGS_SLAB_BLOCK;
760         bp->destructor = 0;
761
762         bp->parent = parent;
763
764         if (parent->children == 0) {
765                 parent->children = bp;
766                 bp->next = bp->prev = bp;
767
768         } else {
769                 /*
770                  *      Append to the end of the list. Preserve alloc order
771                  */
772                 bp->next = parent->children;
773                 bp->prev = parent->children->prev;
774                 parent->children->prev->next = bp;
775                 parent->children->prev = bp;
776         }
777
778         bp->children = 0;
779
780         bp->app = app;
781
782 #if BLD_FEATURE_ALLOC_LEAK_TRACK
783         bp->location = loc;
784 #endif
785         mprUnlock(app->allocLock);
786
787         return GET_PTR(bp);
788 #endif
789 }
790
791 /******************************************************************************/
792 /*
793  *      Return a block back to its slab
794  */
795
796 static void slabFree(MprBlk *bp)
797 {
798         MprSlab                 *slab;
799         MprApp                  *app;
800         void                    *ptr;
801         int                             slabIndex;
802
803         mprAssert(VALID_HDR(bp));
804
805         slabIndex = GET_SLAB(bp->size);
806         mprAssert(0 <= slabIndex && slabIndex < MPR_MAX_SLAB);
807
808         if (0 <= slabIndex && slabIndex < MPR_MAX_SLAB) {
809                 mprLock(bp->app->allocLock);
810                 slab = &bp->app->alloc.slabs[slabIndex];
811                 app = bp->app;
812
813 #if BLD_DEBUG
814                 memset(bp, 0xfc, bp->size + HDR_SIZE);
815 #endif
816
817                 ptr = GET_PTR(bp);
818                 ((MprSlabBlock*) ptr)->next = slab->next;
819                 slab->next = ((MprSlabBlock*) ptr);
820
821 #if BLD_FEATURE_ALLOC_STATS
822 {
823                 MprSlabStats    *slabStats;
824                 slabStats = &slab->stats;
825
826                 slabStats->freeCount++;
827                 slabStats->allocCount--;
828
829                 if (slabStats->freeCount >= slabStats->peakFreeCount) {
830                         slabStats->peakFreeCount = slabStats->freeCount;
831                 }
832 }
833 #endif
834                 mprUnlock(app->allocLock);
835         }
836 }
837
838 /******************************************************************************/
839 /*
840  *      Grow the slab and return the next free block
841  *      Must be called locked.
842  */
843
844 static int growSlab(MPR_LOC_DEC(ctx, loc), MprSlab *slab, uint size, uint inc)
845 {
846         MprBlk                  *bp;
847         MprSlabBlock    *sb;
848         int                             i, chunkSize, len;
849
850         mprAssert(VALID_BLK(ctx));
851         mprAssert(slab);
852         mprAssert(size > 0);
853
854         /*
855          *      Take the maximum requested by anyone
856          */
857         slab->preAllocateIncr = max(slab->preAllocateIncr, inc);
858
859         /*
860          *      We allocate an array of blocks each of user "size" bytes.
861          */
862         chunkSize = HDR_SIZE + size;
863         len = chunkSize * slab->preAllocateIncr;
864         bp = mprAllocBlock(MPR_LOC_PASS(ctx, loc), len);
865
866 #if BLD_DEBUG
867         memset(bp, 0xf1, len);
868 #endif
869
870         if (bp == 0) {
871                 mprAssert(0);
872                 return MPR_ERR_MEMORY;
873         }
874         bp->flags |= ALLOC_FLAGS_IS_SLAB;
875
876         /*
877          *      We store the slab information in the user data portion
878          */
879         sb = (MprSlabBlock*) GET_PTR(bp);
880
881
882         sb = (MprSlabBlock*) ((char*) sb + len - chunkSize);
883         for (i = slab->preAllocateIncr - 1; i >= 0; i--) {
884                 sb->next = slab->next;
885                 slab->next = sb;
886                 sb = (MprSlabBlock*) ((char*) sb - chunkSize);
887         }
888
889 #if BLD_FEATURE_ALLOC_STATS
890 {
891         MprSlabStats    *stats;
892         stats = &slab->stats;
893         stats->freeCount += slab->preAllocateIncr;
894         if (stats->freeCount > stats->peakFreeCount) {
895                 stats->peakFreeCount = stats->freeCount;
896         }
897 }
898 #endif
899
900         return 0;
901 }
902
903 /******************************************************************************/
904 /*
905  *      Set the pre-allocate amount
906  */
907
908 int mprSetSlabPreAllocate(MprCtx ctx, int slabIndex, int preAllocateIncr)
909 {
910         MprApp          *app;
911         MprSlab         *slab;
912
913         mprAssert(VALID_BLK(ctx));
914         mprAssert(0 <= slabIndex && slabIndex < MPR_MAX_SLAB);
915         mprAssert(preAllocateIncr > 0);
916
917         if (0 <= slabIndex && slabIndex < MPR_MAX_SLAB) {
918                 app = mprGetApp(ctx);
919                 slab = &app->alloc.slabs[slabIndex];
920                 slab->preAllocateIncr = preAllocateIncr;
921         } else {
922                 return MPR_ERR_BAD_ARGS;
923         }
924         return 0;
925 }
926
927 /******************************************************************************/
928
929 void *mprSlabAllocZeroedBlock(MPR_LOC_DEC(ctx, loc), uint size, uint inc)
930 {
931         void    *newBlock;
932
933         mprAssert(VALID_BLK(ctx));
934         mprAssert(size > 0);
935
936         newBlock = mprSlabAllocBlock(MPR_LOC_PASS(ctx, loc), size, inc);
937         if (newBlock) {
938                 memset(newBlock, 0, size);
939         }
940         return newBlock;
941 }
942
943 /******************************************************************************/
944 /*
945  *      Internal strdup function. Will use the slab allocator for small strings
946  */
947
948 char *mprStrdupInternal(MPR_LOC_DEC(ctx, loc), const char *str)
949 {
950         char    *newp;
951         int             len;
952
953         mprAssert(VALID_BLK(ctx));
954
955         if (str == 0) {
956                 str = "";
957         }
958
959         len = strlen(str) + 1;
960
961         if (len < MPR_SLAB_STR_MAX) {
962                 newp = mprSlabAllocBlock(MPR_LOC_PASS(ctx, loc), MPR_SLAB_STR_MAX,
963                         MPR_SLAB_STR_INC);
964         } else {
965                 newp = mprAllocBlock(MPR_LOC_PASS(ctx, loc), len);
966         }
967
968         if (newp) {
969                 memcpy(newp, str, len);
970         }
971
972         return newp;
973 }
974
975 /******************************************************************************/
976 /*
977  *      Internal strndup function. Will use the slab allocator for small strings
978  */
979
980 char *mprStrndupInternal(MPR_LOC_DEC(ctx, loc), const char *str, uint size)
981 {
982         char    *newp;
983         uint    len;
984
985         mprAssert(VALID_BLK(ctx));
986
987         if (str == 0) {
988                 str = "";
989         }
990         len = strlen(str) + 1;
991         len = min(len, size);
992
993         if (len < MPR_SLAB_STR_MAX) {
994                 newp = mprSlabAllocBlock(MPR_LOC_PASS(ctx, loc), MPR_SLAB_STR_MAX,
995                         MPR_SLAB_STR_INC);
996         } else {
997                 newp = mprAllocBlock(MPR_LOC_PASS(ctx, loc), len);
998         }
999
1000         if (newp) {
1001                 memcpy(newp, str, len);
1002         }
1003
1004         return newp;
1005 }
1006
1007 /******************************************************************************/
1008 /*
1009  *      Internal memcpy function. Will use the slab allocator for small strings
1010  */
1011
1012 void *mprMemdupInternal(MPR_LOC_DEC(ctx, loc), const void *ptr, uint size)
1013 {
1014         char    *newp;
1015
1016         mprAssert(VALID_BLK(ctx));
1017
1018         if (size < MPR_SLAB_STR_MAX) {
1019                 newp = mprSlabAllocBlock(MPR_LOC_PASS(ctx, loc), MPR_SLAB_STR_MAX,
1020                         MPR_SLAB_STR_INC);
1021         } else {
1022                 newp = mprAllocBlock(MPR_LOC_PASS(ctx, loc), size);
1023         }
1024
1025         if (newp) {
1026                 memcpy(newp, ptr, size);
1027         }
1028
1029         return newp;
1030 }
1031
1032 /******************************************************************************/
1033 /*
1034  *      Steal a block from one context and insert in another
1035  */
1036
1037 int mprStealAllocBlock(MPR_LOC_DEC(ctx, loc), const void *ptr)
1038 {
1039         MprBlk          *bp, *parent;
1040
1041         if (ptr == 0) {
1042                 return 0;
1043         }
1044
1045         mprAssert(VALID_BLK(ctx));
1046         mprAssert(VALID_BLK(ptr));
1047
1048         bp = GET_HDR(ptr);
1049
1050 #if BLD_DEBUG && !BREW
1051         if (bp == stopAlloc) {
1052                 mprBreakpoint(MPR_LOC, "breakOnAddr");
1053         }
1054 #endif
1055
1056         mprAssert(bp);
1057         mprAssert(VALID_HDR(bp));
1058         mprAssert(ptr != mprGetAllocParent(ptr));
1059
1060         CHECK_HDR(bp);
1061
1062         mprAssert(bp->prev);
1063         mprAssert(bp->prev->next);
1064         mprAssert(bp->next);
1065         mprAssert(bp->next->prev);
1066
1067         parent = bp->parent;
1068         mprAssert(VALID_HDR(parent));
1069
1070         mprLock(bp->app->allocLock);
1071         if (parent->children == bp) {
1072                 if (bp->next == bp) {
1073                         parent->children = 0;
1074                 } else {
1075                         parent->children = bp->next;
1076                 }
1077         }
1078
1079         bp->prev->next = bp->next;
1080         bp->next->prev = bp->prev;
1081
1082         parent = GET_HDR(ctx);
1083         mprAssert(VALID_HDR(parent));
1084         bp->parent = parent;
1085
1086         if (parent->children == 0) {
1087                 parent->children = bp;
1088                 bp->next = bp->prev = bp;
1089
1090         } else {
1091                 bp->next = parent->children;
1092                 bp->prev = parent->children->prev;
1093                 parent->children->prev->next = bp;
1094                 parent->children->prev = bp;
1095         }
1096
1097 #if BLD_FEATURE_ALLOC_LEAK_TRACK
1098         bp->location = loc;
1099 #endif
1100
1101         VALIDATE_BLOCK(GET_PTR(bp));
1102
1103         mprUnlock(bp->app->allocLock);
1104
1105         return 0;
1106 }
1107
1108 /******************************************************************************/
1109
1110 void mprSetRequiredAlloc(MprCtx ptr, bool recurse)
1111 {
1112         MprBlk  *bp, *firstChild, *cp;
1113
1114         bp = GET_HDR(ptr);
1115
1116         bp->flags |= ALLOC_FLAGS_REQUIRED;
1117
1118         if (recurse && (firstChild = bp->children) != 0) {
1119                 cp = firstChild;
1120                 do {
1121                         mprSetRequiredAlloc(GET_PTR(cp), recurse);
1122                         cp = cp->next;
1123                 } while (cp != firstChild);
1124         }
1125 }
1126
1127 /******************************************************************************/
1128 /*
1129  *      Monitor stack usage. Return true if the stack has grown
1130  */
1131
1132 int mprStackCheck(MprCtx ptr)
1133 {
1134         MprApp *app;
1135         int     size;
1136
1137         mprAssert(VALID_BLK(ptr));
1138
1139         app = mprGetApp(ptr);
1140
1141         size = (int) app->stackStart - (int) &app;
1142         if (size < 0) {
1143                 app->maxStack -= size;
1144                 app->stackStart = (void*) &app;
1145                 size = 0;
1146         }
1147         if ((uint) size > app->maxStack) {
1148                 app->maxStack = size;
1149                 return 1;
1150         }
1151         return 0;
1152 }
1153
1154 /******************************************************************************/
1155 /*
1156  *      Return the stack size
1157  */
1158
1159 int mprStackSize(MprCtx ptr)
1160 {
1161         MprApp *app;
1162
1163         mprAssert(VALID_BLK(ptr));
1164
1165         app = mprGetApp(ptr);
1166         return app->maxStack;
1167 }
1168
1169 /******************************************************************************/
1170
1171 static int mprAllocException(MPR_LOC_DEC(ctx, loc), uint size, bool granted)
1172 {
1173         MprApp          *app;
1174         MprAlloc        *alloc;
1175         int                     rc;
1176
1177         mprAssert(VALID_BLK(ctx));
1178
1179         app = mprGetApp(ctx);
1180         alloc = &app->alloc;
1181
1182         if (alloc->cback == 0) {
1183                 return 0;
1184         }
1185
1186         mprLock(app->allocLock);
1187         if (alloc->inAllocException == 0) {
1188                 alloc->inAllocException = 1;
1189                 mprUnlock(app->allocLock);
1190
1191                 rc = (alloc->cback)(app, size, alloc->stats.bytesAllocated, granted);
1192
1193                 mprLock(app->allocLock);
1194                 app->alloc.inAllocException = 0;
1195                 mprUnlock(app->allocLock);
1196
1197                 return rc;
1198         }
1199         return 0;
1200 }
1201
1202 /******************************************************************************/
1203
1204 void mprSetAllocLimits(MprApp *app, uint redLine, uint maxMemory)
1205 {
1206         app->alloc.stats.redLine = redLine;
1207         app->alloc.stats.maxMemory = maxMemory;
1208 }
1209
1210 /******************************************************************************/
1211
1212 MprAllocCback mprSetAllocCallback(MprApp *app, MprAllocCback cback)
1213 {
1214         MprAllocCback   old;
1215
1216         mprAssert(app);
1217         mprAssert(VALID_BLK(app));
1218
1219         old = app->alloc.cback;
1220         app->alloc.cback = cback;
1221         return old;
1222 }
1223
1224 /******************************************************************************/
1225
1226 uint mprGetAllocBlockSize(MprCtx ptr)
1227 {
1228         MprBlk  *bp;
1229
1230         mprAssert(VALID_BLK(ptr));
1231
1232         if (ptr == 0) {
1233                 return 0;
1234         }
1235
1236         bp = GET_HDR(ptr);
1237         mprAssert(VALID_HDR(bp));
1238
1239         CHECK_HDR(bp);
1240
1241         return bp->size;
1242 }
1243
1244 /******************************************************************************/
1245 /* 
1246  *      Return the total block count used by a block including all children
1247  */
1248
1249 uint mprGetAllocBlockCount(MprCtx ptr)
1250 {
1251         MprBlk  *bp, *firstChild, *cp;
1252         uint    count;
1253
1254         mprAssert(VALID_BLK(ptr));
1255
1256         if (ptr == 0) {
1257                 return 0;
1258         }
1259
1260         bp = GET_HDR(ptr);
1261         mprAssert(VALID_HDR(bp));
1262
1263         /*
1264          *      Add one for itself
1265          */
1266         count = 1;
1267         if ((firstChild = bp->children) != 0) {
1268                 cp = firstChild;
1269                 do {
1270                         count += mprGetAllocBlockCount(GET_PTR(cp));
1271                         cp = cp->next;
1272                 } while (cp != firstChild);
1273         }
1274         return count;
1275 }
1276
1277 /******************************************************************************/
1278 /*
1279  *      Return the total of all memory allocated including slabs
1280  */
1281
1282 uint mprGetAllocBlockMemory(MprCtx ptr)
1283 {
1284         MprBlk  *bp, *firstChild, *cp;
1285         uint    count;
1286
1287         mprAssert(VALID_BLK(ptr));
1288
1289         if (ptr == 0) {
1290                 return 0;
1291         }
1292
1293         bp = GET_HDR(ptr);
1294         mprAssert(VALID_HDR(bp));
1295
1296         count = bp->size + HDR_SIZE;
1297         if ((firstChild = bp->children) != 0) {
1298                 cp = firstChild;
1299                 do {
1300                         count += mprGetAllocBlockMemory(GET_PTR(cp));
1301                         cp = cp->next;
1302                 } while (cp != firstChild);
1303         }
1304         return count;
1305 }
1306
1307 /******************************************************************************/
1308 #if BLD_FEATURE_ALLOC_LEAK_TRACK
1309
1310 const char *mprGetAllocLocation(MprCtx ptr)
1311 {
1312         MprBlk  *bp;
1313
1314         if (ptr == 0) {
1315                 return 0;
1316         }
1317         mprAssert(VALID_BLK(ptr));
1318
1319         bp = GET_HDR(ptr);
1320         mprAssert(VALID_HDR(bp));
1321         return bp->location;
1322 }
1323
1324 #endif
1325 /******************************************************************************/
1326
1327 void *mprGetAllocParent(MprCtx ptr)
1328 {
1329         MprBlk  *bp;
1330
1331         mprAssert(VALID_BLK(ptr));
1332
1333         if (ptr == 0) {
1334                 return 0;
1335         }
1336
1337         bp = GET_HDR(ptr);
1338         mprAssert(VALID_HDR(bp));
1339
1340         CHECK_HDR(bp);
1341
1342         return GET_PTR(bp->parent);
1343 }
1344
1345 /******************************************************************************/
1346
1347 MprAllocStats *mprGetAllocStats(MprApp *app)
1348 {
1349         mprAssert(VALID_BLK(app));
1350
1351         return &app->alloc.stats;
1352 }
1353
1354 /******************************************************************************/
1355 #if BLD_FEATURE_ALLOC_STATS
1356
1357 MprSlabStats *mprGetSlabAllocStats(MprApp *app, int slabIndex)
1358 {
1359         MprSlab         *slab;
1360
1361         mprAssert(VALID_BLK(app));
1362
1363         if (0 <= slabIndex && slabIndex < MPR_MAX_SLAB) {
1364                 slab = &app->alloc.slabs[slabIndex];
1365                 return &slab->stats;
1366         }
1367
1368         mprAssert(0 <= slabIndex && slabIndex < MPR_MAX_SLAB);
1369         return 0;
1370 }
1371
1372 #endif /* BLD_FEATURE_ALLOC_STATS */
1373 /******************************************************************************/
1374 #if BLD_DEBUG
1375
1376 int mprPrintAllocBlocks(MprCtx ptr, int indent)
1377 {
1378         MprBlk          *bp, *firstChild, *cp;
1379         const char      *location;
1380         int                     subTotal, size, indentSpaces, code;
1381
1382         subTotal = 0;
1383
1384         bp = GET_HDR(ptr);
1385
1386         if (! (bp->flags & ALLOC_FLAGS_REQUIRED)) {
1387                 size = bp->size + HDR_SIZE;
1388
1389                 /*
1390                  *      Take one level off because we don't trace app
1391                  */
1392                 indentSpaces = indent;
1393
1394                 if (bp->flags & ALLOC_FLAGS_REQUIRED) {
1395                         code = 'R';
1396                 } else if (bp->flags & ALLOC_FLAGS_IS_SLAB) {
1397                         code = 'S';
1398                 } else {
1399                         code = ' ';
1400                 }
1401
1402 #if BLD_FEATURE_ALLOC_LEAK_TRACK
1403                 location = bp->location;
1404 #else
1405                 location = "";
1406 #endif
1407                 mprLog(bp->app, 0, 
1408                         "%c %.*s %-16s %.*s size %5d has %3d deps, total %6d", code,
1409                         indentSpaces, "                   ",
1410                         mprGetBaseName(location),
1411                         8 - indent, "          ",
1412                         size, 
1413                         mprGetAllocBlockCount(GET_PTR(bp)), 
1414                         mprGetAllocBlockMemory(GET_PTR(bp))
1415                         /* (uint) bp */
1416                         );
1417
1418                 subTotal += size;
1419         }
1420                 
1421         if ((firstChild = bp->children) != 0) {
1422                 cp = firstChild;
1423                 do {
1424                         subTotal += mprPrintAllocBlocks(GET_PTR(cp), indent + 2);
1425                         cp = cp->next;
1426                 } while (cp != firstChild);
1427         }
1428
1429         return subTotal;
1430 }
1431
1432 #endif
1433 /******************************************************************************/
1434 #if BLD_FEATURE_ALLOC_STATS
1435 /*
1436  *      Print a memory allocation report that includes a list of allocated blocks
1437  *      and a statistics summary
1438  */
1439
1440 void mprPrintAllocReport(MprApp *app, bool printBlocks, const char *msg)
1441 {
1442         MprSlabStats    *stats;
1443         uint                    total;
1444         int                             i, size;
1445         
1446         mprAssert(VALID_BLK(app));
1447
1448         if (msg) {
1449                 mprLog(app, 0, " ");
1450                 mprLog(app, 0, "%s", msg);
1451         }
1452
1453 #if BLD_DEBUG
1454         /*
1455          *      Do block stats
1456          */
1457         if (printBlocks) {
1458                 int     sum;
1459                 mprLog(app, 0, " ");
1460                 sum = mprPrintAllocBlocks(app, 0);
1461                 if (sum) {
1462                         mprLog(app, 0, "  Sum of blocks %d", sum);
1463                 } else {
1464                         mprLog(app, 0, "  None");
1465                 }
1466         }
1467 #endif
1468
1469         /*
1470          *      Do Slab stats
1471          */
1472         mprLog(app, 0, " ");
1473         mprLog(app, 0, "MPR Slab Memory Stats");
1474         mprLog(app, 0, " ");
1475
1476         mprLog(app, 0, 
1477         "  Index Size    Total Allocated   Free PeakAlloc PeakFree TotalAlloc");
1478
1479         total = 0;
1480         for (i = 0; i < MPR_MAX_SLAB; i++) {
1481                 stats = &app->alloc.slabs[i].stats;
1482                 size = 1 << (i + 5);
1483                 if (stats->totalAllocCount > 0) {
1484                         mprLog(app, 0, "   %2d %6d %8d %9d %6d %9d %8d %10d", 
1485                                 i, size, size * (stats->allocCount + stats->freeCount),
1486                                 stats->allocCount, stats->freeCount, 
1487                                 stats->peakAllocCount, stats->peakFreeCount, 
1488                                 stats->totalAllocCount); 
1489                         total += size * (stats->allocCount + stats->freeCount);
1490                 }
1491         }
1492         mprLog(app, 0, " ");
1493         mprLog(app, 0, "MPR Total Allocated Slab RAM: %10d", total);
1494         mprLog(app, 0, "MPR Total Allocated RAM:      %10d", 
1495                 mprGetAllocatedMemory(app));
1496         mprLog(app, 0, "MPR Peak Allocated RAM:       %10d", 
1497                 mprGetPeakAllocatedMemory(app));
1498         mprLog(app, 0, " ");
1499 }
1500
1501 /******************************************************************************/
1502 /*
1503  *      Return the total memory allocated.
1504  */
1505
1506 uint mprGetAllocatedMemory(MprCtx ctx)
1507 {
1508         MprApp                  *app;
1509
1510         app = mprGetApp(ctx);
1511
1512         return app->alloc.stats.bytesAllocated;
1513 }
1514
1515 /******************************************************************************/
1516 /*
1517  *      Return the peak memory allocated.
1518  */
1519
1520 uint mprGetPeakAllocatedMemory(MprCtx ctx)
1521 {
1522         MprApp                  *app;
1523
1524         app = mprGetApp(ctx);
1525
1526         return app->alloc.stats.peakAllocated;
1527 }
1528
1529 /******************************************************************************/
1530 /*
1531  *      Return memory in the MPR slab. This excludes the EJS slabs
1532  */
1533
1534 uint mprGetAllocatedSlabMemory(MprCtx ctx)
1535 {
1536         MprApp                  *app;
1537         MprSlabStats    *stats;
1538         uint                    total;
1539         int                             i, size;
1540
1541         app = mprGetApp(ctx);
1542
1543         total = 0;
1544         for (i = 0; i < MPR_MAX_SLAB; i++) {
1545                 stats = &app->alloc.slabs[i].stats;
1546                 size = 1 << (i + 5);
1547                 if (stats->totalAllocCount > 0) {
1548                         total += size * (stats->allocCount + stats->freeCount);
1549                 }
1550         }
1551         return total;
1552 }
1553
1554 #endif /* BLD_FEATURE_ALLOC_STATS */
1555 /******************************************************************************/
1556
1557 MprDestructor mprSetDestructor(MprCtx ptr, MprDestructor destructor)
1558 {
1559         MprDestructor   old;
1560         MprBlk                  *bp;
1561
1562         mprAssert(VALID_BLK(ptr));
1563
1564         if (ptr == 0) {
1565                 return 0;
1566         }
1567
1568         bp = GET_HDR(ptr);
1569
1570         mprAssert(bp);
1571         mprAssert(VALID_HDR(bp));
1572         mprAssert(ptr != mprGetAllocParent(ptr));
1573
1574         CHECK_HDR(bp);
1575
1576         old = bp->destructor;
1577         bp->destructor = destructor;
1578
1579         return old;
1580 }
1581
1582 /******************************************************************************/
1583
1584 int mprIsAllocBlockValid(MprCtx ptr)
1585 {
1586         MprBlk  *bp;
1587
1588         bp = GET_HDR(ptr);
1589         return (bp && VALID_HDR(bp));
1590 }
1591
1592 /******************************************************************************/
1593 #if VALIDATE_ALLOC
1594 /*
1595  *      Exhaustive validation of the block and its children. Does not go recursive
1596  *      as it would be too slow.
1597  */
1598
1599 int mprValidateBlock(MprCtx ptr)
1600 {
1601         MprBlk                  *bp, *parent, *cp, *firstChild;
1602         int                             count;
1603
1604         mprAssert(ptr);
1605         mprAssert(VALID_BLK(ptr));
1606
1607         bp = GET_HDR(ptr);
1608
1609         mprAssert(bp);
1610         mprAssert(VALID_HDR(bp));
1611         mprAssert(VALID_HDR(bp->parent));
1612
1613         if (ptr != bp->app) {
1614                 mprAssert(bp != bp->parent);
1615         }
1616         mprAssert(! (bp->flags & ALLOC_FLAGS_FREE));
1617         mprAssert(! (bp->flags & ALLOC_FLAGS_FREEING));
1618
1619         /*
1620          *      
1621          */
1622         count = 0;
1623         parent = bp->parent;
1624
1625         if ((firstChild = bp->children) != 0) {
1626                 cp = firstChild;
1627                 mprAssert((int) cp != 0xfeefee);
1628                 do {
1629                         mprAssert(bp->next->prev == bp);
1630                         mprAssert(bp->prev->next == bp);
1631                         mprAssert(bp->prev->parent == parent);
1632                         mprAssert(bp->next->parent == parent);
1633
1634                         count++;
1635                         cp = cp->next;
1636
1637                         if (bp->next == bp) {
1638                                 mprAssert(bp->prev == bp);
1639                                 if (ptr != bp->app) {
1640                                         mprAssert(parent->children == bp);
1641                                 }
1642                         }
1643                         if (bp->prev == bp) {
1644                                 mprAssert(bp->next == bp);
1645                                 if (ptr != bp->app) {
1646                                         mprAssert(parent->children == bp);
1647                                 }
1648                         }
1649                 } while (cp != firstChild);
1650         }
1651
1652         return 0;
1653 }
1654
1655 #endif
1656 /******************************************************************************/
1657 /*
1658  *      Validate a block and all children
1659  */
1660
1661 int mprValidateAllocTree(MprCtx ptr)
1662 {
1663 #if VALIDATE_ALLOC
1664         MprBlk                  *bp, *cp, *firstChild;
1665
1666         mprAssert(ptr);
1667         mprAssert(VALID_BLK(ptr));
1668
1669         bp = GET_HDR(ptr);
1670
1671         mprValidateBlock(GET_PTR(bp));
1672
1673         if ((firstChild = bp->children) != 0) {
1674                 cp = firstChild;
1675                 do {
1676                         mprValidateAllocTree(GET_PTR(cp));
1677                         cp = cp->next;
1678                 } while (cp != firstChild);
1679         }
1680
1681 #endif
1682         return 0;
1683 }
1684
1685 /******************************************************************************/
1686 #if UNUSED && FUTURE
1687 /*
1688  *      Exhaustive validation of the block and its children. Does not go recursive
1689  *      as it would be too slow.
1690  */
1691
1692 int mprValidateSlabs(MprApp *app)
1693 {
1694         MprSlab                 *slab;
1695         MprSlabStats    *slabStats;
1696         MprSlabBlock    *sp;
1697         int                             count, i;
1698
1699         for (i = 0; i < MPR_MAX_SLAB; i++) {
1700                 slab = &app->alloc.slabs[i];
1701                 slabStats = &slab->stats;
1702
1703                 count = 0;
1704                 for (sp = slab->next; sp; sp = sp->next) {
1705                         count++;
1706                 }
1707                 mprAssert(count == (int) slabStats->freeCount);
1708         }
1709         return 0;
1710 }
1711
1712 #endif
1713 /******************************************************************************/
1714
1715 void mprAllocAbort()
1716 {
1717 #if BREW
1718         printf("Bad block header");
1719 #else
1720         exit(255);
1721 #endif
1722 }
1723
1724 /******************************************************************************/
1725 #undef mprGetApp
1726 /*
1727  *      Get the root parent from any block (which is the MprApp structure)
1728  */
1729
1730 MprApp *mprGetApp(MprCtx ptr)
1731 {
1732         MprBlk  *bp;
1733
1734         mprAssert(ptr);
1735
1736         bp = GET_HDR(ptr);
1737         mprAssert(VALID_HDR(bp));
1738
1739         CHECK_HDR(bp);
1740
1741         mprAssert(bp->app->magic == APP_MAGIC);
1742
1743         return bp->app;
1744 }
1745
1746 /******************************************************************************/
1747
1748 int mprGetAllocErrors(MprCtx ctx)
1749 {
1750         MprApp  *app;
1751
1752         app = mprGetApp(ctx);
1753         return app->alloc.stats.errors;
1754 }
1755
1756 /******************************************************************************/
1757
1758 void mprClearAllocErrors(MprCtx ctx)
1759 {
1760         MprApp  *app;
1761
1762         app = mprGetApp(ctx);
1763         app->alloc.stats.errors = 0;
1764 }
1765
1766 /******************************************************************************/
1767 /*
1768  * Local variables:
1769  * tab-width: 4
1770  * c-basic-offset: 4
1771  * End:
1772  * vim:tw=78
1773  * vim600: sw=4 ts=4 fdm=marker
1774  * vim<600: sw=4 ts=4
1775  */