summaryrefslogtreecommitdiffstats
path: root/private/crt32/heap/heapadd.c
blob: 587e4cb1e0a38325cc98b87d1c1f36b8ad372aba (plain) (blame)
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
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
/***
*heapadd.c - Add a block of memory to the heap
*
*	Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved.
*
*Purpose:
*	Add a block of memory to the heap.
*
*Revision History:
*	07-07-89   JCR	Module created.
*	07-20-89   JCR	Re-use dummy descriptor on exact fit (dummy collection)
*	11-09-89   JCR	Corrected plastdesc updating code
*	11-13-89   GJF	Added MTHREAD support, also fixed copyright
*	11-15-89   JCR	Minor improvement (got rid of a local variable)
*	11-16-89   JCR	Bug fix - squirrly case in _HEAPFIND_EXACT
*	12-04-89   GJF	A little tuning and cleanup. Also, changed header file
*			name to heap.h.
*	12-18-89   GJF	Removed DEBUG286 stuff. Also, added explicit _cdecl to
*			function definitions.
*	12-19-89   GJF	Removed references and uses of plastdesc (revising
*			code as necessary)
*	03-09-90   GJF	Replaced _cdecl with _CALLTYPE1, added #include
*			<cruntime.h> and removed #include <register.h>.
*	03-29-90   GJF	Made _before() _CALLTYPE4.
*	07-24-90   SBM	Compiles cleanly with -W3 (tentatively removed
*			unreferenced label)
*	09-27-90   GJF	New-style function declarators.
*	03-05-91   GJF	Changed strategy for rover - old version available
*			by #define-ing _OLDROVER_.
*
*******************************************************************************/

#include <cruntime.h>
#include <heap.h>
#include <malloc.h>
#include <os2dll.h>
#include <stdlib.h>

static void _CALLTYPE4 _before(_PBLKDESC, size_t, _PBLKDESC);

/***
*int _heapadd(block, size) - Add a block of memory to the heap
*
*Purpose:
*	Add a block of user memory the heap.
*
*	NOTE:  The reason for the level of indirection between _heapadd
*	and _heap_addblock is (1) to validate the input, and (2) for
*	mthread locking/unlocking purposes.
*
*	NOTE: _heapadd() DOES NOT enter the block of memory into the region
*	table! This is the cleanest way to avoid nasty bugs such as attempting
*	to grow, shrink or free static memory (e.g., a block that started out
*	being a static array). If the memory block does in fact belong in the
*	region table, it is the caller's responsibility to do it (internal
*	routines only, user programs should NEVER do this).
*
*Entry:
*	void * block = block of memory
*	size_t size = size of memory block
*
*Exit:
*	 0 = success
*	-1 = failure
*
*Exceptions:
*
*******************************************************************************/

int _CALLTYPE1 _heapadd (
	void * block,
	size_t size
	)
{
	int retval;

	/*
	 * Validate user's input
	 */

	if ( (size == 0) ||
	     ((unsigned)block & (sizeof(int)-1)) ||
	     (size & (sizeof(int)-1))
	   )
		return(-1);

	/*
	 * Add the block to the heap.
	 */

	_mlock(_HEAP_LOCK);
	retval = _heap_addblock(block, size);
	_munlock(_HEAP_LOCK);

	return(retval);

}


/***
*int _heap_addblock(block, size) - Add a block of memory to the heap
*
*Purpose:
*	Add a block of memory to the heap.
*
*	Notes:
*	(1) Must handle case where new memory is already in heap
*	(i.e., could be the address of a previous 'dummy' entry).
*
*Entry:
*	void * block = address of memory block
*	size_t size = size of memory block
*
*Exit:
*	0 = success
*	-1 = failure
*
*Exceptions:
*
*******************************************************************************/

int _CALLTYPE1 _heap_addblock (
	void * block,
	size_t size
	)
{
	_PBLKDESC pdesc;
	REG1 _PBLKDESC pnewdesc;
	size_t lastsize;
	int find;


	/*
	 * Find where the address fits into the heap.
	 */

	find = _heap_findaddr(block, &pdesc);


	/*
	 * Fill in the new heap descriptor.
	 * (1) If the new address is an exact fit, use the dummy
	 * descriptor that already exists for it.
	 * (2) If the address is NOT in the heap, allocate a new one.
	 */

	if (find == _HEAPFIND_EXACT) {

		if (!(_IS_DUMMY(pdesc)))
			goto error1;

		pnewdesc = pdesc;
		}

	else {
		_GETEMPTY(pnewdesc);
	       }

	pnewdesc->pblock = block;	/* pointer to block */
	_SET_FREE(pnewdesc);		/* set me free (why don't ya, babe) */
	*(_PBLKDESC*)block = pnewdesc;	/* init back pointer */


	/*
	 * Put the block in the heap
	 * find = result of _heap_findaddr() call
	 * pnewdesc = points to desc to be inserted
	 * pdesc = filled in by _heap_findaddr() call as appropriate
	 */

	switch (find) {


		case(_HEAPFIND_EMPTY):

			/*
			 * No memory in heap yet
			 */

			_heap_desc.sentinel.pblock = (char *) block + size;
			_before(pnewdesc, size, &_heap_desc.sentinel);

			_heap_desc.pfirstdesc = _heap_desc.proverdesc =
				pnewdesc;

			break;


		case(_HEAPFIND_BEFORE):

			/*
			 * New block is before the heap
			 */

			_before(pnewdesc, size, _heap_desc.pfirstdesc);
			_heap_desc.pfirstdesc = pnewdesc;
			break;


		case(_HEAPFIND_AFTER):

			/*
			 * New block is after the heap
			 *
			 * Find the current last block in the heap
			 */

			if ( _heap_findaddr((void *)((char *)
			    (_heap_desc.sentinel.pblock) - 1), &pdesc) !=
			    _HEAPFIND_WITHIN )
				_heap_abort();

			lastsize = _MEMSIZE(pdesc);

			/*
			 * Start insertion by placing new block immediately
			 * in front of the sentinel
			 */

			_heap_desc.sentinel.pblock = (char *) block + size;
			pnewdesc->pnextdesc = &_heap_desc.sentinel;

			/*
			 * Finish insertion by placing new block after the
			 * old last block (with a possible intervening dummy
			 * block being created)
			 */

			_before(pdesc, lastsize, pnewdesc);
			break;


		case(_HEAPFIND_EXACT):

			/*
			 * Block is already in the heap (and we've checked
			 * that it was a "dummy" before this call).
			 *
			 * [NOTES: (1) pnewdesc and pdesc are the same,
			 * (2) pnewdesc is already linked to the previous
			 * heap entry, (3) pdesc->pnextdesc is still valid!
			 * (4) Also, if pdesc->pnextdesc is the sentinel,
			 * then simply update the sentinel size (calling
			 * before will cause an error if the previous last
			 * block was bigger than the current one!).
			 * (see code at top of this routine).]
			 */

			if (pdesc->pnextdesc == &_heap_desc.sentinel)

				_heap_desc.sentinel.pblock =
					(char *) _ADDRESS(pdesc) + size;

			else
				_before(pnewdesc, size, pdesc->pnextdesc);

			break;

#ifdef	DEBUG
		case(_HEAPFIND_WITHIN):
#else
		default:
#endif
			/*
			 * New block is within heap
			 */

			if (!(_IS_DUMMY(pdesc)))
				goto error0;

			_before(pnewdesc, size, pdesc->pnextdesc);
			_before(pdesc, _MEMSIZE(pdesc), pnewdesc);
			break;

#ifdef	DEBUG
		/*
		 * Return value unknown -- abort!
		 */

		default:
			_heap_abort();
#endif

		}

	/*
	 * Update rover, if appropriate
	 */
#ifdef	_OLDROVER_

	 if (block < _ADDRESS(_heap_desc.proverdesc))
		_heap_desc.proverdesc = pnewdesc;

#else	/* ndef _OLDROVER_ */

	 if ( (block < _ADDRESS(_heap_desc.proverdesc)) &&
	 (_BLKSIZE(pnewdesc) >= _heap_resetsize) )
		_heap_desc.proverdesc = pnewdesc;

#endif	/* _OLDROVER_ */

	/*
	 * Good return
	 */

	/* good:   unreferenced label to be removed */
		return(0);

	/*
	 * Error return
	 */

	error0:
		_PUTEMPTY(pnewdesc);
	error1:
		return(-1);

}


/***
*static void _before(pdesc1, size, pdesc2) - Insert a block before a
*	supplied descriptor
*
*Purpose:
*	This routine inserts a new descriptor before
*	another descriptor.
*
*	Notes:
*	(1) A dummy descriptor will be inserted into the heap as
*	necessary.
*	(2) This routine only updates FORWARD links. Call this
*	routine twice to update links in both directions.
*
*Entry:
*	_PBLKDESC pdesc1 = new descriptor to insert in the heap
*	size_t size = size of pdesc1 block
*	_PBLKDESC pdesc2 = descriptor before which block should go
*
*Exit:
*	(void)
*
*Exceptions:
*
*******************************************************************************/

static void _CALLTYPE4 _before (
	REG1 _PBLKDESC pdesc1,
	size_t size,
	REG2 _PBLKDESC pdesc2
	)
{
	size_t diff;
	_PBLKDESC pdummydesc;
	void * dummyaddr;

	/*
	 * Check for dummy descriptors:
	 * (1) If first block is dummy, no adjustement needed.
	 * (2) If second block is dummy, simply adjust size.
	 */

	if (_IS_DUMMY(pdesc1))
		goto link;

	if (_IS_DUMMY(pdesc2)) {
		pdesc2->pblock = (char *)_ADDRESS(pdesc1) + size;
		_SET_DUMMY(pdesc2);
		goto link;
		}


	/*
	 * See how much space is between this block and the next one.
	 */

	diff = ( (char *) _ADDRESS(pdesc2) -
		 (char *) (dummyaddr = (char *) _ADDRESS(pdesc1) + size) );

	if (diff != 0) {

#ifdef	DEBUG
		/*
		 * Internal bogosity check
		 */

		if ((int)diff < 0)
			_heap_abort();
#endif
		/*
		 * There is some space between the two blocks.	Insert
		 * a fake "in use" block.  Remember, there is no 'back
		 * pointer' in dummy blocks.
		 */

		_GETEMPTY(pdummydesc);

		pdummydesc->pblock = (char *) dummyaddr;
		_SET_DUMMY(pdummydesc);

		pdesc1->pnextdesc = pdummydesc;
		pdesc1 = pdummydesc;

		}

	/*
	 * Put the new block in the heap.
	 */

	link:
		pdesc1->pnextdesc = pdesc2;

}