|
|
1.1 root 1: /* $Header: /y/coh.386/RCS/alloc.c,v 1.4 93/04/14 10:06:13 root Exp $ */
2: /* (lgl-
3: * The information contained herein is a trade secret of Mark Williams
4: * Company, and is confidential information. It is provided under a
5: * license agreement, and may be copied or disclosed only under the
6: * terms of that agreement. Any reproduction or disclosure of this
7: * material without the express written authorization of Mark Williams
8: * Company or persuant to the license agreement is unlawful.
9: *
10: * COHERENT Version 2.3.37
11: * Copyright (c) 1982, 1983, 1984.
12: * An unpublished work by Mark Williams Company, Chicago.
13: * All rights reserved.
14: -lgl) */
15: /*
16: * Coherent.
17: * Storage allocator.
18: *
19: * $Log: alloc.c,v $
20: * Revision 1.4 93/04/14 10:06:13 root
21: * r75
22: *
23: * Revision 1.2 92/01/06 11:58:31 hal
24: * Compile with cc.mwc.
25: *
26: * Revision 1.1 88/03/24 16:13:25 src
27: * Initial revision
28: *
29: */
30: #include <sys/coherent.h>
31: #include <sys/alloc.h>
32: #include <errno.h>
33: #include <sys/proc.h>
34: #include <sys/param.h>
35:
36: #ifndef TEST /* Do not test setarena() or alloc() or free(). */
37: /*
38: * Create an arena.
39: */
40: ALL *
41: setarena(cp, n)
42: register char *cp;
43: {
44: register ALL *ap1;
45: register ALL *ap2;
46:
47: if ((char *)(ap1=align(cp)) < (char *)cp)
48: ap1++;
49: if ((ap2=align(&cp[n])-1) < ap1)
50: panic("Arena %x too small", (int) cp);
51: ap1->a_link = (char *)ap2;
52: ap2->a_link = (char *)ap1;
53: setused(ap2);
54: return (ap1);
55: }
56:
57: /*
58: * Allocate `l' bytes of memory.
59: */
60: char *
61: alloc(apq, l)
62: ALL *apq;
63: unsigned l;
64: {
65: register ALL *ap;
66: register ALL *ap1;
67: register ALL *ap2;
68: register unsigned i;
69: register unsigned n;
70: register unsigned s;
71: char * ret = NULL;
72:
73: n = 1 + (l + sizeof(ALL) - 1) / sizeof(ALL);
74: for (i=0; i<2; i++) {
75: for (ap1=apq; link(ap1)!=apq; ap1=link(ap1)) {
76: if (vtop(ap1) == 0) {
77: panic("Corrupt arena");
78: goto alloc_done;
79: }
80: if (tstfree(ap1)) {
81: for (ap2=link(ap1); tstfree(ap2); ap2=link(ap2))
82: if (ap2 == apq)
83: break;
84: ap1->a_link = (char *)ap2;
85: if ((s=ap2-ap1) >= n) {
86: if (s > n) {
87: if (i == 0)
88: continue;
89: ap = &ap1[n];
90: ap->a_link = (char *)ap2;
91: ap1->a_link = (char *)ap;
92: }
93: setused(ap1);
94: kclear((char *)ap1->a_data, l);
95: ret = ap1->a_data;
96: goto alloc_done;
97: }
98: }
99: }
100: }
101: u.u_error = ENOSPC;
102: goto alloc_done;
103: alloc_done:
104: return ret;
105: }
106:
107: /*
108: * Free memory.
109: */
110: free(cp)
111: char *cp;
112: {
113: register ALL *ap;
114: extern char __end;
115:
116: #if 0
117: ap = ((ALL *)cp) - 1;
118: if (ap<(ALL *)&__end || tstfree(ap))
119: panic("Bad free %x\n", (unsigned)cp);
120: #else
121: ap = ((ALL *)cp) - 1;
122: if (ap<(ALL *)&__end) {
123: int *r = (int *)(&cp); /* return address */
124: printf("cp=%x ap=%x &__end=%x\n", cp, ap, &__end);
125: panic("Bad free() from eip=%x\n", *(r-1));
126: }
127: if (tstfree(ap)) {
128: int *r = (int *)(&cp); /* return address */
129: printf("cp=%x tstfree(%x)=%x\n", cp, ap, tstfree(ap));
130: panic("Bad free() from eip=%x\n", *(r-1));
131: }
132: #endif
133: setfree(ap);
134: }
135:
136: #endif /* TEST */
137:
138: #ifdef _I386
139: /*
140: * unsigned char *palloc(int size);
141: *
142: * Allocate 'size' bytes of kernel space, which does not cross a click
143: * boundary. Returns a pointer to the space allocated on success,
144: * NULL on failure.
145: *
146: * Allocate twice as much memory as we need, and then return a chunk that
147: * does not cross a click boundary. Immediately before the chunk that
148: * we return, we store the true address of the chunk that was kalloc()'d.
149: *
150: * Since this routine is for relatively small short-lived objects,
151: * which we expect to allocate frequently, speed is more important than
152: * space overhead.
153: *
154: * We assume that kalloc() returns word aligned addresses.
155: *
156: * There are two cases:
157: * There is enough room before the click boundary (or there is no click
158: * boundary) for the pointer and the memory we need.
159: * Otherwise, return the chunk starting at the click boundary, storing
160: * the pointer right before the click boundary. This trick allows
161: * us to allocate up to 1 full click.
162: *
163: * If kalloc() did NOT return word aligned chunks, then there would be
164: * a third case, where there might not be enough space for the pointer
165: * before the click boundary.
166: */
167:
168: #define c_boundry(x) ctob(btoc((x)+1)) /* Next click boundary above x. */
169: #define VOID unsigned char
170:
171: #ifdef TEST
172: #undef kalloc
173: #undef kfree
174: VOID *kalloc();
175: void kfree();
176: #endif /* TEST */
177:
178: VOID *
179: palloc(size)
180: int size; /* Size in bytes of area to allocate. */
181: {
182: VOID *local_arena; /* Value returned by kalloc(). */
183: VOID *boundry; /* Next click boundry above local_arena. */
184: VOID *retval; /* What we give back to our caller. */
185:
186: if (size > NBPC) {
187: panic("palloc(%x): can not palloc more than 1 click.", size);
188: }
189:
190: /* Fetch twice as much space as requested, plus a pointer. */
191: if ( NULL == (local_arena =
192: (VOID *)kalloc(sizeof(VOID *) + (2 * size)))) {
193: return NULL;
194: }
195:
196:
197: boundry = (VOID *) c_boundry(local_arena);
198:
199: T_PIGGY(0x2000, printf("b: %x ", boundry); );
200:
201: /* First case: enough space before the boundry. */
202: if ( (boundry - local_arena) >= (size + sizeof(VOID *)) ) {
203:
204: T_PIGGY(0x2000, printf("c1 "); );
205:
206: * (VOID **)local_arena = local_arena;
207: retval = local_arena + sizeof(VOID *);
208: } else if ((boundry - local_arena) < sizeof(VOID *)) {
209: /*
210: * Second case: There is not enough space before the
211: * boundry for the whole pointer.
212: */
213: T_PIGGY(0x2000, printf("c2 "); );
214:
215: * (VOID **)local_arena = local_arena;
216: retval = local_arena + sizeof(VOID *);
217: } else {
218:
219: T_PIGGY(0x2000, printf("c3: %x ", (boundry - local_arena)); );
220:
221: * (VOID **)(boundry - sizeof(VOID *)) = local_arena;
222: retval = boundry;
223: }
224:
225: T_PIGGY( 0x2000, {
226: printf("palloc(%x) = %x:%x (was %x:%x), ",
227: size, retval, (retval+size)-1,
228: local_arena, (local_arena+(2*size)+sizeof(VOID *))-1);
229: } );
230:
231: T_PIGGY( 0x2000, {
232: if ((retval+size)-1 > (local_arena+(2*size)+sizeof(VOID *))-1) {
233: printf("\npalloc() overrun\n");
234: }
235: if (retval < local_arena) {
236: printf("\npalloc() underrun\n");
237: }
238: } );
239: return((VOID *)retval);
240: } /* palloc() */
241:
242: /*
243: * void pfree(VOID *ptr);
244: * Free the chunk of memory 'ptr' allocated by palloc().
245: *
246: * Note that 'ptr' is really a VOID *, but we call it VOID **
247: * to simplify arithmetic.
248: *
249: * The address returned by kalloc() is stored immediately
250: * before the chunk returned by palloc().
251: */
252: void
253: pfree(ptr)
254: VOID *ptr[];
255: {
256: T_PIGGY(0x2000, { printf("pfree(%x):kfree(%x), ", ptr, *(ptr-1)); } );
257: kfree(*(ptr-1));
258: } /* pfree() */
259:
260:
261: #ifdef TEST
262:
263: #include <stdio.h>
264: #define FOURK 4096 /* How many bytes in 4K? */
265: #define NUM_TESTS 40 /* How many tests do we run? */
266: #define SMALL_NUMBER 6 /* A small number whose exact value we don't care about. */
267: #define HUGE (100*FOURK) /* Allocate from this pool. */
268: #define IGNORE(v) (v==v) /* Lint food. */
269:
270: unsigned t_piggy = 0x2000; /* Turn on TRACER bits. */
271:
272: main()
273: {
274: int i;
275: VOID *chunk;
276:
277: for (i = 0; i < NUM_TESTS; ++i) {
278: if (NULL == (chunk = palloc(SMALL_NUMBER))) {
279: printf("No more fake memory to eat.\n");
280: printf("This is probably a bug.\n");
281: exit(1);
282: }
283:
284: printf("chunk: %x\n", chunk);
285: }
286: } /* main() for TEST */
287:
288: /*
289: * Print a message and die.
290: */
291: panic(args)
292: {
293: printf("%r\n", &args);
294: exit(1);
295: }
296:
297: /*
298: * Fake kalloc() for use by palloc().
299: * Allocate a chunk of some non-existant memory space.
300: */
301: VOID *
302: kalloc(size)
303: int size;
304: {
305: static VOID *base = NULL;
306: static VOID *top_free = NULL;
307: VOID *retval;
308:
309:
310: /*
311: * First time through, allocate a nice big chunk of memory
312: * to carve up.
313: */
314: if (NULL == base) {
315: if (NULL == (base = malloc(HUGE))) {
316: printf("Can not malloc %d bytes.\n", HUGE);
317: exit(1);
318: }
319: /* Make sure we start close to a click boundry. */
320: top_free = c_boundry(base) + SMALL_NUMBER;
321: }
322:
323: retval = top_free;
324: /*
325: * We want to encourage test addresses to migrate accross
326: * click boundries.
327: */
328: if (size < (FOURK - 1)) {
329: top_free += (FOURK - 1);
330: } else {
331: top_free += size;
332: }
333:
334: return(retval);
335: } /* kalloc() */
336:
337: /*
338: * Fake kfree for pfree() to use.
339: */
340: void
341: kfree(addr)
342: VOID *addr;
343: {
344: IGNORE(addr);
345: /* Do nothing! */
346: } /* kfree() */
347:
348: #endif /* TEST */
349:
350: #endif /* _I386 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.