|
|
1.1 root 1: /* malloc.c - Quipu DSA specific memory management */
2:
3: #ifndef lint
4: static char *rcsid = "$Header: /f/osi/quipu/RCS/malloc.c,v 7.1 90/07/09 14:46:17 mrose Exp $";
5: #endif
6:
7: /*
8: * $Header: /f/osi/quipu/RCS/malloc.c,v 7.1 90/07/09 14:46:17 mrose Exp $
9: *
10: *
11: * $Log: malloc.c,v $
12: * Revision 7.1 90/07/09 14:46:17 mrose
13: * sync
14: *
15: * Revision 7.0 89/11/23 22:20:55 mrose
16: * Release 6.0
17: *
18: */
19:
20: /*
21: * NOTICE
22: *
23: * Acquisition, use, and distribution of this module and related
24: * materials are subject to the restrictions of a license agreement.
25: * Consult the Preface in the User's Manual for the full terms of
26: * this agreement.
27: *
28: */
29:
30: #include <stdio.h>
31: #include "manifest.h"
32: #include "quipu/malloc.h"
33: #include "quipu/util.h"
34:
35: static int malloc_file = 0;
36:
37: #ifdef QUIPU_MALLOC
38:
39: extern LLog * log_dsap;
40: extern SFD attempt_restart();
41:
42: #if defined(DEBUG) && defined(sun3)
43: #define MALLOCSTACK
44: #endif
45:
46: #ifdef MALLOCSTACK
47: #include <sys/file.h>
48: off_t lseek();
49: #ifndef MALLOCTRACE
50: #define MALLOCTRACE
51: #endif
52: #else
53: #define write_stack(x)
54: #endif
55:
56:
57: #define MAXHEAP 100 /* Number of heaps */
58: #ifndef BSD42
59: #define PAGESIZE 0x2000 /* The systems memory page size */
60: #else
61: #define PAGESIZE pagesize
62: #endif
63:
64: #define ALIGN(x) (((x) + (sizeof(char *) - 1)) & ~(sizeof(char *) - 1))
65: #define PAGEALIGN(x) (((x) + (PAGESIZE-1)) & ~(PAGESIZE-1))
66: #define SMALLMAX 65536 /* largest block a short can reference */
67:
68:
69: struct header {
70: union {
71: struct {
72: unsigned short control;
73: unsigned short size;
74: } small;
75: unsigned int big;
76: } un;
77: };
78:
79: #define bigsize un.big
80: #define smallsize un.small.size
81: #define use un.small.control
82:
83: #define INUSE 0x1000
84: #define USED(x) (x->use & INUSE)
85:
86: /* sizes chosen for anticipated QUIPU behaviour */
87: #define BUCKETS 11
88: static unsigned sizes [BUCKETS] = { 0, 12, 16, 24, 48, 64, 128, 256, 512, 8191, 0 };
89:
90: struct freelist {
91: struct header * block;
92: unsigned int size;
93: struct freelist * next;
94: struct freelist * prev;
95: };
96:
97: struct freehead {
98: struct header head;
99: struct freelist * flist;
100: };
101:
102: static struct freelist heaps[MAXHEAP][BUCKETS];
103: static struct freelist *heapptr[MAXHEAP];
104: static struct freelist bigmem = { 0,0,&bigmem, &bigmem};
105: static struct freelist *bigfree = &bigmem;
106: static struct freelist freemem = { 0,0,&freemem, &freemem};
107: static struct freelist *listfree = &freemem;
108:
109: static int first_malloc = 1;
110: static char * top_mem;
111:
112: #ifdef BSD42
113: static int pagesize = 0x2000;
114: #endif
115:
116: extern caddr_t sbrk();
117:
118: #ifdef MALLOCTRACE
119: static int malloc_started = 0;
120: static char * malloc_fname = (char *)0;
121: #endif
122:
123: #ifndef MALLOCTRACE
124: /* ARGSUSED */
125: #endif
126:
127: #endif
128:
129: start_malloc_trace(f)
130: char * f;
131: {
132: #ifdef MALLOCTRACE
133: char * env, *getenv ();
134:
135: if (((env = getenv ("TRACE_MEMORY")) == (char *)0) || (*env == 0))
136: return;
137:
138: if (! malloc_started) {
139: if (f == (char *)0)
140: malloc_fname = "memory.out";
141: else
142: malloc_fname = f;
143: malloc_file = creat (malloc_fname,0644);
144: malloc_started = 1;
145: } else {
146: malloc_file = open (malloc_fname,1);
147: (void) lseek (malloc_file,0l,2);
148: }
149: #else
150: malloc_file = 0;
151: #endif
152: }
153:
154: stop_malloc_trace ()
155: {
156: #ifdef MALLOCTRACE
157: if (malloc_file)
158: (void) close (malloc_file);
159: #endif
160: malloc_file = 0;
161: }
162:
163: #ifdef QUIPU_MALLOC
164: #ifdef MALLOCTRACE
165:
166: static write_string (p)
167: char *p;
168: {
169: register char *q;
170:
171: if (!malloc_file)
172: return;
173:
174: q = p;
175: while (*q++)
176: ;
177: (void) write(malloc_file, p, q-p-1);
178: }
179:
180: static write_addr(addr)
181: char *addr;
182: {
183: char buf[20];
184: static char hex[] = "0123456789abcdef";
185: char *ptr;
186: int x;
187:
188: if (!malloc_file)
189: return;
190:
191: x = (int) addr;
192:
193: if (x == 0) {
194: (void) write(malloc_file, "0 ",2);
195: return;
196: }
197:
198: ptr = buf;
199: while (x > 0)
200: *ptr++ = hex[x % 16], x /= 16;
201: *ptr = 0;
202:
203: while (ptr != buf)
204: (void) write(malloc_file, --ptr,1);
205:
206: (void) write (malloc_file," ",1);
207: }
208:
209: static write_int(x)
210: unsigned x;
211: {
212: char buf[20];
213: static char dec[] = "0123456789";
214: char *ptr;
215:
216: if (!malloc_file)
217: return;
218:
219: if (x == 0) {
220: (void) write(malloc_file, "0 ",2);
221: return;
222: }
223:
224: ptr = buf;
225: while (x > 0)
226: *ptr++ = dec[x % 10], x /= 10;
227:
228: while (ptr != buf)
229: (void) write(malloc_file, --ptr,1);
230:
231: (void) write (malloc_file," ",1);
232: }
233:
234: static char * log_realloc (oldlen,newlen,bsize,addr)
235: unsigned oldlen,newlen,bsize;
236: char * addr;
237: {
238: write_string ("realloc of "); write_int (oldlen);
239: write_string ("at "); write_addr (addr);
240: write_string ("\n");
241: write_stack("x");
242:
243: write_string ("realloc-to of "); write_int (newlen);
244: write_string ("gets "); write_int (bsize);
245: write_string ("at "); write_addr (addr);
246: write_string ("\n");
247: write_stack("x");
248: }
249:
250: static print_free_list (heap)
251: unsigned heap;
252: {
253: int i;
254: struct freelist * top;
255: struct freelist * ptr;
256:
257: write_string ("free list for heap ");write_int(heap);write_string(":\n");
258: for (i=0; i<BUCKETS; i++) {
259: top = &heaps[heap][i];
260: write_int (sizes[i]); write_string (": ");
261: for (ptr = top->next ; ptr != top; ptr=ptr->next)
262: write_int (ptr->size);
263: write_string ("\n");
264: }
265: }
266:
267: #ifdef MALLOCSTACK
268:
269: /* ever so slightly machine dependant !!! */
270:
271: static write_stack (x)
272: char * x;
273: {
274:
275: struct stackframe {
276: struct stackframe *next;
277: char *addr;
278: } * frame;
279:
280: for (frame = ((struct stackframe *)(&x-2))->next ; frame; frame = frame->next) {
281: write_string ("C ");
282: write_addr ((char *)frame->addr);
283: write_string ("\n");
284: }
285: write_string ("\n");
286:
287: }
288: #endif
289: #endif
290:
291:
292: static return_freelist (next)
293: struct freelist *next;
294: {
295: next->next = listfree->next;
296: next->prev = listfree;
297: listfree->next->prev = next;
298: listfree->next = next;
299: }
300:
301: static struct freelist * new_freelist ()
302: {
303: struct freelist * flist;
304:
305: flist = listfree->next;
306:
307: if (flist == listfree) {
308: int i;
309: struct freelist * next;
310: /* go and get some more */
311: if ((flist = (struct freelist *) sbrk (PAGESIZE)) == (struct freelist *)0) {
312: /* there are 100s of places where Quipu would choke on a naff malloc */
313: attempt_restart (-2);
314: return ((struct freelist *)0);
315: }
316: top_mem = (char *)flist + PAGESIZE;
317: next = (struct freelist *)flist;
318: next++;
319: for (i=sizeof (struct freelist); i< PAGESIZE ; i+=sizeof (struct freelist))
320: return_freelist (next++);
321: } else {
322: flist->prev->next = flist->next;
323: flist->next->prev = flist->prev;
324: }
325:
326: return (flist);
327: }
328:
329:
330: static char * big_malloc (realsize)
331: /* used for mallocs of > MAXSMALL */
332: unsigned realsize;
333: {
334: unsigned blocksize;
335: struct freelist * flist;
336: struct header * head = (struct header *)0;
337: char * mem;
338:
339: for (flist = bigfree->next; flist != bigfree; flist=flist->next) {
340: if (flist->size >= realsize) {
341: head = flist->block;
342: flist->prev->next = flist->next;
343: flist->next->prev = flist->prev;
344: return_freelist (flist);
345: break;
346: }
347: }
348:
349: if (head == (struct header *)0) {
350: /* go and get on then !!! */
351: blocksize = PAGEALIGN(realsize);
352: if ((head = (struct header *) sbrk ((int)blocksize)) == (struct header *)0) {
353: /* there are 100s of places where Quipu would choke on a naff malloc */
354: attempt_restart (-2);
355: return ((char *)0);
356: }
357: top_mem = (char *)head + blocksize;
358: head->bigsize = blocksize | 0x01;
359: } else
360: head->bigsize |= 0x01;
361:
362: mem = (char *) head + ALIGN(sizeof (struct header));
363:
364: #ifdef MALLOCTRACE
365: write_string ("gets "); write_int (head->bigsize);
366: write_string ("at "); write_addr (mem);
367: write_string ("\n");
368: write_stack("x");
369: #endif
370:
371: return (mem);
372:
373: }
374:
375: static big_free (ptr)
376: struct header *ptr;
377: {
378: struct freelist *next;
379: struct freehead *x;
380:
381: if ((next = new_freelist ()) == (struct freelist *)0)
382: return;
383: next->size=ptr->bigsize;
384: next->block = ptr;
385: ptr->bigsize &= ~1;
386: next->next = bigfree->next;
387: next->prev = bigfree;
388: bigfree->next->prev = next;
389: bigfree->next = next;
390:
391: x = (struct freehead *) ptr;
392: x->flist = next;
393: }
394:
395: static which_list (size)
396: register unsigned size;
397: {
398: register unsigned * p;
399:
400: p = sizes;
401: p [BUCKETS -1] = size; /* force stop to while loop */
402:
403: while ( size > *p++ )
404: ;
405:
406: return ( (p-1) - sizes);
407: }
408:
409: static add_free (x)
410: struct header * x;
411: {
412: struct freelist *next, *c;
413: struct freehead *ptr;
414:
415: x->use &= ~INUSE;
416:
417: if ((c = heapptr[x->use]) == (struct freelist *) 0)
418: c = heapptr[x->use] = heaps[x->use];
419:
420: c = &c[which_list(x->smallsize)];
421:
422: if ((next = new_freelist ()) == (struct freelist *)0)
423: return;
424: next->size=x->smallsize;
425: next->block = x;
426: next->next = c->next;
427: next->prev = c;
428: c->next->prev = next;
429: c->next = next;
430:
431: ptr = (struct freehead *) x;
432: ptr->flist = next;
433: }
434:
435: static remove_free (a)
436: register struct freelist * a;
437: {
438: a->block->use |= INUSE;
439: a->prev->next = a->next;
440: a->next->prev = a->prev;
441: return_freelist(a);
442: }
443:
444: static struct header * next_free_block (ptr)
445: register struct header * ptr;
446: {
447: register struct header * next;
448:
449: next = (struct header *)((char *)ptr + ptr->smallsize);
450: if (PAGEALIGN((int)ptr) != PAGEALIGN((int)next + 1))
451: return (struct header *)0;
452: if (((char *)next < top_mem) && (next->use == (ptr->use & ~INUSE)))
453: return (next);
454:
455: return (struct header *)0;
456:
457: }
458:
459: static struct header * find_block (size)
460: unsigned size;
461: {
462: register struct freelist * top;
463: register struct freelist * ptr;
464: register int i;
465: #ifdef BESTFIT
466: struct freelist * best = (struct freelist *)0;
467: #endif
468:
469: if ((top = heapptr[mem_heap]) == (struct freelist *)0)
470: return ((struct header *) 0);
471:
472: top = &top[i = which_list (size)];
473:
474: for (; i < BUCKETS ; i++,top++ ) {
475: for (ptr = top->next ; ptr != top; ptr=ptr->next) {
476: if (ptr->size >= size) {
477: #ifdef BESTFIT
478: if (ptr->size == size) {
479: remove_free (ptr);
480: return (&(ptr->block));
481: }
482: if ( (best == (struct freelist *)0)
483: || (ptr->size < best->size))
484: best = ptr;
485:
486: #else
487: remove_free (ptr);
488: return (ptr->block);
489: #endif
490: }
491: }
492:
493: #ifdef BESTFIT
494: if (best != (struct freelist *)0) {
495: remove_free (best);
496: return (&(best->block));
497: }
498: #endif
499: }
500: return (struct header *)0;
501: }
502:
503: static use_block (ptr,size)
504: register struct header *ptr;
505: register unsigned size;
506: {
507: register struct header *next;
508:
509: if ((ptr->smallsize == size) || (ptr->smallsize < size + sizeof (struct freehead)))
510: return; /* don't split it -> left with block too small for use */
511:
512: next = (struct header *)((char *)ptr + size);
513: next->smallsize = ptr->smallsize - size;
514: next->use = ptr->use & ~INUSE;
515:
516: ptr->smallsize = size;
517: ptr->use |= INUSE;
518:
519: add_free (next);
520: }
521:
522: char * malloc (size)
523: register unsigned size;
524: {
525: char * mem;
526: struct header *head;
527: register unsigned realsize, blocksize;
528:
529: #ifdef BSD42
530: if (first_malloc)
531: pagesize = getpagesize ();
532: #endif
533:
534: if (mem_heap >= MAXHEAP)
535: mem_heap = MAXHEAP - 1;
536:
537: if (size < sizeof (struct freelist *)) /* memory will be used when freed for freelist !!! */
538: realsize = ALIGN (sizeof (struct freehead));
539: else
540: realsize = ALIGN (size) + ALIGN (sizeof (struct header));
541:
542: if (realsize >= SMALLMAX) {
543: #ifdef MALLOCTRACE
544: write_string ("malloc of "); write_int (size);
545: #endif
546: return (big_malloc (realsize));
547: }
548:
549: if (first_malloc) {
550: /* set up freelist */
551: unsigned x;
552: int i,j;
553:
554: for (i = 0; i < MAXHEAP; i++) {
555: heapptr[i] = (struct freelist *) 0;
556: for (j = 0 ; j<BUCKETS; j++) {
557: heaps[i][j].prev = &heaps[i][j];
558: heaps[i][j].next = &heaps[i][j];
559: heaps[i][j].size = 0;
560: }
561: }
562:
563: /* align first sbrk to page boundary */
564: x = (unsigned)sbrk(0);
565: x = PAGEALIGN (x) - x;
566: blocksize = PAGEALIGN(realsize) + x;
567: if ((head = (struct header *) sbrk ((int)blocksize)) == (struct header *)0) {
568: /* there are 100s of places where Quipu would choke on a naff malloc */
569: attempt_restart (-2);
570: return ((char *)0);
571: }
572: head->smallsize = blocksize;
573: top_mem = (char *)head + blocksize;
574: first_malloc = 0;
575: head->use = INUSE | mem_heap;
576: use_block (head,realsize);
577:
578: } else if ((head = find_block (realsize)) == (struct header *)0) {
579: blocksize = PAGEALIGN(realsize);
580: if ((head = (struct header *) sbrk ((int)blocksize)) == (struct header *)0) {
581: /* there are 100s of places where Quipu would choke on a naff malloc */
582: attempt_restart (-2);
583: return ((char *)0);
584: }
585: head->smallsize = blocksize;
586: top_mem = (char *)head + blocksize;
587: head->use = INUSE | mem_heap;
588: use_block (head,realsize);
589: } else
590: use_block (head,realsize);
591:
592: mem = (char *) head + ALIGN(sizeof (struct header));
593:
594: #ifdef MALLOCTRACE
595: write_string ("malloc of "); write_int (size);
596: write_string ("gets "); write_int (head->smallsize);
597: write_string ("at "); write_addr (mem);
598: write_string ("heap ");write_int (mem_heap);
599: write_string ("\n");
600: write_stack("x");
601: #endif
602:
603: return (mem);
604: }
605:
606: free(s)
607: char *s;
608: {
609: struct header * ptr;
610: struct header * next;
611:
612: ptr = (struct header *) (s - ALIGN (sizeof (struct header)));
613:
614: if (ptr->smallsize & 1) {
615: #ifdef MALLOCTRACE
616: write_string ("free of "); write_int (ptr->bigsize);
617: write_string ("at "); write_addr (s);
618: write_string ("heap (big)\n");
619: write_stack("x");
620: #endif
621: big_free (ptr);
622: return;
623: }
624:
625: #ifdef MALLOCTRACE
626: write_string ("free of "); write_int (ptr->smallsize);
627: write_string ("at "); write_addr (s);
628: write_string ("heap "); write_int (ptr->use & ~INUSE);
629: write_string ("\n");
630: write_stack("x");
631: #endif
632:
633: if (! USED(ptr)) {
634: LLOG (log_dsap,LLOG_EXCEPTIONS,("freeing problem"));
635: return; /* already freed !!! */
636: }
637:
638: /* join forward free block in loop to catch previous back blocks ! */
639: while ((next = next_free_block(ptr)) != (struct header *) 0) {
640: ptr->smallsize += next->smallsize;
641: remove_free (((struct freehead *)next)->flist);
642: }
643: add_free (ptr);
644:
645: return;
646:
647: }
648:
649:
650: char *realloc(s, n)
651: char *s;
652: register unsigned n;
653: {
654: char * mem;
655: register unsigned realsize;
656: struct header * ptr;
657: struct header * next;
658:
659: ptr = (struct header *) (s - ALIGN (sizeof (struct header)));
660:
661: if (ptr->smallsize & 1) {
662: DLOG (log_dsap,LLOG_DEBUG,("re-alloc of big block"));
663: #ifdef MALLOCTRACE
664: write_stack ("x");
665: #endif
666: goto out;
667: }
668:
669: if (! USED(ptr)) {
670: LLOG (log_dsap,LLOG_EXCEPTIONS,("re-alloc problem"));
671: #ifdef MALLOCTRACE
672: write_stack ("x");
673: #endif
674: goto out;
675: }
676:
677: realsize = ALIGN (n) + ALIGN (sizeof (struct header));
678: if (ptr->smallsize >= realsize) {
679: #ifdef MALLOCTRACE
680: log_realloc (ptr->smallsize,realsize,ptr->smallsize,s);
681: #endif
682: return (s);
683: }
684:
685: /* see if next block is free */
686: if ((next = next_free_block(ptr)) != (struct header *) 0) {
687: struct header * top;
688:
689: top = next;
690: /* join with other free blocks */
691: while ((next = next_free_block(top)) != (struct header *) 0) {
692: top->smallsize += next->smallsize;
693: remove_free (((struct freehead *)next)->flist);
694: }
695: remove_free (((struct freehead *)top)->flist);
696:
697: /* is it big enough ? */
698: if (ptr->smallsize + top->smallsize >= realsize) {
699: #ifdef MALLOCTRACE
700: unsigned savesize;
701: savesize = ptr->smallsize;
702: #endif
703:
704: ptr->smallsize += top->smallsize;
705: use_block (ptr,realsize);
706: #ifdef MALLOCTRACE
707: log_realloc (savesize,realsize,ptr->smallsize,s);
708: #endif
709: return (s);
710: } else
711: /* return to free list */
712: add_free (top);
713: }
714:
715: out:;
716: if ((mem = malloc (n)) == (char *)0)
717: return ((char *)0);
718: bcopy (s,mem,(int)n);
719: free (s);
720:
721: return (mem);
722: }
723:
724: char *calloc(n, size)
725: unsigned n, size;
726: {
727: char * mem;
728: unsigned x;
729:
730: x= n*size;
731: if ((mem = malloc (x)) == (char *)0)
732: return ((char *)0);
733: bzero (mem,(int)x);
734: return (mem);
735: }
736:
737: void
738: cfree(mem)
739: char * mem;
740: {
741: free(mem);
742: }
743:
744: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.