-
Notifications
You must be signed in to change notification settings - Fork 0
/
imalloc.c
256 lines (243 loc) · 7.17 KB
/
imalloc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
/*
* Copyright (C) 1992 by Rush Record
* Copyright (C) 1993 by Charles Sandmann (sandmann@clio.rice.edu)
*
* This file is part of ED.
*
* ED is free software; you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation.
*
* ED is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with ED
* (see the file COPYING). If not, write to the Free Software Foundation, 675
* Mass Ave, Cambridge, MA 02139, USA.
*/
#include "opsys.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include "rec.h"
#include "window.h"
#include "ed_dec.h"
#define GETSIZE 131584 /* NOTE: GETSIZE must be a multiple of 512 */
typedef struct free_str *free_ptr;
typedef struct free_str
{
Int size;
free_ptr next,prev;
Int data[1];
} free_node;
typedef struct zone_str *zone_ptr;
typedef struct zone_str
{
zone_ptr next,prev;
free_ptr first,last,current;
Int data[1];
} zone_node;
/******************************************************************************\
|Routine: zone_size
|Callby: imalloc
|Purpose: Returns the size of a zone that will hold a given number of bytes.
|Arguments:
| size is the size of the largest imalloc anticipated.
\******************************************************************************/
size_t zone_size(size)
size_t size;
{
if(size > GETSIZE - sizeof(zone_node) - sizeof(free_node))
return((size + sizeof(zone_node) + sizeof(free_node) + 511) & ~511);
else
return(GETSIZE);
}
/******************************************************************************\
|Routine: ifree
|Callby: buffer_empty cfrendly command edit express find_files get_colbyt init_term inquire killer load_file load_key main rec_insert rec_merge rec_trim remove_win slip_message sort_recs toss_data
|Purpose: To free got memory.
|Arguments:
| block is the address of a previously got block.
\******************************************************************************/
void ifree(block)
void *block;
{
register free_ptr this,other,p,n;
register zone_ptr z;
register Int size,qok;
#ifdef NO_SBRK
free(block);
return;
#else
qok = 0;
this = (free_ptr)((Int *)block - 2);
z = (zone_ptr)this->next; /* the zone header for the zone this block lies in */
if((size = this->data[-4]) > 0) /* coalesce with predecessor */
{
other = (free_ptr)((Int *)this - size - 3);
other->size += 3 - this->size;
if(this == z->current)
z->current = other;
this = other;
qok = 1;
}
else
this->size = -this->size;
other = (free_ptr)&this->data[this->size];
if((size = other->size) > 0) /* coalesce with follower */
{
n = other->next;
p = other->prev;
if(qok) /* the block-of-interest is already in the queue due to coalescence, just remove follower from queue */
{
n->prev = p;
p->next = n;
}
else /* the block-of-interest is not in the queue, make it replace the follower */
{
this->next = n;
this->prev = p;
p->next = this;
n->prev = this;
}
this->size += size + 3;
if(other == z->current)
z->current = this;
qok = 1;
}
if(!qok)
{
p = z->last;
n = (free_ptr)&z->prev; /* prev corresponds to size in free node */
this->next = n;
this->prev = p;
p->next = n->prev = this;
}
this->data[this->size - 1] = this->size;
if(!z->current)
z->current = this;
#endif
}
/******************************************************************************\
|Routine: imalloc
|Callby: buffer_app carriage_ret cfrendly command copy_buffer cqsort do_grep edit
| express find_files get_colbyt help_get_kw help_load imalloc include_file
| init_term inquire insert_win load_buffer load_file load_key main
| new_window openline rec_copy rec_insert rec_merge rec_split rec_trim
| restore_par slip_message sort_recs str_to_buf wincom
|Purpose: To get memory.
|Arguments:
| size is the number of bytes to get.
\******************************************************************************/
void *imalloc(size)
size_t size;
{
static zone_ptr start_zone = NULL;
static zone_ptr scan_zone;
static Int zonesize;
static zone_node base;
register free_ptr n,p,fit,other;
register free_ptr scan_free,header;
register Int actual;
Int new,remain;
struct {void *first,*last;} region;
#ifdef NO_SBRK
void *vp;
if(!(vp = (void *)malloc(size)))
{
move(NROW,1);
putout();
printf("\r\n\nRan out of memory, sorry.\r\n");
cleanup(-1);
}
return(vp);
#else
/* calculate the required size of the storage area, in ints, minimum 2 */
if((actual = (size + 3) >> 2) < 1)
actual = 1;
if(!(scan_zone = start_zone))
/* on first call, initialize the zone queue header */
{
base.next = &base;
base.prev = &base;
zonesize = (sizeof(zone_node) + sizeof(free_node))/sizeof(int);
}
else
{
/* scan through all existing zones */
do
{
if((scan_free = scan_zone->current))
{
header = (free_ptr)&scan_zone->prev;
/* scan until a fit is found */
do
{
if((remain = scan_free->size - actual) >= 0)
{
fit = scan_free;
n = fit->next;
p = fit->prev;
if(remain < 4)
{
actual = fit->size;
p->next = fit->next;
n->prev = fit->prev;
if(n == p)
scan_zone->current = NULL;
else
{
if(n == header)
n = n->next;
scan_zone->current = n;
}
}
else
{
scan_zone->current = other = (free_ptr)&fit->data[actual];
other->prev = p;
other->next = n;
p->next = n->prev = other;
remain -= 3;
other->size = other->data[remain - 1] = remain;
}
fit->size = fit->data[actual - 1] = -actual;
start_zone = scan_zone;
fit->next = (free_ptr)scan_zone; /* set zone header backpointer */
return((void *)&fit->prev);
}
if((scan_free = scan_free->next) == header) /* pass through header */
scan_free = scan_free->next;
} while(scan_free != scan_zone->current);
}
if((scan_zone = scan_zone->next) == (zone_ptr)&base) /* pass through header */
scan_zone = scan_zone->next;
}while(scan_zone != start_zone);
}
/* no space available, create new zone */
new = zone_size(actual << 2);
#ifdef VMS
if(!(SYS$EXPREG(new >> 9,®ion,0,0) & 1))
#else
if((region.first = (Char *)sbrk(new)) == (void *)(-1))
#endif
{
move(NROW,1);
putout();
printf("\r\n\nRan out of memory, sorry.\r\n");
cleanup(-1);
}
new >>= 2; /* convert to ints */
start_zone = (zone_ptr)region.first;
start_zone->next = &base;
start_zone->prev = base.prev;
base.prev->next = start_zone;
base.prev = start_zone;
start_zone->data[0] = -1; /* used-tag for backup from first region */
scan_free = start_zone->current = start_zone->first = start_zone->last = (free_ptr)&start_zone->data[1];
scan_free->next = scan_free->prev = (free_ptr)&start_zone->prev; /* zone header appears to contain a free node */
scan_free->size = scan_free->data[new - zonesize - 1] = new - zonesize;
scan_free->data[new - zonesize] = -1; /* used-tag for following last region */
return(imalloc(size));
#endif
}