source: rtems/cpukit/httpd/balloc.c @ 73b5bd5d

4.104.114.84.95
Last change on this file since 73b5bd5d was 73b5bd5d, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/15/04 at 13:33:58

Remove stray white spaces.

  • Property mode set to 100644
File size: 23.9 KB
Line 
1/*
2 * balloc.c -- Block allocation module
3 *
4 * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
5 *
6 * See the file "license.txt" for usage and redistribution license requirements
7 *
8 * $Id$
9 */
10
11/******************************** Description *********************************/
12
13/*
14 *      This module implements a very fast block allocation scheme suitable for
15 *      ROMed environments. It maintains block class queues for rapid allocation
16 *      and minimal fragmentation. This module does not coalesce blocks. The
17 *      storage space may be populated statically or via the traditional malloc
18 *      mechanisms. Large blocks greater than the maximum class size may be
19 *      allocated from the O/S or run-time system via malloc. To permit the use
20 *      of malloc, call bopen with flags set to B_USE_MALLOC (this is the default).
21 *      It is recommended that bopen be called first thing in the application.
22 *      If it is not, it will be called with default values on the first call to
23 *      balloc(). Note that this code is not designed for multi-threading purposes
24 *      and it depends on newly declared variables being initialized to zero.
25 */ 
26
27/********************************* Includes ***********************************/
28
29#define IN_BALLOC
30
31#ifdef UEMF
32        #include        "uemf.h"
33#else
34        #include        "basic/basicInternal.h"
35#endif
36
37#include        <stdarg.h>
38#include        <stdlib.h>
39
40#ifndef NO_BALLOC
41/********************************* Defines ************************************/
42
43/*
44 *      Define B_STATS if you wish to track memory block and stack usage
45 */
46#ifdef B_STATS
47/*
48 *      Optional statistics
49 */
50
51typedef struct {
52        long    alloc;                                                          /* Block allocation calls */
53        long    inuse;                                                          /* Blocks in use */
54} bStatsType;
55
56typedef struct {
57        char_t  file[FNAMESIZE];
58        long    allocated;                                                      /* Bytes currently allocated */
59        long    count;                                                          /* Current block count */
60        long    times;                                                          /* Count of alloc attempts */
61        long    largest;                                                        /* largest allocated here */
62        int             q;
63} bStatsFileType;
64
65/*
66 *      This one is very expensive but great stats
67 */
68typedef struct {
69        void                    *ptr;                                           /* Pointer to memory */
70        bStatsFileType  *who;                                           /* Who allocated the memory */
71} bStatsBlkType;
72
73static bStatsType               bStats[B_MAX_CLASS];    /* Per class stats */
74static bStatsFileType   bStatsFiles[B_MAX_FILES];/* Per file stats */
75static bStatsBlkType    bStatsBlks[B_MAX_BLOCKS];/* Per block stats */
76static int                              bStatsBlksMax = 0;              /* Max block entry */
77static int                              bStatsFilesMax = 0;             /* Max file entry */
78static int                              bStatsMemInUse = 0;             /* Memory currently in use */
79static int                              bStatsBallocInUse = 0;  /* Memory currently balloced */
80static int                              bStatsMemMax = 0;               /* Max memory ever used */
81static int                              bStatsBallocMax = 0;    /* Max memory ever balloced */
82static void                             *bStackMin = (void*) -1;/* Miniumum stack position */
83static void                             *bStackStart;                   /* Starting stack position */
84static int                              bStatsMemMalloc = 0;    /* Malloced memory */
85#endif /* B_STATS */
86
87/*
88 *      ROUNDUP4(size) returns the next higher integer value of size that is
89 *      divisible by 4, or the value of size if size is divisible by 4.
90 *      ROUNDUP4() is used in aligning memory allocations on 4-byte boundaries.
91 *
92 *      Note:  ROUNDUP4() is only required on some operating systems (IRIX).
93 */
94
95#define ROUNDUP4(size) ((size) % 4) ? (size) + (4 - ((size) % 4)) : (size)
96
97/********************************** Locals ************************************/
98/*
99 *      bQhead blocks are created as the original memory allocation is freed up.
100 *      See bfree.
101 */
102static bType                    *bQhead[B_MAX_CLASS];   /* Per class block q head */
103static char                             *bFreeBuf;                              /* Pointer to free memory */
104static char                             *bFreeNext;                             /* Pointer to next free mem */
105static int                              bFreeSize;                              /* Size of free memory */
106static int                              bFreeLeft;                              /* Size of free left for use */
107static int                              bFlags = B_USE_MALLOC;  /* Default to auto-malloc */
108static int                              bopenCount = 0;                 /* Num tasks using balloc */
109
110/*************************** Forward Declarations *****************************/
111
112#ifdef B_STATS
113static void bStatsAlloc(B_ARGS_DEC, void *ptr, int q, int size);
114static void bStatsFree(B_ARGS_DEC, void *ptr, int q, int size);
115static void bstatsWrite(int handle, char_t *fmt, ...);
116static int      bStatsFileSort(const void *cp1, const void *cp2);
117#endif /* B_STATS */
118
119#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
120static void bFillBlock(void *buf, int bufsize);
121#endif
122
123#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
124static void verifyUsedBlock(bType *bp, int q);
125static void verifyFreeBlock(bType *bp, int q);
126void verifyBallocSpace();
127#endif
128
129static int ballocGetSize(int size, int *q);
130
131/********************************** Code **************************************/
132/*
133 *      Initialize the balloc module. bopen should be called the very first thing
134 *      after the application starts and bclose should be called the last thing
135 *      before exiting. If bopen is not called, it will be called on the first
136 *      allocation with default values. "buf" points to memory to use of size
137 *      "bufsize". If buf is NULL, memory is allocated using malloc. flags may
138 *      be set to B_USE_MALLOC if using malloc is okay. This routine will allocate
139 *      an initial buffer of size bufsize for use by the application.
140 */
141
142int bopen(void *buf, int bufsize, int flags)
143{
144        bFlags = flags;
145
146#ifdef BASTARD_TESTING
147        srand(time(0L));
148#endif /* BASTARD_TESTING */
149
150/*
151 *      If bopen already called by a shared process, just increment the count
152 *      and return;
153 */
154        if (++bopenCount > 1) {
155                return 0;
156        }
157
158        if (buf == NULL) {
159                if (bufsize == 0) {
160                        bufsize = B_DEFAULT_MEM;
161                }
162#ifdef IRIX
163                bufsize = ROUNDUP4(bufsize);
164#endif
165                if ((buf = malloc(bufsize)) == NULL) {
166                        return -1;
167                }
168#ifdef B_STATS
169                bStatsMemMalloc += bufsize;
170#endif
171        } else {
172                bFlags |= B_USER_BUF;
173        }
174
175        bFreeSize = bFreeLeft = bufsize;
176        bFreeBuf = bFreeNext = buf;
177        memset(bQhead, 0, sizeof(bQhead));
178#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
179        bFillBlock(buf, bufsize);
180#endif
181#ifdef B_STATS
182        bStackStart = &buf;
183#endif
184#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
185        verifyFreeBlock(buf, bufsize);
186#endif
187        return 0;
188}
189
190/******************************************************************************/
191/*
192 *      Close down the balloc module and free all malloced memory.
193 */
194
195void bclose()
196{
197#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
198        verifyBallocSpace();
199#endif
200        if (--bopenCount <= 0 && !(bFlags & B_USER_BUF)) {
201                free(bFreeBuf);
202                bopenCount = 0;
203        }
204}
205
206/******************************************************************************/
207/*
208 *      Allocate a block of the requested size. First check the block
209 *      queues for a suitable one.
210 */
211
212void *balloc(B_ARGS_DEC, int size)
213{
214        bType   *bp;
215        int             q, memSize;
216
217/*
218 *      Call bopen with default values if the application has not yet done so
219 */
220        if (bFreeBuf == NULL) {
221                if (bopen(NULL, B_DEFAULT_MEM, 0) < 0) {
222                        return NULL;
223                }
224        }
225#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
226        verifyBallocSpace();
227#endif
228        if (size < 0) {
229                return NULL;
230        }
231
232#ifdef BASTARD_TESTING
233        if (rand() == 0x7fff) {
234                return NULL;
235        }
236#endif /* BASTARD_TESTING */
237
238
239        memSize = ballocGetSize(size, &q);
240
241        if (q >= B_MAX_CLASS) {
242/*
243 *              Size if bigger than the maximum class. Malloc if use has been okayed
244 */
245                if (bFlags & B_USE_MALLOC) {
246#ifdef B_STATS
247                        bstats(0, NULL);
248#endif
249#ifdef IRIX
250                        memSize = ROUNDUP4(memSize);
251#endif
252                        bp = (bType*) malloc(memSize);
253                        if (bp == NULL) {
254                                traceRaw(T("B: malloc failed\n"));
255                                return NULL;
256                        }
257#ifdef B_STATS
258                        bStatsMemMalloc += memSize;
259#endif
260#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
261                        bFillBlock(bp, memSize);
262#endif
263
264                } else {
265                        traceRaw(T("B: malloc failed\n"));
266                        return NULL;
267                }
268
269/*
270 *              the u.size is the actual size allocated for data
271 */
272                bp->u.size = memSize - sizeof(bType);
273                bp->flags = B_MALLOCED;
274
275        } else if ((bp = bQhead[q]) != NULL) {
276/*
277 *              Take first block off the relevant q if non-empty
278 */
279                bQhead[q] = bp->u.next;
280#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
281                verifyFreeBlock(bp, q);
282#endif
283#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
284                bFillBlock(bp, memSize);
285#endif
286                bp->u.size = memSize - sizeof(bType);
287                bp->flags = 0;
288
289        } else {
290                if (bFreeLeft > memSize) {
291/*
292 *                      The q was empty, and the free list has spare memory so
293 *                      create a new block out of the primary free block
294 */
295                        bp = (bType*) bFreeNext;
296#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
297                        verifyFreeBlock(bp, q);
298#endif
299                        bFreeNext += memSize;
300                        bFreeLeft -= memSize;
301#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
302                        bFillBlock(bp, memSize);
303#endif
304                        bp->u.size = memSize - sizeof(bType);
305                        bp->flags = 0;
306
307                } else if (bFlags & B_USE_MALLOC) {
308#ifdef B_STATS
309                        static int once = 0;
310                        if (once++ == 0) {
311                                bstats(0, NULL);
312                        }
313#endif
314/*
315 *                      Nothing left on the primary free list, so malloc a new block
316 */
317#ifdef IRIX
318                        memSize = ROUNDUP4(memSize);
319#endif
320                        if ((bp = (bType*) malloc(memSize)) == NULL) {
321                                traceRaw(T("B: malloc failed\n"));
322                                return NULL;
323                        }
324#ifdef B_STATS
325                        bStatsMemMalloc += memSize;
326#endif
327#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
328                        bFillBlock(bp, memSize);
329#endif
330                        bp->u.size = memSize - sizeof(bType);
331                        bp->flags = B_MALLOCED;
332
333                } else {
334                        traceRaw(T("B: malloc failed\n"));
335                        return NULL;
336                }
337        }
338
339#ifdef B_STATS
340        bStatsAlloc(B_ARGS, bp, q, memSize);
341#endif
342        bp->flags |= B_INTEGRITY;
343
344/*
345 *      The following is a good place to put a breakpoint when trying to reduce
346 *      determine and reduce maximum memory use.
347 */
348#if 0
349#ifdef B_STATS
350        if (bStatsBallocInUse == bStatsBallocMax) {
351                bstats(0, NULL);
352        }
353#endif
354#endif
355        return (void*) ((char*) bp + sizeof(bType));
356}
357
358/******************************************************************************/
359/*
360 *      Free a block back to the relevant free q. We don't free back to the O/S
361 *      or run time system unless the block is greater than the maximum class size.
362 *      We also do not coalesce blocks.
363 */
364
365void bfree(B_ARGS_DEC, void *mp)
366{
367        bType   *bp;
368        int             q, memSize;
369
370#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
371        verifyBallocSpace();
372#endif
373        bp = (bType*) ((char*) mp - sizeof(bType));
374
375        a_assert((bp->flags & B_INTEGRITY_MASK) == B_INTEGRITY);
376
377        if ((bp->flags & B_INTEGRITY_MASK) != B_INTEGRITY) {
378                return;
379        }
380
381        memSize = ballocGetSize(bp->u.size, &q);
382
383#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
384        verifyUsedBlock(bp,q);
385#endif
386#ifdef B_STATS
387        bStatsFree(B_ARGS, bp, q, bp->u.size+sizeof(bType));
388#endif
389        if (bp->flags & B_MALLOCED) {
390                free(bp);
391                return;
392        }
393               
394#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
395        bFillBlock(bp, memSize);
396#endif
397
398/*
399 *      Simply link onto the head of the relevant q
400 */
401        bp->u.next = bQhead[q];
402        bQhead[q] = bp;
403
404        bp->flags = B_FILL_WORD;
405}
406
407/******************************************************************************/
408/*
409 *      Safe free
410 */
411
412void bfreeSafe(B_ARGS_DEC, void *mp)
413{
414        if (mp) {
415                bfree(B_ARGS, mp);
416        }
417}
418
419/******************************************************************************/
420#ifdef UNICODE
421/*
422 *      Duplicate a string, allow NULL pointers and then dup an empty string.
423 */
424
425char *bstrdupA(B_ARGS_DEC, char *s)
426{
427        char    *cp;
428        int             len;
429
430        if (s == NULL) {
431                s = "";
432        }
433        len = strlen(s) + 1;
434        if (cp = balloc(B_ARGS, len)) {
435                strcpy(cp, s);
436        }
437        return cp;
438}
439
440#endif /* UNICODE */
441/******************************************************************************/
442/*
443 *      Duplicate an ascii string, allow NULL pointers and then dup an empty string.
444 *      If UNICODE, bstrdup above works with wide chars, so we need this routine
445 *      for ascii strings.
446 */
447
448char_t *bstrdup(B_ARGS_DEC, char_t *s)
449{
450        char_t  *cp;
451        int             len;
452
453        if (s == NULL) {
454                s = T("");
455        }
456        len = gstrlen(s) + 1;
457        if ((cp = balloc(B_ARGS, len * sizeof(char_t))) != NULL) {
458                gstrcpy(cp, s);
459        }
460        return cp;
461}
462
463/******************************************************************************/
464/*
465 *      Reallocate a block. Allow NULL pointers and just do a malloc.
466 *      Note: if the realloc fails, we return NULL and the previous buffer is
467 *      preserved.
468 */
469
470void *brealloc(B_ARGS_DEC, void *mp, int newsize)
471{
472        bType   *bp;
473        void    *newbuf;
474
475        if (mp == NULL) {
476                return balloc(B_ARGS, newsize);
477        }
478        bp = (bType*) ((char*) mp - sizeof(bType));
479        a_assert((bp->flags & B_INTEGRITY_MASK) == B_INTEGRITY);
480
481/*
482 *      If the allocated memory already has enough room just return the previously
483 *      allocated address.
484 */
485        if (bp->u.size >= newsize) {
486                return mp;
487        }
488        if ((newbuf = balloc(B_ARGS, newsize)) != NULL) {
489                memcpy(newbuf, mp, bp->u.size);
490                bfree(B_ARGS, mp);
491        }
492        return newbuf;
493}
494
495/******************************************************************************/
496/*
497 *      Find the size of the block to be balloc'ed.  It takes in a size, finds the
498 *      smallest binary block it fits into, adds an overhead amount and returns.
499 *      q is the binary size used to keep track of block sizes in use.  Called
500 *      from both balloc and bfree.
501 */
502
503static int ballocGetSize(int size, int *q)
504{
505        int     mask;
506
507        mask = (size == 0) ? 0 : (size-1) >> B_SHIFT;
508        for (*q = 0; mask; mask >>= 1) {
509                *q = *q + 1;
510        }
511        return ((1 << (B_SHIFT + *q)) + sizeof(bType));
512}
513
514/******************************************************************************/
515#if (defined (B_FILL) || defined (B_VERIFY_CAUSES_SEVERE_OVERHEAD))
516/*
517 *      Fill the block (useful during development to catch zero fill assumptions)
518 */
519
520static void bFillBlock(void *buf, int bufsize)
521{
522        memset(buf, B_FILL_CHAR, bufsize);
523}
524#endif
525
526/******************************************************************************/
527#ifdef B_STATS
528/*
529 *      Statistics. Do output via calling the writefn callback function with
530 *      "handle" as the output file handle.
531 */
532
533void bstats(int handle, void (*writefn)(int handle, char_t *fmt, ...))
534{
535        bStatsFileType  *fp, *files;
536        bStatsBlkType   *blkp;
537        bType                   *bp;
538        char_t                  *cp;
539        int                             q, count, mem, total, len;
540        static  int     recurseProtect = 0;
541
542        if (recurseProtect++ > 0) {
543                recurseProtect--;
544                return;
545        }
546
547        if (writefn == NULL) {
548                writefn = bstatsWrite;
549        }
550
551/*
552 *      Print stats for each memory block
553 */
554        (*writefn)(handle, T("\nMemory Stats\n"));
555
556/*
557 *      The following tabular format is now used for the output.
558 *   Q  Size  Free Bytes Inuse Bytes Allocs
559 *      dd ddddd   ddd ddddd  dddd ddddd   dddd
560 */
561        (*writefn)(handle, " Q  Size   Free  Bytes Inuse Bytes Allocs\n");
562
563        total = 0;
564        for (q = 0; q < B_MAX_CLASS; q++) {
565                count = 0;
566                for (bp = bQhead[q]; bp; bp = bp->u.next) {
567                        count++;
568                }
569                mem = count * (1 << (q + B_SHIFT));
570                total += mem;
571                (*writefn)(handle,
572                        T("%2d %5d   %4d %6d  %4d %5d   %4d\n"),
573                        q, 1 << (q + B_SHIFT), count, mem, bStats[q].inuse,
574                        bStats[q].inuse * (1 << (q + B_SHIFT)), bStats[q].alloc);
575        }
576
577        (*writefn)(handle, T("\n"));
578
579/*
580 *      Print summary stats
581 *
582 *      bFreeSize                       Initial memory reserved with bopen call
583 *      bStatsMemMalloc         memory from calls to system MALLOC
584 *      bStatsMemMax           
585 *      bStatsBallocMax         largest amount of memory from balloc calls
586 *      bStatsMemInUse
587 *      bStatsBallocInUse       present balloced memory being used
588 *      bStatsBlksMax);
589 *      bStackStart
590 *      bStackMin);
591 *      total);
592 *      bFreeLeft);
593 *
594 */
595        (*writefn)(handle, T("Initial free list size    %7d\n"), bFreeSize);
596        (*writefn)(handle, T("Max memory malloced       %7d\n"), bStatsMemMalloc);
597        (*writefn)(handle, T("Max memory ever used      %7d\n"), bStatsMemMax);
598        (*writefn)(handle, T("Max memory ever balloced  %7d\n"), bStatsBallocMax);
599        (*writefn)(handle, T("Memory currently in use   %7d\n"), bStatsMemInUse);
600        (*writefn)(handle, T("Memory currently balloced %7d\n"), bStatsBallocInUse);
601        (*writefn)(handle, T("Max blocks allocated      %7d\n"), bStatsBlksMax);
602        (*writefn)(handle, T("Maximum stack used        %7d\n"),
603                (int) bStackStart - (int) bStackMin);
604
605        (*writefn)(handle, T("Free memory on all queues %7d\n"), total);
606        (*writefn)(handle, T("Free list buffer left     %7d\n"), bFreeLeft);
607        (*writefn)(handle, T("Total free memory         %7d\n"), bFreeLeft + total);
608
609/*
610 *      Print per file allocation stats. Sort the copied table.
611 */
612        len = sizeof(bStatsFileType) * B_MAX_FILES;
613        files = malloc(len);
614        if (files == NULL) {
615                (*writefn)(handle, T("Can't allocate stats memory\n"));
616                recurseProtect--;
617                return;
618        }
619        memcpy(files, bStatsFiles, len);
620        qsort(files, bStatsFilesMax, sizeof(bStatsFileType), bStatsFileSort);
621       
622        (*writefn)(handle, T("\nMemory Currently Allocated\n"));
623        total = 0;
624        (*writefn)(handle,
625                T("                      bytes, blocks in use, total times,")
626                T("largest,   q\n"));
627
628        for (fp = files; fp < &files[bStatsFilesMax]; fp++) {
629                if (fp->file[0]) {
630                        (*writefn)(handle, T("%18s, %7d,         %5d,      %6d, %7d,%4d\n"),
631                                fp->file, fp->allocated, fp->count, fp->times, fp->largest,
632                                fp->q);
633                        total += fp->allocated;
634                }
635        }
636        (*writefn)(handle, T("\nTotal allocated %7d\n\n"), total);
637
638/*
639 *      Dump the actual strings
640 */
641        (*writefn)(handle, T("\nStrings\n"));
642        for (blkp = &bStatsBlks[bStatsBlksMax - 1]; blkp >= bStatsBlks; blkp--) {
643                if (blkp->ptr) {
644                        cp = (char_t*) ((char*) blkp->ptr + sizeof(bType));
645                        fp = blkp->who;
646                        if (gisalnum(*cp)) {
647                                (*writefn)(handle, T("%-50s allocated by %s\n"), cp,
648                                        fp->file);
649                        }
650                }
651        }
652        free(files);
653        recurseProtect--;
654}
655
656/******************************************************************************/
657/*
658 *      File sort function. Used to sort per file stats
659 */
660
661static int bStatsFileSort(const void *cp1, const void *cp2)
662{
663        bStatsFileType  *s1, *s2;
664
665        s1 = (bStatsFileType*) cp1;
666        s2 = (bStatsFileType*) cp2;
667
668        if (s1->allocated < s2->allocated)
669                return -1;
670        else if (s1->allocated == s2->allocated)
671                return 0;
672        return 1;
673}
674
675/******************************************************************************/
676/*
677 *      Accumulate allocation statistics
678 */
679
680static void bStatsAlloc(B_ARGS_DEC, void *ptr, int q, int size)
681{
682        int                             memSize;
683        bStatsFileType  *fp;
684        bStatsBlkType   *bp;
685        char_t                  name[FNAMESIZE + 10];
686
687        gsprintf(name, T("%s:%d"), B_ARGS);
688
689        bStats[q].alloc++;
690        bStats[q].inuse++;
691        bStatsMemInUse += size;
692        if (bStatsMemInUse > bStatsMemMax) {
693                bStatsMemMax = bStatsMemInUse;
694        }
695        memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
696        bStatsBallocInUse += memSize;
697        if (bStatsBallocInUse > bStatsBallocMax) {
698                bStatsBallocMax = bStatsBallocInUse;
699        }
700
701/*
702 *      Track maximum stack usage. Assumes a stack growth down. Approximate as
703 *      we only measure this on block allocation.
704 */
705        if ((void*) &file < bStackMin) {
706                bStackMin = (void*) &file;
707        }
708
709/*
710 *      Find the file and adjust the stats for this file
711 */
712        for (fp = bStatsFiles; fp < &bStatsFiles[bStatsFilesMax]; fp++) {
713                if (fp->file[0] == file[0] && gstrcmp(fp->file, name) == 0) {
714                        fp->allocated += size;
715                        fp->count++;
716                        fp->times++;
717                        if (fp->largest < size) {
718                                fp->largest = size;
719                                fp->q = q;
720                        }
721                        break;
722                }
723        }
724
725/*
726 *      New entry: find the first free slot and create a new entry
727 */
728        if (fp >= &bStatsFiles[bStatsFilesMax]) {
729                for (fp = bStatsFiles; fp < &bStatsFiles[B_MAX_FILES]; fp++) {
730                        if (fp->file[0] == '\0') {
731                                gstrncpy(fp->file, name, TSZ(fp->file));
732                                fp->allocated += size;
733                                fp->count++;
734                                fp->times++;
735                                fp->largest = size;
736                                fp->q = q;
737                                if ((fp - bStatsFiles) >= bStatsFilesMax) {
738                                        bStatsFilesMax = (fp - bStatsFiles) + 1;
739                                }
740                                break;
741                        }
742                }
743        }
744
745/*
746 *      Update the per block stats. Allocate a new slot.
747 */
748        for (bp = bStatsBlks; bp < &bStatsBlks[B_MAX_BLOCKS]; bp++) {
749                if (bp->ptr == NULL) {
750                        bp->ptr = ptr;
751                        bp->who = fp;
752                        if ((bp - bStatsBlks) >= bStatsBlksMax) {
753                                bStatsBlksMax = (bp - bStatsBlks) + 1;
754                        }
755                        break;
756                }
757        }
758}
759
760/******************************************************************************/
761/*
762 *      Free statistics
763 */
764
765static void bStatsFree(B_ARGS_DEC, void *ptr, int q, int size)
766{
767        int                             memSize;
768        bStatsFileType  *fp;
769        bStatsBlkType   *bp;
770
771        memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
772        bStatsMemInUse -= size;
773        bStatsBallocInUse -= memSize;
774        bStats[q].inuse--;
775
776/*
777 *      Update the per block stats. Try from the end first
778 */
779        for (bp = &bStatsBlks[bStatsBlksMax - 1]; bp >= bStatsBlks; bp--) {
780                if (bp->ptr == ptr) {
781                        bp->ptr = NULL;
782                        fp = bp->who;
783                        bp->who = NULL;
784                        fp->allocated -= size;
785                        fp->count--;
786                        return;
787                }
788        }
789}
790
791/******************************************************************************/
792/*
793 *      Default output function. Just send to trace channel.
794 */
795
796#undef sprintf
797static void bstatsWrite(int handle, char_t *fmt, ...)
798{
799        va_list         args;
800        char_t          buf[BUF_MAX];
801
802        va_start(args, fmt);
803        vsprintf(buf, fmt, args);
804        va_end(args);
805        traceRaw(buf);
806}
807
808
809#else /* not B_STATS */
810/******************************************************************************/
811/*
812 *      Dummy bstats for external calls that aren't protected by #if B_STATS.
813 */
814
815void bstats(int handle, void (*writefn)(int handle, char_t *fmt, ...))
816{
817}
818#endif /* B_STATS */
819
820/******************************************************************************/
821#ifdef B_VERIFY_CAUSES_SEVERE_OVERHEAD
822/*
823 *      The following routines verify the integrity of the balloc memory space.
824 *      These functions use the B_FILL feature.  Corruption is defined
825 *      as bad integrity flags in allocated blocks or data other than B_FILL_CHAR
826 *      being found anywhere in the space which is unallocated and that is not a
827 *      next pointer in the free queues. a_assert is called if any corruption is
828 *      found.  CAUTION:  These functions add severe processing overhead and should
829 *      only be used when searching for a tough corruption problem.
830 */
831
832/******************************************************************************/
833/*
834 *      verifyUsedBlock verifies that a block which was previously allocated is
835 *      still uncorrupted. 
836 */
837
838static void verifyUsedBlock(bType *bp, int q)
839{
840        int             memSize, size;
841        char    *p;
842
843        memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
844        a_assert((bp->flags & ~B_MALLOCED) == B_INTEGRITY);
845        size = bp->u.size;
846        for (p = ((char *)bp)+sizeof(bType)+size; p < ((char*)bp)+memSize; p++) {
847                a_assert(*p == B_FILL_CHAR);
848        }
849}
850
851/******************************************************************************/
852/*
853 *      verifyFreeBlock verifies that a previously free'd block in one of the queues
854 *      is still uncorrupted.
855 */
856
857static void verifyFreeBlock(bType *bp, int q)
858{
859        int             memSize;
860        char    *p;
861
862        memSize = (1 << (B_SHIFT + q)) + sizeof(bType);
863        for (p = ((char *)bp)+sizeof(void*); p < ((char*)bp)+memSize; p++) {
864                a_assert(*p == B_FILL_CHAR);
865        }
866        bp = (bType *)p;
867        a_assert((bp->flags & ~B_MALLOCED) == B_INTEGRITY ||
868                bp->flags == B_FILL_WORD);
869}
870
871/******************************************************************************/
872/*
873 *      verifyBallocSpace reads through the entire balloc memory space and
874 *      verifies that all allocated blocks are uncorrupted and that, with the
875 *      exception of free list next pointers, all other unallocated space is
876 *      filled with B_FILL_CHAR.
877 */
878
879void verifyBallocSpace()
880{
881        int             q;
882        char    *p;
883        bType   *bp;
884
885/*
886 *      First verify all the free blocks.
887 */
888        for (q = 0; q < B_MAX_CLASS; q++) {     
889                for (bp = bQhead[q]; bp != NULL; bp = bp->u.next) {
890                        verifyFreeBlock(bp, q);
891                }
892        }
893
894/*
895 *      Now verify other space
896 */
897        p = bFreeBuf;
898        while (p < (bFreeBuf + bFreeSize)) {
899                bp = (bType *)p;
900                if (bp->u.size > 0xFFFFF) {
901                        p += sizeof(bp->u);
902                        while (p < (bFreeBuf + bFreeSize) && *p == B_FILL_CHAR) {
903                                p++;
904                        }
905                } else {
906                        a_assert(((bp->flags & ~B_MALLOCED) == B_INTEGRITY) ||
907                                bp->flags == B_FILL_WORD);
908                        p += (sizeof(bType) + bp->u.size);
909                        while (p < (bFreeBuf + bFreeSize) && *p == B_FILL_CHAR) {
910                                p++;
911                        }
912                }
913        }
914}
915#endif /* B_VERIFY_CAUSES_SEVERE_OVERHEAD */
916
917/******************************************************************************/
918
919#else /* NO_BALLOC */
920int bopen(void *buf, int bufsize, int flags)
921{
922        return 0;
923}
924
925/******************************************************************************/
926
927void bclose()
928{
929}
930
931/******************************************************************************/
932
933void bstats(int handle, void (*writefn)(int handle, char_t *fmt, ...))
934{
935}
936
937/******************************************************************************/
938
939char_t *bstrdupNoBalloc(char_t *s)
940{
941#ifdef UNICODE
942        if (s) {
943                return wcsdup(s);
944        } else {
945                return wcsdup(T(""));
946        }
947#else
948        return bstrdupANoBalloc(s);
949#endif
950}
951
952/******************************************************************************/
953
954char *bstrdupANoBalloc(char *s)
955{
956        char*   buf;
957
958        if (s == NULL) {
959                s = "";
960        }
961        buf = malloc(strlen(s)+1);
962        strcpy(buf, s);
963        return buf;
964}
965
966#endif /* NO_BALLOC */
967/******************************************************************************/
Note: See TracBrowser for help on using the repository browser.