Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
99 7u83 1
/*
2
 * AT&T Unix 7th Edition memory allocation routines.
3
 *
4
 * Modified for ex by Gunnar Ritter, Freiburg i. Br., Germany,
5
 * July 2000.
6
 *
7
 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 *   Redistributions of source code and documentation must retain the
13
 *    above copyright notice, this list of conditions and the following
14
 *    disclaimer.
15
 *   Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 *   All advertising materials mentioning features or use of this software
19
 *    must display the following acknowledgement:
20
 *      This product includes software developed or owned by Caldera
21
 *      International, Inc.
22
 *   Neither the name of Caldera International, Inc. nor the names of
23
 *    other contributors may be used to endorse or promote products
24
 *    derived from this software without specific prior written permission.
25
 *
26
 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
27
 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
28
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
29
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30
 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
31
 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
32
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
34
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
35
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
36
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
37
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
 *
39
 *	@(#)malloc.c	1.19 (gritter) 2/20/05
40
 */
41
 
42
#ifdef	VMUNIX
43
 
44
#include <sys/types.h>
45
#include <unistd.h>
46
#include <errno.h>
47
 
48
#include "config.h"
49
 
50
#ifdef	LANGMSG
51
#include <nl_types.h>
52
extern	nl_catd	catd;
53
#else
54
#define	catgets(a, b, c, d)	(d)
55
#endif
56
 
57
/*
58
 * Since ex makes use of sbrk(), the C library's version of malloc()
59
 * must be avoided.
60
 *
61
 * In ex, malloc() calls sbrk() only one time with an argument of
62
 * POOL. Ex itselves never uses malloc() internally, so POOL
63
 * must be sufficient for library calls like setlocale() only.
64
 *
65
 * Known problem: If linking against ncurses, changing the terminal
66
 * type repeatedly outruns the pool. Even that is not really a
67
 * problem since the work continues with the old terminal type, so
68
 * there is no need for a large pool here.
69
 */
70
#define	POOL	32768
71
 
72
#ifdef debug
73
#define ASSERT(p) if(!(p))botch("p");else
74
#include <stdio.h>
75
#include <stdlib.h>
76
#include <unistd.h>
77
int 
78
botch(char *s)
79
{
80
	const char msg[] = "assertion botched\n";
81
	write(2, msg, sizeof msg - 1);
82
	/*printf("assertion botched: %s\n",s);*/
83
	abort();
84
}
85
static int allock(void);
86
#else
87
#define ASSERT(p)
88
#endif
89
 
90
/*	avoid break bug */
91
#ifdef pdp11
92
#define GRANULE 64
93
#else
94
#define GRANULE 0
95
#endif
96
/*	C storage allocator
97
 *	circular first-fit strategy
98
 *	works with noncontiguous, but monotonically linked, arena
99
 *	each block is preceded by a ptr to the (pointer of) 
100
 *	the next following block
101
 *	blocks are exact number of words long 
102
 *	aligned to the data type requirements of ALIGN
103
 *	pointers to blocks must have BUSY bit 0
104
 *	bit in ptr is 1 for busy, 0 for idle
105
 *	gaps in arena are merely noted as busy blocks
106
 *	last block of arena (pointed to by alloct) is empty and
107
 *	has a pointer to first
108
 *	idle blocks are coalesced during space search
109
 *
110
 *	a different implementation may need to redefine
111
 *	ALIGN, NALIGN, BLOCK, BUSY, INT
112
 *	where INT is integer type to which a pointer can be cast
113
*/
114
#define	INT		intptr_t
115
#define	ALIGN		intptr_t
116
#define	NALIGN		1
117
#define	WORD		sizeof (union store)
118
#define	BLOCK		1024	/* a multiple of WORD*/
119
#define	BUSY		((intptr_t)1)
120
#ifdef	NULL
121
#undef	NULL
122
#endif
123
#define NULL		 0
124
#define	testbusy(p)	((INT)(p)&BUSY)
125
#define	setbusy(p)	(union store *)((INT)(p)|BUSY)
126
#define	clearbusy(p)	(union store *)((INT)(p)&~BUSY)
127
 
128
union store { union store *ptr;
129
	      ALIGN dummy[NALIGN];
130
	      INT callocsp;	/*calloc clears an array of integers*/
131
};
132
 
133
static	union store allocs[2];	/*initial arena*/
134
static	union store *allocp;	/*search ptr*/
135
static	union store *alloct;	/*arena top*/
136
static	union store *allocx;	/*for benefit of realloc*/
137
extern int	error(char *, ...);
138
 
139
char *
140
poolsbrk(intptr_t inc)
141
{
142
	static char *pool;
143
	static intptr_t ps;
144
	intptr_t os, ns;
145
 
146
	if (pool == NULL)
147
		if ((pool = sbrk(POOL)) == (char *)-1)
148
			error(catgets(catd, 1, 241,
149
				"No memory pool"));
150
	if (inc == 0)
151
		return pool + ps;
152
	os = ps;
153
	ns = ps + inc;
154
	if (ns >= POOL)
155
		error(catgets(catd, 1, 242,
156
				"Memory pool exhausted"));
157
	ps = ns;
158
	return pool + os;
159
}
160
 
161
void *
162
malloc(size_t nbytes)
163
{
164
	register union store *p, *q;
165
	register int nw;
166
	static int temp;	/*coroutines assume no auto*/
167
 
168
	if(allocs[0].ptr==0) {	/*first time*/
169
		allocs[0].ptr = setbusy(&allocs[1]);
170
		allocs[1].ptr = setbusy(&allocs[0]);
171
		alloct = &allocs[1];
172
		allocp = &allocs[0];
173
	}
174
	nw = (nbytes+WORD+WORD-1)/WORD;
175
	ASSERT(allocp>=allocs && allocp<=alloct);
176
	ASSERT(allock());
177
	for(p=allocp; ; ) {
178
		for(temp=0; ; ) {
179
			if(!testbusy(p->ptr)) {
180
				while(!testbusy((q=p->ptr)->ptr)) {
181
					int ua = p->ptr==allocp;
182
					ASSERT(q>p&&q<alloct);
183
					p->ptr = q->ptr;
184
					if (ua)
185
						allocp = p->ptr;
186
				}
187
				if(q>=p+nw && p+nw>=p)
188
					goto found;
189
			}
190
			q = p;
191
			p = clearbusy(p->ptr);
192
			if(p>q)
193
				ASSERT(p<=alloct);
194
			else if(q!=alloct || p!=allocs) {
195
				ASSERT(q==alloct&&p==allocs);
196
				errno = ENOMEM;
197
				return(NULL);
198
			} else if(++temp>1)
199
				break;
200
		}
201
		temp = ((nw+BLOCK/WORD)/(BLOCK/WORD))*(BLOCK/WORD);
202
		q = (union store *)poolsbrk(0);
203
		if(q+temp+GRANULE < q) {
204
			errno = ENOMEM;
205
			return(NULL);
206
		}
207
		q = (union store *)poolsbrk(temp*WORD);
208
		if((INT)q == -1) {
209
			errno = ENOMEM;
210
			return(NULL);
211
		}
212
		ASSERT(q>alloct);
213
		alloct->ptr = q;
214
		if(q!=alloct+1)
215
			alloct->ptr = setbusy(alloct->ptr);
216
		alloct = q->ptr = q+temp-1;
217
		alloct->ptr = setbusy(allocs);
218
	}
219
found:
220
	allocp = p + nw;
221
	ASSERT(allocp<=alloct);
222
	if(q>allocp) {
223
		allocx = allocp->ptr;
224
		allocp->ptr = p->ptr;
225
	}
226
	p->ptr = setbusy(allocp);
227
	return((char *)(p+1));
228
}
229
 
230
/*	freeing strategy tuned for LIFO allocation
231
*/
232
void
233
free(register void *ap)
234
{
235
	register union store *p = ap;
236
 
237
	if (ap == NULL)
238
		return;
239
	ASSERT(p>clearbusy(allocs[1].ptr)&&p<=alloct);
240
	ASSERT(allock());
241
	allocp = --p;
242
	ASSERT(testbusy(p->ptr));
243
	p->ptr = clearbusy(p->ptr);
244
	ASSERT(p->ptr > allocp && p->ptr <= alloct);
245
}
246
 
247
/*	realloc(p, nbytes) reallocates a block obtained from malloc()
248
 *	and freed since last call of malloc()
249
 *	to have new size nbytes, and old content
250
 *	returns new location, or 0 on failure
251
*/
252
 
253
void *
254
realloc(void *ap, size_t nbytes)
255
{
256
	register union store *p = ap;
257
	register union store *q;
258
	union store *s, *t;
259
	register size_t nw;
260
	size_t onw;
261
 
262
	if (p == NULL)
263
		return malloc(nbytes);
264
	if (nbytes == 0) {
265
		free(p);
266
		return NULL;
267
	}
268
	if(testbusy(p[-1].ptr))
269
		free(p);
270
	onw = p[-1].ptr - p;
271
	q = malloc(nbytes);
272
	if(q==NULL || q==p)
273
		return(q);
274
	s = p;
275
	t = q;
276
	nw = (nbytes+WORD-1)/WORD;
277
	if(nw<onw)
278
		onw = nw;
279
	while(onw--!=0)
280
		*t++ = *s++;
281
	if(q<p && q+nw>=p)
282
		(q+(q+nw-p))->ptr = allocx;
283
	return(q);
284
}
285
 
286
#ifdef debug
287
int 
288
allock(void)
289
{
290
#ifdef longdebug
291
	register union store *p;
292
	int x;
293
	x = 0;
294
	for(p= &allocs[0]; clearbusy(p->ptr) > p; p=clearbusy(p->ptr)) {
295
		if(p==allocp)
296
			x++;
297
	}
298
	ASSERT(p==alloct);
299
	return(x==1|p==allocp);
300
#else
301
	return(1);
302
#endif
303
}
304
#endif
305
 
306
/*	calloc - allocate and clear memory block
307
*/
308
#define CHARPERINT (sizeof(INT)/sizeof(char))
309
 
310
void *
311
calloc(size_t num, size_t size)
312
{
313
	register char *mp;
314
	register INT *q;
315
	register int m;
316
 
317
	num *= size;
318
	mp = malloc(num);
319
	if(mp == NULL)
320
		return(NULL);
321
	q = (INT *) mp;
322
	m = (num+CHARPERINT-1)/CHARPERINT;
323
	while(--m >= 0)
324
		*q++ = 0;
325
	return(mp);
326
}
327
 
328
#ifdef	notdef
329
/*ARGSUSED*/
330
void 
331
cfree(char *p, size_t num, size_t size)
332
{
333
	free(p);
334
}
335
 
336
/*
337
 * Just in case ...
338
 */
339
char *
340
memalign(size_t alignment, size_t size)
341
{
342
	return NULL;
343
}
344
 
345
char *
346
valloc(size_t size)
347
{
348
	return NULL;
349
}
350
 
351
char *
352
mallinfo(void)
353
{
354
	return NULL;
355
}
356
 
357
int 
358
mallopt(void)
359
{
360
	return -1;
361
}
362
#endif	/* notdef */
363
 
364
#endif	/* VMUNIX */