~mirabilos/klibc/master

« back to all changes in this revision

Viewing changes to usr/dash/memalloc.c

  • Committer: H. Peter Anvin
  • Date: 2006-05-01 00:56:02 UTC
  • Revision ID: git-v1:5dea5e01daaaff0685016f23b5cb46240f28e792
[klibc] Reorganize the standalone klibc tree to match the in-kernel tree

Right now, it's harder than it should to apply and test patches using
the standalone klibc tree.  Reorganize the standalone tree to match
the in-kernel tree.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * Copyright (c) 1991, 1993
 
3
 *      The Regents of the University of California.  All rights reserved.
 
4
 * Copyright (c) 1997-2005
 
5
 *      Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
 
6
 *
 
7
 * This code is derived from software contributed to Berkeley by
 
8
 * Kenneth Almquist.
 
9
 *
 
10
 * Redistribution and use in source and binary forms, with or without
 
11
 * modification, are permitted provided that the following conditions
 
12
 * are met:
 
13
 * 1. Redistributions of source code must retain the above copyright
 
14
 *    notice, this list of conditions and the following disclaimer.
 
15
 * 2. 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
 * 3. Neither the name of the University nor the names of its contributors
 
19
 *    may be used to endorse or promote products derived from this software
 
20
 *    without specific prior written permission.
 
21
 *
 
22
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
32
 * SUCH DAMAGE.
 
33
 */
 
34
 
 
35
#include <stdlib.h>
 
36
#include <unistd.h>
 
37
 
 
38
#include "shell.h"
 
39
#include "output.h"
 
40
#include "memalloc.h"
 
41
#include "error.h"
 
42
#include "machdep.h"
 
43
#include "mystring.h"
 
44
#include "system.h"
 
45
 
 
46
/*
 
47
 * Like malloc, but returns an error when out of space.
 
48
 */
 
49
 
 
50
pointer
 
51
ckmalloc(size_t nbytes)
 
52
{
 
53
        pointer p;
 
54
 
 
55
        p = malloc(nbytes);
 
56
        if (p == NULL)
 
57
                sh_error("Out of space");
 
58
        return p;
 
59
}
 
60
 
 
61
 
 
62
/*
 
63
 * Same for realloc.
 
64
 */
 
65
 
 
66
pointer
 
67
ckrealloc(pointer p, size_t nbytes)
 
68
{
 
69
        p = realloc(p, nbytes);
 
70
        if (p == NULL)
 
71
                sh_error("Out of space");
 
72
        return p;
 
73
}
 
74
 
 
75
 
 
76
/*
 
77
 * Make a copy of a string in safe storage.
 
78
 */
 
79
 
 
80
char *
 
81
savestr(const char *s)
 
82
{
 
83
        char *p = strdup(s);
 
84
        if (!p)
 
85
                sh_error("Out of space");
 
86
        return p;
 
87
}
 
88
 
 
89
 
 
90
/*
 
91
 * Parse trees for commands are allocated in lifo order, so we use a stack
 
92
 * to make this more efficient, and also to avoid all sorts of exception
 
93
 * handling code to handle interrupts in the middle of a parse.
 
94
 *
 
95
 * The size 504 was chosen because the Ultrix malloc handles that size
 
96
 * well.
 
97
 */
 
98
 
 
99
/* minimum size of a block */
 
100
#define MINSIZE SHELL_ALIGN(504)
 
101
 
 
102
struct stack_block {
 
103
        struct stack_block *prev;
 
104
        char space[MINSIZE];
 
105
};
 
106
 
 
107
struct stack_block stackbase;
 
108
struct stack_block *stackp = &stackbase;
 
109
struct stackmark *markp;
 
110
char *stacknxt = stackbase.space;
 
111
size_t stacknleft = MINSIZE;
 
112
char *sstrend = stackbase.space + MINSIZE;
 
113
int herefd = -1;
 
114
 
 
115
pointer
 
116
stalloc(size_t nbytes)
 
117
{
 
118
        char *p;
 
119
        size_t aligned;
 
120
 
 
121
        aligned = SHELL_ALIGN(nbytes);
 
122
        if (aligned > stacknleft) {
 
123
                size_t len;
 
124
                size_t blocksize;
 
125
                struct stack_block *sp;
 
126
 
 
127
                blocksize = aligned;
 
128
                if (blocksize < MINSIZE)
 
129
                        blocksize = MINSIZE;
 
130
                len = sizeof(struct stack_block) - MINSIZE + blocksize;
 
131
                if (len < blocksize)
 
132
                        sh_error("Out of space");
 
133
                INTOFF;
 
134
                sp = ckmalloc(len);
 
135
                sp->prev = stackp;
 
136
                stacknxt = sp->space;
 
137
                stacknleft = blocksize;
 
138
                sstrend = stacknxt + blocksize;
 
139
                stackp = sp;
 
140
                INTON;
 
141
        }
 
142
        p = stacknxt;
 
143
        stacknxt += aligned;
 
144
        stacknleft -= aligned;
 
145
        return p;
 
146
}
 
147
 
 
148
 
 
149
void
 
150
stunalloc(pointer p)
 
151
{
 
152
#ifdef DEBUG
 
153
        if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
 
154
                write(2, "stunalloc\n", 10);
 
155
                abort();
 
156
        }
 
157
#endif
 
158
        stacknleft += stacknxt - (char *)p;
 
159
        stacknxt = p;
 
160
}
 
161
 
 
162
 
 
163
 
 
164
void
 
165
setstackmark(struct stackmark *mark)
 
166
{
 
167
        mark->stackp = stackp;
 
168
        mark->stacknxt = stacknxt;
 
169
        mark->stacknleft = stacknleft;
 
170
        mark->marknext = markp;
 
171
        markp = mark;
 
172
}
 
173
 
 
174
 
 
175
void
 
176
popstackmark(struct stackmark *mark)
 
177
{
 
178
        struct stack_block *sp;
 
179
 
 
180
        INTOFF;
 
181
        markp = mark->marknext;
 
182
        while (stackp != mark->stackp) {
 
183
                sp = stackp;
 
184
                stackp = sp->prev;
 
185
                ckfree(sp);
 
186
        }
 
187
        stacknxt = mark->stacknxt;
 
188
        stacknleft = mark->stacknleft;
 
189
        sstrend = mark->stacknxt + mark->stacknleft;
 
190
        INTON;
 
191
}
 
192
 
 
193
 
 
194
/*
 
195
 * When the parser reads in a string, it wants to stick the string on the
 
196
 * stack and only adjust the stack pointer when it knows how big the
 
197
 * string is.  Stackblock (defined in stack.h) returns a pointer to a block
 
198
 * of space on top of the stack and stackblocklen returns the length of
 
199
 * this block.  Growstackblock will grow this space by at least one byte,
 
200
 * possibly moving it (like realloc).  Grabstackblock actually allocates the
 
201
 * part of the block that has been used.
 
202
 */
 
203
 
 
204
void
 
205
growstackblock(void)
 
206
{
 
207
        size_t newlen;
 
208
 
 
209
        newlen = stacknleft * 2;
 
210
        if (newlen < stacknleft)
 
211
                sh_error("Out of space");
 
212
        if (newlen < 128)
 
213
                newlen += 128;
 
214
 
 
215
        if (stacknxt == stackp->space && stackp != &stackbase) {
 
216
                struct stack_block *oldstackp;
 
217
                struct stackmark *xmark;
 
218
                struct stack_block *sp;
 
219
                struct stack_block *prevstackp;
 
220
                size_t grosslen;
 
221
 
 
222
                INTOFF;
 
223
                oldstackp = stackp;
 
224
                sp = stackp;
 
225
                prevstackp = sp->prev;
 
226
                grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
 
227
                sp = ckrealloc((pointer)sp, grosslen);
 
228
                sp->prev = prevstackp;
 
229
                stackp = sp;
 
230
                stacknxt = sp->space;
 
231
                stacknleft = newlen;
 
232
                sstrend = sp->space + newlen;
 
233
 
 
234
                /*
 
235
                 * Stack marks pointing to the start of the old block
 
236
                 * must be relocated to point to the new block
 
237
                 */
 
238
                xmark = markp;
 
239
                while (xmark != NULL && xmark->stackp == oldstackp) {
 
240
                        xmark->stackp = stackp;
 
241
                        xmark->stacknxt = stacknxt;
 
242
                        xmark->stacknleft = stacknleft;
 
243
                        xmark = xmark->marknext;
 
244
                }
 
245
                INTON;
 
246
        } else {
 
247
                char *oldspace = stacknxt;
 
248
                int oldlen = stacknleft;
 
249
                char *p = stalloc(newlen);
 
250
 
 
251
                /* free the space we just allocated */
 
252
                stacknxt = memcpy(p, oldspace, oldlen);
 
253
                stacknleft += newlen;
 
254
        }
 
255
}
 
256
 
 
257
void
 
258
grabstackblock(size_t len)
 
259
{
 
260
        len = SHELL_ALIGN(len);
 
261
        stacknxt += len;
 
262
        stacknleft -= len;
 
263
}
 
264
 
 
265
/*
 
266
 * The following routines are somewhat easier to use than the above.
 
267
 * The user declares a variable of type STACKSTR, which may be declared
 
268
 * to be a register.  The macro STARTSTACKSTR initializes things.  Then
 
269
 * the user uses the macro STPUTC to add characters to the string.  In
 
270
 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
 
271
 * grown as necessary.  When the user is done, she can just leave the
 
272
 * string there and refer to it using stackblock().  Or she can allocate
 
273
 * the space for it using grabstackstr().  If it is necessary to allow
 
274
 * someone else to use the stack temporarily and then continue to grow
 
275
 * the string, the user should use grabstack to allocate the space, and
 
276
 * then call ungrabstr(p) to return to the previous mode of operation.
 
277
 *
 
278
 * USTPUTC is like STPUTC except that it doesn't check for overflow.
 
279
 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
 
280
 * is space for at least one character.
 
281
 */
 
282
 
 
283
void *
 
284
growstackstr(void)
 
285
{
 
286
        size_t len = stackblocksize();
 
287
        if (herefd >= 0 && len >= 1024) {
 
288
                xwrite(herefd, stackblock(), len);
 
289
                return stackblock();
 
290
        }
 
291
        growstackblock();
 
292
        return stackblock() + len;
 
293
}
 
294
 
 
295
/*
 
296
 * Called from CHECKSTRSPACE.
 
297
 */
 
298
 
 
299
char *
 
300
makestrspace(size_t newlen, char *p)
 
301
{
 
302
        size_t len = p - stacknxt;
 
303
        size_t size = stackblocksize();
 
304
 
 
305
        for (;;) {
 
306
                size_t nleft;
 
307
 
 
308
                size = stackblocksize();
 
309
                nleft = size - len;
 
310
                if (nleft >= newlen)
 
311
                        break;
 
312
                growstackblock();
 
313
        }
 
314
        return stackblock() + len;
 
315
}
 
316
 
 
317
char *
 
318
stnputs(const char *s, size_t n, char *p)
 
319
{
 
320
        p = makestrspace(n, p);
 
321
        p = mempcpy(p, s, n);
 
322
        return p;
 
323
}
 
324
 
 
325
char *
 
326
stputs(const char *s, char *p)
 
327
{
 
328
        return stnputs(s, strlen(s), p);
 
329
}