Subversion Repositories Kolibri OS

Rev

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