source: rtems/c/src/libnetworking/rtems_webserver/balloc.c @ 7a97f26

4.104.114.84.95
Last change on this file since 7a97f26 was a6b4c0df, checked in by Joel Sherrill <joel.sherrill@…>, on 09/01/00 at 10:57:21

2000-08-30 Joel Sherrill <joel@…>

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