|
|
1.1 root 1: /* $Header: /kernel/kersrc/coh.386/RCS/alloc.c,v 1.2 92/08/04 12:29:54 bin Exp Locker: bin $ */
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.2 92/08/04 12:29:54 bin
21: * changed for kernel 59
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: ap = ((ALL *)cp) - 1;
117: if (ap<(ALL *)&__end || tstfree(ap))
118: panic("Bad free %x\n", (unsigned)cp);
119: setfree(ap);
120: }
121:
122: #endif /* TEST */
123:
124: #ifdef _I386
125: /*
126: * unsigned char *palloc(int size);
127: *
128: * Allocate 'size' bytes of kernel space, which does not cross a click
129: * boundary. Returns a pointer to the space allocated on success,
130: * NULL on failure.
131: *
132: * Allocate twice as much memory as we need, and then return a chunk that
133: * does not cross a click boundary. Immediately before the chunk that
134: * we return, we store the true address of the chunk that was kalloc()'d.
135: *
136: * Since this routine is for relatively small short-lived objects,
137: * which we expect to allocate frequently, speed is more important than
138: * space overhead.
139: *
140: * We assume that kalloc() returns word aligned addresses.
141: *
142: * There are two cases:
143: * There is enough room before the click boundary (or there is no click
144: * boundary) for the pointer and the memory we need.
145: * Otherwise, return the chunk starting at the click boundary, storing
146: * the pointer right before the click boundary. This trick allows
147: * us to allocate up to 1 full click.
148: *
149: * If kalloc() did NOT return word aligned chunks, then there would be
150: * a third case, where there might not be enough space for the pointer
151: * before the click boundary.
152: */
153:
154: #define c_boundry(x) ctob(btoc((x)+1)) /* Next click boundary above x. */
155: #define VOID unsigned char
156:
157: #ifdef TEST
158: #undef kalloc
159: #undef kfree
160: VOID *kalloc();
161: void kfree();
162: #endif /* TEST */
163:
164: VOID *
165: palloc(size)
166: int size; /* Size in bytes of area to allocate. */
167: {
168: VOID *local_arena; /* Value returned by kalloc(). */
169: VOID *boundry; /* Next click boundry above local_arena. */
170: VOID *retval; /* What we give back to our caller. */
171:
172: if (size > NBPC) {
173: panic("palloc(%x): can not palloc more than 1 click.", size);
174: }
175:
176: /* Fetch twice as much space as requested, plus a pointer. */
177: if ( NULL == (local_arena =
178: (VOID *)kalloc(sizeof(VOID *) + (2 * size)))) {
179: return NULL;
180: }
181:
182:
183: boundry = (VOID *) c_boundry(local_arena);
184:
185: T_PIGGY(0x2000, printf("b: %x ", boundry); );
186:
187: /* First case: enough space before the boundry. */
188: if ( (boundry - local_arena) >= (size + sizeof(VOID *)) ) {
189:
190: T_PIGGY(0x2000, printf("c1 "); );
191:
192: * (VOID **)local_arena = local_arena;
193: retval = local_arena + sizeof(VOID *);
194: } else if ((boundry - local_arena) < sizeof(VOID *)) {
195: /*
196: * Second case: There is not enough space before the
197: * boundry for the whole pointer.
198: */
199: T_PIGGY(0x2000, printf("c2 "); );
200:
201: * (VOID **)local_arena = local_arena;
202: retval = local_arena + sizeof(VOID *);
203: } else {
204:
205: T_PIGGY(0x2000, printf("c3: %x ", (boundry - local_arena)); );
206:
207: * (VOID **)(boundry - sizeof(VOID *)) = local_arena;
208: retval = boundry;
209: }
210:
211: T_PIGGY( 0x2000, {
212: printf("palloc(%x) = %x:%x (was %x:%x), ",
213: size, retval, (retval+size)-1,
214: local_arena, (local_arena+(2*size)+sizeof(VOID *))-1);
215: } );
216:
217: T_PIGGY( 0x2000, {
218: if ((retval+size)-1 > (local_arena+(2*size)+sizeof(VOID *))-1) {
219: printf("\npalloc() overrun\n");
220: }
221: if (retval < local_arena) {
222: printf("\npalloc() underrun\n");
223: }
224: } );
225: return((VOID *)retval);
226: } /* palloc() */
227:
228: /*
229: * void pfree(VOID *ptr);
230: * Free the chunk of memory 'ptr' allocated by palloc().
231: *
232: * Note that 'ptr' is really a VOID *, but we call it VOID **
233: * to simplify arithmetic.
234: *
235: * The address returned by kalloc() is stored immediately
236: * before the chunk returned by palloc().
237: */
238: void
239: pfree(ptr)
240: VOID *ptr[];
241: {
242: T_PIGGY(0x2000, { printf("pfree(%x):kfree(%x), ", ptr, *(ptr-1)); } );
243: kfree(*(ptr-1));
244: } /* pfree() */
245:
246:
247: #ifdef TEST
248:
249: #include <stdio.h>
250: #define FOURK 4096 /* How many bytes in 4K? */
251: #define NUM_TESTS 40 /* How many tests do we run? */
252: #define SMALL_NUMBER 6 /* A small number whose exact value we don't care about. */
253: #define HUGE (100*FOURK) /* Allocate from this pool. */
254: #define IGNORE(v) (v==v) /* Lint food. */
255:
256: unsigned t_piggy = 0x2000; /* Turn on TRACER bits. */
257:
258: main()
259: {
260: int i;
261: VOID *chunk;
262:
263: for (i = 0; i < NUM_TESTS; ++i) {
264: if (NULL == (chunk = palloc(SMALL_NUMBER))) {
265: printf("No more fake memory to eat.\n");
266: printf("This is probably a bug.\n");
267: exit(1);
268: }
269:
270: printf("chunk: %x\n", chunk);
271: }
272: } /* main() for TEST */
273:
274: /*
275: * Print a message and die.
276: */
277: panic(args)
278: {
279: printf("%r\n", &args);
280: exit(1);
281: }
282:
283: /*
284: * Fake kalloc() for use by palloc().
285: * Allocate a chunk of some non-existant memory space.
286: */
287: VOID *
288: kalloc(size)
289: int size;
290: {
291: static VOID *base = NULL;
292: static VOID *top_free = NULL;
293: VOID *retval;
294:
295:
296: /*
297: * First time through, allocate a nice big chunk of memory
298: * to carve up.
299: */
300: if (NULL == base) {
301: if (NULL == (base = malloc(HUGE))) {
302: printf("Can not malloc %d bytes.\n", HUGE);
303: exit(1);
304: }
305: /* Make sure we start close to a click boundry. */
306: top_free = c_boundry(base) + SMALL_NUMBER;
307: }
308:
309: retval = top_free;
310: /*
311: * We want to encourage test addresses to migrate accross
312: * click boundries.
313: */
314: if (size < (FOURK - 1)) {
315: top_free += (FOURK - 1);
316: } else {
317: top_free += size;
318: }
319:
320: return(retval);
321: } /* kalloc() */
322:
323: /*
324: * Fake kfree for pfree() to use.
325: */
326: void
327: kfree(addr)
328: VOID *addr;
329: {
330: IGNORE(addr);
331: /* Do nothing! */
332: } /* kfree() */
333:
334: #endif /* TEST */
335:
336: #endif /* _I386 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.