Subversion Repositories Kolibri OS

Rev

Rev 553 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
553 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:  Heap growing routines - allocate near heap memory from OS.
28
*
29
****************************************************************************/
30
 
31
 
32
#include "variety.h"
33
#include 
34
#include 
35
#include 
36
#include "heapacc.h"
37
#include "heap.h"
38
#include 
39
#if defined(__DOS_EXT__)
40
// #include "extender.h"
41
// #include "tinyio.h"
42
#endif
43
#if defined(__CALL21__)
44
// #include "tinyio.h"
45
#endif
46
#if defined(__WINDOWS_286__) || defined(__NT__)
704 serge 47
 #include "kolibri.h"
553 serge 48
#endif
49
#if defined(__OS2__)
50
// #include 
51
#endif
52
#if defined(__WINDOWS_386__)
53
// extern void * pascal DPMIAlloc(unsigned long);
54
#endif
55
 
56
static frlptr __LinkUpNewMHeap( mheapptr );
57
 
58
#if defined(__DOS_EXT__)
59
 
60
extern  int                     SegmentLimit();
61
#pragma aux SegmentLimit        = \
62
        "xor    eax,eax"        \
63
        "mov    ax,ds"          \
64
        "lsl    eax,ax"         \
65
        "inc    eax"            \
66
        value                   [eax] \
67
        modify exact            [eax];
68
 
69
static void __unlink( mheapptr miniheapptr )
70
{
71
    mheapptr            prev_link;
72
    mheapptr            next_link;
73
 
74
    if( __nheapbeg == miniheapptr ) {
75
        __nheapbeg = miniheapptr->next;
76
    }
77
    if( miniheapptr == __MiniHeapRover ) {
78
        __MiniHeapRover = miniheapptr->prev;
79
        if( __MiniHeapRover == NULL ) {
80
            __MiniHeapRover = __nheapbeg;
81
            __LargestSizeB4MiniHeapRover = 0;
82
        }
83
    }
84
    if( miniheapptr == __MiniHeapFreeRover ) {
85
        __MiniHeapFreeRover = 0;
86
    }
87
    prev_link = miniheapptr->prev;
88
    next_link = miniheapptr->next;
89
    if( prev_link != NULL )  prev_link->next = next_link;
90
    if( next_link != NULL )  next_link->prev = prev_link;
91
}
92
 
93
void __FreeDPMIBlocks()
94
{
95
    mheapptr            mhp;
96
    struct dpmi_hdr     *dpmi;
97
 
98
    mhp = __nheapbeg;
99
    while( mhp != NULL ) {
100
        // see if the last free entry has the full size of
101
        // the DPMI block ( - overhead).  If it is then we can give this
102
        // DPMI block back to the DPMI host.
103
        if( (mhp->freehead.prev)->len + sizeof(struct miniheapblkp) ==
104
            mhp->len ) {
105
            mheapptr    pnext;
106
 
107
            dpmi = ((struct dpmi_hdr *)mhp) - 1;
108
            pnext = mhp->next;
109
            __unlink( mhp );
110
            mhp = pnext;
111
            if( dpmi->dos_seg_value == 0 ) {    // if DPMI block
112
                TinyDPMIFree( dpmi->dpmi_handle );
113
            } else {                            // else DOS block below 1MB
114
                TinyFreeBlock( dpmi->dos_seg_value );
115
            }
116
        } else {
117
            mhp = mhp->next;
118
        }
119
    }
120
}
121
 
122
void *__ReAllocDPMIBlock( frlptr p1, unsigned req_size )
123
{
124
    mheapptr            mhp;
125
    struct dpmi_hdr     *dpmi;
126
    struct dpmi_hdr     *prev_dpmi;
127
    unsigned            size;
128
    frlptr              flp, flp2;
129
 
130
    if( !__heap_enabled ) return( 0 );
131
    __FreeDPMIBlocks();
132
    prev_dpmi = NULL;
133
    for( mhp = __nheapbeg; mhp; mhp = mhp->next ) {
134
        if( ((PTR)mhp + sizeof(struct miniheapblkp) == (PTR)p1)
135
          && (mhp->numalloc == 1) ) {
136
            // The mini-heap contains only this memblk
137
            __unlink( mhp );
138
            dpmi = ((struct dpmi_hdr *)mhp) - 1;
139
            if( dpmi->dos_seg_value != 0 ) return( NULL );
140
            size = mhp->len + sizeof(struct dpmi_hdr) + TAG_SIZE;
141
            size += ( req_size - (p1->len-TAG_SIZE) );
142
            size += 0x0fff;
143
            size &= ~0x0fff;
144
            prev_dpmi = dpmi;
145
            dpmi = TinyDPMIRealloc( dpmi, size );
146
            if( dpmi == NULL ) {
147
                dpmi = prev_dpmi;
148
                return( NULL );         // indicate resize failed
149
            }
150
            dpmi->dos_seg_value = 0;
151
            mhp = (mheapptr)( dpmi + 1 );
152
            mhp->len = size - sizeof(struct dpmi_hdr) - TAG_SIZE;
153
            flp = __LinkUpNewMHeap( mhp );
154
            mhp->numalloc = 1;
155
 
156
            // round up to even number
157
            req_size = (req_size + 1) & ~1;
158
            size = flp->len - req_size;
159
            if( size >= FRL_SIZE ) {    // Enough to spare a free block
160
                flp->len = req_size | 1;// adjust size and set allocated bit
161
                // Make up a free block at the end
162
                flp2 = (frlptr)((PTR)flp + req_size);
163
                flp2->len = size | 1;
164
                ++mhp->numalloc;
165
                mhp->largest_blk = 0;
166
                _nfree( (PTR)flp2 + TAG_SIZE );
167
            } else {
168
                flp->len |= 1; // set allocated bit
169
            }
170
            return( flp );
171
        }
172
    }
173
    return( NULL );
174
}
175
#endif
176
 
177
static frlptr __LinkUpNewMHeap( mheapptr p1 ) // originally __AddNewHeap()
178
{
179
    mheapptr    p2;
180
    mheapptr    p2_prev;
181
    tag         *last_tag;
182
    unsigned    amount;
183
 
184
    /* insert into ordered heap list (14-jun-91 AFS) */
185
    /* logic wasn't inserting heaps in proper ascending order */
186
    /* (09-nov-93 Fred) */
187
    p2_prev = NULL;
188
    for( p2 = __nheapbeg; p2 != NULL; p2 = p2->next ) {
189
        if( p1 < p2 ) break;
190
        p2_prev = p2;
191
    }
192
    /* ascending order should be: p2_prev < p1 < p2  */
193
    /* except for special cases when p2_prev and/or p2 are NULL */
194
    p1->prev = p2_prev;
195
    p1->next = p2;
196
    if( p2_prev != NULL ) {
197
        p2_prev->next = p1;
198
    } else {            /* add p1 to beginning of heap */
199
        __nheapbeg = p1;
200
    }
201
    if( p2 != NULL ) {
202
        /* insert before 'p2' (list is non-empty) */
203
        p2->prev = p1;
204
    }
205
    amount = p1->len - sizeof( struct miniheapblkp );
206
    /* Fill out the new miniheap descriptor */
207
    p1->freehead.len = 0;
208
    p1->freehead.prev = &p1->freehead;
209
    p1->freehead.next = &p1->freehead;
210
    p1->rover = &p1->freehead;
211
    p1->b4rover = 0;
212
    p1->numalloc = 0;
213
    p1->numfree  = 0;
214
    p1++;
215
    ((frlptr)p1)->len = amount;
216
    /* fix up end of heap links */
217
    last_tag = (tag *) ( (PTR)p1 + amount );
218
    *last_tag = END_TAG;
219
    return( (frlptr) p1 );
220
}
221
 
222
#if ! ( defined(__WINDOWS_286__) || \
223
        defined(__WINDOWS_386__) || \
224
        defined(__WARP__)        || \
225
        defined(__NT__)             \
226
    )
227
size_t __LastFree( void )    /* used by nheapgrow to know about adjustment */
228
{
229
    frlptr p1;
230
    unsigned brk_value;
231
 
232
    if( __nheapbeg == NULL ) {      /* no heap? can't have free blocks */
233
        return( 0 );
234
    }
235
    p1 = __nheapbeg->freehead.prev;        /* point to last free block */
236
    brk_value = (unsigned)((PTR)p1 + p1->len + TAG_SIZE );
237
    #if defined(__DOS_EXT__)
238
        if( _IsPharLap() && !__X32VM) _curbrk = SegmentLimit(); /*19-feb-94*/
239
    #endif
240
    if( brk_value == _curbrk ) {   /* if last free block is at the end */
241
        return( p1->len );
242
    }
243
    return( 0 );
244
}
245
#endif
246
 
247
#if ! defined(__CALL21__)
248
#if defined(__DOS_EXT__)
249
static void *RationalAlloc( size_t size )
250
{
251
    struct dpmi_hdr     *dpmi;
252
    mheapptr            mhp;
253
    tiny_ret_t          save_DOS_block;
254
    tiny_ret_t          DOS_block;
255
 
256
    __FreeDPMIBlocks();
257
    /* size is a multiple of 4k */
258
    dpmi = TinyDPMIAlloc( size );
259
    if( dpmi != NULL ) {
260
        mhp = (mheapptr)( dpmi + 1 );
261
        mhp->len = size - sizeof( struct dpmi_hdr );
262
        dpmi->dos_seg_value = 0;        // indicate DPMI block
263
        return( (void *)mhp );
264
    }
265
    if( __minreal & 0xfff00000 ) {
266
        /* checks for users that want >1M real memory saved */
267
        __minreal = 0xfffff;
268
    }
269
    if( size > 0x00010000 ) {
270
        /* cannot allocate more than 64k from DOS real memory */
271
        return( NULL );
272
    }
273
    save_DOS_block = TinyAllocBlock(( __minreal >> 4 ) | 1 );
274
    if( TINY_OK( save_DOS_block ) ) {
275
        DOS_block = TinyAllocBlock( size >> 4 );
276
        TinyFreeBlock( save_DOS_block );
277
        if( TINY_OK( DOS_block ) ) {
278
            dpmi = (struct dpmi_hdr *) TinyDPMIBase( DOS_block );
279
            dpmi->dos_seg_value = DOS_block;
280
            mhp = (mheapptr)( dpmi + 1 );
281
            mhp->len = size - sizeof( struct dpmi_hdr );
282
            return( (void *)mhp );
283
        }
284
    }
285
    return( NULL );
286
}
287
#endif
288
#endif
289
 
290
static int __AdjustAmount( unsigned *amount )
291
{
292
    unsigned old_amount = *amount;
293
    unsigned amt;
294
    #if ! ( defined(__WINDOWS_286__) || \
295
            defined(__WINDOWS_386__) || \
296
            defined(__WARP__)        || \
297
            defined(__NT__)             \
298
        )
299
        unsigned last_free_amt;
300
    #endif
301
 
302
    amt = old_amount;
303
    amt = ( amt + TAG_SIZE + ROUND_SIZE) & ~ROUND_SIZE;
304
    if( amt < old_amount ) {
305
        return( 0 );
306
    }
307
    #if ! ( defined(__WINDOWS_286__) || \
308
            defined(__WINDOWS_386__) || \
309
            defined(__WARP__)        || \
310
            defined(__NT__)             \
311
        )
312
        #if defined(__DOS_EXT__)
313
            if( _IsRationalZeroBase() || _IsCodeBuilder() ) {
314
                // Allocating extra to identify the dpmi block
315
                amt += sizeof(struct dpmi_hdr);
316
            } else {
317
        #else
318
            {
319
        #endif
320
                last_free_amt = __LastFree();   /* adjust for last free block */
321
                if( last_free_amt >= amt ) {
322
                    amt = 0;
323
                } else {
324
                    amt -= last_free_amt;
325
                }
326
            }
327
    #endif
328
    /* amount is even here */
329
    /*
330
      extra amounts        (22-feb-91 AFS)
331
 
332
       (1) adding a new heap needs:
333
           frl                    free block req'd for _nmalloc request
334
                                  (frl is the MINIMUM because the block
335
                                  may be freed)
336
           tag                    end of miniheap descriptor
337
           struct miniheapblkp    start of miniheap descriptor
338
       (2) extending heap needs:
339
           tag               free block req'd for _nmalloc request
340
    */
341
    *amount = amt;
342
    amt += ( (TAG_SIZE) + sizeof(frl) + sizeof(struct miniheapblkp) );
343
    if( amt < *amount ) return( 0 );
344
    if( amt < _amblksiz ) {
345
        /*
346
          _amblksiz may not be even so round down to an even number
347
          nb. pathological case: where _amblksiz == 0xffff, we don't
348
                                 want the usual round up to even
349
        */
350
        amt = _amblksiz & ~1u;
351
    }
352
    #if defined(__WINDOWS_386__) || \
353
        defined(__WARP__)        || \
354
        defined(__NT__)          || \
355
        defined(__CALL21__)      || \
356
        defined(__DOS_EXT__)
357
        /* make sure amount is a multiple of 4k */
358
        *amount = amt;
359
        amt += 0x0fff;
360
        if( amt < *amount ) return( 0 );
361
        amt &= ~0x0fff;
362
    #endif
363
    *amount = amt;
364
    return( *amount != 0 );
365
}
366
 
367
#if defined(__WINDOWS_286__) || \
368
    defined(__WINDOWS_386__) || \
369
    defined(__WARP__)        || \
370
    defined(__NT__)          || \
371
    defined(__CALL21__)      || \
372
    defined(__DOS_EXT__)
373
static int __CreateNewNHeap( unsigned amount )
374
{
375
    mheapptr        p1;
376
    frlptr          flp;
377
    unsigned        brk_value;
378
 
379
    if( !__heap_enabled ) return( 0 );
380
    if( _curbrk == ~1u ) return( 0 );
381
    if( __AdjustAmount( &amount ) == 0 ) return( 0 );
382
#if defined(__WINDOWS_286__)
383
    brk_value = (unsigned) LocalAlloc( LMEM_FIXED, amount );
384
    if( brk_value == 0 ) {
385
        return( 0 );
386
    }
387
#elif defined(__WINDOWS_386__)
388
    brk_value = (unsigned) DPMIAlloc( amount );
389
    if( brk_value == 0 ) {
390
        return( 0 );
391
    }
392
#elif defined(__WARP__)
393
    {
394
        PBYTE           p;
395
 
396
        if( DosAllocMem( &p, amount, PAG_COMMIT|PAG_READ|PAG_WRITE ) ) {
397
            return( 0 );
398
        }
399
        brk_value = (unsigned)p;
400
    }
401
#elif defined(__NT__)
402
//    brk_value = (unsigned) VirtualAlloc( NULL, amount, MEM_COMMIT,
403
//                                        PAGE_EXECUTE_READWRITE );
704 serge 404
      brk_value = (unsigned) user_alloc(amount );
553 serge 405
 
406
    //brk_value = (unsigned) LocalAlloc( LMEM_FIXED, amount );
407
    if( brk_value == 0 ) {
408
        return( 0 );
409
    }
410
#elif defined(__CALL21__)
411
    {
412
        tag _WCNEAR *tmp_tag;
413
 
414
        tmp_tag = (tag _WCNEAR *)TinyMemAlloc( amount );
415
        if( tmp_tag == NULL ) {
416
            return( 0 );
417
        }
418
        /* make sure it will not look like the end of a heap */
419
        tmp_tag[0] = ! END_TAG;
420
        brk_value = (unsigned) &tmp_tag[2];
421
        amount -= 2 * TAG_SIZE; // 11-jun-95, subtract extra tag
422
    }
423
#elif defined(__DOS_EXT__)
424
    // if( _IsRationalZeroBase() || _IsCodeBuilder() ) {
425
    {
426
        tag         *tmp_tag;
427
 
428
        if( _IsRational() ) {
429
            tmp_tag = RationalAlloc( amount );
430
            if( tmp_tag ) amount = *tmp_tag;
431
        } else {    /* CodeBuilder */
432
            tmp_tag = TinyCBAlloc( amount );
433
            amount -= TAG_SIZE;
434
        }
435
        if( tmp_tag == NULL ) {
436
            return( 0 );
437
        }
438
        brk_value = (unsigned) tmp_tag;
439
    }
440
    // Pharlap, RSI/non-zero can never call this function
441
#endif
442
    if( amount - TAG_SIZE > amount ) {
443
        return( 0 );
444
    } else {
445
        amount -= TAG_SIZE;
446
    }
447
    if( amount < sizeof( struct miniheapblkp ) + sizeof( frl ) ) {
448
        /* there isn't enough for a heap block (struct miniheapblkp) and
449
           one free block (frl) */
450
        return( 0 );
451
    }
452
    /* we've got a new heap block */
453
    p1 = (mheapptr) brk_value;
454
    p1->len = amount;
455
    // Now link it up
456
    flp = __LinkUpNewMHeap( p1 );
457
    amount = flp->len;
458
    /* build a block for _nfree() */
459
    flp->len = amount | 1;
460
    ++p1->numalloc;                         /* 28-dec-90 */
461
    p1->largest_blk = 0;
462
    _nfree( (PTR)flp + TAG_SIZE );
463
    return( 1 );
464
}
465
#endif
466
 
467
int __ExpandDGROUP( unsigned amount )
468
{
469
    #if defined(__WINDOWS_286__) || \
470
        defined(__WINDOWS_386__) || \
471
        defined(__WARP__)        || \
472
        defined(__NT__)          || \
473
        defined(__CALL21__)
474
        // first try to free any available storage
475
        _nheapshrink();
476
        return( __CreateNewNHeap( amount ) );
477
    #else
478
        mheapptr        p1;
479
        frlptr          flp;
480
        unsigned brk_value;
481
        tag     *last_tag;
482
        unsigned new_brk_value;
483
        void _WCNEAR *brk_ret;
484
 
485
        #if defined(__DOS_EXT__)
486
            if( ( _IsRationalZeroBase() || _IsCodeBuilder() ) ) {
487
                return( __CreateNewNHeap( amount ) );   // Won't slice either
488
            }
489
            // Rational non-zero based system should go through.
490
        #endif
491
        if( !__heap_enabled ) return( 0 );
492
        if( _curbrk == ~1u ) return( 0 );
493
        if( __AdjustAmount( &amount ) == 0 ) return( 0 );
494
        #if defined(__DOS_EXT__)
495
            if( _IsPharLap() && !__X32VM ) {        /* 19-feb-94 */
496
                _curbrk = SegmentLimit();
497
            }
498
        #endif
499
        new_brk_value = amount + _curbrk;
500
        if( new_brk_value < _curbrk ) {
501
            new_brk_value = ~1u;
502
        }
503
        brk_ret = __brk( new_brk_value );
504
        if( brk_ret == (void _WCNEAR *) -1 ) {
505
            return( 0 );
506
        }
507
        brk_value = (unsigned) brk_ret;
508
        if( brk_value >  /*0xfff8*/ ~7u ) {
509
            return( 0 );
510
        }
511
        if( new_brk_value <= brk_value ) {
512
            return( 0 );
513
        }
514
        amount = new_brk_value - brk_value;
515
        if( amount - TAG_SIZE > amount ) {
516
            return( 0 );
517
        } else {
518
            amount -= TAG_SIZE;
519
        }
520
        for( p1 = __nheapbeg; p1 != NULL; p1 = p1->next ) {
521
            if( p1->next == NULL ) break;
522
            if( (unsigned)p1 <= brk_value &&
523
                ((unsigned)p1)+p1->len+TAG_SIZE >= brk_value ) break;
524
        }
525
        if( (p1 != NULL) &&
526
        ((brk_value - TAG_SIZE) == (unsigned)( (PTR)p1 + p1->len) ) ) {
527
                /* we are extending the previous heap block (slicing) */
528
                /* nb. account for the end-of-heap tag */
529
                brk_value -= TAG_SIZE;
530
                amount += TAG_SIZE;
531
                flp = (frlptr) brk_value;
532
                /* adjust current entry in heap list */
533
                p1->len += amount;
534
                /* fix up end of heap links */
535
                last_tag = (tag *) ( (PTR)flp + amount );
536
                last_tag[0] = END_TAG;
537
        } else {
538
            if( amount < sizeof( struct miniheapblkp ) + sizeof( frl ) ) {
539
            /*  there isn't enough for a heap block (struct miniheapblkp) and
540
                one free block (frl) */
541
                return( 0 );
542
            }
543
            // Initializing the near heap if __nheapbeg == NULL,
544
            // otherwise, a new mini-heap is getting linked up
545
            p1 = (mheapptr) brk_value;
546
            p1->len = amount;
547
            flp = __LinkUpNewMHeap( p1 );
548
            amount = flp->len;
549
        }
550
        /* build a block for _nfree() */
551
        flp->len = amount | 1;
552
        ++p1->numalloc;                         /* 28-dec-90 */
553
        p1->largest_blk = ~0;    /* set to largest value to be safe */
554
        _nfree( (PTR)flp + TAG_SIZE );
555
        return( 1 );
556
    #endif
557
}