malloc.c

Go to the documentation of this file.
00001 
00002 /**********************************************************/
00003 /*
00004 /*               This was file READ_ME
00005 /*
00006 /**********************************************************/
00007 
00008 /*
00009         PROGRAM
00010                 malloc(), free(), realloc()
00011         AUTHOR
00012                 Dick Grune, Free University, Amsterdam
00013                 Modified by Ceriel Jacobs, Free University, Amsterdam,
00014                 to make it faster
00015         VERSION
00016                 $Header: /opt/proj/minix/cvsroot/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $
00017         DESCRIPTION
00018         This is an independent rewrite of the malloc/free package; it is
00019         fast and efficient.  Free blocks are kept in doubly linked lists,
00020         list N holding blocks with sizes between 2**N and 2**(N+1)-1.
00021         Consequently neither malloc nor free have to do any searching:
00022         the cost of a call of malloc() (or free()) is constant, however
00023         many blocks you have got.
00024         
00025         If you switch on the NON_STANDARD macro (see param.h) every block
00026         costs 2 pointers overhead (otherwise it's 4).
00027 */
00028 /*
00029         There is an organisational problem here: during devellopment
00030         I want the package divided into modules, which implies external
00031         names for the communication.  The only external names I want in
00032         the finished product are malloc, realloc and free.  This requires
00033         some hanky-panky.
00034 */
00035 
00036 
00037 /**********************************************************/
00038 /*
00039 /*               This was file size_type.h
00040 /*
00041 /**********************************************************/
00042 
00043 #if     _EM_WSIZE == _EM_PSIZE
00044 typedef unsigned int size_type;
00045 #elif   _EM_LSIZE == _EM_PSIZE
00046 typedef unsigned long size_type;
00047 #else
00048 #error funny pointer size
00049 #endif
00050 #include        <stdlib.h>
00051 #include        <stdio.h>
00052 
00053 
00054 /**********************************************************/
00055 /*
00056 /*               This was file param.h
00057 /*
00058 /**********************************************************/
00059 
00060 /* $Header: /opt/proj/minix/cvsroot/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
00061 /*
00062  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
00063  * See the copyright notice in the ACK home directory, in the file "Copyright".
00064  */
00065 
00066 #       undef   NON_STANDARD    /*      If defined, the contents of a block
00067                                         will NOT be left undisturbed after it
00068                                         is freed, as opposed to what it says
00069                                         in the manual (malloc(2)).
00070                                         Setting this option reduces the memory
00071                                         overhead considerably.  I personally
00072                                         consider the specified behaviour an
00073                                         artefact of the original
00074                                         implementation.
00075                                 */
00076 
00077 #       define  ASSERT          /*      If defined, some inexpensive tests
00078                                         will be made to ensure the
00079                                         correctness of some sensitive data.
00080                                         It often turns an uncontrolled crash
00081                                         into a controlled one.
00082                                 */
00083 
00084 #       define  CHECK           /*      If defined, extensive and expensive
00085                                         tests will be done, inculding a
00086                                         checksum on the mallinks (chunk
00087                                         information blocks).  The resulting
00088                                         information will be printed on a file
00089                                         called mal.out .
00090                                         Additionally a function
00091                                                 maldump(n) int n;
00092                                         will be defined, which will dump
00093                                         pertinent info in pseudo-readable
00094                                         form; it aborts afterwards if n != 0.
00095                                 */
00096 
00097 #       undef   EXTERN          /*      If defined, all static names will
00098                                         become extern, which is a help in
00099                                         using adb(1) or prof(1)
00100                                 */
00101 
00102 #       define  STORE           /*      If defined, separate free lists will
00103                                         be kept of chunks with small sizes,
00104                                         to speed things up a little.
00105                                 */
00106 
00107 #       undef SYSTEM            /*      If defined, the system module is used.
00108                                         Otherwise, "sbrk" is called directly.
00109                                 */
00110 
00111 #define ALIGNMENT       8       
00112                                 /* alignment common to all types */
00113 #define LOG_MIN_SIZE    3
00114 #define LOG_MAX_SIZE    24
00115 
00116 
00117 /**********************************************************/
00118 /*
00119 /*               This was file impl.h
00120 /*
00121 /**********************************************************/
00122 
00123 /* $Header: /opt/proj/minix/cvsroot/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
00124 /*
00125  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
00126  * See the copyright notice in the ACK home directory, in the file "Copyright".
00127  */
00128 /*      This file essentially describes how the mallink info block
00129         is implemented.
00130 */
00131 
00132 #define MIN_SIZE        (1<<LOG_MIN_SIZE)
00133 #define MAX_FLIST       (LOG_MAX_SIZE - LOG_MIN_SIZE)
00134 #if ALIGNMENT != 4 && ALIGNMENT != 8 && ALIGNMENT != 16
00135 #error ALIGNMENT must be 4, 8 or 16
00136 #elif ALIGNMENT % _EM_LSIZE
00137 /* since calloc() does it's initialization in longs */
00138 #error ALIGNMENT must be a multiple of the long size
00139 #endif
00140 #define align(n)        (((n) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
00141 
00142 union _inf {
00143         union _inf *ptr;
00144         size_type ui;
00145 };
00146 
00147 typedef union _inf mallink;
00148 #define MAL_NULL        ((mallink *)0)
00149 
00150 /*      Access macros; only these macros know where to find values.
00151         They are also lvalues.
00152 */
00153 #ifndef NON_STANDARD
00154 #define OFF_SET 0
00155 #else   /* def NON_STANDARD */
00156 #define OFF_SET 2
00157 #endif  /* NON_STANDARD */
00158 
00159 #define _log_prev_of(ml)        ((ml)[-1+OFF_SET]).ptr
00160 #define _log_next_of(ml)        ((ml)[-2+OFF_SET]).ptr
00161 #define _phys_prev_of(ml)       ((ml)[-3+OFF_SET]).ptr
00162 #define _this_size_of(ml)       ((ml)[-4+OFF_SET]).ui
00163 #ifndef CHECK
00164 #define N_WORDS                 4
00165 #else   /* ifdef        CHECK */
00166 #define _checksum_of(ml)        ((ml)[-5+OFF_SET]).ui
00167 #define _print_of(ml)           ((ml)[-6+OFF_SET]).ui
00168 #define _mark_of(ml)            ((ml)[-7+OFF_SET]).ui
00169 #define N_WORDS                 7
00170 #endif  /* CHECK */
00171 
00172 #define mallink_size()          (size_t) \
00173         align((N_WORDS - OFF_SET) * sizeof (mallink))
00174 
00175 #ifdef  CHECK
00176 #define set_mark(ml,e)          (_mark_of(ml) = (e))
00177 #define mark_of(ml)             (_mark_of(ml))
00178 
00179 #define set_checksum(ml,e)      (_checksum_of(ml) = (e))
00180 #define checksum_of(ml)         (_checksum_of(ml))
00181 #endif  /* CHECK */
00182 
00183 #define new_mallink(ml)         ( _log_prev_of(ml) = 0, \
00184                                   _log_next_of(ml) = 0, \
00185                                   _phys_prev_of(ml) = 0, \
00186                                   _this_size_of(ml) = 0 )
00187 
00188 #define block_of_mallink(ml)    ((void *)ml)
00189 #define mallink_of_block(addr)  ((mallink *)addr)
00190 
00191 #define public  extern
00192 #define publicdata      extern
00193 #ifndef EXTERN
00194 #define private static
00195 #define privatedata     static
00196 #else   /* def  EXTERN */
00197 #define private extern
00198 #define privatedata
00199 #endif  /* EXTERN */
00200 
00201 #ifdef  ASSERT
00202 private m_assert(const char *fn, int ln);
00203 #define assert(b)               (!(b) ? m_assert(__FILE__, __LINE__) : 0)
00204 #else   /* ndef ASSERT */
00205 #define assert(b)               0
00206 #endif  /* ASSERT */
00207 
00208 
00209 /**********************************************************/
00210 /*
00211 /*               This was file check.h
00212 /*
00213 /**********************************************************/
00214 
00215 /* $Header: /opt/proj/minix/cvsroot/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
00216 /*
00217  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
00218  * See the copyright notice in the ACK home directory, in the file "Copyright".
00219  */
00220 #ifdef  CHECK
00221 
00222 private check_mallinks(const char *s), calc_checksum(mallink *ml);
00223 private check_work_empty(const char *s);
00224 private started_working_on(mallink *ml), stopped_working_on(mallink *ml);
00225 
00226 #else   /* ifndef       CHECK */
00227 
00228 #define maldump(n)              abort()
00229 #define check_mallinks(s)       0
00230 #define calc_checksum(ml)       0
00231 #define started_working_on(ml)  0
00232 #define stopped_working_on(ml)  0
00233 #define check_work_empty(s)     0
00234 
00235 #endif  /* CHECK */
00236 
00237 
00238 /**********************************************************/
00239 /*
00240 /*               This was file log.h
00241 /*
00242 /**********************************************************/
00243 
00244 /* $Header: /opt/proj/minix/cvsroot/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
00245 /*
00246  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
00247  * See the copyright notice in the ACK home directory, in the file "Copyright".
00248  */
00249 /*      Algorithms to manipulate the doubly-linked lists of free
00250         chunks.
00251 */
00252 
00253 private link_free_chunk(mallink *ml), unlink_free_chunk(mallink *ml);
00254 private mallink *first_present(int class);
00255 private mallink *search_free_list(int class, size_t n);
00256 
00257 #ifdef STORE
00258 #define in_store(ml)            ((size_type)_phys_prev_of(ml) & STORE_BIT)
00259 #define set_store(ml, e) \
00260         (_phys_prev_of(ml) = (mallink *) \
00261                 ((e) ? (size_type) _phys_prev_of(ml) | STORE_BIT : \
00262                        (size_type) _phys_prev_of(ml) & ~STORE_BIT))
00263 #endif
00264 #define set_log_prev(ml,e)      (_log_prev_of(ml) = (e))
00265 #define log_prev_of(ml)         (mallink *) (_log_prev_of(ml))
00266 
00267 #define set_log_next(ml,e)      (_log_next_of(ml) = (e))
00268 #define log_next_of(ml)         (mallink *) (_log_next_of(ml))
00269 
00270 
00271 
00272 /**********************************************************/
00273 /*
00274 /*               This was file phys.h
00275 /*
00276 /**********************************************************/
00277 
00278 /* $Header: /opt/proj/minix/cvsroot/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
00279 /*
00280  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
00281  * See the copyright notice in the ACK home directory, in the file "Copyright".
00282  */
00283 /*      Algorithms to manipulate the doubly-linked list of physical
00284         chunks.
00285 */
00286 privatedata mallink *ml_last;
00287 
00288 #define FREE_BIT                01
00289 #ifdef STORE
00290 #define STORE_BIT               02
00291 #define BITS                    (FREE_BIT|STORE_BIT)
00292 #else
00293 #define BITS                    (FREE_BIT)
00294 #endif
00295 
00296 #define __bits(ml)              ((int)((size_type)_phys_prev_of(ml) & BITS))
00297 #define __free_of(ml)           ((int)((size_type)_phys_prev_of(ml) & FREE_BIT))
00298 #define __phys_prev_of(ml)      ((mallink *)((size_type)_phys_prev_of(ml) & ~BITS))
00299 #define prev_size_of(ml)        ((char *)(ml) - \
00300                                  (char *)__phys_prev_of(ml) - \
00301                                  mallink_size() \
00302                                 )
00303 #define set_phys_prev(ml,e) \
00304         (_phys_prev_of(ml) = (mallink *) ((char *)e + __bits(ml)))
00305 
00306 #ifdef  CHECK
00307 private Error(const char *fmt, const char *s, mallink *ml);
00308 #define phys_prev_of(ml)        (mallink *) \
00309         (first_mallink(ml) ? \
00310                 (char *)Error("phys_prev_of first_mallink %p", "somewhere", ml) : \
00311                 (char *)__phys_prev_of(ml) \
00312         )
00313 #else   /* ndef CHECK */
00314 #define phys_prev_of(ml)        __phys_prev_of(ml)
00315 #endif  /* CHECK */
00316 
00317 #define first_mallink(ml)       (int) (__phys_prev_of(ml) == 0)
00318 #define last_mallink(ml)        (int) ((ml) == ml_last)
00319 
00320 /*      There is an ambiguity in the semantics of phys_next_of: sometimes
00321         one wants it to return MAL_NULL if there is no next chunk, at
00322         other times one wants the address of the virtual chunk at the
00323         end of memory.  The present version returns the address of the
00324         (virtual) chunk and relies on the user to test last_mallink(ml)
00325         first.
00326 */
00327 #define size_of(ml)             (_this_size_of(ml) - mallink_size())
00328 #define set_phys_next(ml,e) \
00329         (_this_size_of(ml) = (size_type)((char *)(e) - (char *)(ml)))
00330 #define phys_next_of(ml)        (mallink *) ((char *)(ml) + _this_size_of(ml))
00331 
00332 #define set_free(ml,e) \
00333         (_phys_prev_of(ml) = (mallink *) \
00334                 ((e) ? (size_type) _phys_prev_of(ml) | FREE_BIT : \
00335                        (size_type) _phys_prev_of(ml) & ~FREE_BIT))
00336 #define free_of(ml)             (__free_of(ml))
00337 
00338 #define coalesce_forw(ml,nxt)   ( unlink_free_chunk(nxt), \
00339                                   combine_chunks((ml), (nxt)))
00340 
00341 #define coalesce_backw(ml,prv)  ( unlink_free_chunk(prv), \
00342                                   stopped_working_on(ml), \
00343                                   combine_chunks((prv), (ml)), \
00344                                   started_working_on(prv))
00345 
00346 #ifdef  CHECK
00347 #define set_print(ml,e)         (_print_of(ml) = (e))
00348 #define print_of(ml)            (_print_of(ml))
00349 #endif  /* CHECK */
00350 
00351 private truncate(mallink *ml, size_t size);
00352 private combine_chunks(register mallink *ml1, register mallink *ml2);
00353 private mallink *create_chunk(void *p, size_t n);
00354 
00355 
00356 /**********************************************************/
00357 /*
00358 /*               This was file mal.c
00359 /*
00360 /**********************************************************/
00361 
00362 /* $Header: /opt/proj/minix/cvsroot/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
00363 /*
00364  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
00365  * See the copyright notice in the ACK home directory, in the file "Copyright".
00366  */
00367 #include        <limits.h>
00368 #include        <stdlib.h>
00369 
00370 /*      Malloc space is traversed by N doubly-linked lists of chunks, each
00371         containing a couple of house-keeping data addressed as a
00372         'mallink' and a piece of useful space, called the block.
00373         The N lists are accessed through their starting pointers in
00374         free_list[].  Free_list[n] points to a list of chunks between
00375         2**(n+LOG_MIN_SIZE) and 2**(n+LOG_MIN_SIZE+1)-1, which means
00376         that the smallest chunk is 2**LOG_MIN_SIZE (== MIN_SIZE).
00377 */
00378 
00379 #ifdef SYSTEM
00380 #include        <system.h>
00381 #define SBRK    sys_break
00382 #else
00383 #define SBRK    _sbrk
00384 #define ILL_BREAK               (void *)(-1)    /* funny failure value */
00385 #endif
00386 extern void *SBRK(int incr);
00387 #ifdef STORE
00388 #define MAX_STORE       32
00389 private do_free(mallink *ml), sell_out(void);
00390 privatedata mallink *store[MAX_STORE];
00391 #endif /* STORE */
00392 
00393 void *privious_free= (void *)-1;
00394 void *
00395 malloc(register size_t n)
00396 {check_mallinks("malloc entry");{
00397         register mallink *ml;
00398         register int min_class;
00399         void *tmp;
00400 
00401 { static int reent= 0; if (!reent) { reent++; printf("malloc\n"); reent--; } }
00402 privious_free= (void *)-1;
00403         if (n == 0) {
00404                 return NULL;
00405         }
00406         if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
00407 #ifdef STORE
00408         if (n <= MAX_STORE*MIN_SIZE)    {
00409                 /* look in the store first */
00410                 register mallink **stp = &store[(n >> LOG_MIN_SIZE) - 1];
00411                 
00412                 if (ml = *stp)  {
00413                         *stp = log_next_of(ml);
00414                         set_store(ml, 0);
00415                         check_mallinks("malloc fast exit");
00416                         assert(! in_store(ml));
00417                         tmp= block_of_mallink(ml);
00418 { static int reent= 0; if (!reent) { reent++; printf("= 0x%x\n", tmp);reent--; } }
00419                         return tmp;
00420                 }
00421         }
00422 #endif /* STORE */
00423 
00424         check_work_empty("malloc, entry");
00425 
00426         /*      Acquire a chunk of at least size n if at all possible;
00427                 Try everything.
00428         */
00429         {
00430                 /*      Inline substitution of "smallest".
00431                 */
00432                 register size_t n1 = n;
00433 
00434                 assert(n1 < (1L << LOG_MAX_SIZE));
00435                 min_class = 0;
00436 
00437                 do {
00438                         n1 >>= 1;
00439                         min_class++;
00440                 } while (n1 >= MIN_SIZE);
00441         }
00442 
00443         if (min_class >= MAX_FLIST)
00444                 return NULL;            /* we don't deal in blocks that big */
00445         ml = first_present(min_class);
00446         if (ml == MAL_NULL)     {
00447                 /*      Try and extend */
00448                 register void *p;
00449 #define GRABSIZE        4096            /* Power of 2 */
00450                 register size_t req =
00451                         ((MIN_SIZE<<min_class)+ mallink_size() + GRABSIZE - 1) &
00452                                 ~(GRABSIZE-1);
00453         
00454                 if (!ml_last)   {
00455                         /* first align SBRK() */
00456                 
00457                         p = SBRK(0);
00458                         SBRK((int) (align((size_type) p) - (size_type) p));
00459                 }
00460 
00461                 /* SBRK takes an int; sorry ... */
00462                 if ((int) req < 0) {
00463                         p = ILL_BREAK;
00464                 } else {
00465                         p = SBRK((int)req);
00466                 }
00467                 if (p == ILL_BREAK) {
00468                         req = n + mallink_size();
00469                         if ((int) req >= 0) p = SBRK((int)req);
00470                 }
00471                 if (p == ILL_BREAK)     {
00472                         /*      Now this is bad.  The system will not give us
00473                                 more memory.  We can only liquidate our store
00474                                 and hope it helps.
00475                         */
00476 #ifdef STORE
00477                         sell_out();
00478                         ml = first_present(min_class);
00479                         if (ml == MAL_NULL)     {
00480 #endif /* STORE */
00481                                 /* In this emergency we try to locate a suitable
00482                                    chunk in the free_list just below the safe
00483                                    one; some of these chunks may fit the job.
00484                                 */
00485                                 ml = search_free_list(min_class - 1, n);
00486                                 if (!ml)        /* really out of space */
00487                                         return NULL;
00488                                 started_working_on(ml);
00489                                 unlink_free_chunk(ml);
00490                                 check_mallinks("suitable_chunk, forced");
00491 #ifdef STORE
00492                         }
00493                         else started_working_on(ml);
00494 #endif /* STORE */
00495                 }
00496                 else {
00497                         assert((size_type)p == align((size_type)p));
00498                         ml = create_chunk(p, req);
00499                 }
00500                 check_mallinks("suitable_chunk, extended");
00501         }
00502         else started_working_on(ml);
00503 
00504         /* we have a chunk */
00505         set_free(ml, 0);
00506         calc_checksum(ml);
00507         check_mallinks("suitable_chunk, removed");
00508         n += mallink_size();
00509         if (n + MIN_SIZE <= size_of(ml)) {
00510                 truncate(ml, n);
00511         }
00512         stopped_working_on(ml);
00513         check_mallinks("malloc exit");
00514         check_work_empty("malloc exit");
00515 #ifdef STORE
00516         assert(! in_store(ml));
00517 #endif
00518         tmp= block_of_mallink(ml);
00519 { static int reent= 0; if (!reent) { reent++; printf("= 0x%x\n", tmp);reent--; } }
00520         return tmp;
00521 }}
00522 
00523 void
00524 free(void *addr)
00525 {check_mallinks("free entry");{
00526         register mallink *ml;
00527 
00528 printf("free 0x%x\n", addr);
00529 if (privious_free == addr) { fflush(stdout); fflush(stderr); abort(); }
00530 privious_free= addr;
00531         if (addr == NULL) {
00532                 check_mallinks("free(0) very fast exit");
00533                 return;
00534         }
00535 
00536         ml = mallink_of_block(addr);
00537 #ifdef STORE
00538 
00539         if (free_of(ml) || in_store(ml))
00540                 return;                         /* user frees free block */
00541         if (size_of(ml) <= MAX_STORE*MIN_SIZE)  {
00542                 /* return to store */
00543                 mallink **stp = &store[(size_of(ml) >> LOG_MIN_SIZE) - 1];
00544                 
00545                 set_log_next(ml, *stp);
00546                 *stp = ml;
00547                 set_store(ml, 1);
00548                 calc_checksum(ml);
00549                 check_mallinks("free fast exit");
00550         }
00551         else    {
00552                 do_free(ml);
00553                 check_mallinks("free exit");
00554         }
00555 }}
00556 
00557 private
00558 do_free(register mallink *ml)
00559 {{
00560 #endif
00561 
00562 #ifndef STORE
00563         if (free_of(ml))        return;
00564 #endif /* STORE */
00565         started_working_on(ml);
00566         set_free(ml, 1);
00567         calc_checksum(ml);
00568         if (! last_mallink(ml)) {
00569                 register mallink *next = phys_next_of(ml);
00570 
00571                 if (free_of(next)) coalesce_forw(ml, next);
00572         }
00573 
00574         if (! first_mallink(ml)) {
00575                 register mallink *prev = phys_prev_of(ml);
00576 
00577                 if (free_of(prev)) {
00578                         coalesce_backw(ml, prev);
00579                         ml = prev;
00580                 }
00581         }
00582         link_free_chunk(ml);
00583         stopped_working_on(ml);
00584         check_work_empty("free");
00585 
00586         /* Compile-time checks on param.h */
00587         switch (0)      {
00588         case MIN_SIZE < OFF_SET * sizeof(mallink):      break;
00589         case 1: break;
00590         /*      If this statement does not compile due to duplicate case
00591                 entry, the minimum size block cannot hold the links for
00592                 the free blocks.  Either raise LOG_MIN_SIZE or switch
00593                 off NON_STANDARD.
00594         */
00595         }
00596         switch(0)       {
00597         case sizeof(void *) != sizeof(size_type):       break;
00598         case 1: break;
00599         /*      If this statement does not compile due to duplicate
00600                 case entry, size_type is not defined correctly.
00601                 Redefine and compile again.
00602         */
00603         }
00604 }}
00605 
00606 void *
00607 realloc(void *addr, register size_t n)
00608 {check_mallinks("realloc entry");{
00609         register mallink *ml, *ph_next;
00610         register size_type size;
00611 
00612 printf("realloc 0x%x, %d\n", addr, n);
00613         if (addr == NULL) {
00614                 /*      Behave like most Unix realloc's when handed a
00615                         null-pointer
00616                 */
00617                 return malloc(n);
00618         }
00619         if (n == 0) {
00620                 free(addr);
00621                 return NULL;
00622         }
00623         ml = mallink_of_block(addr);
00624         if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
00625 #ifdef STORE
00626         if (in_store(ml)) {
00627                 register mallink *stp = store[(size_of(ml) >> LOG_MIN_SIZE) - 1];
00628                 mallink *stp1 = NULL;
00629                 while (ml != stp)       {
00630                         stp1 = stp;
00631                         stp = log_next_of(stp);
00632                 }
00633                 stp = log_next_of(stp);
00634                 if (! stp1) store[(size_of(ml) >> LOG_MIN_SIZE) - 1] = stp;
00635                 else set_log_next(stp1, stp);
00636                 set_store(ml, 0);
00637                 calc_checksum(ml);
00638         }
00639 #endif
00640         if (free_of(ml)) {
00641                 unlink_free_chunk(ml);
00642                 set_free(ml, 0);                /* user reallocs free block */
00643         }
00644         started_working_on(ml);
00645         size = size_of(ml);
00646         if (    /* we can simplify the problem by adding the next chunk: */
00647                 n > size &&
00648                 !last_mallink(ml) &&
00649                 (ph_next = phys_next_of(ml), free_of(ph_next)) &&
00650                 n <= size + mallink_size() + size_of(ph_next)
00651         )       {
00652                 /* add in the physically next chunk */
00653                 unlink_free_chunk(ph_next);
00654                 combine_chunks(ml, ph_next);
00655                 size = size_of(ml);
00656                 check_mallinks("realloc, combining");
00657         }
00658         if (n > size)   {               /* this didn't help */
00659                 void *new;
00660                 register char *l1, *l2 = addr;
00661 
00662                 stopped_working_on(ml);
00663                 if (!(new = l1 = malloc(n))) return NULL;       /* no way */
00664                 while (size--) *l1++ = *l2++;
00665                 free(addr);
00666                 check_work_empty("mv_realloc");
00667 #ifdef STORE
00668                 assert(! in_store(mallink_of_block(new)));
00669 #endif
00670                 return new;
00671         }
00672         /* it helped, but maybe too well */
00673         n += mallink_size();
00674         if (n + MIN_SIZE <= size_of(ml)) {
00675                 truncate(ml, n);
00676         }
00677         stopped_working_on(ml);
00678         check_mallinks("realloc exit");
00679         check_work_empty("realloc");
00680 #ifdef STORE
00681         assert(! in_store(ml));
00682 #endif
00683         return addr;
00684 }}
00685 
00686 void *
00687 calloc(size_t nmemb, size_t size)
00688 {check_mallinks("calloc entry");{
00689         long *l1, *l2;
00690         size_t n;
00691 
00692 printf("calloc\n");
00693         if (size == 0) return NULL;
00694         if (nmemb == 0) return NULL;
00695 
00696         /* Check for overflow on the multiplication. The peephole-optimizer
00697          * will eliminate all but one of the possibilities.
00698          */
00699         if (sizeof(size_t) == sizeof(int)) {
00700                 if (UINT_MAX / size < nmemb) return NULL;
00701         } else if (sizeof(size_t) == sizeof(long)) {
00702                 if (ULONG_MAX / size < nmemb) return NULL;
00703         } else return NULL;             /* can't happen, can it ? */
00704 
00705         n = size * nmemb;
00706         if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
00707         if (n >= (1L << LOG_MAX_SIZE)) return NULL;
00708         l1 = (long *) malloc(n);
00709         l2 = l1 + (n / sizeof(long));   /* n is at least long aligned */
00710         while ( l2 != l1 ) *--l2 = 0;
00711         check_mallinks("calloc exit");
00712         check_work_empty("calloc exit");
00713         return (void *)l1;
00714 }}
00715 /*      Auxiliary routines */
00716 
00717 #ifdef STORE
00718 private
00719 sell_out(void)  {
00720         /*      Frees all block in store.
00721         */
00722         register mallink **stp;
00723         
00724         for (stp = &store[0]; stp < &store[MAX_STORE]; stp++)   {
00725                 register mallink *ml = *stp;
00726                 
00727                 while (ml)      {
00728                         *stp = log_next_of(ml);
00729                         set_store(ml, 0);
00730                         do_free(ml);
00731                         ml = *stp;
00732                 }
00733         }
00734 
00735 }
00736 #endif /* STORE */
00737 
00738 #ifdef  ASSERT
00739 private
00740 m_assert(const char *fn, int ln)
00741 {
00742         char ch;
00743         
00744         while (*fn)
00745                 write(2, fn++, 1);
00746         write(2, ": malloc assert failed in line ", 31);
00747         ch = (ln / 100) + '0'; write(2, &ch, 1); ln %= 100;
00748         ch = (ln / 10) + '0'; write(2, &ch, 1); ln %= 10;
00749         ch = (ln / 1) + '0'; write(2, &ch, 1);
00750         write(2, "\n", 1);
00751         maldump(1);
00752 }
00753 #endif  /* ASSERT */
00754 
00755 
00756 /**********************************************************/
00757 /*
00758 /*               This was file log.c
00759 /*
00760 /**********************************************************/
00761 
00762 /* $Header: /opt/proj/minix/cvsroot/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
00763 /*
00764  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
00765  * See the copyright notice in the ACK home directory, in the file "Copyright".
00766  */
00767 
00768 /*      Logical manipulations.
00769         The chunks are properly chained in the physical chain.
00770 */
00771 
00772 privatedata mallink *free_list[MAX_FLIST];
00773 
00774 private
00775 link_free_chunk(register mallink *ml)
00776 {
00777         /*      The free chunk ml is inserted in its proper logical
00778                 chain.
00779         */
00780         register mallink **mlp = &free_list[-1];
00781         register size_type n = size_of(ml);
00782         register mallink *ml1;
00783 
00784         assert(n < (1L << LOG_MAX_SIZE));
00785 
00786         do {
00787                 n >>= 1;
00788                 mlp++;
00789         }
00790         while (n >= MIN_SIZE);
00791 
00792         ml1 = *mlp;
00793         set_log_prev(ml, MAL_NULL);
00794         set_log_next(ml, ml1);
00795         calc_checksum(ml);
00796         if (ml1) {
00797                 /* link backwards
00798                 */
00799                 set_log_prev(ml1, ml);
00800                 calc_checksum(ml1);
00801         }
00802         *mlp = ml;
00803 }
00804 
00805 private
00806 unlink_free_chunk(register mallink *ml)
00807 {
00808         /*      Unlinks a free chunk from (the middle of) the
00809                 logical chain.
00810         */
00811         register mallink *next = log_next_of(ml);
00812         register mallink *prev = log_prev_of(ml);
00813 
00814         if (!prev)      {
00815                 /* it is the first in the chain */
00816                 register mallink **mlp = &free_list[-1];
00817                 register size_type n = size_of(ml);
00818 
00819                 assert(n < (1L << LOG_MAX_SIZE));
00820                 do {
00821                         n >>= 1;
00822                         mlp++;
00823                 }
00824                 while (n >= MIN_SIZE);
00825                 *mlp = next;
00826         }
00827         else    {
00828                 set_log_next(prev, next);
00829                 calc_checksum(prev);
00830         }
00831         if (next) {
00832                 set_log_prev(next, prev);
00833                 calc_checksum(next);
00834         }
00835 }
00836 
00837 private mallink *
00838 search_free_list(int class, size_t n)
00839 {
00840         /*      Searches the free_list[class] for a chunk of at least size n;
00841                 since it is searching a slightly undersized list,
00842                 such a block may not be there.
00843         */
00844         register mallink *ml;
00845         
00846         for (ml = free_list[class]; ml; ml = log_next_of(ml))
00847                 if (size_of(ml) >= n)
00848                         return ml;
00849         return MAL_NULL;                /* nothing found */
00850 }
00851 
00852 private mallink *
00853 first_present(int class)
00854 {
00855         /*      Find the index i in free_list[] such that:
00856                         i >= class && free_list[i] != MAL_NULL.
00857                 Return MAL_NULL if no such i exists;
00858                 Otherwise, return the first block of this list, after
00859                 unlinking it.
00860         */
00861         register mallink **mlp, *ml;
00862 
00863         for (mlp = &free_list[class]; mlp < &free_list[MAX_FLIST]; mlp++) {
00864                 if ((ml = *mlp) != MAL_NULL)    {
00865         
00866                         *mlp = log_next_of(ml); /* may be MAL_NULL */
00867                         if (*mlp) {
00868                                 /* unhook backward link
00869                                 */
00870                                 set_log_prev(*mlp, MAL_NULL);
00871                                 calc_checksum(*mlp);
00872                         }
00873                         return ml;
00874                 }
00875         }
00876         return MAL_NULL;
00877 }
00878 
00879 #ifdef  CHECK
00880 private mallink *
00881 free_list_entry(int i)  {
00882         /*      To allow maldump.c access to log.c's private data.
00883         */
00884         return free_list[i];
00885 }
00886 #endif  /* CHECK */
00887 
00888 
00889 /**********************************************************/
00890 /*
00891 /*               This was file phys.c
00892 /*
00893 /**********************************************************/
00894 
00895 /* $Header: /opt/proj/minix/cvsroot/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
00896 /*
00897  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
00898  * See the copyright notice in the ACK home directory, in the file "Copyright".
00899  */
00900 #include        <stdlib.h>
00901 
00902 /*      Physical manipulations.
00903         The blocks concerned are not in any logical chain.
00904 */
00905 
00906 private mallink *
00907 create_chunk(void *p, size_t n)
00908 {
00909         /*      The newly acquired piece of memory at p, of length n,
00910                 is turned into a free chunk, properly chained in the
00911                 physical chain.
00912                 The address of the chunk is returned.
00913         */
00914         register mallink *ml;
00915         /*      All of malloc memory is followed by a virtual chunk, the
00916                 mallink of which starts mallink_size() bytes past the last
00917                 byte in memory.
00918                 Its use is prevented by testing for ml == ml_last first.
00919         */
00920         register mallink *last = ml_last;
00921         
00922         assert(!last || p == (char *)phys_next_of(last) - mallink_size());
00923         ml = (mallink *)((char *)p + mallink_size());   /* bump ml */
00924         new_mallink(ml);
00925         started_working_on(ml);
00926         set_free(ml, 1);
00927         set_phys_prev(ml, last);
00928         ml_last = ml;
00929 
00930         set_phys_next(ml, (mallink *)((char *)ml + n));
00931         calc_checksum(ml);
00932         assert(size_of(ml) + mallink_size() == n);
00933         if (last && free_of(last)) {
00934                 coalesce_backw(ml, last);
00935                 ml = last;
00936         }
00937         check_mallinks("create_chunk, phys. linked");
00938         return ml;
00939 }
00940 
00941 private
00942 truncate(register mallink *ml, size_t size)
00943 {
00944         /*      The chunk ml is truncated.
00945                 The chunk at ml is split in two.
00946                 The remaining part is then freed.
00947         */
00948         register mallink *new = (mallink *)((char *)ml + size);
00949         register mallink *ph_next = phys_next_of(ml);
00950 
00951         new_mallink(new);
00952         set_free(new, 1);
00953         set_phys_prev(new, ml);
00954         set_phys_next(new, ph_next);
00955         calc_checksum(new);
00956         if (! last_mallink(ml)) {
00957                 set_phys_prev(ph_next, new);
00958                 calc_checksum(ph_next);
00959                 if (free_of(ph_next)) coalesce_forw(new, ph_next);
00960         }
00961         else    ml_last = new;
00962         set_phys_next(ml, new);
00963         calc_checksum(ml);
00964 
00965         started_working_on(new);
00966         link_free_chunk(new);
00967         stopped_working_on(new);
00968         check_mallinks("truncate");
00969 }
00970 
00971 private
00972 combine_chunks(register mallink *ml1, register mallink *ml2)
00973 {
00974         /*      The chunks ml1 and ml2 are combined.
00975         */
00976         register mallink *ml3 = phys_next_of(ml2);
00977 
00978         set_phys_next(ml1, ml3);
00979         calc_checksum(ml1);
00980         if (!last_mallink(ml2)) {
00981                 set_phys_prev(ml3, ml1);
00982                 calc_checksum(ml3);
00983         }
00984         if (ml_last == ml2)
00985                 ml_last = ml1;
00986 }
00987 
00988 
00989 /**********************************************************/
00990 /*
00991 /*               This was file check.c
00992 /*
00993 /**********************************************************/
00994 
00995 /* $Header: /opt/proj/minix/cvsroot/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
00996 /*
00997  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
00998  * See the copyright notice in the ACK home directory, in the file "Copyright".
00999  */
01000 #include        <stdio.h>
01001 
01002 #ifdef  CHECK                   /* otherwise this whole file is skipped */
01003 
01004 /* ??? check these later */
01005 private acquire_malout(void), check_ml_last(const char *s);
01006 private dump_all_mallinks(void), dump_free_list(int i);
01007 private dump_mallink(const char *s, mallink *ml), print_loop(mallink *ml);
01008 private working_on(mallink *ml);
01009 private size_type checksum(mallink *ml);
01010 static FILE *malout;
01011 
01012 private mallink *free_list_entry(int i);
01013 
01014 #define for_free_list(i,p) \
01015         for (p = free_list_entry(i); p; p = log_next_of(p))
01016 
01017 #define for_all_mallinks(ml)    /* backwards! */ \
01018         for (ml = ml_last; ml; \
01019                 ml = first_mallink(ml) ? MAL_NULL : phys_prev_of(ml))
01020 
01021 /* Maldump */
01022 
01023 static int pr_cnt = 0;
01024 
01025 maldump(int n)  {
01026         /*      Dump pertinent info in pseudo-readable format;
01027                 abort afterwards if n != 0.
01028         */
01029         static int dumping = 0;
01030         int i;
01031         
01032         if (dumping)
01033                 return;
01034         dumping++;
01035         acquire_malout();
01036         fprintf(malout,
01037                 ">>>>>>>>>>>>>>>> DUMP OF ALL MALLINKS <<<<<<<<<<<<<<<<");
01038         fprintf(malout, "    ml_last = %p\n", ml_last);
01039         if (++pr_cnt == 100) pr_cnt = 0;
01040         dump_all_mallinks();
01041         fprintf(malout,
01042                 ">>>>>>>>>>>>>>>> DUMP OF FREE_LISTS <<<<<<<<<<<<<<<<\n");
01043         if (++pr_cnt == 100) pr_cnt = 0;
01044         for (i = 0; i < MAX_FLIST; i++)
01045                 dump_free_list(i);
01046         fprintf(malout,
01047                 ">>>>>>>>>>>>>>>> END OF DUMP <<<<<<<<<<<<<<<<\n");
01048         fclose(malout);
01049         dumping--;
01050         if (n)
01051                 abort();
01052 }
01053 
01054 private
01055 acquire_malout(void)    {
01056         static char buf[BUFSIZ];
01057         
01058         if (!malout)    {
01059                 malout = freopen("mal.out", "w", stderr);       
01060                 setbuf(malout, buf);
01061         }
01062 }
01063 
01064 private
01065 dump_all_mallinks(void) {
01066         mallink *ml;
01067         
01068         for_all_mallinks (ml)   {
01069                 if (print_loop(ml))
01070                         return;
01071                 dump_mallink((char *)0, ml);
01072         }
01073 }
01074 
01075 private
01076 dump_free_list(int i)   {
01077         mallink *ml = free_list_entry(i);
01078         
01079         if (!ml)
01080                 return;
01081         fprintf(malout, "%2d: ", i);
01082         for_free_list(i, ml)    {
01083                 if (print_loop(ml))
01084                         return;
01085                 fprintf(malout, "%p ", ml);
01086         }
01087         fprintf(malout, "<\n");
01088 }
01089 
01090 private int
01091 print_loop(mallink *ml) {
01092         if (print_of(ml) == pr_cnt)     {
01093                 fprintf(malout, "... PRINT LOOP\n");
01094                 return 1;
01095         }
01096         set_print(ml, pr_cnt);
01097         return 0;
01098 }
01099 
01100 private
01101 dump_mallink(const char *s, mallink *ml)        {
01102         acquire_malout();
01103         if (s)
01104                 fprintf(malout, "%s: ", s);
01105         fprintf(malout, "@: %p;", ml);
01106         if (ml && checksum_of(ml) != checksum(ml))
01107                 fprintf(malout, ">>>> CORRUPTED <<<<");
01108         if (!ml)        {
01109                 fprintf(malout, "\n");
01110                 return;
01111         }       
01112         if (free_of(ml))        {
01113                 fprintf(malout, " l_p: %p;", _log_prev_of(ml));
01114                 fprintf(malout, " l_n: %p;", _log_next_of(ml));
01115         }
01116         fprintf(malout, " p_s: %p;", prev_size_of(ml));
01117         fprintf(malout, " t_s: %p;", _this_size_of(ml));
01118         fprintf(malout, " sz: %lu;", (unsigned long) size_of(ml));
01119         fprintf(malout, " fr: %d;", free_of(ml));
01120         fprintf(malout, "\n");
01121 }
01122 
01123 /*      Check_mallinks() checks the total data structure as accessible
01124         through free_list[] and ml_last.  All check_sums should be OK,
01125         except those held in the small array off_colour.  This is a
01126         trick to allow to continue checking even when a few mallinks
01127         are temporarily out of order.
01128         Check_mallinks() tests for a lot of internal consistency.
01129 */
01130 
01131 /* Some arbitrary constants */
01132 #define IN_ML_LAST      93
01133 #define IN_FREE_LIST    57              /* and in ml_last */
01134 #define CLEAR           21
01135 
01136 #define VRIJ            1
01137 #define BEZET           2
01138 
01139 private
01140 check_mallinks(const char *s)   {
01141         mallink *ml;
01142         size_type size;
01143         int i;
01144         char stat;
01145         
01146         check_ml_last(s);
01147         stat = BEZET;
01148         for_all_mallinks(ml)    {
01149                 if (checksum_of(ml) != checksum(ml))
01150                         Error("mallink info at %p corrupted", s, ml);
01151                 if (working_on(ml))     {
01152                         stat = BEZET;
01153                         continue;
01154                 }
01155                 if (    !last_mallink(ml) &&
01156                         phys_prev_of(phys_next_of(ml)) != ml
01157                 )
01158                         Error("upward chain bad at %p", s, ml);
01159                 if (    !first_mallink(ml) &&
01160                         phys_next_of(phys_prev_of(ml)) != ml
01161                 )
01162                         Error("downward chain bad at %p", s, ml);
01163                 if (free_of(ml))        {
01164                         if (stat == VRIJ)
01165                                 Error("free mallink at %p follows free mallink",
01166                                                                 s, ml);
01167                         stat = VRIJ;
01168                 }
01169                 else
01170                         stat = BEZET;
01171                 set_mark(ml, IN_ML_LAST);
01172         }
01173         
01174         for (i = 0, size = MIN_SIZE; i < MAX_FLIST; i++, size *= 2)     {
01175                 for_free_list(i, ml)    {
01176                         if (working_on(ml))
01177                                 continue;
01178                         if (!free_of(ml))
01179                                 Error("occupied mallink %p occurs in free_list", s, ml);
01180                         switch (mark_of(ml))    {
01181                         case IN_ML_LAST:
01182                                 set_mark(ml, IN_FREE_LIST);
01183                                 break;
01184                         case IN_FREE_LIST:
01185                                 Error("mallink %p occurs in 2 free_lists",
01186                                                                 s, ml);
01187                         default:
01188                                 Error("unknown mallink %p in free_list",
01189                                                                 s, ml);
01190                         }
01191                         if (size_of(ml) < size)
01192                                 Error("size of mallink %p too small", s, ml);
01193                         if (size_of(ml) >= 2*size)
01194                                 Error("size of mallink %p too large", s, ml);
01195                 }
01196         }
01197         for_all_mallinks (ml)   {
01198                 if (working_on(ml))
01199                         continue;
01200                 if (free_of(ml) && mark_of(ml) != IN_FREE_LIST)
01201                         Error("free mallink %p is in no free_list", s, ml);
01202                 set_mark(ml, CLEAR);
01203         }
01204 }
01205 
01206 private
01207 check_ml_last(const char *s)    {
01208         if (ml_last && _this_size_of(ml_last) == 0)
01209                 Error("size of ml_last == 0, at %p", s, ml_last);
01210 }
01211 
01212 private size_type
01213 checksum(mallink *ml)   {
01214         size_type sum = 0;
01215         
01216         if (free_of(ml))        {
01217                 sum += (size_type)_log_prev_of(ml);
01218                 sum += (size_type)_log_next_of(ml);
01219         }
01220         sum += (size_type)prev_size_of(ml);
01221         sum += (size_type)_this_size_of(ml);
01222         return sum;
01223 }
01224 
01225 private
01226 calc_checksum(mallink *ml)      {
01227         set_checksum(ml, checksum(ml));
01228 }
01229 
01230 #define N_COLOUR        10
01231 static mallink *off_colour[N_COLOUR];
01232 
01233 private
01234 started_working_on(mallink *ml) {
01235         int i;
01236         
01237         for (i = 0; i < N_COLOUR; i++)
01238                 if (off_colour[i] == MAL_NULL)  {
01239                         off_colour[i] = ml;
01240                         return;
01241                 }
01242         Error("out of off_colour array at %p", "started_working_on", ml);
01243 }
01244 
01245 private
01246 stopped_working_on(mallink *ml) {
01247         int i;
01248         
01249         for (i = 0; i < N_COLOUR; i++)
01250                 if (off_colour[i] == ml)        {
01251                         off_colour[i] = MAL_NULL;
01252                         return;
01253                 }
01254         Error("stopped working on mallink %p", "stopped_working_on", ml);
01255 }
01256 
01257 private int
01258 working_on(mallink *ml) {
01259         int i;
01260         
01261         for (i = 0; i < N_COLOUR; i++)
01262                 if (off_colour[i] == ml)
01263                         return 1;
01264         return 0;
01265 }
01266 
01267 private
01268 check_work_empty(const char *s) {
01269         int i;
01270         int cnt = 0;
01271         
01272         for (i = 0; i < N_COLOUR; i++)
01273                 if (off_colour[i] != MAL_NULL)
01274                         cnt++;
01275         if (cnt != 0)
01276                 Error("off_colour not empty", s, MAL_NULL);
01277 }
01278 
01279 private int
01280 Error(const char *fmt, const char *s, mallink *ml)      {
01281         static int already_called = 0;
01282 
01283         if (already_called++) return 0;
01284         setbuf(stdout, (char *) 0);
01285         printf("%s: ", s);
01286         printf(fmt, (long)ml);
01287         printf("\n");
01288         acquire_malout();
01289         fprintf(malout, "%s: ", s);
01290         fprintf(malout, fmt, (long)ml);
01291         fprintf(malout, "\n");
01292         fflush(stdout);
01293         maldump(1);
01294         return 0;                       /* to satisfy lint */
01295 }
01296 
01297 #endif  /* CHECK */
01298 

Generated on Fri Apr 14 22:56:41 2006 for minix by  doxygen 1.4.6