Files
Arquivotheca.AIX-4.1.3/bos/kernel/ldr/ff_alloc.c
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

297 lines
7.6 KiB
C

static char sccsid[] = "@(#)01 1.2 src/bos/kernel/ldr/ff_alloc.c, sysldr, bos411, 9428A410j 12/15/92 09:43:40";
/*
* COMPONENT_NAME: (SYSLDR) Program Management
*
* FUNCTIONS: ff_init, ff_alloc, ff_free
*
* ORIGINS: 27
*
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
* combined with the aggregated modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1991
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
/*
* First fit memory allocator.
*/
#include <sys/types.h>
#include <sys/malloc.h>
#include <sys/syspest.h>
#include <sys/param.h>
#include "ff_alloc.h"
#define PAGEMASK (PAGESIZE - 1)
/*
* Initializes the pool of free memory
* to contain an initial chunk of size bytes.
* Returns 0 on failure, non-zero otherwise.
*/
int ff_init (fflist_t *fflist, size_t size)
{
int lock_rc;
space_t *space;
if ((lock_rc = lockl (&fflist->ff_lock, LOCK_SHORT)) != LOCK_SUCC)
panic ("ff_init: lock nest/fail\n");
if (fflist->ff_list)
panic ("ff_init: called more than once\n");
if (size < FFALIGN)
panic ("ff_init: size too small\n");
size += FFALIGN_MASK;
size &= ~FFALIGN_MASK;
if (space = (space_t *) xmalloc (size, PGSHIFT, kernel_heap)) {
fflist->ff_list = space;
fflist->ff_start = (char *) space;
fflist->ff_end = (char *) space + size;
space->sp_next = (space_t *) NULL;
space->sp_size = size;
}
unlockl (&fflist->ff_lock);
return (int) space;
}
/*
* Allocate size bytes of memory, return a pointer
* to the allocated memory or NULL in case of failure.
* The memory is aligned to a multiple of (1 << align).
*/
void *ff_alloc (fflist_t *fflist, size_t size, int align)
{
int lock_rc;
space_t **prev_space;
space_t *temp_space;
space_t *space;
char *end_space;
char *mem;
char *end_mem;
void *m;
/*
* Allocation size should be a multiple of FFALIGN.
*/
if (size < FFALIGN)
size = FFALIGN;
else {
size += FFALIGN_MASK;
size &= ~FFALIGN_MASK;
}
m = NULL;
align = (1 << align) - 1;
if (align <= FFALIGN_MASK)
align = 0;
if ((lock_rc = lockl (&fflist->ff_lock, LOCK_SHORT)) != LOCK_SUCC)
panic ("ff_alloc: lock nest/fail\n");
for (prev_space = &fflist->ff_list;
space = *prev_space;
prev_space = &space->sp_next) {
/*
* Make mem be the next aligned address after space.
* Leave space for a space_t header.
*/
mem = (char *) (((int) (space + 1) + align) & ~align);
/*
* Aligned fragment should fit in the memory covered by space.
* Note that enough bytes for the header exist before mem and
* that space->sp_size includes the bytes used by the space_t
* header pointed by space.
*/
end_mem = mem + size;
end_space = (char *) space + space->sp_size;
if (end_mem > end_space)
continue;
/*
* Space descriptor requires FFALIGN bytes.
*/
size += FFALIGN;
if (space->sp_size == size) {
/*
* Exact fit.
* space->sp_size == size && end_mem <= end_space
* ==>>
* mem == (char *) (space + 1)
*/
assert (mem == (char *) (space + 1));
*prev_space = space->sp_next;
space->sp_fflist = fflist;
} else {
if (end_mem < end_space) {
/*
* Create a fragment for the bytes at the end.
*/
temp_space = (space_t *) end_mem;
temp_space->sp_size = end_space - end_mem;
temp_space->sp_next = space->sp_next;
space->sp_next = temp_space;
}
temp_space = (space_t *) mem - 1;
if (temp_space == space)
*prev_space = space->sp_next;
else
space->sp_size =
(char *) temp_space - (char *) space;
temp_space->sp_size = size;
temp_space->sp_fflist = fflist;
}
assert(! ((int) mem & align));
m = mem;
break;
}
unlockl (&fflist->ff_lock);
return m;
}
/*
* Deallocate a fragment of memory
* coalescing (if possible) with the
* previous and next fragments.
* The arena where the memory was
* allocated is recorded in the
* descriptor.
*/
void ff_free (void *mem)
{
int lock_rc;
int size;
fflist_t *fflist;
space_t *free_space;
space_t *space;
space_t *next_space;
space_t **prev_spacep;
free_space = (space_t *) mem - 1;
fflist = free_space->sp_fflist;
if ((lock_rc = lockl (&fflist->ff_lock, LOCK_SHORT)) != LOCK_SUCC)
panic ("ff_free: lock nest/fail\n");
prev_spacep = &fflist->ff_list;
while (next_space = *prev_spacep) {
if (free_space < next_space) {
/* merge with next? */
if (next_space == (space_t *)
((char *) free_space + free_space->sp_size)) {
free_space->sp_size += next_space->sp_size;
next_space = next_space->sp_next;
}
break;
}
prev_spacep = &next_space->sp_next;
}
/*
* When we exit the previous while, either:
* - merged with next, next_space points to the next block
* after the one we merged with, which might be NULL; or
* - next_space points to the block that should fallow
* free_space, i.e. there was some block at higher addres
* but no merge happened; or
* - next_space is NULL, i.e. no next block (or empty list).
* In any case next_space has the propper value to store in the
* sp_next field of free_space, I postpone storing this value
* becouse the block might still merge with the previous block.
*/
/*
* Prev_spacep is used to keep track of the previous pointer
* where to link free_space.
* Also (if prev_spacep != &fflist.ff_list) to point to the
* previous space_t in the list.
* For the prev_spacep == &fflist.ff_list the code that merges
* with the previous one works ok even in the case when space
* is at a higher address than free_space.
*/
if (prev_spacep == &fflist->ff_list)
space = *prev_spacep;
else
/*
* Prev_spacep points to the sp_next pointer, but also
* to the whole structure. The expression below is
* equivalent to:
* space = (space_t *) prev_spacep;
* Becouse sp_next is the first field in a space_t,
* the offset substracted is just zero, this
* avoids "coding" knowledge about the space_t
* layout in this file.
*/
space = (space_t *)
((char *) prev_spacep - (int) &((space_t *) 0)->sp_next);
/*
* If the list was empty from the beggining; or
* was not empty but there will be no merge with previous block
*/
if (!space ||
free_space != (space_t *) ((char *) space + space->sp_size))
*prev_spacep = free_space; /* insert on list */
else {
space->sp_size += free_space->sp_size; /* merge with prev */
free_space = space;
}
/* link the rest of the list */
free_space->sp_next = next_space;
/*
* Release vmm resources of
* released + coalesced fragments.
*/
size = free_space->sp_size - FFALIGN;
if (size >= PAGESIZE) {
int p, pg;
p = (int) ++free_space;
pg = (p + PAGEMASK) & ~PAGEMASK;
size -= pg - p + ((p + size) & PAGEMASK);
if (size != 0)
assert (! vm_release (pg, size));
}
unlockl (&fflist->ff_lock);
}
#if 0
/*
* Relase nbytes from the beggining of pre-allocated memory.
* Returns a pointer to the beggining of the new fragment.
* Returns NULL if trims all the fragment.
* Panics if tries to trim more than allocated.
*/
void *ff_trim (void *mem, int nbytes)
{
space_t *free_space;
space_t *new_space;
if (nbytes <= FFALIGN)
return mem;
free_space = (space_t *) mem - 1;
if (nbytes > free_space->sp_size)
panic ("ff_trim: nbytes to large\n");
nbytes &= ~FFALIGN_MASK;
new_space = (space_t *) ((char *) free_space + nbytes);
new_space->sp_fflist = free_space->sp_fflist;
new_space->sp_size = free_space->sp_size - nbytes;
free_space->sp_size = nbytes;
ff_free ((void *) (free_space + 1));
return (void *) (new_space + 1);
}
#endif