home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / proglang / dmake38b.arj / MALLOC.C < prev    next >
C/C++ Source or Header  |  1992-01-23  |  13KB  |  655 lines

  1. /*
  2.  * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).  
  3.  * You may copy, distribute, and use this software as long as this
  4.  * copyright statement is not removed.
  5.  */
  6. #include <stdio.h>
  7. #include <fcntl.h>
  8. #include "malloc.h"
  9. #include "tostring.h"
  10.  
  11. /*
  12.  * Function:    malloc()
  13.  *
  14.  * Purpose:    memory allocator
  15.  *
  16.  * Arguments:    size    - size of data area needed
  17.  *
  18.  * Returns:    pointer to allocated area, or NULL if unable
  19.  *        to allocate addtional data.
  20.  *
  21.  * Narrative:
  22.  *
  23.  */
  24. #ifndef lint
  25. static
  26. char rcs_hdr[] = "$Id: malloc.c,v 1.1 1992/01/24 03:29:05 dvadura Exp $";
  27. #endif
  28.  
  29. extern int      malloc_checking;
  30. char        * malloc_data_start;
  31. char        * malloc_data_end;
  32. struct mlist     * malloc_end;
  33. int          malloc_errfd = 2;
  34. int          malloc_errno;
  35. int          malloc_fatal_level = M_HANDLE_CORE;
  36. struct mlist      malloc_start;
  37. int          malloc_warn_level;
  38. void          malloc_memset();
  39.  
  40. char *
  41. malloc(size)
  42.     unsigned int      size;
  43. {
  44.     char        * func = "malloc";
  45.     char        * getenv();
  46.     void          malloc_fatal();
  47.     void          malloc_init();
  48.     void          malloc_split();
  49.     void          malloc_warning();
  50.     unsigned int      need;
  51.     struct mlist    * oldptr;
  52.     struct mlist    * ptr;
  53.     char        * sbrk();
  54.  
  55.     /*
  56.      * If this is the first call to malloc...
  57.      */
  58.     if( malloc_data_start == (char *) 0 )
  59.     {
  60.         malloc_init();
  61.     }
  62.  
  63.     /*
  64.      * If malloc chain checking is on, go do it.
  65.      */
  66.     if( malloc_checking )
  67.     {
  68.         (void) malloc_chain_check(1);
  69.     }
  70.  
  71.     /*
  72.      * always make sure there is at least on extra byte in the malloc
  73.      * area so that we can verify that the user does not overrun the
  74.      * data area.
  75.      */
  76.     size++;
  77.  
  78.     /*
  79.      * Now look for a free area of memory of size bytes...
  80.      */
  81.     oldptr = NULL;
  82.     for(ptr = &malloc_start; ; ptr = ptr->next)
  83.     {
  84.         /*
  85.          * Since the malloc chain is a forward only chain, any
  86.          * pointer that we get should always be positioned in 
  87.          * memory following the previous pointer.  If this is not
  88.          * so, we must have a corrupted chain.
  89.          */
  90.         if( ptr )
  91.         {
  92.             if( IsLess(ptr,oldptr) )
  93.             {
  94.                 malloc_errno = M_CODE_CHAIN_BROKE;
  95.                 malloc_fatal(func);
  96.                 return(NULL);
  97.             }
  98.             oldptr = ptr;
  99.         }
  100.         else if( oldptr != malloc_end )
  101.         {
  102.             /*
  103.              * This should never happen.  If it does, then
  104.              * we got a real problem.
  105.              */
  106.             malloc_errno = M_CODE_NO_END;
  107.             malloc_fatal(func);
  108.             return(NULL);
  109.         }
  110.         
  111.  
  112.         /*
  113.          * if this element is already in use...
  114.          */
  115.         if( ptr && ((ptr->flag & M_INUSE) != 0) )
  116.         {
  117.             continue;
  118.         }
  119.  
  120.         /*
  121.          * if there isn't room for this block..
  122.          */
  123.         if( ptr && (ptr->s.size < size) )
  124.         {
  125.             continue;
  126.         }
  127.  
  128.         /*
  129.          * If ptr is null, we have run out of memory and must sbrk more
  130.          */
  131.         if( ptr == NULL )
  132.         {
  133.             need = (size + M_SIZE) * (size > 10*1024 ? 1:2);
  134.             if( need < M_BLOCKSIZE )
  135.             {
  136.                 need = M_BLOCKSIZE;
  137.             }
  138.             else if( need & (M_BLOCKSIZE-1) )
  139.             {
  140.                 need &= ~(M_BLOCKSIZE-1);
  141.                 need += M_BLOCKSIZE;
  142.             }
  143.             ptr = (struct mlist *) sbrk((int)need);
  144.             if( ptr == (struct mlist *) -1 )
  145.             {
  146.                 malloc_errno = M_CODE_NOMORE_MEM;
  147.                 malloc_fatal(func);
  148.             }
  149.             malloc_data_end = sbrk((int)0);
  150.  
  151.             ptr->prev   = oldptr;
  152.             ptr->next   = (struct mlist *) 0;
  153.             ptr->s.size = need - M_SIZE;
  154.             ptr->flag  = M_MAGIC;
  155.  
  156.             oldptr->next = ptr;
  157.             malloc_end = ptr;
  158.  
  159.  
  160.         } /* if( ptr ==... */
  161.  
  162.         /*
  163.           * Now ptr points to a memory location that can store
  164.          * this data, so lets go to work.
  165.          */
  166.  
  167.         ptr->r_size = size;        /* save requested size    */
  168.         ptr->flag |= M_INUSE;
  169.  
  170.         /*
  171.           * split off unneeded data area in this block, if possible...
  172.          */
  173.         malloc_split(ptr);
  174.  
  175.         /*
  176.          * re-adjust the requested size so that it is what the user
  177.          * actually requested...
  178.          */
  179.  
  180.         ptr->r_size--;
  181.  
  182.         /*
  183.          * just to make sure that noone is misusing malloced
  184.           * memory without initializing it, lets set it to
  185.          * all '\01's.  We call local_memset() because memset()
  186.          * may be checking for malloc'd ptrs and this isn't
  187.          * a malloc'd ptr yet.
  188.          */
  189.         malloc_memset(ptr->data,M_FILL,(int)ptr->s.size);
  190.  
  191.         return( ptr->data);
  192.  
  193.     } /* for(... */
  194.  
  195. } /* malloc(... */
  196.  
  197. /*
  198.  * Function:    malloc_split()
  199.  *
  200.  * Purpose:    to split a malloc segment if there is enough room at the
  201.  *        end of the segment that isn't being used
  202.  *
  203.  * Arguments:    ptr    - pointer to segment to split
  204.  *
  205.  * Returns:    nothing of any use.
  206.  *
  207.  * Narrative:
  208.  *        get the needed size of the module
  209.  *         round the size up to appropriat boundry
  210.  *        calculate amount of left over space
  211.  *        if there is enough left over space
  212.  *            create new malloc block out of remainder
  213.  *            if next block is free 
  214.  *            join the two blocks together
  215.  *            fill new empty block with free space filler
  216.  *             re-adjust pointers and size of current malloc block
  217.  *        
  218.  *        
  219.  *
  220.  * Mod History:    
  221.  *   90/01/27    cpcahil        Initial revision.
  222.  */
  223. void
  224. malloc_split(ptr)
  225.     struct mlist        * ptr;
  226. {
  227.     extern struct mlist    * malloc_end;
  228.     void              malloc_join();
  229.     int              rest;
  230.     int              size;
  231.     struct mlist        * tptr;
  232.  
  233.     size = ptr->r_size;
  234.  
  235.     /*
  236.      * roundup size to the appropriate boundry
  237.      */
  238.  
  239.     M_ROUNDUP(size);
  240.  
  241.     /*
  242.      * figure out how much room is left in the array.
  243.      * if there is enough room, create a new mlist 
  244.      *     structure there.
  245.      */
  246.  
  247.     if( ptr->s.size > size )
  248.     {
  249.         rest = ptr->s.size - size;
  250.     }
  251.     else
  252.     {
  253.         rest = 0;
  254.     }
  255.     
  256.     if( rest > (M_SIZE+M_RND) )
  257.     {
  258.         tptr = (struct mlist *) (ptr->data+size);
  259.         tptr->prev = ptr;
  260.         tptr->next = ptr->next;
  261.         tptr->flag = M_MAGIC;
  262.         tptr->s.size = rest - M_SIZE;
  263.  
  264.         /*
  265.          * If possible, join this segment with the next one
  266.          */
  267.  
  268.         malloc_join(tptr, tptr->next,0,0);
  269.  
  270.         if( tptr->next )
  271.         {
  272.             tptr->next->prev = tptr;
  273.         }
  274.  
  275.         malloc_memset(tptr->data,M_FREE_FILL, (int)tptr->s.size);
  276.  
  277.         ptr->next = tptr;
  278.         ptr->s.size = size;
  279.  
  280.         if( malloc_end == ptr )
  281.         {
  282.             malloc_end = tptr;
  283.         }
  284.     }
  285.  
  286. } /* malloc_split(... */
  287.  
  288. /*
  289.  * Function:    malloc_join()
  290.  *
  291.  * Purpose:    to join two malloc segments together (if possible)
  292.  *
  293.  * Arguments:    ptr    - pointer to segment to join to.
  294.  *         nextptr    - pointer to next segment to join to ptr.
  295.  *
  296.  * Returns:    nothing of any values.
  297.  *
  298.  * Narrative:
  299.  *
  300.  * Mod History:    
  301.  *   90/01/27    cpcahil        Initial revision.
  302.  */
  303. void
  304. malloc_join(ptr,nextptr, inuse_override, fill_flag)
  305.     struct mlist    * ptr;
  306.     struct mlist    * nextptr;
  307.     int          inuse_override;
  308.     int          fill_flag;
  309. {
  310.     unsigned int      newsize;
  311.  
  312.     if(     ptr     && ! (inuse_override || (ptr->flag & M_INUSE)) && 
  313.         nextptr && ! (nextptr->flag & M_INUSE) &&
  314.         ((ptr->data+ptr->s.size) == (char *) nextptr) )
  315.     {
  316.         if( malloc_end == nextptr )
  317.         {
  318.             malloc_end = ptr;
  319.         }
  320.         ptr->next = nextptr->next;
  321.         newsize = nextptr->s.size + M_SIZE;
  322.  
  323.         /*
  324.          * if we are to fill and this segment is in use,
  325.          *   fill in with M_FILL newly added space...
  326.           */
  327.  
  328.         if(fill_flag && (ptr->flag & M_INUSE) )
  329.         {
  330.             malloc_memset(ptr->data+ptr->s.size,
  331.                       M_FILL, (int)(nextptr->s.size + M_SIZE));
  332.         }
  333.  
  334.         ptr->s.size += newsize;
  335.         if( ptr->next )
  336.         {
  337.             ptr->next->prev = ptr;
  338.         }
  339.     }
  340.  
  341. } /* malloc_join(... */
  342.  
  343.  
  344. /*
  345.  * The following mess is just to ensure that the versions of these functions in
  346.  * the current library are included (to make sure that we don't accidentaly get 
  347.  * the libc versions. (This is the lazy man's -u ld directive)
  348.  */
  349.  
  350. void free();
  351. int strcmp();
  352. int memcmp();
  353. char    * realloc();
  354.  
  355. void        (*malloc_void_funcs[])() =
  356. {
  357.     free,
  358. };
  359.  
  360. int        (*malloc_int_funcs[])() =
  361. {
  362.     strcmp,
  363.     memcmp,
  364. };
  365.  
  366. char        * (*malloc_char_star_funcs[])() =
  367. {
  368.     realloc,
  369. };
  370.  
  371. /*
  372.  * This is malloc's own memset which is used without checking the parameters.
  373.  */
  374.  
  375. void
  376. malloc_memset(ptr,byte,len)
  377.     char        * ptr;
  378.     char          byte;
  379.     int          len;
  380. {
  381.  
  382.     while(len-- > 0)
  383.     {
  384.         *ptr++ = byte;
  385.     }
  386.  
  387. } /* malloc_memset(... */
  388.  
  389. /*
  390.  * Function:    malloc_fatal()
  391.  *
  392.  * Purpose:    to display fatal error message and take approrpriate action
  393.  *
  394.  * Arguments:    funcname - name of function calling this routine
  395.  *
  396.  * Returns:    nothing of any value
  397.  *
  398.  * Narrative:
  399.  *
  400.  * Notes:    This routine does not make use of any libc functions to build
  401.  *        and/or disply the error message.  This is due to the fact that
  402.  *        we are probably at a point where malloc is having a real problem
  403.  *        and we don't want to call any function that may use malloc.
  404.  */
  405. void
  406. malloc_fatal(funcname)
  407.     char        * funcname;
  408. {
  409.     char          errbuf[128];
  410.     void          exit();
  411.     void          malloc_err_handler();
  412.     extern char    * malloc_err_strings[];
  413.     extern int      malloc_errno;
  414.     extern int      malloc_fatal_level;
  415.     char        * s;
  416.     char        * t;
  417.  
  418.     s = errbuf;
  419.     t = "Fatal error: ";
  420.     while( *s = *t++)
  421.     {
  422.         s++;
  423.     }
  424.     t = funcname;
  425.     while( *s = *t++)
  426.     {
  427.         s++;
  428.     }
  429.  
  430.     t = "(): ";
  431.     while( *s = *t++)
  432.     {
  433.         s++;
  434.     }
  435.  
  436.     t = malloc_err_strings[malloc_errno];
  437.     while( *s = *t++)
  438.     {
  439.         s++;
  440.     }
  441.  
  442.     *(s++) = '\n';
  443.  
  444.     if( write(malloc_errfd,errbuf,(unsigned)(s-errbuf)) != (s-errbuf))
  445.     {
  446.         (void) write(2,"I/O error to error file\n",(unsigned)24);
  447.         exit(110);
  448.     }
  449.     malloc_err_handler(malloc_fatal_level);
  450.  
  451. } /* malloc_fatal(... */
  452.  
  453. /*
  454.  * Function:    malloc_warning()
  455.  *
  456.  * Purpose:    to display warning error message and take approrpriate action
  457.  *
  458.  * Arguments:    funcname - name of function calling this routine
  459.  *
  460.  * Returns:    nothing of any value
  461.  *
  462.  * Narrative:
  463.  *
  464.  * Notes:    This routine does not make use of any libc functions to build
  465.  *        and/or disply the error message.  This is due to the fact that
  466.  *        we are probably at a point where malloc is having a real problem
  467.  *        and we don't want to call any function that may use malloc.
  468.  */
  469. void
  470. malloc_warning(funcname)
  471.     char        * funcname;
  472. {
  473.     char          errbuf[128];
  474.     void          exit();
  475.     void          malloc_err_handler();
  476.     extern char    * malloc_err_strings[];
  477.     extern int      malloc_errno;
  478.     extern int      malloc_warn_level;
  479.     char        * s;
  480.     char        * t;
  481.  
  482.     s = errbuf;
  483.     t = "Warning: ";
  484.     while( *s = *t++)
  485.     {
  486.         s++;
  487.     }
  488.     t = funcname;
  489.     while( *s = *t++)
  490.     {
  491.         s++;
  492.     }
  493.  
  494.     t = "(): ";
  495.     while( *s = *t++)
  496.     {
  497.         s++;
  498.     }
  499.  
  500.     t = malloc_err_strings[malloc_errno];
  501.     while( *s = *t++)
  502.     {
  503.         s++;
  504.     }
  505.  
  506.     *(s++) = '\n';
  507.  
  508.     if( write(malloc_errfd,errbuf,(unsigned)(s-errbuf)) != (s-errbuf))
  509.     {
  510.         (void) write(2,"I/O error to error file\n",(unsigned)24);
  511.         exit(110);
  512.     }
  513.  
  514.     malloc_err_handler(malloc_warn_level);
  515.  
  516. } /* malloc_warning(... */
  517.  
  518. /*
  519.  * Function:    malloc_err_handler()
  520.  *
  521.  * Purpose:    to take the appropriate action for warning and/or fatal 
  522.  *        error conditions.
  523.  *
  524.  * Arguments:    level - error handling level 
  525.  *
  526.  * Returns:    nothing of any value
  527.  *
  528.  * Narrative:
  529.  *
  530.  * Notes:    This routine does not make use of any libc functions to build
  531.  *        and/or disply the error message.  This is due to the fact that
  532.  *        we are probably at a point where malloc is having a real problem
  533.  *        and we don't want to call any function that may use malloc.
  534.  */
  535. void
  536. malloc_err_handler(level)
  537. {
  538.     void          exit();
  539.     void          malloc_dump();
  540.     extern int      malloc_errfd;
  541.  
  542.     if( level & M_HANDLE_DUMP )
  543.     {
  544.         malloc_dump(malloc_errfd);
  545.     }
  546.  
  547.     switch( level & ~M_HANDLE_DUMP )
  548.     {
  549.         /*
  550.          * If we are to drop a core file and exit
  551.          */
  552.         case M_HANDLE_ABORT:
  553.             (void) abort();
  554.             break;
  555.  
  556.         /*
  557.          * If we are to exit..
  558.          */
  559.         case M_HANDLE_EXIT:
  560.             exit(200);
  561.             break;
  562.  
  563. #ifndef __MSDOS__
  564.         /*
  565.          * If we are to dump a core, but keep going on our merry way
  566.          */
  567.         case M_HANDLE_CORE:
  568.             {
  569.                 int      pid;
  570.  
  571.                 /*
  572.                  * fork so child can abort (and dump core)
  573.                  */
  574.                 if( (pid = fork()) == 0 )
  575.                 {
  576.                     (void) write(2,"Child dumping core\n",
  577.                             (unsigned)9);
  578.                     (void) abort();
  579.                 }
  580.  
  581.                 /*
  582.                   * wait for child to finish dumping core
  583.                  */
  584.                 while( wait((int *)0) != pid)
  585.                 {
  586.                 }
  587.  
  588.                 /*
  589.                  * Move core file to core.pid.cnt so 
  590.                  * multiple cores don't overwrite each
  591.                  * other.
  592.                  */
  593.                 if( access("core",0) == 0 )
  594.                 {
  595.                     static int      corecnt;
  596.                     char            filenam[32];
  597.                     filenam[0] = 'c';
  598.                     filenam[1] = 'o';
  599.                     filenam[2] = 'r';
  600.                     filenam[3] = 'e';
  601.                     filenam[4] = '.';
  602.                     (void)tostring(filenam+5,getpid(),
  603.                         5, B_DEC, '0');
  604.                     filenam[10] = '.';
  605.                     (void)tostring(filenam+11,corecnt++,
  606.                         3, B_DEC, '0');
  607.                     filenam[14] = '\0';
  608.                     (void) unlink(filenam);
  609.                     if( link("core",filenam) == 0)
  610.                     {
  611.                         (void) unlink("core");
  612.                     }
  613.                 }
  614.             }
  615. #endif
  616.  
  617.  
  618.         /* 
  619.          * If we are to just ignore the error and keep on processing
  620.          */
  621.         case M_HANDLE_IGNORE:
  622.             break;
  623.  
  624.     } /* switch(... */
  625.  
  626. } /* malloc_err_handler(... */
  627.  
  628. /*
  629.  * $Log: malloc.c,v $
  630.  * Revision 1.1  1992/01/24  03:29:05  dvadura
  631.  * dmake Version 3.8, Initial revision
  632.  *
  633.  * Revision 1.6  90/05/11  00:13:09  cpcahil
  634.  * added copyright statment
  635.  * 
  636.  * Revision 1.5  90/02/25  11:01:18  cpcahil
  637.  * added support for malloc chain checking.
  638.  * 
  639.  * Revision 1.4  90/02/24  21:50:21  cpcahil
  640.  * lots of lint fixes
  641.  * 
  642.  * Revision 1.3  90/02/24  14:51:18  cpcahil
  643.  * 1. changed malloc_fatal and malloc_warn to use malloc_errno and be passed
  644.  *    the function name as a parameter.
  645.  * 2. Added several function headers.
  646.  * 3. Changed uses of malloc_fatal/warning to conform to new usage.
  647.  * 
  648.  * Revision 1.2  90/02/23  18:05:23  cpcahil
  649.  * fixed open of error log to use append mode.
  650.  * 
  651.  * Revision 1.1  90/02/22  23:17:43  cpcahil
  652.  * Initial revision
  653.  * 
  654.  */
  655.