Subversion Repositories Kolibri OS

Rev

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

  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 <stddef.h>
  34. #include <stdlib.h>
  35. #include <malloc.h>
  36. #include "heapacc.h"
  37. #include "heap.h"
  38. #include <errno.h>
  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__)
  47.  #include "kolibri.h"
  48. #endif
  49. #if defined(__OS2__)
  50. // #include <wos2.h>
  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 );
  404.       brk_value = (unsigned) user_alloc(amount );
  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. }
  558.