1 /*
2  * mpatrol
3  * A library for controlling and tracing dynamic memory allocations.
4  * Copyright (C) 1997-2002 Graeme S. Roy <graeme.roy@analog.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the Free
18  * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19  * MA 02111-1307, USA.
20  */
21 
22 
23 /*
24  * Simulated UNIX heap.  This implements the brk() and sbrk() functions on
25  * non-UNIX platforms by allocating a single block of memory for a simulated
26  * heap from the low-level memory allocator.  These functions are not normally
27  * used by the mpatrol library and are only defined to resolve any references
28  * to them from user code.
29  */
30 
31 
32 #include "sbrk.h"
33 #include "memory.h"
34 #include "utils.h"
35 #include <stdlib.h>
36 #include <errno.h>
37 
38 
39 #if MP_IDENT_SUPPORT
40 #ident "$Id: sbrk.c,v 1.13 2002/01/08 20:13:59 graeme Exp $"
41 #else /* MP_IDENT_SUPPORT */
42 static MP_CONST MP_VOLATILE char *sbrk_id = "$Id: sbrk.c,v 1.13 2002/01/08 20:13:59 graeme Exp $";
43 #endif /* MP_IDENT_SUPPORT */
44 
45 
46 /* The brkinfo structure contains information about the simulated heap.
47  */
48 
49 typedef struct brkinfo
50 {
51     meminfo memory; /* memory details */
52     void *block;    /* pointer to block of memory */
53     size_t size;    /* size of block of memory */
54     size_t len;     /* current break length */
55 }
56 brkinfo;
57 
58 
59 #ifdef __cplusplus
60 extern "C"
61 {
62 #endif /* __cplusplus */
63 
64 
65 /* The break header structure used to contain information about the heap.
66  */
67 
68 static brkinfo brkhead;
69 
70 
71 /* Finalise the break header structure so that the heap becomes empty.
72  */
73 
74 static
75 void
finibrk(void)76 finibrk(void)
77 {
78     if (brkhead.block != NULL)
79         __mp_memfree(&brkhead.memory, brkhead.block, brkhead.size);
80     __mp_endmemory(&brkhead.memory);
81     brkhead.block = NULL;
82     brkhead.size = 0;
83     brkhead.len = 0;
84 }
85 
86 
87 /* Initialise the fields of the break header structure so that the heap
88  * becomes empty.
89  */
90 
91 static
92 int
initbrk(void)93 initbrk(void)
94 {
95     size_t l;
96 
97     l = MP_BREAK_SIZE;
98     __mp_newmemory(&brkhead.memory);
99     if ((brkhead.block = __mp_memalloc(&brkhead.memory, &l,
100           brkhead.memory.align, 1)) == NULL)
101         return 0;
102     brkhead.size = l;
103     brkhead.len = 0;
104 #if MP_DELETEHEAP
105     atexit(finibrk);
106 #endif /* MP_DELETEHEAP */
107     return 1;
108 }
109 
110 
111 /* Set the address of the first byte beyond the end of the heap.
112  */
113 
114 MP_API
115 int
brk(void * p)116 brk(void *p)
117 {
118     if ((brkhead.block != NULL) || initbrk())
119     {
120         p = (void *) __mp_roundup((unsigned long) p, brkhead.memory.align);
121         if ((p >= brkhead.block) &&
122             ((char *) p <= (char *) brkhead.block + brkhead.size))
123         {
124             brkhead.len = (char *) p - (char *) brkhead.block;
125             return 0;
126         }
127     }
128     errno = ENOMEM;
129     return -1;
130 }
131 
132 
133 /* Increase or decrease the amount of available heap space.
134  */
135 
136 MP_API
137 void *
sbrk(long l)138 sbrk(long l)
139 {
140     void *p;
141     unsigned long s;
142 
143     p = (void *) -1;
144     if ((brkhead.block != NULL) || initbrk())
145         if (l > 0)
146         {
147             s = __mp_roundup((unsigned long) l, brkhead.memory.align);
148             if (brkhead.len + s <= brkhead.size)
149             {
150                 p = (char *) brkhead.block + brkhead.len;
151                 brkhead.len += s;
152             }
153         }
154         else if (l < 0)
155         {
156             s = __mp_roundup((unsigned long) -l, brkhead.memory.align);
157             if (brkhead.len >= s)
158             {
159                 p = (char *) brkhead.block + brkhead.len;
160                 brkhead.len -= s;
161             }
162         }
163         else
164             p = (char *) brkhead.block + brkhead.len;
165     if (p == (void *) -1)
166         errno = ENOMEM;
167     return p;
168 }
169 
170 
171 #ifdef __cplusplus
172 }
173 #endif /* __cplusplus */
174