summaryrefslogblamecommitdiffstats
path: root/heap.h
blob: 5eed7e495d5495305bdf5a3134083f0ccc3e6d99 (plain) (tree)






































































































































                                                                                              



                                                                      









                                                                 
/**
 * heap.h
 * Copyright (c) 2021 Jon Santmyer <jon@jonsantmyer.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/**
 * File              : heap.h
 * Author            : Jon Santmyer <jon@jonsantmyer.com>
 * Date              : 10.12.2021
 *
 * A simple thread-unsafe double linked-list bucket heap allocator.
 * Written for moderately fast variable size object allocations without
 * external memory regions
 * Heap object is expected to be allocated by the system
 * Heap members (lists, buckets, crates) are stored in the heap memory region.
 * Users are expected to write wrapper functions that handles errors and 
 * provides a locking mechanism for threaded applications.
 *
 * Required functions and headers:
 * stdint.h
 *  uintptr_t, uintmax_t
 * stddef.h
 *  size_t
 * string.h
 *  memset 
 *
 * Lists are defined by the elements they contain: they are named thusly.
 * The first element of the list is suffixed by _tail
 * The last element of the list is suffixed by _head
 *
 * Crates are page-sized bucket containers allocated inside of heap memory
 * designed to allow the heap to dynamically create and destroy buckets.
 * The amount of buckets each crate can hold depends on the preset size defined
 * in HEAP_CRATE_SIZE, calculated in HEAP_CRATE_BUCKETS.
 * Crates are stored in the previous crate's reserved bucket, except for the
 * initial crate, which stores itself.
 * Crates are singly linked, with the head and tail stored in the heap
 * data structure.
 *
 * Buckets hold information about which memory region it represents, it's 
 * neighbors, and if it's been taken by an allocation.
 * Buckets determine if they are taken by setting the first bit in the
 * sizetaken field. 0 represents free, 1 represents taken.
 * Buckets currently in-use by the heap are stored in the general
 * buckets list, with buckets reserved for future allocations stored in
 * the buckets_unused list.
 *
 * The heap datatype stores information about where allocations can take
 * place, the buckets allocated, a list of crates, and a list of
 * unused buckets.
 * Unused buckets are taken when a bucket is split into two, or a bucket needs
 * to be appended to the heap.
 *
 * When buckets assigned to an allocation are bigger than the needed size, the
 * bucket is "split". the difference in sizes are stored, the bucket is
 * resized to the requested size, and a new bucket is appended to the old
 * bucket with the difference as it's size.
 * When a bucket is freed, the bucket checks it's neighbors to see if it can be
 * combined. If two adjacent buckets are not taken, they are "merged".
 * both buckets' sizes are added into the left-most bucket, and the right-most
 * bucket is released into the unused list.
 * These actions are made to ensure that memory allocations are as compact
 * as possible.
 *
 * When the unused list is empty and a bucket needs to be appended, the heap
 * calls for a new crate to be created. The new crate occupies the reserved
 * bucket of the head crate, and the bucket is pointed to the last address
 * in the bucket list. The crates' buckets are initialized to link with
 * eachother and are set as the head of the unused list.
 */
#ifndef JSH_HEAP_H
#define JSH_HEAP_H 1

#include <stdint.h>
#include <stddef.h>

//I want the crate to be loaded into the l1 cache
#define HEAP_CRATE_SIZE       4096
#define HEAP_BUCKET_SIZE      sizeof(struct bucket)
#define HEAP_CRATE_BUCKETS    (((HEAP_CRATE_SIZE - sizeof(uintptr_t)) / HEAP_BUCKET_SIZE) - 1)

#define HEAP_BUCKET_TAKEN(b)  (b->sizetaken & 1)
#define HEAP_ALLOC_GRAN       sizeof(uintptr_t)

struct bucket
{
    uintptr_t address;
    uintmax_t sizetaken;
    struct bucket *prev;
    struct bucket *next;
};

struct crate
{
    struct bucket buckets[HEAP_CRATE_BUCKETS];
    struct bucket reserved;
    struct crate *next;
};

struct heap
{
    uintptr_t start;
    size_t size;
    size_t used;

    struct crate *crates_tail;
    struct crate *crates_head;
    struct bucket *buckets_tail;
    struct bucket *buckets_head;
    struct bucket *buckets_unused_tail;
};

/*  Fills a heap datastructure with passed arguments and populates the first crate
 *  If len is less than MODIT_HEAP_CRATE_SIZE, function fails
 * */
int heap_create(struct heap *heap, uintptr_t at, size_t len);

/*  Expands the heap's allocation area. Does not support reallocations
 * */
void heap_resize(struct heap *heap, size_t newsize);

/*  Allocates a block of memory atleast [size] bytes long in heap
 * */
void *heap_alloc(struct heap *heap, size_t size);

/*  Frees the memory pointed at by [ptr] for later allocations.
 *  Returns 0 if memory was found and freed
 * */
int heap_free(struct heap *heap, void *ptr);

#endif