OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tcl/] [generic/] [tclAlloc.c] - Blame information for rev 578

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tclAlloc.c --
3
 *
4
 *      This is a very fast storage allocator.  It allocates blocks of a
5
 *      small number of different sizes, and keeps free lists of each size.
6
 *      Blocks that don't exactly fit are passed up to the next larger size.
7
 *      Blocks over a certain size are directly allocated from the system.
8
 *
9
 * Copyright (c) 1983 Regents of the University of California.
10
 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
11
 *
12
 * Portions contributed by Chris Kingsley, Jack Jansen and Ray Johnson.
13
 *
14
 * See the file "license.terms" for information on usage and redistribution
15
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16
 *
17
 * RCS: @(#) $Id: tclAlloc.c,v 1.1.1.1 2002-01-16 10:25:25 markom Exp $
18
 */
19
 
20
#include "tclInt.h"
21
#include "tclPort.h"
22
 
23
#ifdef TCL_DEBUG
24
#   define DEBUG
25
/* #define MSTATS */
26
#   define RCHECK
27
#endif
28
 
29
#ifndef __CYGWIN__
30
typedef unsigned long caddr_t;
31
#endif
32
 
33
/*
34
 * The overhead on a block is at least 4 bytes.  When free, this space
35
 * contains a pointer to the next free block, and the bottom two bits must
36
 * be zero.  When in use, the first byte is set to MAGIC, and the second
37
 * byte is the size index.  The remaining bytes are for alignment.
38
 * If range checking is enabled then a second word holds the size of the
39
 * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
40
 * The order of elements is critical: ov_magic must overlay the low order
41
 * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
42
 */
43
 
44
union overhead {
45
    union overhead *ov_next;    /* when free */
46
    struct {
47
        unsigned char   ovu_magic0;     /* magic number */
48
        unsigned char   ovu_index;      /* bucket # */
49
        unsigned char   ovu_unused;     /* unused */
50
        unsigned char   ovu_magic1;     /* other magic number */
51
#ifdef RCHECK
52
        unsigned short  ovu_rmagic;     /* range magic number */
53
        unsigned long   ovu_size;       /* actual block size */
54
#endif
55
    } ovu;
56
#define ov_magic0       ovu.ovu_magic0
57
#define ov_magic1       ovu.ovu_magic1
58
#define ov_index        ovu.ovu_index
59
#define ov_rmagic       ovu.ovu_rmagic
60
#define ov_size ovu.ovu_size
61
};
62
 
63
 
64
#define MAGIC           0xef            /* magic # on accounting info */
65
#define RMAGIC          0x5555          /* magic # on range info */
66
 
67
#ifdef RCHECK
68
#define RSLOP           sizeof (unsigned short)
69
#else
70
#define RSLOP           0
71
#endif
72
 
73
#define OVERHEAD (sizeof(union overhead) + RSLOP)
74
 
75
/*
76
 * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
77
 * smallest allocatable block is 8 bytes.  The overhead information
78
 * precedes the data area returned to the user.
79
 */
80
 
81
#define NBUCKETS        13
82
#define MAXMALLOC       (1<<(NBUCKETS+2))
83
static  union overhead *nextf[NBUCKETS];
84
 
85
#ifdef MSTATS
86
 
87
/*
88
 * nmalloc[i] is the difference between the number of mallocs and frees
89
 * for a given block size.
90
 */
91
 
92
static  unsigned int nmalloc[NBUCKETS+1];
93
#include <stdio.h>
94
#endif
95
 
96
#if defined(DEBUG) || defined(RCHECK)
97
#define ASSERT(p)   if (!(p)) panic(# p)
98
#define RANGE_ASSERT(p) if (!(p)) panic(# p)
99
#else
100
#define ASSERT(p)
101
#define RANGE_ASSERT(p)
102
#endif
103
 
104
/*
105
 * Prototypes for functions used only in this file.
106
 */
107
 
108
static void             MoreCore _ANSI_ARGS_((int bucket));
109
 
110
/*
111
 *----------------------------------------------------------------------
112
 *
113
 * TclpAlloc --
114
 *
115
 *      Allocate more memory.
116
 *
117
 * Results:
118
 *      None.
119
 *
120
 * Side effects:
121
 *      None.
122
 *
123
 *----------------------------------------------------------------------
124
 */
125
 
126
char *
127
TclpAlloc(
128
    unsigned int nbytes)        /* Number of bytes to allocate. */
129
{
130
    register union overhead *op;
131
    register long bucket;
132
    register unsigned amt;
133
 
134
    /*
135
     * First the simple case: we simple allocate big blocks directly
136
     */
137
    if (nbytes + OVERHEAD >= MAXMALLOC) {
138
        op = (union overhead *)TclpSysAlloc(nbytes+OVERHEAD, 0);
139
        if (op == NULL) {
140
            return NULL;
141
        }
142
        op->ov_magic0 = op->ov_magic1 = MAGIC;
143
        op->ov_index = 0xff;
144
#ifdef MSTATS
145
        nmalloc[NBUCKETS]++;
146
#endif
147
#ifdef RCHECK
148
        /*
149
         * Record allocated size of block and
150
         * bound space with magic numbers.
151
         */
152
        op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
153
        op->ov_rmagic = RMAGIC;
154
        *(unsigned short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
155
#endif
156
        return (void *)(op+1);
157
    }
158
    /*
159
     * Convert amount of memory requested into closest block size
160
     * stored in hash buckets which satisfies request.
161
     * Account for space used per block for accounting.
162
     */
163
#ifndef RCHECK
164
    amt = 8;    /* size of first bucket */
165
    bucket = 0;
166
#else
167
    amt = 16;   /* size of first bucket */
168
    bucket = 1;
169
#endif
170
    while (nbytes + OVERHEAD > amt) {
171
        amt <<= 1;
172
        if (amt == 0) {
173
            return (NULL);
174
        }
175
        bucket++;
176
    }
177
    ASSERT( bucket < NBUCKETS );
178
 
179
    /*
180
     * If nothing in hash bucket right now,
181
     * request more memory from the system.
182
     */
183
    if ((op = nextf[bucket]) == NULL) {
184
        MoreCore(bucket);
185
        if ((op = nextf[bucket]) == NULL) {
186
            return (NULL);
187
        }
188
    }
189
    /*
190
     * Remove from linked list
191
     */
192
    nextf[bucket] = op->ov_next;
193
    op->ov_magic0 = op->ov_magic1 = MAGIC;
194
    op->ov_index = (unsigned char) bucket;
195
#ifdef MSTATS
196
    nmalloc[bucket]++;
197
#endif
198
#ifdef RCHECK
199
    /*
200
     * Record allocated size of block and
201
     * bound space with magic numbers.
202
     */
203
    op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
204
    op->ov_rmagic = RMAGIC;
205
    *(unsigned short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
206
#endif
207
    return ((char *)(op + 1));
208
}
209
 
210
/*
211
 *----------------------------------------------------------------------
212
 *
213
 * MoreCore --
214
 *
215
 *      Allocate more memory to the indicated bucket.
216
 *
217
 * Results:
218
 *      None.
219
 *
220
 * Side effects:
221
 *      Attempts to get more memory from the system.
222
 *
223
 *----------------------------------------------------------------------
224
 */
225
 
226
static void
227
MoreCore(
228
    int bucket)         /* What bucket to allocat to. */
229
{
230
    register union overhead *op;
231
    register long sz;           /* size of desired block */
232
    long amt;                   /* amount to allocate */
233
    int nblks;                  /* how many blocks we get */
234
 
235
    /*
236
     * sbrk_size <= 0 only for big, FLUFFY, requests (about
237
     * 2^30 bytes on a VAX, I think) or for a negative arg.
238
     */
239
    sz = 1 << (bucket + 3);
240
    ASSERT(sz > 0);
241
 
242
    amt = MAXMALLOC;
243
    nblks = amt / sz;
244
    ASSERT(nblks*sz == amt);
245
 
246
    op = (union overhead *)TclpSysAlloc(amt, 1);
247
    /* no more room! */
248
    if (op == NULL) {
249
        return;
250
    }
251
 
252
    /*
253
     * Add new memory allocated to that on
254
     * free list for this hash bucket.
255
     */
256
    nextf[bucket] = op;
257
    while (--nblks > 0) {
258
        op->ov_next = (union overhead *)((caddr_t)op + sz);
259
        op = (union overhead *)((caddr_t)op + sz);
260
    }
261
    op->ov_next = (union overhead *)NULL;
262
}
263
 
264
/*
265
 *----------------------------------------------------------------------
266
 *
267
 * TclpFree --
268
 *
269
 *      Free memory.
270
 *
271
 * Results:
272
 *      None.
273
 *
274
 * Side effects:
275
 *      None.
276
 *
277
 *----------------------------------------------------------------------
278
 */
279
 
280
void
281
TclpFree(
282
    char *cp)           /* Pointer to memory to free. */
283
{
284
    register long size;
285
    register union overhead *op;
286
 
287
    if (cp == NULL) {
288
        return;
289
    }
290
 
291
    op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
292
 
293
    ASSERT(op->ov_magic0 == MAGIC);             /* make sure it was in use */
294
    ASSERT(op->ov_magic1 == MAGIC);
295
    if (op->ov_magic0 != MAGIC || op->ov_magic1 != MAGIC) {
296
        return;
297
    }
298
 
299
    RANGE_ASSERT(op->ov_rmagic == RMAGIC);
300
    RANGE_ASSERT(*(unsigned short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
301
    size = op->ov_index;
302
    if ( size == 0xff ) {
303
#ifdef MSTATS
304
        nmalloc[NBUCKETS]--;
305
#endif
306
        TclpSysFree(op);
307
        return;
308
    }
309
    ASSERT(size < NBUCKETS);
310
    op->ov_next = nextf[size];  /* also clobbers ov_magic */
311
    nextf[size] = op;
312
#ifdef MSTATS
313
    nmalloc[size]--;
314
#endif
315
}
316
 
317
/*
318
 *----------------------------------------------------------------------
319
 *
320
 * TclpRealloc --
321
 *
322
 *      Reallocate memory.
323
 *
324
 * Results:
325
 *      None.
326
 *
327
 * Side effects:
328
 *      None.
329
 *
330
 *----------------------------------------------------------------------
331
 */
332
 
333
char *
334
TclpRealloc(
335
    char *cp,                   /* Pointer to alloced block. */
336
    unsigned int nbytes)        /* New size of memory. */
337
{
338
    int i;
339
    union overhead *op;
340
    int expensive;
341
    unsigned long maxsize;
342
 
343
    if (cp == NULL) {
344
        return (TclpAlloc(nbytes));
345
    }
346
 
347
    op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
348
 
349
    ASSERT(op->ov_magic0 == MAGIC);             /* make sure it was in use */
350
    ASSERT(op->ov_magic1 == MAGIC);
351
    if (op->ov_magic0 != MAGIC || op->ov_magic1 != MAGIC) {
352
        return NULL;
353
    }
354
 
355
    RANGE_ASSERT(op->ov_rmagic == RMAGIC);
356
    RANGE_ASSERT(*(unsigned short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
357
    i = op->ov_index;
358
 
359
    /*
360
     * If the block isn't in a bin, just realloc it.
361
     */
362
 
363
    if (i == 0xff) {
364
        op = (union overhead *) TclpSysRealloc(op, nbytes+OVERHEAD);
365
        if (op == NULL) {
366
            return NULL;
367
        }
368
#ifdef MSTATS
369
        nmalloc[NBUCKETS]++;
370
#endif
371
#ifdef RCHECK
372
        /*
373
         * Record allocated size of block and update magic number bounds.
374
         */
375
 
376
        op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
377
        *(unsigned short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
378
#endif
379
        return (char *)(op+1);
380
    }
381
    maxsize = 1 << (i+3);
382
    expensive = 0;
383
    if ( nbytes + OVERHEAD > maxsize ) {
384
        expensive = 1;
385
    } else if ( i > 0 && nbytes + OVERHEAD < (maxsize/2) ) {
386
        expensive = 1;
387
    }
388
 
389
    if (expensive) {
390
        void *newp;
391
 
392
        newp = TclpAlloc(nbytes);
393
        if ( newp == NULL ) {
394
            return NULL;
395
        }
396
        maxsize -= OVERHEAD;
397
        if ( maxsize < nbytes )
398
            nbytes = maxsize;
399
        memcpy((VOID *) newp, (VOID *) cp, (size_t) nbytes);
400
        TclpFree(cp);
401
        return newp;
402
    }
403
 
404
    /*
405
     * Ok, we don't have to copy, it fits as-is
406
     */
407
#ifdef RCHECK
408
    op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
409
    *(unsigned short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
410
#endif
411
    return(cp);
412
}
413
 
414
/*
415
 *----------------------------------------------------------------------
416
 *
417
 * mstats --
418
 *
419
 *      Prints two lines of numbers, one showing the length of the
420
 *      free list for each size category, the second showing the
421
 *      number of mallocs - frees for each size category.
422
 *
423
 * Results:
424
 *      None.
425
 *
426
 * Side effects:
427
 *      None.
428
 *
429
 *----------------------------------------------------------------------
430
 */
431
 
432
#ifdef MSTATS
433
void
434
mstats(
435
    char *s)    /* Where to write info. */
436
{
437
    register int i, j;
438
    register union overhead *p;
439
    int totfree = 0,
440
        totused = 0;
441
 
442
    fprintf(stderr, "Memory allocation statistics %s\nTclpFree:\t", s);
443
    for (i = 0; i < NBUCKETS; i++) {
444
        for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
445
            fprintf(stderr, " %d", j);
446
        totfree += j * (1 << (i + 3));
447
    }
448
    fprintf(stderr, "\nused:\t");
449
    for (i = 0; i < NBUCKETS; i++) {
450
        fprintf(stderr, " %d", nmalloc[i]);
451
        totused += nmalloc[i] * (1 << (i + 3));
452
    }
453
    fprintf(stderr, "\n\tTotal small in use: %d, total free: %d\n",
454
            totused, totfree);
455
    fprintf(stderr, "\n\tNumber of big (>%d) blocks in use: %d\n",
456
            MAXMALLOC, nmalloc[NBUCKETS]);
457
}
458
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.