1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
29
30 #include <sys/types.h>
31
32 #ifndef debug
33 #define NDEBUG
34 #endif
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <errno.h>
39 #include "assert.h"
40 #include "malloc.h"
41 #include "mallint.h"
42 #include <thread.h>
43 #include <pthread.h>
44 #include <synch.h>
45 #include <unistd.h>
46 #include <limits.h>
47
48 static mutex_t mlock = DEFAULTMUTEX;
49 static ssize_t freespace(struct holdblk *);
50 static void *malloc_unlocked(size_t, int);
51 static void *realloc_unlocked(void *, size_t);
52 static void free_unlocked(void *);
53 static void *morecore(size_t);
54
55 /*
56 * use level memory allocater (malloc, free, realloc)
57 *
58 * -malloc, free, realloc and mallopt form a memory allocator
59 * similar to malloc, free, and realloc. The routines
60 * here are much faster than the original, with slightly worse
61 * space usage (a few percent difference on most input). They
62 * do not have the property that data in freed blocks is left
63 * untouched until the space is reallocated.
64 *
65 * -Memory is kept in the "arena", a singly linked list of blocks.
66 * These blocks are of 3 types.
67 * 1. A free block. This is a block not in use by the
68 * user. It has a 3 word header. (See description
69 * of the free queue.)
70 * 2. An allocated block. This is a block the user has
71 * requested. It has only a 1 word header, pointing
72 * to the next block of any sort.
73 * 3. A permanently allocated block. This covers space
74 * aquired by the user directly through sbrk(). It
75 * has a 1 word header, as does 2.
76 * Blocks of type 1 have the lower bit of the pointer to the
77 * nextblock = 0. Blocks of type 2 and 3 have that bit set,
78 * to mark them busy.
79 *
80 * -Unallocated blocks are kept on an unsorted doubly linked
81 * free list.
82 *
83 * -Memory is allocated in blocks, with sizes specified by the
84 * user. A circular first-fit startegy is used, with a roving
85 * head of the free queue, which prevents bunching of small
86 * blocks at the head of the queue.
87 *
88 * -Compaction is performed at free time of any blocks immediately
89 * following the freed block. The freed block will be combined
90 * with a preceding block during the search phase of malloc.
91 * Since a freed block is added at the front of the free queue,
92 * which is moved to the end of the queue if considered and
93 * rejected during the search, fragmentation only occurs if
94 * a block with a contiguious preceding block that is free is
95 * freed and reallocated on the next call to malloc. The
96 * time savings of this strategy is judged to be worth the
97 * occasional waste of memory.
98 *
99 * -Small blocks (of size < MAXSIZE) are not allocated directly.
100 * A large "holding" block is allocated via a recursive call to
101 * malloc. This block contains a header and ?????? small blocks.
102 * Holding blocks for a given size of small block (rounded to the
103 * nearest ALIGNSZ bytes) are kept on a queue with the property that any
104 * holding block with an unused small block is in front of any without.
105 * A list of free blocks is kept within the holding block.
106 */
107
108 /*
109 * description of arena, free queue, holding blocks etc.
110 *
111 * New compiler and linker does not guarentee order of initialized data.
112 * Define freeptr as arena[2-3] to guarentee it follows arena in memory.
113 * Later code depends on this order.
114 */
115
116 static struct header arena[4] = {
117 {0, 0, 0},
118 {0, 0, 0},
119 {0, 0, 0},
120 {0, 0, 0}
121 };
122 /*
123 * the second word is a minimal block to
124 * start the arena. The first is a busy
125 * block to be pointed to by the last block.
126 */
127
128 #define freeptr (arena + 2)
129 /* first and last entry in free list */
130 static struct header *arenaend; /* ptr to block marking high end of arena */
131 static struct header *lastblk; /* the highest block in the arena */
132 static struct holdblk **holdhead; /* pointer to array of head pointers */
133 /* to holding block chains */
134 /*
135 * In order to save time calculating indices, the array is 1 too
136 * large, and the first element is unused
137 *
138 * Variables controlling algorithm, esp. how holding blocs are used
139 */
140 static int numlblks = NUMLBLKS;
141 static int minhead = MINHEAD;
142 static int change = 0; /* != 0, once param changes are no longer allowed */
143 static int fastct = FASTCT;
144 static unsigned int maxfast = MAXFAST;
145 /* number of small block sizes to map to one size */
146
147 static int grain = ALIGNSZ;
148
149 #ifdef debug
150 static int case1count = 0;
151
152 static void
checkq(void)153 checkq(void)
154 {
155 register struct header *p;
156
157 p = &freeptr[0];
158
159 /* check forward */
160 /*CSTYLED*/
161 while (p != &freeptr[1]) {
162 p = p->nextfree;
163 assert(p->prevfree->nextfree == p);
164 }
165
166 /* check backward */
167 /*CSTYLED*/
168 while (p != &freeptr[0]) {
169 p = p->prevfree;
170 assert(p->nextfree->prevfree == p);
171 }
172 }
173 #endif
174
175
176 /*
177 * malloc(nbytes) - give a user nbytes to use
178 */
179
180 void *
malloc(size_t nbytes)181 malloc(size_t nbytes)
182 {
183 void *ret;
184
185 (void) mutex_lock(&mlock);
186 ret = malloc_unlocked(nbytes, 0);
187 (void) mutex_unlock(&mlock);
188 return (ret);
189 }
190
191 /*
192 * Use malloc_unlocked() to get the address to start with; Given this
193 * address, find out the closest address that aligns with the request
194 * and return that address after doing some house keeping (refer to the
195 * ascii art below).
196 */
197 void *
memalign(size_t alignment,size_t size)198 memalign(size_t alignment, size_t size)
199 {
200 void *alloc_buf;
201 struct header *hd;
202 size_t alloc_size;
203 uintptr_t fr;
204 static int realloc;
205
206 if (size == 0 || alignment == 0 ||
207 (alignment & (alignment - 1)) != 0) {
208 return (NULL);
209 }
210 if (alignment <= ALIGNSZ)
211 return (malloc(size));
212
213 alloc_size = size + alignment;
214 if (alloc_size < size) { /* overflow */
215 return (NULL);
216 }
217
218 (void) mutex_lock(&mlock);
219 alloc_buf = malloc_unlocked(alloc_size, 1);
220 (void) mutex_unlock(&mlock);
221
222 if (alloc_buf == NULL)
223 return (NULL);
224 fr = (uintptr_t)alloc_buf;
225
226 fr = (fr + alignment - 1) / alignment * alignment;
227
228 if (fr == (uintptr_t)alloc_buf)
229 return (alloc_buf);
230
231 if ((fr - (uintptr_t)alloc_buf) <= HEADSZ) {
232 /*
233 * we hit an edge case, where the space ahead of aligned
234 * address is not sufficient to hold 'header' and hence we
235 * can't free it. So double the allocation request.
236 */
237 realloc++;
238 free(alloc_buf);
239 alloc_size = size + alignment*2;
240 if (alloc_size < size) {
241 return (NULL);
242 }
243
244 (void) mutex_lock(&mlock);
245 alloc_buf = malloc_unlocked(alloc_size, 1);
246 (void) mutex_unlock(&mlock);
247
248 if (alloc_buf == NULL)
249 return (NULL);
250 fr = (uintptr_t)alloc_buf;
251
252 fr = (fr + alignment - 1) / alignment * alignment;
253 if (fr == (uintptr_t)alloc_buf)
254 return (alloc_buf);
255 if ((fr - (uintptr_t)alloc_buf) <= HEADSZ) {
256 fr = fr + alignment;
257 }
258 }
259
260 /*
261 * +-------+ +-------+
262 * +---| <a> | | <a> |--+
263 * | +-------+<--alloc_buf-->+-------+ |
264 * | | | | | |
265 * | | | | | |
266 * | | | | | |
267 * | | | hd--> +-------+ |
268 * | | | +---| <b> |<-+
269 * | | | | +-------+<--- fr
270 * | | | | | |
271 * | | | | | |
272 * | | | | | |
273 * | | | | | |
274 * | | | | | |
275 * | | | | | |
276 * | +-------+ | +-------+
277 * +-->| next | +-->| next |
278 * +-------+ +-------+
279 *
280 */
281 hd = (struct header *)((char *)fr - minhead);
282 (void) mutex_lock(&mlock);
283 hd->nextblk = ((struct header *)((char *)alloc_buf - minhead))->nextblk;
284 ((struct header *)((char *)alloc_buf - minhead))->nextblk = SETBUSY(hd);
285 (void) mutex_unlock(&mlock);
286 free(alloc_buf);
287 CHECKQ
288 return ((void *)fr);
289 }
290
291 void *
valloc(size_t size)292 valloc(size_t size)
293 {
294 static unsigned pagesize;
295 if (size == 0)
296 return (NULL);
297
298 if (!pagesize)
299 pagesize = sysconf(_SC_PAGESIZE);
300
301 return (memalign(pagesize, size));
302 }
303
304 /*
305 * malloc_unlocked(nbytes, nosmall) - Do the real work for malloc
306 */
307
308 static void *
malloc_unlocked(size_t nbytes,int nosmall)309 malloc_unlocked(size_t nbytes, int nosmall)
310 {
311 struct header *blk;
312 size_t nb; /* size of entire block we need */
313
314 /* on first call, initialize */
315 if (freeptr[0].nextfree == GROUND) {
316 /* initialize arena */
317 arena[1].nextblk = (struct header *)BUSY;
318 arena[0].nextblk = (struct header *)BUSY;
319 lastblk = arenaend = &(arena[1]);
320 /* initialize free queue */
321 freeptr[0].nextfree = &(freeptr[1]);
322 freeptr[1].nextblk = &(arena[0]);
323 freeptr[1].prevfree = &(freeptr[0]);
324 /* mark that small blocks not init yet */
325 }
326 if (nbytes == 0)
327 return (NULL);
328
329 if (nbytes <= maxfast && !nosmall) {
330 /*
331 * We can allocate out of a holding block
332 */
333 struct holdblk *holdblk; /* head of right sized queue */
334 struct lblk *lblk; /* pointer to a little block */
335 struct holdblk *newhold;
336
337 if (!change) {
338 int i;
339 /*
340 * This allocates space for hold block
341 * pointers by calling malloc recursively.
342 * Maxfast is temporarily set to 0, to
343 * avoid infinite recursion. allocate
344 * space for an extra ptr so that an index
345 * is just ->blksz/grain, with the first
346 * ptr unused.
347 */
348 change = 1; /* change to algorithm params */
349 /* no longer allowed */
350 /*
351 * temporarily alter maxfast, to avoid
352 * infinite recursion
353 */
354 maxfast = 0;
355 holdhead = (struct holdblk **)
356 malloc_unlocked(sizeof (struct holdblk *) *
357 (fastct + 1), 0);
358 if (holdhead == NULL)
359 return (malloc_unlocked(nbytes, 0));
360 for (i = 1; i <= fastct; i++) {
361 holdhead[i] = HGROUND;
362 }
363 maxfast = fastct * grain;
364 }
365 /*
366 * Note that this uses the absolute min header size (MINHEAD)
367 * unlike the large block case which uses minhead
368 *
369 * round up to nearest multiple of grain
370 * code assumes grain is a multiple of MINHEAD
371 */
372 /* round up to grain */
373 nb = (nbytes + grain - 1) / grain * grain;
374 holdblk = holdhead[nb / grain];
375 nb = nb + MINHEAD;
376 /*
377 * look for space in the holding block. Blocks with
378 * space will be in front of those without
379 */
380 if ((holdblk != HGROUND) && (holdblk->lfreeq != LGROUND)) {
381 /* there is space */
382 lblk = holdblk->lfreeq;
383
384 /*
385 * Now make lfreeq point to a free block.
386 * If lblk has been previously allocated and
387 * freed, it has a valid pointer to use.
388 * Otherwise, lblk is at the beginning of
389 * the unallocated blocks at the end of
390 * the holding block, so, if there is room, take
391 * the next space. If not, mark holdblk full,
392 * and move holdblk to the end of the queue
393 */
394 if (lblk < holdblk->unused) {
395 /* move to next holdblk, if this one full */
396 if ((holdblk->lfreeq =
397 CLRSMAL(lblk->header.nextfree)) ==
398 LGROUND) {
399 holdhead[(nb-MINHEAD) / grain] =
400 holdblk->nexthblk;
401 }
402 } else if (((char *)holdblk->unused + nb) <
403 ((char *)holdblk + HOLDSZ(nb))) {
404 holdblk->unused = (struct lblk *)
405 ((char *)holdblk->unused+nb);
406 holdblk->lfreeq = holdblk->unused;
407 } else {
408 holdblk->unused = (struct lblk *)
409 ((char *)holdblk->unused+nb);
410 holdblk->lfreeq = LGROUND;
411 holdhead[(nb-MINHEAD)/grain] =
412 holdblk->nexthblk;
413 }
414 /* mark as busy and small */
415 lblk->header.holder = (struct holdblk *)SETALL(holdblk);
416 } else {
417 /* we need a new holding block */
418 newhold = (struct holdblk *)
419 malloc_unlocked(HOLDSZ(nb), 0);
420 if ((char *)newhold == NULL) {
421 return (NULL);
422 }
423 /* add to head of free queue */
424 if (holdblk != HGROUND) {
425 newhold->nexthblk = holdblk;
426 newhold->prevhblk = holdblk->prevhblk;
427 holdblk->prevhblk = newhold;
428 newhold->prevhblk->nexthblk = newhold;
429 } else {
430 newhold->nexthblk = newhold->prevhblk = newhold;
431 }
432 holdhead[(nb-MINHEAD)/grain] = newhold;
433 /* set up newhold */
434 lblk = (struct lblk *)(newhold->space);
435 newhold->lfreeq = newhold->unused =
436 (struct lblk *)((char *)newhold->space+nb);
437 lblk->header.holder = (struct holdblk *)SETALL(newhold);
438 newhold->blksz = nb-MINHEAD;
439 }
440 #ifdef debug
441 assert(((struct holdblk *)CLRALL(lblk->header.holder))->blksz >=
442 nbytes);
443 #endif /* debug */
444 return ((char *)lblk + MINHEAD);
445 } else {
446 /*
447 * We need an ordinary block
448 */
449 struct header *newblk; /* used for creating a block */
450
451 /* get number of bytes we need */
452 nb = nbytes + minhead;
453 nb = (nb + ALIGNSZ - 1) / ALIGNSZ * ALIGNSZ; /* align */
454 nb = (nb > MINBLKSZ) ? nb : MINBLKSZ;
455 /*
456 * see if there is a big enough block
457 * If none exists, you will get to freeptr[1].
458 * freeptr[1].next = &arena[0], so when you do the test,
459 * the result is a large positive number, since arena[0]
460 * comes before all blocks. Arena[0] is marked busy so
461 * that it will not be compacted. This kludge is for the
462 * sake of the almighty efficiency.
463 */
464 /* check that a very large request won't cause an inf. loop */
465
466 if ((freeptr[1].nextblk-&(freeptr[1])) < nb) {
467 return (NULL);
468 } else {
469 struct header *next; /* following block */
470 struct header *nextnext; /* block after next */
471
472 blk = freeptr;
473 do {
474 blk = blk->nextfree;
475 /* see if we can compact */
476 next = blk->nextblk;
477 if (!TESTBUSY(nextnext = next->nextblk)) {
478 do {
479 DELFREEQ(next);
480 next = nextnext;
481 nextnext = next->nextblk;
482 } while (!TESTBUSY(nextnext));
483 /*
484 * next will be at most == to lastblk,
485 * but I think the >= test is faster
486 */
487 if (next >= arenaend)
488 lastblk = blk;
489 blk->nextblk = next;
490 }
491 } while (((char *)(next) - (char *)blk) < nb);
492 }
493 /*
494 * if we didn't find a block, get more memory
495 */
496 if (blk == &(freeptr[1])) {
497 /*
498 * careful coding could likely replace
499 * newend with arenaend
500 */
501 struct header *newend; /* new end of arena */
502 ssize_t nget; /* number of words to get */
503
504 /*
505 * Three cases - 1. There is space between arenaend
506 * and the break value that will become
507 * a permanently allocated block.
508 * 2. Case 1 is not true, and the last
509 * block is allocated.
510 * 3. Case 1 is not true, and the last
511 * block is free
512 */
513 if ((newblk = (struct header *)sbrk(0)) !=
514 (struct header *)((char *)arenaend + HEADSZ)) {
515 /* case 1 */
516 #ifdef debug
517 if (case1count++ > 0)
518 (void) write(2, "Case 1 hit more that once."
519 " brk or sbrk?\n", 41);
520 #endif
521 /* get size to fetch */
522 nget = nb + HEADSZ;
523 /* round up to a block */
524 nget = (nget + BLOCKSZ - 1)/BLOCKSZ * BLOCKSZ;
525 assert((uintptr_t)newblk % ALIGNSZ == 0);
526 /* get memory */
527 if (morecore(nget) == (void *)-1)
528 return (NULL);
529 /* add to arena */
530 newend = (struct header *)((char *)newblk + nget
531 - HEADSZ);
532 assert((uintptr_t)newblk % ALIGNSZ == 0);
533 newend->nextblk = SETBUSY(&(arena[1]));
534 /* ??? newblk ?? */
535 newblk->nextblk = newend;
536
537 /*
538 * space becomes a permanently allocated block.
539 * This is likely not mt-safe as lock is not
540 * shared with brk or sbrk
541 */
542 arenaend->nextblk = SETBUSY(newblk);
543 /* adjust other pointers */
544 arenaend = newend;
545 lastblk = newblk;
546 blk = newblk;
547 } else if (TESTBUSY(lastblk->nextblk)) {
548 /* case 2 */
549 nget = (nb + BLOCKSZ - 1) / BLOCKSZ * BLOCKSZ;
550 if (morecore(nget) == (void *)-1)
551 return (NULL);
552 /* block must be word aligned */
553 assert(((uintptr_t)newblk%ALIGNSZ) == 0);
554 /*
555 * stub at old arenaend becomes first word
556 * in blk
557 */
558 /* ??? newblk = arenaend; */
559
560 newend =
561 (struct header *)((char *)arenaend+nget);
562 newend->nextblk = SETBUSY(&(arena[1]));
563 arenaend->nextblk = newend;
564 lastblk = blk = arenaend;
565 arenaend = newend;
566 } else {
567 /* case 3 */
568 /*
569 * last block in arena is at end of memory and
570 * is free
571 */
572 /* 1.7 had this backward without cast */
573 nget = nb -
574 ((char *)arenaend - (char *)lastblk);
575 nget = (nget + (BLOCKSZ - 1)) /
576 BLOCKSZ * BLOCKSZ;
577 assert(((uintptr_t)newblk % ALIGNSZ) == 0);
578 if (morecore(nget) == (void *)-1)
579 return (NULL);
580 /* combine with last block, put in arena */
581 newend = (struct header *)
582 ((char *)arenaend + nget);
583 arenaend = lastblk->nextblk = newend;
584 newend->nextblk = SETBUSY(&(arena[1]));
585 /* set which block to use */
586 blk = lastblk;
587 DELFREEQ(blk);
588 }
589 } else {
590 struct header *nblk; /* next block */
591
592 /* take block found of free queue */
593 DELFREEQ(blk);
594 /*
595 * make head of free queue immediately follow blk,
596 * unless blk was at the end of the queue
597 */
598 nblk = blk->nextfree;
599 if (nblk != &(freeptr[1])) {
600 MOVEHEAD(nblk);
601 }
602 }
603 /* blk now points to an adequate block */
604 if (((char *)blk->nextblk - (char *)blk) - nb >= MINBLKSZ) {
605 /* carve out the right size block */
606 /* newblk will be the remainder */
607 newblk = (struct header *)((char *)blk + nb);
608 newblk->nextblk = blk->nextblk;
609 /* mark the block busy */
610 blk->nextblk = SETBUSY(newblk);
611 ADDFREEQ(newblk);
612 /* if blk was lastblk, make newblk lastblk */
613 if (blk == lastblk)
614 lastblk = newblk;
615 } else {
616 /* just mark the block busy */
617 blk->nextblk = SETBUSY(blk->nextblk);
618 }
619 }
620 CHECKQ
621 assert((char *)CLRALL(blk->nextblk) -
622 ((char *)blk + minhead) >= nbytes);
623 assert((char *)CLRALL(blk->nextblk) -
624 ((char *)blk + minhead) < nbytes + MINBLKSZ);
625 return ((char *)blk + minhead);
626 }
627
628 /*
629 * free(ptr) - free block that user thinks starts at ptr
630 *
631 * input - ptr-1 contains the block header.
632 * If the header points forward, we have a normal
633 * block pointing to the next block
634 * if the header points backward, we have a small
635 * block from a holding block.
636 * In both cases, the busy bit must be set
637 */
638
639 void
free(void * ptr)640 free(void *ptr)
641 {
642 (void) mutex_lock(&mlock);
643 free_unlocked(ptr);
644 (void) mutex_unlock(&mlock);
645 }
646
647 /*
648 * free_unlocked(ptr) - Do the real work for free()
649 */
650
651 void
free_unlocked(void * ptr)652 free_unlocked(void *ptr)
653 {
654 struct holdblk *holdblk; /* block holding blk */
655 struct holdblk *oldhead; /* former head of the hold block */
656 /* queue containing blk's holder */
657
658 if (ptr == NULL)
659 return;
660 if (TESTSMAL(((struct header *)((char *)ptr - MINHEAD))->nextblk)) {
661 struct lblk *lblk; /* pointer to freed block */
662 ssize_t offset; /* choice of header lists */
663
664 lblk = (struct lblk *)CLRBUSY((char *)ptr - MINHEAD);
665 assert((struct header *)lblk < arenaend);
666 assert((struct header *)lblk > arena);
667 /* allow twits (e.g. awk) to free a block twice */
668 holdblk = lblk->header.holder;
669 if (!TESTBUSY(holdblk))
670 return;
671 holdblk = (struct holdblk *)CLRALL(holdblk);
672 /* put lblk on its hold block's free list */
673 lblk->header.nextfree = SETSMAL(holdblk->lfreeq);
674 holdblk->lfreeq = lblk;
675 /* move holdblk to head of queue, if its not already there */
676 offset = holdblk->blksz / grain;
677 oldhead = holdhead[offset];
678 if (oldhead != holdblk) {
679 /* first take out of current spot */
680 holdhead[offset] = holdblk;
681 holdblk->nexthblk->prevhblk = holdblk->prevhblk;
682 holdblk->prevhblk->nexthblk = holdblk->nexthblk;
683 /* now add at front */
684 holdblk->nexthblk = oldhead;
685 holdblk->prevhblk = oldhead->prevhblk;
686 oldhead->prevhblk = holdblk;
687 holdblk->prevhblk->nexthblk = holdblk;
688 }
689 } else {
690 struct header *blk; /* real start of block */
691 struct header *next; /* next = blk->nextblk */
692 struct header *nextnext; /* block after next */
693
694 blk = (struct header *)((char *)ptr - minhead);
695 next = blk->nextblk;
696 /* take care of twits (e.g. awk) who return blocks twice */
697 if (!TESTBUSY(next))
698 return;
699 blk->nextblk = next = CLRBUSY(next);
700 ADDFREEQ(blk);
701 /* see if we can compact */
702 if (!TESTBUSY(nextnext = next->nextblk)) {
703 do {
704 DELFREEQ(next);
705 next = nextnext;
706 } while (!TESTBUSY(nextnext = next->nextblk));
707 if (next == arenaend) lastblk = blk;
708 blk->nextblk = next;
709 }
710 }
711 CHECKQ
712 }
713
714
715 /*
716 * realloc(ptr, size) - give the user a block of size "size", with
717 * the contents pointed to by ptr. Free ptr.
718 */
719
720 void *
realloc(void * ptr,size_t size)721 realloc(void *ptr, size_t size)
722 {
723 void *retval;
724
725 (void) mutex_lock(&mlock);
726 retval = realloc_unlocked(ptr, size);
727 (void) mutex_unlock(&mlock);
728 return (retval);
729 }
730
731
732 /*
733 * realloc_unlocked(ptr) - Do the real work for realloc()
734 */
735
736 static void *
realloc_unlocked(void * ptr,size_t size)737 realloc_unlocked(void *ptr, size_t size)
738 {
739 struct header *blk; /* block ptr is contained in */
740 size_t trusize; /* block size as allocater sees it */
741 char *newptr; /* pointer to user's new block */
742 size_t cpysize; /* amount to copy */
743 struct header *next; /* block after blk */
744
745 if (ptr == NULL)
746 return (malloc_unlocked(size, 0));
747
748 if (size == 0) {
749 free_unlocked(ptr);
750 return (NULL);
751 }
752
753 if (TESTSMAL(((struct lblk *)((char *)ptr - MINHEAD))->
754 header.holder)) {
755 /*
756 * we have a special small block which can't be expanded
757 *
758 * This makes the assumption that even if the user is
759 * reallocating a free block, malloc doesn't alter the contents
760 * of small blocks
761 */
762 newptr = malloc_unlocked(size, 0);
763 if (newptr == NULL)
764 return (NULL);
765 /* this isn't to save time--its to protect the twits */
766 if ((char *)ptr != newptr) {
767 struct lblk *lblk;
768 lblk = (struct lblk *)((char *)ptr - MINHEAD);
769 cpysize = ((struct holdblk *)
770 CLRALL(lblk->header.holder))->blksz;
771 cpysize = (size > cpysize) ? cpysize : size;
772 (void) memcpy(newptr, ptr, cpysize);
773 free_unlocked(ptr);
774 }
775 } else {
776 blk = (struct header *)((char *)ptr - minhead);
777 next = blk->nextblk;
778 /*
779 * deal with twits who reallocate free blocks
780 *
781 * if they haven't reset minblk via getopt, that's
782 * their problem
783 */
784 if (!TESTBUSY(next)) {
785 DELFREEQ(blk);
786 blk->nextblk = SETBUSY(next);
787 }
788 next = CLRBUSY(next);
789 /* make blk as big as possible */
790 if (!TESTBUSY(next->nextblk)) {
791 do {
792 DELFREEQ(next);
793 next = next->nextblk;
794 } while (!TESTBUSY(next->nextblk));
795 blk->nextblk = SETBUSY(next);
796 if (next >= arenaend) lastblk = blk;
797 }
798 /* get size we really need */
799 trusize = size+minhead;
800 trusize = (trusize + ALIGNSZ - 1)/ALIGNSZ*ALIGNSZ;
801 trusize = (trusize >= MINBLKSZ) ? trusize : MINBLKSZ;
802 /* see if we have enough */
803 /* this isn't really the copy size, but I need a register */
804 cpysize = (char *)next - (char *)blk;
805 if (cpysize >= trusize) {
806 /* carve out the size we need */
807 struct header *newblk; /* remainder */
808
809 if (cpysize - trusize >= MINBLKSZ) {
810 /*
811 * carve out the right size block
812 * newblk will be the remainder
813 */
814 newblk = (struct header *)((char *)blk +
815 trusize);
816 newblk->nextblk = next;
817 blk->nextblk = SETBUSY(newblk);
818 /* at this point, next is invalid */
819 ADDFREEQ(newblk);
820 /* if blk was lastblk, make newblk lastblk */
821 if (blk == lastblk)
822 lastblk = newblk;
823 }
824 newptr = ptr;
825 } else {
826 /* bite the bullet, and call malloc */
827 cpysize = (size > cpysize) ? cpysize : size;
828 newptr = malloc_unlocked(size, 0);
829 if (newptr == NULL)
830 return (NULL);
831 (void) memcpy(newptr, ptr, cpysize);
832 free_unlocked(ptr);
833 }
834 }
835 return (newptr);
836 }
837
838
839 /*
840 * calloc - allocate and clear memory block
841 */
842
843 void *
calloc(size_t num,size_t size)844 calloc(size_t num, size_t size)
845 {
846 char *mp;
847 size_t total;
848
849 if (num == 0 || size == 0) {
850 total = 0;
851 } else {
852 total = num * size;
853
854 /* check for overflow */
855 if ((total / num) != size) {
856 errno = ENOMEM;
857 return (NULL);
858 }
859 }
860
861 mp = malloc(total);
862 if (mp == NULL)
863 return (NULL);
864 (void) memset(mp, 0, total);
865 return (mp);
866 }
867
868
869 /*
870 * Mallopt - set options for allocation
871 *
872 * Mallopt provides for control over the allocation algorithm.
873 * The cmds available are:
874 *
875 * M_MXFAST Set maxfast to value. Maxfast is the size of the
876 * largest small, quickly allocated block. Maxfast
877 * may be set to 0 to disable fast allocation entirely.
878 *
879 * M_NLBLKS Set numlblks to value. Numlblks is the number of
880 * small blocks per holding block. Value must be
881 * greater than 0.
882 *
883 * M_GRAIN Set grain to value. The sizes of all blocks
884 * smaller than maxfast are considered to be rounded
885 * up to the nearest multiple of grain. The default
886 * value of grain is the smallest number of bytes
887 * which will allow alignment of any data type. Grain
888 * will be rounded up to a multiple of its default,
889 * and maxsize will be rounded up to a multiple of
890 * grain. Value must be greater than 0.
891 *
892 * M_KEEP Retain data in freed block until the next malloc,
893 * realloc, or calloc. Value is ignored.
894 * This option is provided only for compatibility with
895 * the old version of malloc, and is not recommended.
896 *
897 * returns - 0, upon successful completion
898 * 1, if malloc has previously been called or
899 * if value or cmd have illegal values
900 */
901
902 int
mallopt(int cmd,int value)903 mallopt(int cmd, int value)
904 {
905 /* disallow changes once a small block is allocated */
906 (void) mutex_lock(&mlock);
907 if (change) {
908 (void) mutex_unlock(&mlock);
909 return (1);
910 }
911 switch (cmd) {
912 case M_MXFAST:
913 if (value < 0) {
914 (void) mutex_unlock(&mlock);
915 return (1);
916 }
917 fastct = (value + grain - 1) / grain;
918 maxfast = grain*fastct;
919 break;
920 case M_NLBLKS:
921 if (value <= 1) {
922 (void) mutex_unlock(&mlock);
923 return (1);
924 }
925 numlblks = value;
926 break;
927 case M_GRAIN:
928 if (value <= 0) {
929 (void) mutex_unlock(&mlock);
930 return (1);
931 }
932
933 /* round grain up to a multiple of ALIGNSZ */
934 grain = (value + ALIGNSZ - 1)/ALIGNSZ*ALIGNSZ;
935
936 /* reduce fastct appropriately */
937 fastct = (maxfast + grain - 1) / grain;
938 maxfast = grain * fastct;
939 break;
940 case M_KEEP:
941 if (change && holdhead != NULL) {
942 (void) mutex_unlock(&mlock);
943 return (1);
944 }
945 minhead = HEADSZ;
946 break;
947 default:
948 (void) mutex_unlock(&mlock);
949 return (1);
950 }
951 (void) mutex_unlock(&mlock);
952 return (0);
953 }
954
955 /*
956 * mallinfo-provide information about space usage
957 *
958 * input - max; mallinfo will return the size of the
959 * largest block < max.
960 *
961 * output - a structure containing a description of
962 * of space usage, defined in malloc.h
963 */
964
965 struct mallinfo
mallinfo(void)966 mallinfo(void)
967 {
968 struct header *blk, *next; /* ptr to ordinary blocks */
969 struct holdblk *hblk; /* ptr to holding blocks */
970 struct mallinfo inf; /* return value */
971 int i; /* the ubiquitous counter */
972 ssize_t size; /* size of a block */
973 ssize_t fsp; /* free space in 1 hold block */
974
975 (void) mutex_lock(&mlock);
976 (void) memset(&inf, 0, sizeof (struct mallinfo));
977 if (freeptr[0].nextfree == GROUND) {
978 (void) mutex_unlock(&mlock);
979 return (inf);
980 }
981 blk = CLRBUSY(arena[1].nextblk);
982 /* return total space used */
983 inf.arena = (char *)arenaend - (char *)blk;
984
985 /*
986 * loop through arena, counting # of blocks, and
987 * and space used by blocks
988 */
989 next = CLRBUSY(blk->nextblk);
990 while (next != &(arena[1])) {
991 inf.ordblks++;
992 size = (char *)next - (char *)blk;
993 if (TESTBUSY(blk->nextblk)) {
994 inf.uordblks += size;
995 inf.keepcost += HEADSZ-MINHEAD;
996 } else {
997 inf.fordblks += size;
998 }
999 blk = next;
1000 next = CLRBUSY(blk->nextblk);
1001 }
1002
1003 /*
1004 * if any holding block have been allocated
1005 * then examine space in holding blks
1006 */
1007 if (change && holdhead != NULL) {
1008 for (i = fastct; i > 0; i--) { /* loop thru ea. chain */
1009 hblk = holdhead[i];
1010 /* do only if chain not empty */
1011 if (hblk != HGROUND) {
1012 size = hblk->blksz +
1013 sizeof (struct lblk) - sizeof (int);
1014 do { /* loop thru 1 hold blk chain */
1015 inf.hblks++;
1016 fsp = freespace(hblk);
1017 inf.fsmblks += fsp;
1018 inf.usmblks += numlblks*size - fsp;
1019 inf.smblks += numlblks;
1020 hblk = hblk->nexthblk;
1021 } while (hblk != holdhead[i]);
1022 }
1023 }
1024 }
1025 inf.hblkhd = (inf.smblks / numlblks) * sizeof (struct holdblk);
1026 /* holding block were counted in ordblks, so subtract off */
1027 inf.ordblks -= inf.hblks;
1028 inf.uordblks -= inf.hblkhd + inf.usmblks + inf.fsmblks;
1029 inf.keepcost -= inf.hblks*(HEADSZ - MINHEAD);
1030 (void) mutex_unlock(&mlock);
1031 return (inf);
1032 }
1033
1034
1035 /*
1036 * freespace - calc. how much space is used in the free
1037 * small blocks in a given holding block
1038 *
1039 * input - hblk = given holding block
1040 *
1041 * returns space used in free small blocks of hblk
1042 */
1043
1044 static ssize_t
freespace(struct holdblk * holdblk)1045 freespace(struct holdblk *holdblk)
1046 {
1047 struct lblk *lblk;
1048 ssize_t space = 0;
1049 ssize_t size;
1050 struct lblk *unused;
1051
1052 lblk = CLRSMAL(holdblk->lfreeq);
1053 size = holdblk->blksz + sizeof (struct lblk) - sizeof (int);
1054 unused = CLRSMAL(holdblk->unused);
1055 /* follow free chain */
1056 while ((lblk != LGROUND) && (lblk != unused)) {
1057 space += size;
1058 lblk = CLRSMAL(lblk->header.nextfree);
1059 }
1060 space += ((char *)holdblk + HOLDSZ(size)) - (char *)unused;
1061 return (space);
1062 }
1063
1064 static void *
morecore(size_t bytes)1065 morecore(size_t bytes)
1066 {
1067 void * ret;
1068
1069 if (bytes > LONG_MAX) {
1070 intptr_t wad;
1071 /*
1072 * The request size is too big. We need to do this in
1073 * chunks. Sbrk only takes an int for an arg.
1074 */
1075 if (bytes == ULONG_MAX)
1076 return ((void *)-1);
1077
1078 ret = sbrk(0);
1079 wad = LONG_MAX;
1080 while (wad > 0) {
1081 if (sbrk(wad) == (void *)-1) {
1082 if (ret != sbrk(0))
1083 (void) sbrk(-LONG_MAX);
1084 return ((void *)-1);
1085 }
1086 bytes -= LONG_MAX;
1087 wad = bytes;
1088 }
1089 } else
1090 ret = sbrk(bytes);
1091
1092 return (ret);
1093 }
1094
1095 #ifdef debug
1096 int
check_arena(void)1097 check_arena(void)
1098 {
1099 struct header *blk, *prev, *next; /* ptr to ordinary blocks */
1100
1101 (void) mutex_lock(&mlock);
1102 if (freeptr[0].nextfree == GROUND) {
1103 (void) mutex_unlock(&mlock);
1104 return (-1);
1105 }
1106 blk = arena + 1;
1107
1108 /* loop through arena, checking */
1109 blk = (struct header *)CLRALL(blk->nextblk);
1110 next = (struct header *)CLRALL(blk->nextblk);
1111 while (next != arena + 1) {
1112 assert(blk >= arena + 1);
1113 assert(blk <= lastblk);
1114 assert(next >= blk + 1);
1115 assert(((uintptr_t)((struct header *)blk->nextblk) &
1116 (4 | SMAL)) == 0);
1117
1118 if (TESTBUSY(blk->nextblk) == 0) {
1119 assert(blk->nextfree >= freeptr);
1120 assert(blk->prevfree >= freeptr);
1121 assert(blk->nextfree <= lastblk);
1122 assert(blk->prevfree <= lastblk);
1123 assert(((uintptr_t)((struct header *)blk->nextfree) &
1124 7) == 0);
1125 assert(((uintptr_t)((struct header *)blk->prevfree) &
1126 7) == 0 || blk->prevfree == freeptr);
1127 }
1128 blk = next;
1129 next = CLRBUSY(blk->nextblk);
1130 }
1131 (void) mutex_unlock(&mlock);
1132 return (0);
1133 }
1134
1135 #define RSTALLOC 1
1136 #endif
1137
1138 #ifdef RSTALLOC
1139 /*
1140 * rstalloc - reset alloc routines
1141 *
1142 * description - return allocated memory and reset
1143 * allocation pointers.
1144 *
1145 * Warning - This is for debugging purposes only.
1146 * It will return all memory allocated after
1147 * the first call to malloc, even if some
1148 * of it was fetched by a user's sbrk().
1149 */
1150
1151 void
rstalloc(void)1152 rstalloc(void)
1153 {
1154 (void) mutex_lock(&mlock);
1155 minhead = MINHEAD;
1156 grain = ALIGNSZ;
1157 numlblks = NUMLBLKS;
1158 fastct = FASTCT;
1159 maxfast = MAXFAST;
1160 change = 0;
1161 if (freeptr[0].nextfree == GROUND) {
1162 (void) mutex_unlock(&mlock);
1163 return;
1164 }
1165 brk(CLRBUSY(arena[1].nextblk));
1166 freeptr[0].nextfree = GROUND;
1167 #ifdef debug
1168 case1count = 0;
1169 #endif
1170 (void) mutex_unlock(&mlock);
1171 }
1172 #endif /* RSTALLOC */
1173
1174 /*
1175 * cfree is an undocumented, obsolete function
1176 */
1177
1178 /* ARGSUSED1 */
1179 void
cfree(void * p,size_t num,size_t size)1180 cfree(void *p, size_t num, size_t size)
1181 {
1182 free(p);
1183 }
1184
1185 static void
malloc_prepare()1186 malloc_prepare()
1187 {
1188 (void) mutex_lock(&mlock);
1189 }
1190
1191 static void
malloc_release()1192 malloc_release()
1193 {
1194 (void) mutex_unlock(&mlock);
1195 }
1196
1197 #pragma init(malloc_init)
1198 static void
malloc_init(void)1199 malloc_init(void)
1200 {
1201 (void) pthread_atfork(malloc_prepare, malloc_release, malloc_release);
1202 }
1203