Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
359 serge 1
/****************************************************************************
2
*
3
*                            Open Watcom Project
4
*
5
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
6
*
7
*  ========================================================================
8
*
9
*    This file contains Original Code and/or Modifications of Original
10
*    Code as defined in and that are subject to the Sybase Open Watcom
11
*    Public License version 1.0 (the 'License'). You may not use this file
12
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
13
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
14
*    provided with the Original Code and Modifications, and is also
15
*    available at www.sybase.com/developer/opensource.
16
*
17
*    The Original Code and all software distributed under the License are
18
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
19
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
20
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
21
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
22
*    NON-INFRINGEMENT. Please see the License for the specific language
23
*    governing rights and limitations under the License.
24
*
25
*  ========================================================================
26
*
27
* Description:  Heart of the heap manager. Do not break
28
*               unless you have a death wish.
29
*
30
****************************************************************************/
31
 
32
 
33
#include "variety.h"
34
#include 
35
#include 
36
#include "heap.h"
37
 
38
 
39
#if defined(M_I86)
40
    extern unsigned setup_ds( unsigned );
41
    #pragma aux setup_ds = \
42
                "push ax" \
43
                "mov ax,ds" \
44
                "pop ds" \
45
                parm [ax] value [ax];
46
    #define setup_segment( _x ) _x = setup_ds( _x );
47
#else
48
    #define setup_segment( _x ) (void)(_x = _x);
49
#endif
50
 
51
//
52
// input:
53
//      size    - #bytes to allocate
54
//      segment - 16bit Intel data selector containing heap
55
//      offset  - address of heap control block
56
//                if 16bit Intel -> offset within segment
57
//                else           -> absolute pointer value
58
//
59
// output:
60
//      result  - address of allocated storage or zero on failure
61
//                if 16bit Intel -> offset within segment
62
//                else           -> absolute pointer value
63
//
64
unsigned __MemAllocator( unsigned size, unsigned segment, unsigned offset )
65
{
66
    frlptr result;
67
    result = 0;                                 // assume the worst
68
 
69
    setup_segment( segment );                   // setup DS for 16bit Intel
70
 
71
    if( size != 0 ) {                           // quit if size is zero
72
        unsigned new_size;
73
        new_size = size + TAG_SIZE + ROUND_SIZE;// round up size
74
        if( new_size >= size ) {                // quit if overflowed
75
            struct heapblkp _WCI86NEAR *heap;
76
            unsigned largest;
77
            heap = (struct heapblkp _WCI86NEAR *)offset;
78
            size = new_size & ~ROUND_SIZE;      // make size even
79
            largest = heap->largest_blk;
80
            if( size < FRL_SIZE ) {
81
                size = FRL_SIZE;
82
            }
83
            if( size <= largest ) {             // quit if size too big
84
                frlptr pcur;
85
                unsigned len;
86
                pcur = heap->rover;             // start at rover
87
                largest = heap->b4rover;
88
                if( size <= largest ) {         // check size with rover
89
                    pcur = heap->freehead.next; // start at beginning
90
                    largest = 0;                // reset largest block size
91
                }
92
                for(;;) {                       // search free list
93
                    len = pcur->len;
94
                    if( size <= len ) {         // found one
95
                        break;
96
                    }
97
                    if( len > largest ) {       // update largest block size
98
                        largest = len;
99
                    }
100
                    pcur = pcur->next;          // advance to next entry
101
                    if( pcur ==                 // if back at start
102
                        (frlptr)&(heap->freehead)) {
103
                        heap->largest_blk = largest;    // update largest
104
                        setup_segment( segment );       // 16bit Intel restore
105
                        return( (unsigned)result );     // return 0
106
                    }
107
                }
108
                heap->b4rover = largest;        // update rover size
109
                heap->numalloc++;               // udpate allocation count
110
                len -= size;                    // compute leftover size
111
                if( len >= FRL_SIZE ) {         // if leftover big enough
112
                                                // split into two chunks
113
                    frlptr pprev;               // before current
114
                    frlptr pnext;               // after current
115
                    frlptr pnew;                // start of new piece
116
                    pnew = (frlptr)((PTR)pcur + size);
117
                    heap->rover = pnew;         // update rover
118
                    pnew->len = len;            // set new size
119
                    pcur->len = size;           // reset current size
120
                    pprev = pcur->prev;         // update next/prev links
121
                    pnew->prev = pprev;
122
                    pnext = pcur->next;
123
                    pnew->next = pnext;
124
                    pprev->next = pnew;
125
                    pnext->prev = pnew;
126
                } else {                        // just use this chunk
127
                    frlptr pprev;               // before current
128
                    frlptr pnext;               // after current
129
                    heap->numfree--;            // 1 fewer entries in free list
130
                    pprev = pcur->prev;
131
                    heap->rover = pprev;        // update rover
132
                    pnext = pcur->next;         // update next/prev links
133
                    pprev->next = pnext;
134
                    pnext->prev = pprev;
135
                }
136
                pcur->len |= 1;                 // mark as allocated
137
                                                // get pointer to user area
138
                result = (frlptr)((PTR)pcur + TAG_SIZE);
139
            }
140
        }
141
    }
142
    setup_segment( segment );                   // 16bit Intel restore
143
    return( (unsigned)result );
144
}
145
 
146
//
147
// input:
148
//      pointer - address of block to free
149
//                if 16bit Intel -> offset within segment
150
//                else           -> absolute pointer value
151
//      segment - 16bit Intel data selector containing heap
152
//      offset  - address of heap control block
153
//                if 16bit Intel -> offset within segment
154
//                else           -> absolute pointer value
155
//
156
// output:
157
//      none
158
//
159
void __MemFree( unsigned pointer, unsigned segment, unsigned offset )
160
{
161
    setup_segment( segment );                   // setup DS for 16bit Intel
162
 
163
    if( pointer != 0 ) {                        // quit if pointer is zero
164
        frlptr pfree;
165
        pfree = (frlptr)(pointer - TAG_SIZE);
166
        if( pfree->len & 1 ) {                  // quit if storage is free
167
            struct heapblkp _WCI86NEAR *heap;
168
            frlptr pnext;
169
            frlptr pprev;
170
            frlptr ptr;
171
            unsigned len;
172
            heap = (struct heapblkp _WCI86NEAR *)offset;
173
            do {                                // this allows break statement
174
                unsigned average;
175
                unsigned numfree;
176
 
177
                // look at next block to try and coalesce
178
                len = pfree->len & ~1;          // get next block
179
                pnext = (frlptr)((PTR)pfree + len);
180
                if( (pnext->len & 1) == 0 ) {   // if it is free
181
                    len += pnext->len;          // include the length
182
                    pfree->len = len;           // update pfree length
183
                    if( pnext == heap->rover ) {    // check for rover
184
                        heap->rover = pfree;    // update rover
185
                    }
186
                    pprev = pnext->prev;        // fixup next/prev links
187
                    pnext = pnext->next;
188
                    pprev->next = pnext;
189
                    pnext->prev = pprev;
190
                    heap->numfree--;            // reduce numfree
191
                    break;                      // proceed to coalesce code
192
                }
193
 
194
                // following block is not free
195
                // we must now try to figure out where pfree
196
                // is in relation to the entries in the free list
197
                pfree->len = len;               // remove allocated marker
198
 
199
                // check a few special places
200
                // see if pfree is:
201
                // - just before or just after the rover
202
                // - at the very beginning or very end of the heap
203
                pnext = heap->rover;            // get rover
204
                if( pfree < pnext ) {           // where is pfree?
205
                                                // pfree is before rover
206
                    if( pfree > pnext->prev ) { // where is pfree?
207
                                                // pfree is next to rover
208
                        break;                  // proceed to coalesce code
209
                    }
210
                    pnext = heap->freehead.next;    // get start of free list
211
                    if( pfree < pnext ) {       // where is pfree?
212
                                                // pfree is at start of list
213
                        break;                  // proceed to coalesce code
214
                    }
215
                } else {                        // pfree is after rover
216
                    pnext = pnext->next;        // pnext is after rover
217
                    if( pfree < pnext ) {       // where is pfree?
218
                                                // pfree is just after rover
219
                        break;                  // proceed to coalesce code
220
                    }
221
                                                // get end of free list
222
                    pnext = (frlptr)&(heap->freehead);
223
                    pprev = pnext->prev;
224
                    if( pfree > pprev ) {       // where is pfree?
225
                                                // pfree is at end of list
226
                        break;                  // proceed to coalesce code
227
                    }
228
                }
229
 
230
                // Calculate the average number of allocated blocks we may
231
                // have to skip until we expect to find a free block.  If
232
                // this number is less than the total number of free blocks,
233
                // chances are that we can find the correct position in the
234
                // free list by scanning ahead for a free block and linking
235
                // this free block before the found free block.  We protect
236
                // ourself against the degenerate case where there is an
237
                // extremely long string of allocated blocks by limiting the
238
                // number of blocks we will search to twice the calculated
239
                // average.
240
 
241
                numfree = heap->numfree;
242
                average = heap->numalloc / (numfree+1);
243
                if( average < numfree ) {
244
 
245
                    // There are lots of allocated blocks and lots of free
246
                    // blocks.  On average we should find a free block
247
                    // quickly by following the allocated blocks, but the
248
                    // worst case can be very bad.  So, we try scanning the
249
                    // allocated blocks and give up once we have looked at
250
                    // twice the average.
251
 
252
                    unsigned worst;
253
                    worst = heap->numalloc - numfree;
254
                    average *= 2;               // give up after this many
255
                    if( worst <= numfree ) {
256
                        average = UINT_MAX;     // we won't give up loop
257
                    }
258
                                                // point at next allocated
259
                    pnext = (frlptr)((PTR)pfree + pfree->len);
260
                    for(;;) {
261
                        len = pnext->len;
262
                        if( len & 1 ) {         // pnext is allocated
263
                            if( len != END_TAG ) {  // check for end TAG
264
                                len &= ~1;          // advance pnext
265
                                pnext = (frlptr)((PTR)pnext + len);
266
                                average--;
267
                                if( !average ) {    // give up search
268
                                    break;
269
                                }
270
                            } else {
271
                                break;          // stop at end tag
272
                            }
273
                        } else {
274
                            // break twice!
275
                            goto found_it;      // we have the spot
276
                        }
277
                    }
278
                }
279
 
280
                // when all else fails, search the free list
281
                pnext = heap->rover;            // begin at rover
282
                if( pfree < pnext ) {           // is pfree before rover?
283
                                                // then begin at start
284
                    pnext = heap->freehead.next;
285
                }
286
                for(;;) {
287
                    if( pfree < pnext ) {       // if pfree before pnext
288
                        break;                  // we found it
289
                    }
290
                    pnext = pnext->next;        // advance pnext
291
 
292
                    if( pfree < pnext ) {       // if pfree before pnext
293
                        break;                  // we found it
294
                    }
295
                    pnext = pnext->next;        // advance pnext
296
 
297
                    if( pfree < pnext ) {       // if pfree before pnext
298
                        break;                  // we found it
299
                    }
300
                    pnext = pnext->next;        // advance pnext
301
                }
302
            } while( 0 );                       // only do once
303
 
304
found_it:
305
            // if we are here, then we found the spot
306
            pprev = pnext->prev;                // setup pprev
307
 
308
            // pprev, pfree, pnext are all setup
309
            len = pfree->len;
310
 
311
                                                // check pprev and pfree
312
            ptr = (frlptr)((PTR)pprev + pprev->len);
313
            if( ptr == pfree ) {                // are they adjacent?
314
                                                // coalesce pprev and pfree
315
                len += pprev->len;              // udpate len
316
                pprev->len = len;
317
                if( heap->rover == pfree ) {    // check rover impact
318
                    heap->rover = pprev;        // update rover
319
                }
320
                pfree = pprev;                  // now work with coalesced blk
321
            } else {
322
                heap->numfree++;                // one more free entry
323
                pfree->next = pnext;            // update next/prev entries
324
                pfree->prev = pprev;
325
                pprev->next = pfree;
326
                pnext->prev = pfree;
327
            }
328
            heap->numalloc--;                   // one fewer allocated
329
 
330
            if( pfree < heap->rover ) {         // check rover impact
331
                if( len > heap->b4rover ) {     // is len bigger than b4rover
332
                    heap->b4rover = len;        // then update b4rover
333
                }
334
            }
335
 
336
            if( len > heap->largest_blk ) {     // check largest block
337
                heap->largest_blk = len;
338
            }
339
        }
340
    }
341
 
342
    setup_segment( segment );                   // 16bit Intel restore
343
}