[9] | 1 |
|
---|
| 2 | /**********************************************************/
|
---|
| 3 | /*
|
---|
| 4 | /* This was file READ_ME
|
---|
| 5 | /*
|
---|
| 6 | /**********************************************************/
|
---|
| 7 |
|
---|
| 8 | /*
|
---|
| 9 | PROGRAM
|
---|
| 10 | malloc(), free(), realloc()
|
---|
| 11 | AUTHOR
|
---|
| 12 | Dick Grune, Free University, Amsterdam
|
---|
| 13 | Modified by Ceriel Jacobs, Free University, Amsterdam,
|
---|
| 14 | to make it faster
|
---|
| 15 | VERSION
|
---|
| 16 | $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $
|
---|
| 17 | DESCRIPTION
|
---|
| 18 | This is an independent rewrite of the malloc/free package; it is
|
---|
| 19 | fast and efficient. Free blocks are kept in doubly linked lists,
|
---|
| 20 | list N holding blocks with sizes between 2**N and 2**(N+1)-1.
|
---|
| 21 | Consequently neither malloc nor free have to do any searching:
|
---|
| 22 | the cost of a call of malloc() (or free()) is constant, however
|
---|
| 23 | many blocks you have got.
|
---|
| 24 |
|
---|
| 25 | If you switch on the NON_STANDARD macro (see param.h) every block
|
---|
| 26 | costs 2 pointers overhead (otherwise it's 4).
|
---|
| 27 | */
|
---|
| 28 | /*
|
---|
| 29 | There is an organisational problem here: during devellopment
|
---|
| 30 | I want the package divided into modules, which implies external
|
---|
| 31 | names for the communication. The only external names I want in
|
---|
| 32 | the finished product are malloc, realloc and free. This requires
|
---|
| 33 | some hanky-panky.
|
---|
| 34 | */
|
---|
| 35 |
|
---|
| 36 |
|
---|
| 37 | /**********************************************************/
|
---|
| 38 | /*
|
---|
| 39 | /* This was file size_type.h
|
---|
| 40 | /*
|
---|
| 41 | /**********************************************************/
|
---|
| 42 |
|
---|
| 43 | #if _EM_WSIZE == _EM_PSIZE
|
---|
| 44 | typedef unsigned int size_type;
|
---|
| 45 | #elif _EM_LSIZE == _EM_PSIZE
|
---|
| 46 | typedef unsigned long size_type;
|
---|
| 47 | #else
|
---|
| 48 | #error funny pointer size
|
---|
| 49 | #endif
|
---|
| 50 | #include <stdlib.h>
|
---|
| 51 | #include <stdio.h>
|
---|
| 52 |
|
---|
| 53 |
|
---|
| 54 | /**********************************************************/
|
---|
| 55 | /*
|
---|
| 56 | /* This was file param.h
|
---|
| 57 | /*
|
---|
| 58 | /**********************************************************/
|
---|
| 59 |
|
---|
| 60 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
| 61 | /*
|
---|
| 62 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
| 63 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
| 64 | */
|
---|
| 65 |
|
---|
| 66 | # undef NON_STANDARD /* If defined, the contents of a block
|
---|
| 67 | will NOT be left undisturbed after it
|
---|
| 68 | is freed, as opposed to what it says
|
---|
| 69 | in the manual (malloc(2)).
|
---|
| 70 | Setting this option reduces the memory
|
---|
| 71 | overhead considerably. I personally
|
---|
| 72 | consider the specified behaviour an
|
---|
| 73 | artefact of the original
|
---|
| 74 | implementation.
|
---|
| 75 | */
|
---|
| 76 |
|
---|
| 77 | # define ASSERT /* If defined, some inexpensive tests
|
---|
| 78 | will be made to ensure the
|
---|
| 79 | correctness of some sensitive data.
|
---|
| 80 | It often turns an uncontrolled crash
|
---|
| 81 | into a controlled one.
|
---|
| 82 | */
|
---|
| 83 |
|
---|
| 84 | # define CHECK /* If defined, extensive and expensive
|
---|
| 85 | tests will be done, inculding a
|
---|
| 86 | checksum on the mallinks (chunk
|
---|
| 87 | information blocks). The resulting
|
---|
| 88 | information will be printed on a file
|
---|
| 89 | called mal.out .
|
---|
| 90 | Additionally a function
|
---|
| 91 | maldump(n) int n;
|
---|
| 92 | will be defined, which will dump
|
---|
| 93 | pertinent info in pseudo-readable
|
---|
| 94 | form; it aborts afterwards if n != 0.
|
---|
| 95 | */
|
---|
| 96 |
|
---|
| 97 | # undef EXTERN /* If defined, all static names will
|
---|
| 98 | become extern, which is a help in
|
---|
| 99 | using adb(1) or prof(1)
|
---|
| 100 | */
|
---|
| 101 |
|
---|
| 102 | # define STORE /* If defined, separate free lists will
|
---|
| 103 | be kept of chunks with small sizes,
|
---|
| 104 | to speed things up a little.
|
---|
| 105 | */
|
---|
| 106 |
|
---|
| 107 | # undef SYSTEM /* If defined, the system module is used.
|
---|
| 108 | Otherwise, "sbrk" is called directly.
|
---|
| 109 | */
|
---|
| 110 |
|
---|
| 111 | #define ALIGNMENT 8
|
---|
| 112 | /* alignment common to all types */
|
---|
| 113 | #define LOG_MIN_SIZE 3
|
---|
| 114 | #define LOG_MAX_SIZE 24
|
---|
| 115 |
|
---|
| 116 |
|
---|
| 117 | /**********************************************************/
|
---|
| 118 | /*
|
---|
| 119 | /* This was file impl.h
|
---|
| 120 | /*
|
---|
| 121 | /**********************************************************/
|
---|
| 122 |
|
---|
| 123 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
| 124 | /*
|
---|
| 125 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
| 126 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
| 127 | */
|
---|
| 128 | /* This file essentially describes how the mallink info block
|
---|
| 129 | is implemented.
|
---|
| 130 | */
|
---|
| 131 |
|
---|
| 132 | #define MIN_SIZE (1<<LOG_MIN_SIZE)
|
---|
| 133 | #define MAX_FLIST (LOG_MAX_SIZE - LOG_MIN_SIZE)
|
---|
| 134 | #if ALIGNMENT != 4 && ALIGNMENT != 8 && ALIGNMENT != 16
|
---|
| 135 | #error ALIGNMENT must be 4, 8 or 16
|
---|
| 136 | #elif ALIGNMENT % _EM_LSIZE
|
---|
| 137 | /* since calloc() does it's initialization in longs */
|
---|
| 138 | #error ALIGNMENT must be a multiple of the long size
|
---|
| 139 | #endif
|
---|
| 140 | #define align(n) (((n) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
|
---|
| 141 |
|
---|
| 142 | union _inf {
|
---|
| 143 | union _inf *ptr;
|
---|
| 144 | size_type ui;
|
---|
| 145 | };
|
---|
| 146 |
|
---|
| 147 | typedef union _inf mallink;
|
---|
| 148 | #define MAL_NULL ((mallink *)0)
|
---|
| 149 |
|
---|
| 150 | /* Access macros; only these macros know where to find values.
|
---|
| 151 | They are also lvalues.
|
---|
| 152 | */
|
---|
| 153 | #ifndef NON_STANDARD
|
---|
| 154 | #define OFF_SET 0
|
---|
| 155 | #else /* def NON_STANDARD */
|
---|
| 156 | #define OFF_SET 2
|
---|
| 157 | #endif /* NON_STANDARD */
|
---|
| 158 |
|
---|
| 159 | #define _log_prev_of(ml) ((ml)[-1+OFF_SET]).ptr
|
---|
| 160 | #define _log_next_of(ml) ((ml)[-2+OFF_SET]).ptr
|
---|
| 161 | #define _phys_prev_of(ml) ((ml)[-3+OFF_SET]).ptr
|
---|
| 162 | #define _this_size_of(ml) ((ml)[-4+OFF_SET]).ui
|
---|
| 163 | #ifndef CHECK
|
---|
| 164 | #define N_WORDS 4
|
---|
| 165 | #else /* ifdef CHECK */
|
---|
| 166 | #define _checksum_of(ml) ((ml)[-5+OFF_SET]).ui
|
---|
| 167 | #define _print_of(ml) ((ml)[-6+OFF_SET]).ui
|
---|
| 168 | #define _mark_of(ml) ((ml)[-7+OFF_SET]).ui
|
---|
| 169 | #define N_WORDS 7
|
---|
| 170 | #endif /* CHECK */
|
---|
| 171 |
|
---|
| 172 | #define mallink_size() (size_t) \
|
---|
| 173 | align((N_WORDS - OFF_SET) * sizeof (mallink))
|
---|
| 174 |
|
---|
| 175 | #ifdef CHECK
|
---|
| 176 | #define set_mark(ml,e) (_mark_of(ml) = (e))
|
---|
| 177 | #define mark_of(ml) (_mark_of(ml))
|
---|
| 178 |
|
---|
| 179 | #define set_checksum(ml,e) (_checksum_of(ml) = (e))
|
---|
| 180 | #define checksum_of(ml) (_checksum_of(ml))
|
---|
| 181 | #endif /* CHECK */
|
---|
| 182 |
|
---|
| 183 | #define new_mallink(ml) ( _log_prev_of(ml) = 0, \
|
---|
| 184 | _log_next_of(ml) = 0, \
|
---|
| 185 | _phys_prev_of(ml) = 0, \
|
---|
| 186 | _this_size_of(ml) = 0 )
|
---|
| 187 |
|
---|
| 188 | #define block_of_mallink(ml) ((void *)ml)
|
---|
| 189 | #define mallink_of_block(addr) ((mallink *)addr)
|
---|
| 190 |
|
---|
| 191 | #define public extern
|
---|
| 192 | #define publicdata extern
|
---|
| 193 | #ifndef EXTERN
|
---|
| 194 | #define private static
|
---|
| 195 | #define privatedata static
|
---|
| 196 | #else /* def EXTERN */
|
---|
| 197 | #define private extern
|
---|
| 198 | #define privatedata
|
---|
| 199 | #endif /* EXTERN */
|
---|
| 200 |
|
---|
| 201 | #ifdef ASSERT
|
---|
| 202 | private m_assert(const char *fn, int ln);
|
---|
| 203 | #define assert(b) (!(b) ? m_assert(__FILE__, __LINE__) : 0)
|
---|
| 204 | #else /* ndef ASSERT */
|
---|
| 205 | #define assert(b) 0
|
---|
| 206 | #endif /* ASSERT */
|
---|
| 207 |
|
---|
| 208 |
|
---|
| 209 | /**********************************************************/
|
---|
| 210 | /*
|
---|
| 211 | /* This was file check.h
|
---|
| 212 | /*
|
---|
| 213 | /**********************************************************/
|
---|
| 214 |
|
---|
| 215 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
| 216 | /*
|
---|
| 217 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
| 218 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
| 219 | */
|
---|
| 220 | #ifdef CHECK
|
---|
| 221 |
|
---|
| 222 | private check_mallinks(const char *s), calc_checksum(mallink *ml);
|
---|
| 223 | private check_work_empty(const char *s);
|
---|
| 224 | private started_working_on(mallink *ml), stopped_working_on(mallink *ml);
|
---|
| 225 |
|
---|
| 226 | #else /* ifndef CHECK */
|
---|
| 227 |
|
---|
| 228 | #define maldump(n) abort()
|
---|
| 229 | #define check_mallinks(s) 0
|
---|
| 230 | #define calc_checksum(ml) 0
|
---|
| 231 | #define started_working_on(ml) 0
|
---|
| 232 | #define stopped_working_on(ml) 0
|
---|
| 233 | #define check_work_empty(s) 0
|
---|
| 234 |
|
---|
| 235 | #endif /* CHECK */
|
---|
| 236 |
|
---|
| 237 |
|
---|
| 238 | /**********************************************************/
|
---|
| 239 | /*
|
---|
| 240 | /* This was file log.h
|
---|
| 241 | /*
|
---|
| 242 | /**********************************************************/
|
---|
| 243 |
|
---|
| 244 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
| 245 | /*
|
---|
| 246 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
| 247 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
| 248 | */
|
---|
| 249 | /* Algorithms to manipulate the doubly-linked lists of free
|
---|
| 250 | chunks.
|
---|
| 251 | */
|
---|
| 252 |
|
---|
| 253 | private link_free_chunk(mallink *ml), unlink_free_chunk(mallink *ml);
|
---|
| 254 | private mallink *first_present(int class);
|
---|
| 255 | private mallink *search_free_list(int class, size_t n);
|
---|
| 256 |
|
---|
| 257 | #ifdef STORE
|
---|
| 258 | #define in_store(ml) ((size_type)_phys_prev_of(ml) & STORE_BIT)
|
---|
| 259 | #define set_store(ml, e) \
|
---|
| 260 | (_phys_prev_of(ml) = (mallink *) \
|
---|
| 261 | ((e) ? (size_type) _phys_prev_of(ml) | STORE_BIT : \
|
---|
| 262 | (size_type) _phys_prev_of(ml) & ~STORE_BIT))
|
---|
| 263 | #endif
|
---|
| 264 | #define set_log_prev(ml,e) (_log_prev_of(ml) = (e))
|
---|
| 265 | #define log_prev_of(ml) (mallink *) (_log_prev_of(ml))
|
---|
| 266 |
|
---|
| 267 | #define set_log_next(ml,e) (_log_next_of(ml) = (e))
|
---|
| 268 | #define log_next_of(ml) (mallink *) (_log_next_of(ml))
|
---|
| 269 |
|
---|
| 270 |
|
---|
| 271 |
|
---|
| 272 | /**********************************************************/
|
---|
| 273 | /*
|
---|
| 274 | /* This was file phys.h
|
---|
| 275 | /*
|
---|
| 276 | /**********************************************************/
|
---|
| 277 |
|
---|
| 278 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
| 279 | /*
|
---|
| 280 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
| 281 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
| 282 | */
|
---|
| 283 | /* Algorithms to manipulate the doubly-linked list of physical
|
---|
| 284 | chunks.
|
---|
| 285 | */
|
---|
| 286 | privatedata mallink *ml_last;
|
---|
| 287 |
|
---|
| 288 | #define FREE_BIT 01
|
---|
| 289 | #ifdef STORE
|
---|
| 290 | #define STORE_BIT 02
|
---|
| 291 | #define BITS (FREE_BIT|STORE_BIT)
|
---|
| 292 | #else
|
---|
| 293 | #define BITS (FREE_BIT)
|
---|
| 294 | #endif
|
---|
| 295 |
|
---|
| 296 | #define __bits(ml) ((int)((size_type)_phys_prev_of(ml) & BITS))
|
---|
| 297 | #define __free_of(ml) ((int)((size_type)_phys_prev_of(ml) & FREE_BIT))
|
---|
| 298 | #define __phys_prev_of(ml) ((mallink *)((size_type)_phys_prev_of(ml) & ~BITS))
|
---|
| 299 | #define prev_size_of(ml) ((char *)(ml) - \
|
---|
| 300 | (char *)__phys_prev_of(ml) - \
|
---|
| 301 | mallink_size() \
|
---|
| 302 | )
|
---|
| 303 | #define set_phys_prev(ml,e) \
|
---|
| 304 | (_phys_prev_of(ml) = (mallink *) ((char *)e + __bits(ml)))
|
---|
| 305 |
|
---|
| 306 | #ifdef CHECK
|
---|
| 307 | private Error(const char *fmt, const char *s, mallink *ml);
|
---|
| 308 | #define phys_prev_of(ml) (mallink *) \
|
---|
| 309 | (first_mallink(ml) ? \
|
---|
| 310 | (char *)Error("phys_prev_of first_mallink %p", "somewhere", ml) : \
|
---|
| 311 | (char *)__phys_prev_of(ml) \
|
---|
| 312 | )
|
---|
| 313 | #else /* ndef CHECK */
|
---|
| 314 | #define phys_prev_of(ml) __phys_prev_of(ml)
|
---|
| 315 | #endif /* CHECK */
|
---|
| 316 |
|
---|
| 317 | #define first_mallink(ml) (int) (__phys_prev_of(ml) == 0)
|
---|
| 318 | #define last_mallink(ml) (int) ((ml) == ml_last)
|
---|
| 319 |
|
---|
| 320 | /* There is an ambiguity in the semantics of phys_next_of: sometimes
|
---|
| 321 | one wants it to return MAL_NULL if there is no next chunk, at
|
---|
| 322 | other times one wants the address of the virtual chunk at the
|
---|
| 323 | end of memory. The present version returns the address of the
|
---|
| 324 | (virtual) chunk and relies on the user to test last_mallink(ml)
|
---|
| 325 | first.
|
---|
| 326 | */
|
---|
| 327 | #define size_of(ml) (_this_size_of(ml) - mallink_size())
|
---|
| 328 | #define set_phys_next(ml,e) \
|
---|
| 329 | (_this_size_of(ml) = (size_type)((char *)(e) - (char *)(ml)))
|
---|
| 330 | #define phys_next_of(ml) (mallink *) ((char *)(ml) + _this_size_of(ml))
|
---|
| 331 |
|
---|
| 332 | #define set_free(ml,e) \
|
---|
| 333 | (_phys_prev_of(ml) = (mallink *) \
|
---|
| 334 | ((e) ? (size_type) _phys_prev_of(ml) | FREE_BIT : \
|
---|
| 335 | (size_type) _phys_prev_of(ml) & ~FREE_BIT))
|
---|
| 336 | #define free_of(ml) (__free_of(ml))
|
---|
| 337 |
|
---|
| 338 | #define coalesce_forw(ml,nxt) ( unlink_free_chunk(nxt), \
|
---|
| 339 | combine_chunks((ml), (nxt)))
|
---|
| 340 |
|
---|
| 341 | #define coalesce_backw(ml,prv) ( unlink_free_chunk(prv), \
|
---|
| 342 | stopped_working_on(ml), \
|
---|
| 343 | combine_chunks((prv), (ml)), \
|
---|
| 344 | started_working_on(prv))
|
---|
| 345 |
|
---|
| 346 | #ifdef CHECK
|
---|
| 347 | #define set_print(ml,e) (_print_of(ml) = (e))
|
---|
| 348 | #define print_of(ml) (_print_of(ml))
|
---|
| 349 | #endif /* CHECK */
|
---|
| 350 |
|
---|
| 351 | private truncate(mallink *ml, size_t size);
|
---|
| 352 | private combine_chunks(register mallink *ml1, register mallink *ml2);
|
---|
| 353 | private mallink *create_chunk(void *p, size_t n);
|
---|
| 354 |
|
---|
| 355 |
|
---|
| 356 | /**********************************************************/
|
---|
| 357 | /*
|
---|
| 358 | /* This was file mal.c
|
---|
| 359 | /*
|
---|
| 360 | /**********************************************************/
|
---|
| 361 |
|
---|
| 362 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
| 363 | /*
|
---|
| 364 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
| 365 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
| 366 | */
|
---|
| 367 | #include <limits.h>
|
---|
| 368 | #include <stdlib.h>
|
---|
| 369 |
|
---|
| 370 | /* Malloc space is traversed by N doubly-linked lists of chunks, each
|
---|
| 371 | containing a couple of house-keeping data addressed as a
|
---|
| 372 | 'mallink' and a piece of useful space, called the block.
|
---|
| 373 | The N lists are accessed through their starting pointers in
|
---|
| 374 | free_list[]. Free_list[n] points to a list of chunks between
|
---|
| 375 | 2**(n+LOG_MIN_SIZE) and 2**(n+LOG_MIN_SIZE+1)-1, which means
|
---|
| 376 | that the smallest chunk is 2**LOG_MIN_SIZE (== MIN_SIZE).
|
---|
| 377 | */
|
---|
| 378 |
|
---|
| 379 | #ifdef SYSTEM
|
---|
| 380 | #include <system.h>
|
---|
| 381 | #define SBRK sys_break
|
---|
| 382 | #else
|
---|
| 383 | #define SBRK _sbrk
|
---|
| 384 | #define ILL_BREAK (void *)(-1) /* funny failure value */
|
---|
| 385 | #endif
|
---|
| 386 | extern void *SBRK(int incr);
|
---|
| 387 | #ifdef STORE
|
---|
| 388 | #define MAX_STORE 32
|
---|
| 389 | private do_free(mallink *ml), sell_out(void);
|
---|
| 390 | privatedata mallink *store[MAX_STORE];
|
---|
| 391 | #endif /* STORE */
|
---|
| 392 |
|
---|
| 393 | void *privious_free= (void *)-1;
|
---|
| 394 | void *
|
---|
| 395 | malloc(register size_t n)
|
---|
| 396 | {check_mallinks("malloc entry");{
|
---|
| 397 | register mallink *ml;
|
---|
| 398 | register int min_class;
|
---|
| 399 | void *tmp;
|
---|
| 400 |
|
---|
| 401 | { static int reent= 0; if (!reent) { reent++; printf("malloc\n"); reent--; } }
|
---|
| 402 | privious_free= (void *)-1;
|
---|
| 403 | if (n == 0) {
|
---|
| 404 | return NULL;
|
---|
| 405 | }
|
---|
| 406 | if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
|
---|
| 407 | #ifdef STORE
|
---|
| 408 | if (n <= MAX_STORE*MIN_SIZE) {
|
---|
| 409 | /* look in the store first */
|
---|
| 410 | register mallink **stp = &store[(n >> LOG_MIN_SIZE) - 1];
|
---|
| 411 |
|
---|
| 412 | if (ml = *stp) {
|
---|
| 413 | *stp = log_next_of(ml);
|
---|
| 414 | set_store(ml, 0);
|
---|
| 415 | check_mallinks("malloc fast exit");
|
---|
| 416 | assert(! in_store(ml));
|
---|
| 417 | tmp= block_of_mallink(ml);
|
---|
| 418 | { static int reent= 0; if (!reent) { reent++; printf("= 0x%x\n", tmp);reent--; } }
|
---|
| 419 | return tmp;
|
---|
| 420 | }
|
---|
| 421 | }
|
---|
| 422 | #endif /* STORE */
|
---|
| 423 |
|
---|
| 424 | check_work_empty("malloc, entry");
|
---|
| 425 |
|
---|
| 426 | /* Acquire a chunk of at least size n if at all possible;
|
---|
| 427 | Try everything.
|
---|
| 428 | */
|
---|
| 429 | {
|
---|
| 430 | /* Inline substitution of "smallest".
|
---|
| 431 | */
|
---|
| 432 | register size_t n1 = n;
|
---|
| 433 |
|
---|
| 434 | assert(n1 < (1L << LOG_MAX_SIZE));
|
---|
| 435 | min_class = 0;
|
---|
| 436 |
|
---|
| 437 | do {
|
---|
| 438 | n1 >>= 1;
|
---|
| 439 | min_class++;
|
---|
| 440 | } while (n1 >= MIN_SIZE);
|
---|
| 441 | }
|
---|
| 442 |
|
---|
| 443 | if (min_class >= MAX_FLIST)
|
---|
| 444 | return NULL; /* we don't deal in blocks that big */
|
---|
| 445 | ml = first_present(min_class);
|
---|
| 446 | if (ml == MAL_NULL) {
|
---|
| 447 | /* Try and extend */
|
---|
| 448 | register void *p;
|
---|
| 449 | #define GRABSIZE 4096 /* Power of 2 */
|
---|
| 450 | register size_t req =
|
---|
| 451 | ((MIN_SIZE<<min_class)+ mallink_size() + GRABSIZE - 1) &
|
---|
| 452 | ~(GRABSIZE-1);
|
---|
| 453 |
|
---|
| 454 | if (!ml_last) {
|
---|
| 455 | /* first align SBRK() */
|
---|
| 456 |
|
---|
| 457 | p = SBRK(0);
|
---|
| 458 | SBRK((int) (align((size_type) p) - (size_type) p));
|
---|
| 459 | }
|
---|
| 460 |
|
---|
| 461 | /* SBRK takes an int; sorry ... */
|
---|
| 462 | if ((int) req < 0) {
|
---|
| 463 | p = ILL_BREAK;
|
---|
| 464 | } else {
|
---|
| 465 | p = SBRK((int)req);
|
---|
| 466 | }
|
---|
| 467 | if (p == ILL_BREAK) {
|
---|
| 468 | req = n + mallink_size();
|
---|
| 469 | if ((int) req >= 0) p = SBRK((int)req);
|
---|
| 470 | }
|
---|
| 471 | if (p == ILL_BREAK) {
|
---|
| 472 | /* Now this is bad. The system will not give us
|
---|
| 473 | more memory. We can only liquidate our store
|
---|
| 474 | and hope it helps.
|
---|
| 475 | */
|
---|
| 476 | #ifdef STORE
|
---|
| 477 | sell_out();
|
---|
| 478 | ml = first_present(min_class);
|
---|
| 479 | if (ml == MAL_NULL) {
|
---|
| 480 | #endif /* STORE */
|
---|
| 481 | /* In this emergency we try to locate a suitable
|
---|
| 482 | chunk in the free_list just below the safe
|
---|
| 483 | one; some of these chunks may fit the job.
|
---|
| 484 | */
|
---|
| 485 | ml = search_free_list(min_class - 1, n);
|
---|
| 486 | if (!ml) /* really out of space */
|
---|
| 487 | return NULL;
|
---|
| 488 | started_working_on(ml);
|
---|
| 489 | unlink_free_chunk(ml);
|
---|
| 490 | check_mallinks("suitable_chunk, forced");
|
---|
| 491 | #ifdef STORE
|
---|
| 492 | }
|
---|
| 493 | else started_working_on(ml);
|
---|
| 494 | #endif /* STORE */
|
---|
| 495 | }
|
---|
| 496 | else {
|
---|
| 497 | assert((size_type)p == align((size_type)p));
|
---|
| 498 | ml = create_chunk(p, req);
|
---|
| 499 | }
|
---|
| 500 | check_mallinks("suitable_chunk, extended");
|
---|
| 501 | }
|
---|
| 502 | else started_working_on(ml);
|
---|
| 503 |
|
---|
| 504 | /* we have a chunk */
|
---|
| 505 | set_free(ml, 0);
|
---|
| 506 | calc_checksum(ml);
|
---|
| 507 | check_mallinks("suitable_chunk, removed");
|
---|
| 508 | n += mallink_size();
|
---|
| 509 | if (n + MIN_SIZE <= size_of(ml)) {
|
---|
| 510 | truncate(ml, n);
|
---|
| 511 | }
|
---|
| 512 | stopped_working_on(ml);
|
---|
| 513 | check_mallinks("malloc exit");
|
---|
| 514 | check_work_empty("malloc exit");
|
---|
| 515 | #ifdef STORE
|
---|
| 516 | assert(! in_store(ml));
|
---|
| 517 | #endif
|
---|
| 518 | tmp= block_of_mallink(ml);
|
---|
| 519 | { static int reent= 0; if (!reent) { reent++; printf("= 0x%x\n", tmp);reent--; } }
|
---|
| 520 | return tmp;
|
---|
| 521 | }}
|
---|
| 522 |
|
---|
| 523 | void
|
---|
| 524 | free(void *addr)
|
---|
| 525 | {check_mallinks("free entry");{
|
---|
| 526 | register mallink *ml;
|
---|
| 527 |
|
---|
| 528 | printf("free 0x%x\n", addr);
|
---|
| 529 | if (privious_free == addr) { fflush(stdout); fflush(stderr); abort(); }
|
---|
| 530 | privious_free= addr;
|
---|
| 531 | if (addr == NULL) {
|
---|
| 532 | check_mallinks("free(0) very fast exit");
|
---|
| 533 | return;
|
---|
| 534 | }
|
---|
| 535 |
|
---|
| 536 | ml = mallink_of_block(addr);
|
---|
| 537 | #ifdef STORE
|
---|
| 538 |
|
---|
| 539 | if (free_of(ml) || in_store(ml))
|
---|
| 540 | return; /* user frees free block */
|
---|
| 541 | if (size_of(ml) <= MAX_STORE*MIN_SIZE) {
|
---|
| 542 | /* return to store */
|
---|
| 543 | mallink **stp = &store[(size_of(ml) >> LOG_MIN_SIZE) - 1];
|
---|
| 544 |
|
---|
| 545 | set_log_next(ml, *stp);
|
---|
| 546 | *stp = ml;
|
---|
| 547 | set_store(ml, 1);
|
---|
| 548 | calc_checksum(ml);
|
---|
| 549 | check_mallinks("free fast exit");
|
---|
| 550 | }
|
---|
| 551 | else {
|
---|
| 552 | do_free(ml);
|
---|
| 553 | check_mallinks("free exit");
|
---|
| 554 | }
|
---|
| 555 | }}
|
---|
| 556 |
|
---|
| 557 | private
|
---|
| 558 | do_free(register mallink *ml)
|
---|
| 559 | {{
|
---|
| 560 | #endif
|
---|
| 561 |
|
---|
| 562 | #ifndef STORE
|
---|
| 563 | if (free_of(ml)) return;
|
---|
| 564 | #endif /* STORE */
|
---|
| 565 | started_working_on(ml);
|
---|
| 566 | set_free(ml, 1);
|
---|
| 567 | calc_checksum(ml);
|
---|
| 568 | if (! last_mallink(ml)) {
|
---|
| 569 | register mallink *next = phys_next_of(ml);
|
---|
| 570 |
|
---|
| 571 | if (free_of(next)) coalesce_forw(ml, next);
|
---|
| 572 | }
|
---|
| 573 |
|
---|
| 574 | if (! first_mallink(ml)) {
|
---|
| 575 | register mallink *prev = phys_prev_of(ml);
|
---|
| 576 |
|
---|
| 577 | if (free_of(prev)) {
|
---|
| 578 | coalesce_backw(ml, prev);
|
---|
| 579 | ml = prev;
|
---|
| 580 | }
|
---|
| 581 | }
|
---|
| 582 | link_free_chunk(ml);
|
---|
| 583 | stopped_working_on(ml);
|
---|
| 584 | check_work_empty("free");
|
---|
| 585 |
|
---|
| 586 | /* Compile-time checks on param.h */
|
---|
| 587 | switch (0) {
|
---|
| 588 | case MIN_SIZE < OFF_SET * sizeof(mallink): break;
|
---|
| 589 | case 1: break;
|
---|
| 590 | /* If this statement does not compile due to duplicate case
|
---|
| 591 | entry, the minimum size block cannot hold the links for
|
---|
| 592 | the free blocks. Either raise LOG_MIN_SIZE or switch
|
---|
| 593 | off NON_STANDARD.
|
---|
| 594 | */
|
---|
| 595 | }
|
---|
| 596 | switch(0) {
|
---|
| 597 | case sizeof(void *) != sizeof(size_type): break;
|
---|
| 598 | case 1: break;
|
---|
| 599 | /* If this statement does not compile due to duplicate
|
---|
| 600 | case entry, size_type is not defined correctly.
|
---|
| 601 | Redefine and compile again.
|
---|
| 602 | */
|
---|
| 603 | }
|
---|
| 604 | }}
|
---|
| 605 |
|
---|
| 606 | void *
|
---|
| 607 | realloc(void *addr, register size_t n)
|
---|
| 608 | {check_mallinks("realloc entry");{
|
---|
| 609 | register mallink *ml, *ph_next;
|
---|
| 610 | register size_type size;
|
---|
| 611 |
|
---|
| 612 | printf("realloc 0x%x, %d\n", addr, n);
|
---|
| 613 | if (addr == NULL) {
|
---|
| 614 | /* Behave like most Unix realloc's when handed a
|
---|
| 615 | null-pointer
|
---|
| 616 | */
|
---|
| 617 | return malloc(n);
|
---|
| 618 | }
|
---|
| 619 | if (n == 0) {
|
---|
| 620 | free(addr);
|
---|
| 621 | return NULL;
|
---|
| 622 | }
|
---|
| 623 | ml = mallink_of_block(addr);
|
---|
| 624 | if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
|
---|
| 625 | #ifdef STORE
|
---|
| 626 | if (in_store(ml)) {
|
---|
| 627 | register mallink *stp = store[(size_of(ml) >> LOG_MIN_SIZE) - 1];
|
---|
| 628 | mallink *stp1 = NULL;
|
---|
| 629 | while (ml != stp) {
|
---|
| 630 | stp1 = stp;
|
---|
| 631 | stp = log_next_of(stp);
|
---|
| 632 | }
|
---|
| 633 | stp = log_next_of(stp);
|
---|
| 634 | if (! stp1) store[(size_of(ml) >> LOG_MIN_SIZE) - 1] = stp;
|
---|
| 635 | else set_log_next(stp1, stp);
|
---|
| 636 | set_store(ml, 0);
|
---|
| 637 | calc_checksum(ml);
|
---|
| 638 | }
|
---|
| 639 | #endif
|
---|
| 640 | if (free_of(ml)) {
|
---|
| 641 | unlink_free_chunk(ml);
|
---|
| 642 | set_free(ml, 0); /* user reallocs free block */
|
---|
| 643 | }
|
---|
| 644 | started_working_on(ml);
|
---|
| 645 | size = size_of(ml);
|
---|
| 646 | if ( /* we can simplify the problem by adding the next chunk: */
|
---|
| 647 | n > size &&
|
---|
| 648 | !last_mallink(ml) &&
|
---|
| 649 | (ph_next = phys_next_of(ml), free_of(ph_next)) &&
|
---|
| 650 | n <= size + mallink_size() + size_of(ph_next)
|
---|
| 651 | ) {
|
---|
| 652 | /* add in the physically next chunk */
|
---|
| 653 | unlink_free_chunk(ph_next);
|
---|
| 654 | combine_chunks(ml, ph_next);
|
---|
| 655 | size = size_of(ml);
|
---|
| 656 | check_mallinks("realloc, combining");
|
---|
| 657 | }
|
---|
| 658 | if (n > size) { /* this didn't help */
|
---|
| 659 | void *new;
|
---|
| 660 | register char *l1, *l2 = addr;
|
---|
| 661 |
|
---|
| 662 | stopped_working_on(ml);
|
---|
| 663 | if (!(new = l1 = malloc(n))) return NULL; /* no way */
|
---|
| 664 | while (size--) *l1++ = *l2++;
|
---|
| 665 | free(addr);
|
---|
| 666 | check_work_empty("mv_realloc");
|
---|
| 667 | #ifdef STORE
|
---|
| 668 | assert(! in_store(mallink_of_block(new)));
|
---|
| 669 | #endif
|
---|
| 670 | return new;
|
---|
| 671 | }
|
---|
| 672 | /* it helped, but maybe too well */
|
---|
| 673 | n += mallink_size();
|
---|
| 674 | if (n + MIN_SIZE <= size_of(ml)) {
|
---|
| 675 | truncate(ml, n);
|
---|
| 676 | }
|
---|
| 677 | stopped_working_on(ml);
|
---|
| 678 | check_mallinks("realloc exit");
|
---|
| 679 | check_work_empty("realloc");
|
---|
| 680 | #ifdef STORE
|
---|
| 681 | assert(! in_store(ml));
|
---|
| 682 | #endif
|
---|
| 683 | return addr;
|
---|
| 684 | }}
|
---|
| 685 |
|
---|
| 686 | void *
|
---|
| 687 | calloc(size_t nmemb, size_t size)
|
---|
| 688 | {check_mallinks("calloc entry");{
|
---|
| 689 | long *l1, *l2;
|
---|
| 690 | size_t n;
|
---|
| 691 |
|
---|
| 692 | printf("calloc\n");
|
---|
| 693 | if (size == 0) return NULL;
|
---|
| 694 | if (nmemb == 0) return NULL;
|
---|
| 695 |
|
---|
| 696 | /* Check for overflow on the multiplication. The peephole-optimizer
|
---|
| 697 | * will eliminate all but one of the possibilities.
|
---|
| 698 | */
|
---|
| 699 | if (sizeof(size_t) == sizeof(int)) {
|
---|
| 700 | if (UINT_MAX / size < nmemb) return NULL;
|
---|
| 701 | } else if (sizeof(size_t) == sizeof(long)) {
|
---|
| 702 | if (ULONG_MAX / size < nmemb) return NULL;
|
---|
| 703 | } else return NULL; /* can't happen, can it ? */
|
---|
| 704 |
|
---|
| 705 | n = size * nmemb;
|
---|
| 706 | if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
|
---|
| 707 | if (n >= (1L << LOG_MAX_SIZE)) return NULL;
|
---|
| 708 | l1 = (long *) malloc(n);
|
---|
| 709 | l2 = l1 + (n / sizeof(long)); /* n is at least long aligned */
|
---|
| 710 | while ( l2 != l1 ) *--l2 = 0;
|
---|
| 711 | check_mallinks("calloc exit");
|
---|
| 712 | check_work_empty("calloc exit");
|
---|
| 713 | return (void *)l1;
|
---|
| 714 | }}
|
---|
| 715 | /* Auxiliary routines */
|
---|
| 716 |
|
---|
| 717 | #ifdef STORE
|
---|
| 718 | private
|
---|
| 719 | sell_out(void) {
|
---|
| 720 | /* Frees all block in store.
|
---|
| 721 | */
|
---|
| 722 | register mallink **stp;
|
---|
| 723 |
|
---|
| 724 | for (stp = &store[0]; stp < &store[MAX_STORE]; stp++) {
|
---|
| 725 | register mallink *ml = *stp;
|
---|
| 726 |
|
---|
| 727 | while (ml) {
|
---|
| 728 | *stp = log_next_of(ml);
|
---|
| 729 | set_store(ml, 0);
|
---|
| 730 | do_free(ml);
|
---|
| 731 | ml = *stp;
|
---|
| 732 | }
|
---|
| 733 | }
|
---|
| 734 |
|
---|
| 735 | }
|
---|
| 736 | #endif /* STORE */
|
---|
| 737 |
|
---|
| 738 | #ifdef ASSERT
|
---|
| 739 | private
|
---|
| 740 | m_assert(const char *fn, int ln)
|
---|
| 741 | {
|
---|
| 742 | char ch;
|
---|
| 743 |
|
---|
| 744 | while (*fn)
|
---|
| 745 | write(2, fn++, 1);
|
---|
| 746 | write(2, ": malloc assert failed in line ", 31);
|
---|
| 747 | ch = (ln / 100) + '0'; write(2, &ch, 1); ln %= 100;
|
---|
| 748 | ch = (ln / 10) + '0'; write(2, &ch, 1); ln %= 10;
|
---|
| 749 | ch = (ln / 1) + '0'; write(2, &ch, 1);
|
---|
| 750 | write(2, "\n", 1);
|
---|
| 751 | maldump(1);
|
---|
| 752 | }
|
---|
| 753 | #endif /* ASSERT */
|
---|
| 754 |
|
---|
| 755 |
|
---|
| 756 | /**********************************************************/
|
---|
| 757 | /*
|
---|
| 758 | /* This was file log.c
|
---|
| 759 | /*
|
---|
| 760 | /**********************************************************/
|
---|
| 761 |
|
---|
| 762 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
| 763 | /*
|
---|
| 764 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
| 765 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
| 766 | */
|
---|
| 767 |
|
---|
| 768 | /* Logical manipulations.
|
---|
| 769 | The chunks are properly chained in the physical chain.
|
---|
| 770 | */
|
---|
| 771 |
|
---|
| 772 | privatedata mallink *free_list[MAX_FLIST];
|
---|
| 773 |
|
---|
| 774 | private
|
---|
| 775 | link_free_chunk(register mallink *ml)
|
---|
| 776 | {
|
---|
| 777 | /* The free chunk ml is inserted in its proper logical
|
---|
| 778 | chain.
|
---|
| 779 | */
|
---|
| 780 | register mallink **mlp = &free_list[-1];
|
---|
| 781 | register size_type n = size_of(ml);
|
---|
| 782 | register mallink *ml1;
|
---|
| 783 |
|
---|
| 784 | assert(n < (1L << LOG_MAX_SIZE));
|
---|
| 785 |
|
---|
| 786 | do {
|
---|
| 787 | n >>= 1;
|
---|
| 788 | mlp++;
|
---|
| 789 | }
|
---|
| 790 | while (n >= MIN_SIZE);
|
---|
| 791 |
|
---|
| 792 | ml1 = *mlp;
|
---|
| 793 | set_log_prev(ml, MAL_NULL);
|
---|
| 794 | set_log_next(ml, ml1);
|
---|
| 795 | calc_checksum(ml);
|
---|
| 796 | if (ml1) {
|
---|
| 797 | /* link backwards
|
---|
| 798 | */
|
---|
| 799 | set_log_prev(ml1, ml);
|
---|
| 800 | calc_checksum(ml1);
|
---|
| 801 | }
|
---|
| 802 | *mlp = ml;
|
---|
| 803 | }
|
---|
| 804 |
|
---|
| 805 | private
|
---|
| 806 | unlink_free_chunk(register mallink *ml)
|
---|
| 807 | {
|
---|
| 808 | /* Unlinks a free chunk from (the middle of) the
|
---|
| 809 | logical chain.
|
---|
| 810 | */
|
---|
| 811 | register mallink *next = log_next_of(ml);
|
---|
| 812 | register mallink *prev = log_prev_of(ml);
|
---|
| 813 |
|
---|
| 814 | if (!prev) {
|
---|
| 815 | /* it is the first in the chain */
|
---|
| 816 | register mallink **mlp = &free_list[-1];
|
---|
| 817 | register size_type n = size_of(ml);
|
---|
| 818 |
|
---|
| 819 | assert(n < (1L << LOG_MAX_SIZE));
|
---|
| 820 | do {
|
---|
| 821 | n >>= 1;
|
---|
| 822 | mlp++;
|
---|
| 823 | }
|
---|
| 824 | while (n >= MIN_SIZE);
|
---|
| 825 | *mlp = next;
|
---|
| 826 | }
|
---|
| 827 | else {
|
---|
| 828 | set_log_next(prev, next);
|
---|
| 829 | calc_checksum(prev);
|
---|
| 830 | }
|
---|
| 831 | if (next) {
|
---|
| 832 | set_log_prev(next, prev);
|
---|
| 833 | calc_checksum(next);
|
---|
| 834 | }
|
---|
| 835 | }
|
---|
| 836 |
|
---|
| 837 | private mallink *
|
---|
| 838 | search_free_list(int class, size_t n)
|
---|
| 839 | {
|
---|
| 840 | /* Searches the free_list[class] for a chunk of at least size n;
|
---|
| 841 | since it is searching a slightly undersized list,
|
---|
| 842 | such a block may not be there.
|
---|
| 843 | */
|
---|
| 844 | register mallink *ml;
|
---|
| 845 |
|
---|
| 846 | for (ml = free_list[class]; ml; ml = log_next_of(ml))
|
---|
| 847 | if (size_of(ml) >= n)
|
---|
| 848 | return ml;
|
---|
| 849 | return MAL_NULL; /* nothing found */
|
---|
| 850 | }
|
---|
| 851 |
|
---|
| 852 | private mallink *
|
---|
| 853 | first_present(int class)
|
---|
| 854 | {
|
---|
| 855 | /* Find the index i in free_list[] such that:
|
---|
| 856 | i >= class && free_list[i] != MAL_NULL.
|
---|
| 857 | Return MAL_NULL if no such i exists;
|
---|
| 858 | Otherwise, return the first block of this list, after
|
---|
| 859 | unlinking it.
|
---|
| 860 | */
|
---|
| 861 | register mallink **mlp, *ml;
|
---|
| 862 |
|
---|
| 863 | for (mlp = &free_list[class]; mlp < &free_list[MAX_FLIST]; mlp++) {
|
---|
| 864 | if ((ml = *mlp) != MAL_NULL) {
|
---|
| 865 |
|
---|
| 866 | *mlp = log_next_of(ml); /* may be MAL_NULL */
|
---|
| 867 | if (*mlp) {
|
---|
| 868 | /* unhook backward link
|
---|
| 869 | */
|
---|
| 870 | set_log_prev(*mlp, MAL_NULL);
|
---|
| 871 | calc_checksum(*mlp);
|
---|
| 872 | }
|
---|
| 873 | return ml;
|
---|
| 874 | }
|
---|
| 875 | }
|
---|
| 876 | return MAL_NULL;
|
---|
| 877 | }
|
---|
| 878 |
|
---|
| 879 | #ifdef CHECK
|
---|
| 880 | private mallink *
|
---|
| 881 | free_list_entry(int i) {
|
---|
| 882 | /* To allow maldump.c access to log.c's private data.
|
---|
| 883 | */
|
---|
| 884 | return free_list[i];
|
---|
| 885 | }
|
---|
| 886 | #endif /* CHECK */
|
---|
| 887 |
|
---|
| 888 |
|
---|
| 889 | /**********************************************************/
|
---|
| 890 | /*
|
---|
| 891 | /* This was file phys.c
|
---|
| 892 | /*
|
---|
| 893 | /**********************************************************/
|
---|
| 894 |
|
---|
| 895 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
| 896 | /*
|
---|
| 897 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
| 898 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
| 899 | */
|
---|
| 900 | #include <stdlib.h>
|
---|
| 901 |
|
---|
| 902 | /* Physical manipulations.
|
---|
| 903 | The blocks concerned are not in any logical chain.
|
---|
| 904 | */
|
---|
| 905 |
|
---|
| 906 | private mallink *
|
---|
| 907 | create_chunk(void *p, size_t n)
|
---|
| 908 | {
|
---|
| 909 | /* The newly acquired piece of memory at p, of length n,
|
---|
| 910 | is turned into a free chunk, properly chained in the
|
---|
| 911 | physical chain.
|
---|
| 912 | The address of the chunk is returned.
|
---|
| 913 | */
|
---|
| 914 | register mallink *ml;
|
---|
| 915 | /* All of malloc memory is followed by a virtual chunk, the
|
---|
| 916 | mallink of which starts mallink_size() bytes past the last
|
---|
| 917 | byte in memory.
|
---|
| 918 | Its use is prevented by testing for ml == ml_last first.
|
---|
| 919 | */
|
---|
| 920 | register mallink *last = ml_last;
|
---|
| 921 |
|
---|
| 922 | assert(!last || p == (char *)phys_next_of(last) - mallink_size());
|
---|
| 923 | ml = (mallink *)((char *)p + mallink_size()); /* bump ml */
|
---|
| 924 | new_mallink(ml);
|
---|
| 925 | started_working_on(ml);
|
---|
| 926 | set_free(ml, 1);
|
---|
| 927 | set_phys_prev(ml, last);
|
---|
| 928 | ml_last = ml;
|
---|
| 929 |
|
---|
| 930 | set_phys_next(ml, (mallink *)((char *)ml + n));
|
---|
| 931 | calc_checksum(ml);
|
---|
| 932 | assert(size_of(ml) + mallink_size() == n);
|
---|
| 933 | if (last && free_of(last)) {
|
---|
| 934 | coalesce_backw(ml, last);
|
---|
| 935 | ml = last;
|
---|
| 936 | }
|
---|
| 937 | check_mallinks("create_chunk, phys. linked");
|
---|
| 938 | return ml;
|
---|
| 939 | }
|
---|
| 940 |
|
---|
| 941 | private
|
---|
| 942 | truncate(register mallink *ml, size_t size)
|
---|
| 943 | {
|
---|
| 944 | /* The chunk ml is truncated.
|
---|
| 945 | The chunk at ml is split in two.
|
---|
| 946 | The remaining part is then freed.
|
---|
| 947 | */
|
---|
| 948 | register mallink *new = (mallink *)((char *)ml + size);
|
---|
| 949 | register mallink *ph_next = phys_next_of(ml);
|
---|
| 950 |
|
---|
| 951 | new_mallink(new);
|
---|
| 952 | set_free(new, 1);
|
---|
| 953 | set_phys_prev(new, ml);
|
---|
| 954 | set_phys_next(new, ph_next);
|
---|
| 955 | calc_checksum(new);
|
---|
| 956 | if (! last_mallink(ml)) {
|
---|
| 957 | set_phys_prev(ph_next, new);
|
---|
| 958 | calc_checksum(ph_next);
|
---|
| 959 | if (free_of(ph_next)) coalesce_forw(new, ph_next);
|
---|
| 960 | }
|
---|
| 961 | else ml_last = new;
|
---|
| 962 | set_phys_next(ml, new);
|
---|
| 963 | calc_checksum(ml);
|
---|
| 964 |
|
---|
| 965 | started_working_on(new);
|
---|
| 966 | link_free_chunk(new);
|
---|
| 967 | stopped_working_on(new);
|
---|
| 968 | check_mallinks("truncate");
|
---|
| 969 | }
|
---|
| 970 |
|
---|
| 971 | private
|
---|
| 972 | combine_chunks(register mallink *ml1, register mallink *ml2)
|
---|
| 973 | {
|
---|
| 974 | /* The chunks ml1 and ml2 are combined.
|
---|
| 975 | */
|
---|
| 976 | register mallink *ml3 = phys_next_of(ml2);
|
---|
| 977 |
|
---|
| 978 | set_phys_next(ml1, ml3);
|
---|
| 979 | calc_checksum(ml1);
|
---|
| 980 | if (!last_mallink(ml2)) {
|
---|
| 981 | set_phys_prev(ml3, ml1);
|
---|
| 982 | calc_checksum(ml3);
|
---|
| 983 | }
|
---|
| 984 | if (ml_last == ml2)
|
---|
| 985 | ml_last = ml1;
|
---|
| 986 | }
|
---|
| 987 |
|
---|
| 988 |
|
---|
| 989 | /**********************************************************/
|
---|
| 990 | /*
|
---|
| 991 | /* This was file check.c
|
---|
| 992 | /*
|
---|
| 993 | /**********************************************************/
|
---|
| 994 |
|
---|
| 995 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
| 996 | /*
|
---|
| 997 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
| 998 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
| 999 | */
|
---|
| 1000 | #include <stdio.h>
|
---|
| 1001 |
|
---|
| 1002 | #ifdef CHECK /* otherwise this whole file is skipped */
|
---|
| 1003 |
|
---|
| 1004 | /* ??? check these later */
|
---|
| 1005 | private acquire_malout(void), check_ml_last(const char *s);
|
---|
| 1006 | private dump_all_mallinks(void), dump_free_list(int i);
|
---|
| 1007 | private dump_mallink(const char *s, mallink *ml), print_loop(mallink *ml);
|
---|
| 1008 | private working_on(mallink *ml);
|
---|
| 1009 | private size_type checksum(mallink *ml);
|
---|
| 1010 | static FILE *malout;
|
---|
| 1011 |
|
---|
| 1012 | private mallink *free_list_entry(int i);
|
---|
| 1013 |
|
---|
| 1014 | #define for_free_list(i,p) \
|
---|
| 1015 | for (p = free_list_entry(i); p; p = log_next_of(p))
|
---|
| 1016 |
|
---|
| 1017 | #define for_all_mallinks(ml) /* backwards! */ \
|
---|
| 1018 | for (ml = ml_last; ml; \
|
---|
| 1019 | ml = first_mallink(ml) ? MAL_NULL : phys_prev_of(ml))
|
---|
| 1020 |
|
---|
| 1021 | /* Maldump */
|
---|
| 1022 |
|
---|
| 1023 | static int pr_cnt = 0;
|
---|
| 1024 |
|
---|
| 1025 | maldump(int n) {
|
---|
| 1026 | /* Dump pertinent info in pseudo-readable format;
|
---|
| 1027 | abort afterwards if n != 0.
|
---|
| 1028 | */
|
---|
| 1029 | static int dumping = 0;
|
---|
| 1030 | int i;
|
---|
| 1031 |
|
---|
| 1032 | if (dumping)
|
---|
| 1033 | return;
|
---|
| 1034 | dumping++;
|
---|
| 1035 | acquire_malout();
|
---|
| 1036 | fprintf(malout,
|
---|
| 1037 | ">>>>>>>>>>>>>>>> DUMP OF ALL MALLINKS <<<<<<<<<<<<<<<<");
|
---|
| 1038 | fprintf(malout, " ml_last = %p\n", ml_last);
|
---|
| 1039 | if (++pr_cnt == 100) pr_cnt = 0;
|
---|
| 1040 | dump_all_mallinks();
|
---|
| 1041 | fprintf(malout,
|
---|
| 1042 | ">>>>>>>>>>>>>>>> DUMP OF FREE_LISTS <<<<<<<<<<<<<<<<\n");
|
---|
| 1043 | if (++pr_cnt == 100) pr_cnt = 0;
|
---|
| 1044 | for (i = 0; i < MAX_FLIST; i++)
|
---|
| 1045 | dump_free_list(i);
|
---|
| 1046 | fprintf(malout,
|
---|
| 1047 | ">>>>>>>>>>>>>>>> END OF DUMP <<<<<<<<<<<<<<<<\n");
|
---|
| 1048 | fclose(malout);
|
---|
| 1049 | dumping--;
|
---|
| 1050 | if (n)
|
---|
| 1051 | abort();
|
---|
| 1052 | }
|
---|
| 1053 |
|
---|
| 1054 | private
|
---|
| 1055 | acquire_malout(void) {
|
---|
| 1056 | static char buf[BUFSIZ];
|
---|
| 1057 |
|
---|
| 1058 | if (!malout) {
|
---|
| 1059 | malout = freopen("mal.out", "w", stderr);
|
---|
| 1060 | setbuf(malout, buf);
|
---|
| 1061 | }
|
---|
| 1062 | }
|
---|
| 1063 |
|
---|
| 1064 | private
|
---|
| 1065 | dump_all_mallinks(void) {
|
---|
| 1066 | mallink *ml;
|
---|
| 1067 |
|
---|
| 1068 | for_all_mallinks (ml) {
|
---|
| 1069 | if (print_loop(ml))
|
---|
| 1070 | return;
|
---|
| 1071 | dump_mallink((char *)0, ml);
|
---|
| 1072 | }
|
---|
| 1073 | }
|
---|
| 1074 |
|
---|
| 1075 | private
|
---|
| 1076 | dump_free_list(int i) {
|
---|
| 1077 | mallink *ml = free_list_entry(i);
|
---|
| 1078 |
|
---|
| 1079 | if (!ml)
|
---|
| 1080 | return;
|
---|
| 1081 | fprintf(malout, "%2d: ", i);
|
---|
| 1082 | for_free_list(i, ml) {
|
---|
| 1083 | if (print_loop(ml))
|
---|
| 1084 | return;
|
---|
| 1085 | fprintf(malout, "%p ", ml);
|
---|
| 1086 | }
|
---|
| 1087 | fprintf(malout, "<\n");
|
---|
| 1088 | }
|
---|
| 1089 |
|
---|
| 1090 | private int
|
---|
| 1091 | print_loop(mallink *ml) {
|
---|
| 1092 | if (print_of(ml) == pr_cnt) {
|
---|
| 1093 | fprintf(malout, "... PRINT LOOP\n");
|
---|
| 1094 | return 1;
|
---|
| 1095 | }
|
---|
| 1096 | set_print(ml, pr_cnt);
|
---|
| 1097 | return 0;
|
---|
| 1098 | }
|
---|
| 1099 |
|
---|
| 1100 | private
|
---|
| 1101 | dump_mallink(const char *s, mallink *ml) {
|
---|
| 1102 | acquire_malout();
|
---|
| 1103 | if (s)
|
---|
| 1104 | fprintf(malout, "%s: ", s);
|
---|
| 1105 | fprintf(malout, "@: %p;", ml);
|
---|
| 1106 | if (ml && checksum_of(ml) != checksum(ml))
|
---|
| 1107 | fprintf(malout, ">>>> CORRUPTED <<<<");
|
---|
| 1108 | if (!ml) {
|
---|
| 1109 | fprintf(malout, "\n");
|
---|
| 1110 | return;
|
---|
| 1111 | }
|
---|
| 1112 | if (free_of(ml)) {
|
---|
| 1113 | fprintf(malout, " l_p: %p;", _log_prev_of(ml));
|
---|
| 1114 | fprintf(malout, " l_n: %p;", _log_next_of(ml));
|
---|
| 1115 | }
|
---|
| 1116 | fprintf(malout, " p_s: %p;", prev_size_of(ml));
|
---|
| 1117 | fprintf(malout, " t_s: %p;", _this_size_of(ml));
|
---|
| 1118 | fprintf(malout, " sz: %lu;", (unsigned long) size_of(ml));
|
---|
| 1119 | fprintf(malout, " fr: %d;", free_of(ml));
|
---|
| 1120 | fprintf(malout, "\n");
|
---|
| 1121 | }
|
---|
| 1122 |
|
---|
| 1123 | /* Check_mallinks() checks the total data structure as accessible
|
---|
| 1124 | through free_list[] and ml_last. All check_sums should be OK,
|
---|
| 1125 | except those held in the small array off_colour. This is a
|
---|
| 1126 | trick to allow to continue checking even when a few mallinks
|
---|
| 1127 | are temporarily out of order.
|
---|
| 1128 | Check_mallinks() tests for a lot of internal consistency.
|
---|
| 1129 | */
|
---|
| 1130 |
|
---|
| 1131 | /* Some arbitrary constants */
|
---|
| 1132 | #define IN_ML_LAST 93
|
---|
| 1133 | #define IN_FREE_LIST 57 /* and in ml_last */
|
---|
| 1134 | #define CLEAR 21
|
---|
| 1135 |
|
---|
| 1136 | #define VRIJ 1
|
---|
| 1137 | #define BEZET 2
|
---|
| 1138 |
|
---|
| 1139 | private
|
---|
| 1140 | check_mallinks(const char *s) {
|
---|
| 1141 | mallink *ml;
|
---|
| 1142 | size_type size;
|
---|
| 1143 | int i;
|
---|
| 1144 | char stat;
|
---|
| 1145 |
|
---|
| 1146 | check_ml_last(s);
|
---|
| 1147 | stat = BEZET;
|
---|
| 1148 | for_all_mallinks(ml) {
|
---|
| 1149 | if (checksum_of(ml) != checksum(ml))
|
---|
| 1150 | Error("mallink info at %p corrupted", s, ml);
|
---|
| 1151 | if (working_on(ml)) {
|
---|
| 1152 | stat = BEZET;
|
---|
| 1153 | continue;
|
---|
| 1154 | }
|
---|
| 1155 | if ( !last_mallink(ml) &&
|
---|
| 1156 | phys_prev_of(phys_next_of(ml)) != ml
|
---|
| 1157 | )
|
---|
| 1158 | Error("upward chain bad at %p", s, ml);
|
---|
| 1159 | if ( !first_mallink(ml) &&
|
---|
| 1160 | phys_next_of(phys_prev_of(ml)) != ml
|
---|
| 1161 | )
|
---|
| 1162 | Error("downward chain bad at %p", s, ml);
|
---|
| 1163 | if (free_of(ml)) {
|
---|
| 1164 | if (stat == VRIJ)
|
---|
| 1165 | Error("free mallink at %p follows free mallink",
|
---|
| 1166 | s, ml);
|
---|
| 1167 | stat = VRIJ;
|
---|
| 1168 | }
|
---|
| 1169 | else
|
---|
| 1170 | stat = BEZET;
|
---|
| 1171 | set_mark(ml, IN_ML_LAST);
|
---|
| 1172 | }
|
---|
| 1173 |
|
---|
| 1174 | for (i = 0, size = MIN_SIZE; i < MAX_FLIST; i++, size *= 2) {
|
---|
| 1175 | for_free_list(i, ml) {
|
---|
| 1176 | if (working_on(ml))
|
---|
| 1177 | continue;
|
---|
| 1178 | if (!free_of(ml))
|
---|
| 1179 | Error("occupied mallink %p occurs in free_list", s, ml);
|
---|
| 1180 | switch (mark_of(ml)) {
|
---|
| 1181 | case IN_ML_LAST:
|
---|
| 1182 | set_mark(ml, IN_FREE_LIST);
|
---|
| 1183 | break;
|
---|
| 1184 | case IN_FREE_LIST:
|
---|
| 1185 | Error("mallink %p occurs in 2 free_lists",
|
---|
| 1186 | s, ml);
|
---|
| 1187 | default:
|
---|
| 1188 | Error("unknown mallink %p in free_list",
|
---|
| 1189 | s, ml);
|
---|
| 1190 | }
|
---|
| 1191 | if (size_of(ml) < size)
|
---|
| 1192 | Error("size of mallink %p too small", s, ml);
|
---|
| 1193 | if (size_of(ml) >= 2*size)
|
---|
| 1194 | Error("size of mallink %p too large", s, ml);
|
---|
| 1195 | }
|
---|
| 1196 | }
|
---|
| 1197 | for_all_mallinks (ml) {
|
---|
| 1198 | if (working_on(ml))
|
---|
| 1199 | continue;
|
---|
| 1200 | if (free_of(ml) && mark_of(ml) != IN_FREE_LIST)
|
---|
| 1201 | Error("free mallink %p is in no free_list", s, ml);
|
---|
| 1202 | set_mark(ml, CLEAR);
|
---|
| 1203 | }
|
---|
| 1204 | }
|
---|
| 1205 |
|
---|
| 1206 | private
|
---|
| 1207 | check_ml_last(const char *s) {
|
---|
| 1208 | if (ml_last && _this_size_of(ml_last) == 0)
|
---|
| 1209 | Error("size of ml_last == 0, at %p", s, ml_last);
|
---|
| 1210 | }
|
---|
| 1211 |
|
---|
| 1212 | private size_type
|
---|
| 1213 | checksum(mallink *ml) {
|
---|
| 1214 | size_type sum = 0;
|
---|
| 1215 |
|
---|
| 1216 | if (free_of(ml)) {
|
---|
| 1217 | sum += (size_type)_log_prev_of(ml);
|
---|
| 1218 | sum += (size_type)_log_next_of(ml);
|
---|
| 1219 | }
|
---|
| 1220 | sum += (size_type)prev_size_of(ml);
|
---|
| 1221 | sum += (size_type)_this_size_of(ml);
|
---|
| 1222 | return sum;
|
---|
| 1223 | }
|
---|
| 1224 |
|
---|
| 1225 | private
|
---|
| 1226 | calc_checksum(mallink *ml) {
|
---|
| 1227 | set_checksum(ml, checksum(ml));
|
---|
| 1228 | }
|
---|
| 1229 |
|
---|
| 1230 | #define N_COLOUR 10
|
---|
| 1231 | static mallink *off_colour[N_COLOUR];
|
---|
| 1232 |
|
---|
| 1233 | private
|
---|
| 1234 | started_working_on(mallink *ml) {
|
---|
| 1235 | int i;
|
---|
| 1236 |
|
---|
| 1237 | for (i = 0; i < N_COLOUR; i++)
|
---|
| 1238 | if (off_colour[i] == MAL_NULL) {
|
---|
| 1239 | off_colour[i] = ml;
|
---|
| 1240 | return;
|
---|
| 1241 | }
|
---|
| 1242 | Error("out of off_colour array at %p", "started_working_on", ml);
|
---|
| 1243 | }
|
---|
| 1244 |
|
---|
| 1245 | private
|
---|
| 1246 | stopped_working_on(mallink *ml) {
|
---|
| 1247 | int i;
|
---|
| 1248 |
|
---|
| 1249 | for (i = 0; i < N_COLOUR; i++)
|
---|
| 1250 | if (off_colour[i] == ml) {
|
---|
| 1251 | off_colour[i] = MAL_NULL;
|
---|
| 1252 | return;
|
---|
| 1253 | }
|
---|
| 1254 | Error("stopped working on mallink %p", "stopped_working_on", ml);
|
---|
| 1255 | }
|
---|
| 1256 |
|
---|
| 1257 | private int
|
---|
| 1258 | working_on(mallink *ml) {
|
---|
| 1259 | int i;
|
---|
| 1260 |
|
---|
| 1261 | for (i = 0; i < N_COLOUR; i++)
|
---|
| 1262 | if (off_colour[i] == ml)
|
---|
| 1263 | return 1;
|
---|
| 1264 | return 0;
|
---|
| 1265 | }
|
---|
| 1266 |
|
---|
| 1267 | private
|
---|
| 1268 | check_work_empty(const char *s) {
|
---|
| 1269 | int i;
|
---|
| 1270 | int cnt = 0;
|
---|
| 1271 |
|
---|
| 1272 | for (i = 0; i < N_COLOUR; i++)
|
---|
| 1273 | if (off_colour[i] != MAL_NULL)
|
---|
| 1274 | cnt++;
|
---|
| 1275 | if (cnt != 0)
|
---|
| 1276 | Error("off_colour not empty", s, MAL_NULL);
|
---|
| 1277 | }
|
---|
| 1278 |
|
---|
| 1279 | private int
|
---|
| 1280 | Error(const char *fmt, const char *s, mallink *ml) {
|
---|
| 1281 | static int already_called = 0;
|
---|
| 1282 |
|
---|
| 1283 | if (already_called++) return 0;
|
---|
| 1284 | setbuf(stdout, (char *) 0);
|
---|
| 1285 | printf("%s: ", s);
|
---|
| 1286 | printf(fmt, (long)ml);
|
---|
| 1287 | printf("\n");
|
---|
| 1288 | acquire_malout();
|
---|
| 1289 | fprintf(malout, "%s: ", s);
|
---|
| 1290 | fprintf(malout, fmt, (long)ml);
|
---|
| 1291 | fprintf(malout, "\n");
|
---|
| 1292 | fflush(stdout);
|
---|
| 1293 | maldump(1);
|
---|
| 1294 | return 0; /* to satisfy lint */
|
---|
| 1295 | }
|
---|
| 1296 |
|
---|
| 1297 | #endif /* CHECK */
|
---|
| 1298 |
|
---|