diff options
Diffstat (limited to 'physmem/zalloc.c')
-rw-r--r-- | physmem/zalloc.c | 287 |
1 files changed, 0 insertions, 287 deletions
diff --git a/physmem/zalloc.c b/physmem/zalloc.c deleted file mode 100644 index 93abfd3..0000000 --- a/physmem/zalloc.c +++ /dev/null @@ -1,287 +0,0 @@ -/* Zone allocator for physical memory server. - Copyright (C) 2003 Free Software Foundation, Inc. - Written by Neal H Walfield. - Modified by Marcus Brinkmann. - - This file is part of the GNU Hurd. - - The GNU Hurd is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU Hurd is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#if HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include <string.h> - -#include "output.h" - -#include "zalloc.h" - -/* Zalloc: A fast zone allocator. This is not a general purpose - allocator. If you attempt to use it as such, you will find that it - is very inefficient. It is, however, designed to be very fast and - to be used as a base for building a more general purpose allocator. - - Memory is kept in zones. Zones are of sizes 2 ** N and all memory - is aligned on a similar boundary. Typically, the smallest zone - will be the system page size. Memory of any size can be added to - the pool as long as it is a multiple of the smallest zone: it is - broken up as necessary. - - Memory can be added to the pool by calling the zfree function with - the address of the buffer and its size. The buffer is broken up as - a function of its alignment and size using the buddy system (as - described by e.g. Knuth). Consider the following: zfree (4k, 16k). - This says that a buffer of size 16k starting at address 4k should - be added to the system. Although the size of the buffer is a power - of 2 (2 ** 14 = 16k), it cannot be added to the 16k zone: it has - the wrong alignment. Instead, the initial 4k are broken off, added - to the 4k zone, the next 8k to the 8k zone and the final 4k to the - 4k zone. If, as memory is added to a zone, its buddy is present, - the two buffers are buddied up and promoted to the next zone. For - instance, if the 4k buffer at address 20k was present during the - previous zfree, the bufer at 16k would have been combined with this - and the new larger buffer would have been added to the 8k zone. - - When allocating memory, the smallest zone that is larger than or - equal to the desired size is selected. If the zone is exhausted, - the allocator will look in the next larger zone and break up a - buffer to satisfy the request. This continues recursively if - necessary. If the desired size is smaller than the buffer that is - selected, the difference is returned to the system. For instance, - if an allocation request of 12k is made, the system will start - looking in the 16k zone. If it finds that that zone is exhausted, - it will select a buffer from the 32k zone and place the top half in - the 16k zone and use the lower half for the allocation. However, - as this is 4k too much, the extra is returned to the 4k zone. - - When making allocations, the system will not look for adjacent - memory blocks: if an allocation request of e.g. 8k is issued and - there is no memory in the 8k zones and above, the 4k zone will not - be searched for false buddies. That is, if in the 4k zone there is - a buffer starting at 4k and 8k, the allocator will make no effort - to search for them. Note that they could not have been combined - during the zfree as 4k's buddy is at 0k and 8k's buddy is at - 12k. */ - - -/* A free block list ordered by address. Blocks are of size 2 ** N - and aligned on a similar boundary. Since the contents of a block - does not matter (it is free), the block itself contains this - structure at its start address. */ -struct block -{ - struct block *next; - struct block *prev; -}; - - -/* Given a zone, return its size. */ -#define ZONE_SIZE(x) (1 << ((x) + L4_MIN_PAGE_SIZE_LOG2)) - -/* Number of zones in the system. */ -#define ZONES (sizeof (L4_Word_t) * 8 - L4_MIN_PAGE_SIZE_LOG2) - -/* The zones. */ -static struct block *zone[ZONES] = { 0, }; - - -/* Add the block BLOCK to the zone ZONE_NR. The block has the - right size and alignment. Buddy up if possible. */ -static inline void -add_block (struct block *block, unsigned int zone_nr) -{ - while (1) - { - struct block *left = 0; - struct block *right = zone[zone_nr]; - - /* Find the left and right neighbours of BLOCK. */ - while (right && block > right) - { - left = right; - right = right->next; - } - - if (left && (((l4_word_t) left) ^ ((l4_word_t) block)) - == ZONE_SIZE (zone_nr)) - { - /* Buddy on the left. */ - - /* Remove left neighbour. */ - if (left->prev) - left->prev->next = left->next; - else - zone[zone_nr] = left->next; - if (left->next) - left->next->prev = left->prev; - - block = left; - zone_nr++; - } - else if (right && (((l4_word_t) right) ^ ((l4_word_t) block)) - == ZONE_SIZE (zone_nr)) - { - /* Buddy on the right. */ - - /* Remove right neighbour from the list. */ - if (right->prev) - right->prev->next = right->next; - else - zone[zone_nr] = right->next; - if (right->next) - right->next->prev = right->prev; - - zone_nr++; - } - else - { - /* Could not coalesce. Just insert. */ - - block->next = right; - if (block->next) - block->next->prev = block; - - block->prev = left; - if (block->prev) - block->prev->next = block; - else - zone[zone_nr] = block; - - /* This is the terminating case. */ - break; - } - } -} - - -/* Add the block BLOCK of size SIZE to the pool. BLOCK must be - aligned to the system's minimum page size. SIZE must be a multiple - of the system's minimum page size. */ -void -zfree (l4_word_t block, l4_word_t size) -{ - l4_word_t min_page_size = l4_min_page_size (); - - // debug ("freeing block 0x%x - 0x%x\n", block, block + size); - - if (size & (min_page_size - 1)) - panic ("%s: size 0x%x of freed block 0x%x is not a multiple of " - "minimum page size", __func__, size, block); - - if (block & (min_page_size - 1)) - panic ("%s: freed block 0x%x of size 0x%x is not aligned to " - "minimum page size", __func__, block, size); - - do - { - /* All blocks must be stored aligned to their size. */ - unsigned int block_align = l4_lsb (block) - 1; - unsigned int size_align = l4_msb (size) - 1; - unsigned int zone_nr = (block_align < size_align - ? block_align : size_align) - - L4_MIN_PAGE_SIZE_LOG2; - - add_block ((struct block *) block, zone_nr); - - block += ZONE_SIZE (zone_nr); - size -= ZONE_SIZE (zone_nr); - } - while (size > 0); -} - - -/* Allocate a block of memory of size SIZE and return its address. - SIZE must be a multiple of the system's minimum page size. If no - block of the required size could be allocated, return 0. */ -l4_word_t -zalloc (l4_word_t size) -{ - l4_word_t min_page_size = l4_min_page_size (); - unsigned int zone_nr; - struct block *block; - - // debug ("request for 0x%x bytes\n", size); - - if (size & (min_page_size - 1)) - panic ("%s: requested size 0x%x is not a multiple of " - "minimum page size", __func__, size); - - /* Calculate the logarithm to base two of SIZE rounded up to the - nearest power of two (actually, the MSB function returns one more - than the logarithm to base two of its argument, rounded down to - the nearest power of two - this is the same except for the border - case where only one bit is set. To adjust for this border case, - we subtract one from the argument to the MSB function). Calculate - the zone number by subtracting page shift. */ - zone_nr = l4_msb (size - 1) - L4_MIN_PAGE_SIZE_LOG2; - - /* Find the smallest zone which fits the request and has memory - available. */ - while (!zone[zone_nr] && zone_nr < ZONES) - zone_nr++; - - if (zone_nr == ZONES) - return 0; - - /* Found a zone. Now bite off the beginning of the first block in - this zone. */ - block = zone[zone_nr]; - - zone[zone_nr] = block->next; - if (zone[zone_nr]) - zone[zone_nr]->prev = 0; - - /* And donate back the remainder of this block, if any. */ - if (ZONE_SIZE (zone_nr) > size) - zfree (((l4_word_t) block) + size, ZONE_SIZE (zone_nr) - size); - - /* Zero out the newly allocated block. */ - memset (block, 0, size); - - return (l4_word_t) block; -} - - -/* Dump the internal data structures. */ -#ifndef NDEBUG -void -zalloc_dump_zones (const char *prefix) -{ - l4_word_t min_page_size = l4_min_page_size (); - int i; - struct block *block; - l4_word_t available = 0; - int print_empty = 0; - - for (i = ZONES - 1; ZONE_SIZE (i) >= min_page_size; i--) - if (zone[i] || print_empty) - { - print_empty = 1; - printf ("%s: 0x%x: { ", prefix, ZONE_SIZE (i)); - for (block = zone[i]; block; block = block->next) - { - available += ZONE_SIZE (i); - printf ("%p%s", block, (block->next ? ", " : " ")); - } - printf ("}\n"); - } - - printf ("%s: %llu (0x%llx) bytes available\n", prefix, - (unsigned long long) available, (unsigned long long) available); -} -#endif |