Compare commits

...

10 Commits

Author SHA1 Message Date
4567b1bfd5 Merge pull request 'Zone Freeing - No Fragmentation' (#12) from zone/real-free into main
Reviewed-on: #12
2024-02-18 19:26:19 +00:00
957ba0880d Zone Freeing - No Fragmentation
Now have the ability to keep track of freed zones and will now allocate
to those first before allocating new memory in a zone so that we do not
fragment our zones.
2024-02-18 14:23:34 -05:00
757d795749 Merge pull request 'Linked List Fixes' (#11) from list/fixes into main
Reviewed-on: #11
2024-02-15 22:05:05 +00:00
181ed5f732 Linked List Fixes
Fixed up where there was no error checking of position when inserting
into a position into the list. Also made it so that listCreate returns a
pointer to a list instead of a list so that we can move the definition
of List into the implementation file instead of the header.
2024-02-15 17:00:19 -05:00
1966ddf800 Merge pull request 'Linked List' (#10) from linked-list into main
Reviewed-on: #10
2024-02-15 01:14:27 +00:00
7d7d671dca Linked List
Added in the first support for a linked list type. It is called a List
type in the library. Have tested the functionality and so far all seems
good
2024-02-14 20:12:15 -05:00
3667b777f2 Merge pull request 'Log File' (#9) from logger/file into main
Reviewed-on: #9
2024-02-10 19:04:11 +00:00
446fa704cc Log File
Added in the ability to write logs to a log file as well. For now the
logs write to ./quantum.log. All new log entries append onto the end of
the log. Also added timestamps in front of all log entries that are
generated when the log entry is made.
2024-02-10 13:59:43 -05:00
78798a42fd Merge pull request 'Log Colors' (#8) from logger/colors into main
Reviewed-on: #8
2024-02-10 16:26:48 +00:00
75b5767e36 Log Colors
Added colored output to the logs. Also added the logs to zone for
outputting errors using our logger instead of printf().
2024-02-10 11:24:10 -05:00
7 changed files with 456 additions and 70 deletions

View File

@@ -2,12 +2,16 @@ cmake_minimum_required(VERSION 3.28.1)
project(quantum-utils)
add_compile_options(-g)
set(quantum-src "./quantum/src/")
set(test_stuff-src "./test_stuff/src/")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_library(quantum SHARED ${quantum-src}memory/zone.c
${quantum-src}logger/logger.c)
add_library(
quantum SHARED ${quantum-src}memory/zone.c ${quantum-src}logger/logger.c
${quantum-src}types/linked_list.c)
add_executable(test_stuff ${test_stuff-src}main.c)
target_link_libraries(test_stuff quantum)

View File

@@ -4,6 +4,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
typedef enum level_color {
COLOR_FATAL,
@@ -14,23 +15,43 @@ typedef enum level_color {
} level_color;
void send_to_console(const char *message, level_color color) {
// TODO: Make use of the color we are passing in so that we can color the
// output on the console
const char *color_strings[] = {"41;97", "0;91", "0;93", "0;94", "0;92"};
printf("%s", message);
printf("\033[%sm%s\033[0m\n", color_strings[color], message);
}
void send_to_error_log(const char *message) {
// TODO: Add in file handling here so that we can write the log messages
// to file as well instead of just to console
// First we need to open up our log file to append to it
FILE *log_file = fopen("./quantum.log", "a");
printf("send_to_error_log() called...\n");
// Lets make sure we actually opened the file, and if not we return
if (log_file == NULL) {
send_to_console("[ERROR]: Could not open log file.", COLOR_ERROR);
return;
}
// Now we just need to write our message to the file
int chars_written = fprintf(log_file, "%s\n", message);
// fprintf returns a negative number on an error so let's check for that and
// display an error message
if (chars_written < 0) {
send_to_console("[ERROR]: Could not write to log file.", COLOR_ERROR);
}
// Now we need to make sure we close the file so that we do not leak
fclose(log_file);
}
void log_output(log_level level, const char *message, ...) {
const char *level_strings[] = {
"[FATAL]: ", "[ERROR]: ", "[WARN]: ", "[INFO]: ", "[DEBUG]: "};
// We are going to want to put a timestamp on our logs so lets get the current
// time and convert it into localtime
time_t cur_time = time(NULL);
struct tm local_time = *localtime(&cur_time);
// We are going to impose a 32K char limit on a single log entry
// we will hold this in format_message as a place to collect all
// the variadic arguments and process them together. We make sure
@@ -46,9 +67,12 @@ void log_output(log_level level, const char *message, ...) {
vsnprintf(format_message, msg_length, message, arg_ptr);
va_end(arg_ptr);
// Now we prepend the message with our message level
// Now we prepend the message with a timestamp and our message level
char log_message[msg_length];
sprintf(log_message, "%s%s\n", level_strings[level], format_message);
sprintf(log_message, "[%02d-%02d-%d %02d:%02d:%02d]%s%s",
local_time.tm_mon + 1, local_time.tm_mday, local_time.tm_year + 1900,
local_time.tm_hour, local_time.tm_min, local_time.tm_sec,
level_strings[level], format_message);
// Now we call the appropriate function depending on the level
if (level <= 1) {

View File

@@ -1,15 +1,23 @@
#include <stdio.h> // printf()
#include <stdlib.h> // malloc() free()
#include <string.h>
#include <string.h> // memset()
#include "../defines.h"
#include "../logger/logger.h"
#include "../types/linked_list.h"
#include "zone.h"
typedef struct ZoneHeader {
u64 capacity;
u64 cur_size;
List *free_zones;
} ZoneHeader;
typedef struct FreeZone {
void *start_address;
u64 capacity;
} FreeZone;
Zone *zoneCreate(size_t sizeBytes) {
// First we need to get a block of memory from the OS
// This block needs to include the size of what we want to store
@@ -24,6 +32,7 @@ Zone *zoneCreate(size_t sizeBytes) {
// Initialize the values of the header
zone_header->capacity = sizeBytes;
zone_header->cur_size = 0;
zone_header->free_zones = listCreate();
return zone_addr;
}
@@ -31,8 +40,31 @@ Zone *zoneCreate(size_t sizeBytes) {
void *zoneAlloc(Zone *zone, size_t sizeBytes) {
ZoneHeader *zone_header = (ZoneHeader *)zone - sizeof(ZoneHeader);
u64 cur_free_zones = listSize(zone_header->free_zones);
if (cur_free_zones > 0) {
for (u64 i = 1; i <= cur_free_zones; i++) {
FreeZone *curFreeZone =
(FreeZone *)listDataAt(zone_header->free_zones, i);
u64 freeZoneSize = curFreeZone->capacity;
if (freeZoneSize >= sizeBytes) {
void *ret_addr = curFreeZone->start_address;
curFreeZone->start_address += sizeBytes;
curFreeZone->capacity -= sizeBytes;
if (curFreeZone->capacity <= 0) {
listRemoveAt(zone_header->free_zones, i);
free(curFreeZone);
}
return ret_addr;
}
}
}
if (zone_header->cur_size + sizeBytes > zone_header->capacity) {
printf("Could not allocate, not enough space.");
QERROR("Could not allocate, not enough space.");
return NULL;
}
@@ -40,17 +72,10 @@ void *zoneAlloc(Zone *zone, size_t sizeBytes) {
zone_header->cur_size += sizeBytes;
printf("Zone Header Information:\n");
printf("Current Size: %" PRIu64 "\n", zone_header->cur_size);
printf("Total Capacity: %" PRIu64 "\n", zone_header->capacity);
return new_mem;
}
void zoneFree(void *data, size_t dataSize) {
// TODO: We want to eventually pass in a pointer to the zone so we can track
// our free blocks
void zoneFree(void *data, Zone *zone, size_t dataSize) {
// Lets first check to make sure we weren't given a NULL pointer
if (data == NULL)
return;
@@ -59,26 +84,31 @@ void zoneFree(void *data, size_t dataSize) {
// to 0
memset(data, 0, dataSize);
FreeZone *newFreeZone = malloc(sizeof(FreeZone));
ZoneHeader *zone_header = (ZoneHeader *)zone - sizeof(ZoneHeader);
newFreeZone->start_address = data;
newFreeZone->capacity = dataSize;
listPush(zone_header->free_zones, newFreeZone);
// Now we need to null the pointer
data = NULL;
// TODO: Add logic to alert that this space can now be used
}
void zoneClear(Zone *zone) {
ZoneHeader *zone_header = (ZoneHeader *)zone - sizeof(ZoneHeader);
zone_header->cur_size = 0;
printf("Zone Header Information:\n");
printf("Current Size: %" PRIu64 "\n", zone_header->cur_size);
printf("Total Capacity: %" PRIu64 "\n", zone_header->capacity);
}
void zoneDestroy(Zone *zone) {
// First we need to go back to the beginning of the header as we returned
// an offset for the user to use
void *del_mem = (ZoneHeader *)zone - sizeof(ZoneHeader);
ZoneHeader *del_mem = (ZoneHeader *)zone - sizeof(ZoneHeader);
// Next we need to destory our free_zones list
listDestroy(del_mem->free_zones);
// Free the memory
free(del_mem);

View File

@@ -2,12 +2,10 @@
#include <stddef.h> // size_t definition
#include "../defines.h"
typedef struct _Zone Zone;
typedef struct Zone Zone;
Zone *zoneCreate(size_t sizeBytes);
void *zoneAlloc(Zone *zone, size_t sizeBytes);
void zoneFree(void *data, size_t dataSize);
void zoneFree(void *data, Zone *zone, size_t dataSize);
void zoneClear(Zone *zone);
void zoneDestroy(Zone *zone);

View File

@@ -0,0 +1,332 @@
#include "linked_list.h"
#include "../defines.h"
#include "../logger/logger.h"
#include <stddef.h>
#include <stdlib.h>
typedef struct Node {
struct Node *next;
struct Node *prev;
void *data;
} Node;
typedef struct List {
Node *cur_head;
Node *cur_tail;
u64 cur_size;
} List;
List *listCreate() {
List *new_list = malloc(sizeof(List));
new_list->cur_size = 0;
new_list->cur_head = NULL;
new_list->cur_tail = NULL;
return new_list;
}
void listDestroy(List *list) {
// First lets make sure we don't have a null pointer passed in
if (list == NULL) {
QWARN("Null list passed to listDestroy().");
return;
}
Node *del_node = list->cur_tail;
Node *next_node;
while (del_node != NULL) {
// We want to set del_node to the next_node to free
next_node = del_node->prev;
// Then we want to free del_node
free(del_node);
// Finally we want to set del_node to the next_node to free
del_node = next_node;
}
// Now we null out the cur_head and cur_tail of our list
list->cur_tail = NULL;
list->cur_head = NULL;
// Now we free out the list and make it point to nothing
free(list);
}
u64 listSize(const List *list) {
if (list != NULL)
return list->cur_size;
return 0;
}
void *listPeek(List *list) {
if (list != NULL && list->cur_size > 0)
return list->cur_tail->data;
return NULL;
}
void *listPop(List *list) {
if (list == NULL) {
QWARN("Null list passed to listPop()");
return NULL;
}
Node *pop_node = list->cur_tail;
Node *prev_node = list->cur_head == list->cur_tail ? NULL : pop_node->prev;
void *data = pop_node->data;
if (prev_node != NULL)
prev_node->next = NULL;
list->cur_size--;
list->cur_tail = prev_node;
free(pop_node);
return data;
}
void listPush(List *list, void *data) {
// Allocate the space for our new node
Node *new_node = malloc(sizeof(Node));
// Make sure that we were able to allocate the space, and if not we write an
// error and return
if (new_node == NULL) {
QERROR("Could not allocate space to insert data into list.");
return;
}
// If the current size of our list is 0
if (list->cur_size == 0) {
// Set the head and tail pointer to the new node as we are about to have
// only 1 element
list->cur_tail = new_node;
list->cur_head = new_node;
// Set the next and previous of the new node to NULL as we will only
// have 1 element and nothing to point to
new_node->next = NULL;
new_node->prev = NULL;
} else {
// Set the next of new_node to NULL as it is the new tail,
// and also update prev of new_node to point to the current tail
new_node->next = NULL;
new_node->prev = list->cur_tail;
// Set the next of our current tail to point to the new tail
list->cur_tail->next = new_node;
}
// Set the data of the new node to the data we passed in
new_node->data = data;
// Update the list size
list->cur_size++;
// Set the list tail pointer to the new node
list->cur_tail = new_node;
}
void *listPeekFromFront(List *list) {
if (list != NULL && list->cur_size > 0)
return list->cur_head->data;
return NULL;
}
void *listPopFromFront(List *list) {
if (list == NULL) {
QERROR("Null list passed to listPopFromFront()");
return NULL;
}
Node *pop_node = list->cur_head;
Node *next_node = list->cur_head == list->cur_tail ? NULL : pop_node->next;
void *data = pop_node->data;
if (next_node != NULL)
next_node->next = NULL;
list->cur_size--;
list->cur_head = next_node;
free(pop_node);
return data;
}
void listPushFromFront(List *list, void *data) {
// Allocate the space for our new node
Node *new_node = malloc(sizeof(Node));
// Make sure that we were able to allocate the space, and if not we write an
// error and return
if (new_node == NULL) {
QERROR("Could not allocate space to insert data into list.");
return;
}
// If the current size of our list is 0
if (list->cur_size == 0) {
// Set the head and tail pointer to the new node as we are about to have
// only 1 element
list->cur_tail = new_node;
list->cur_head = new_node;
// Set the next and previous of the new node to NULL as we will only
// have 1 element and nothing to point to
new_node->next = NULL;
new_node->prev = NULL;
} else {
// Set the prev of new_node to NULL as it is the new head,
// and also update next of new_node to point to the current head
new_node->next = list->cur_head;
new_node->prev = NULL;
// Set the prev of our current head to point to the new head
list->cur_head->prev = new_node;
}
// Set the data of the new node to the data we passed in
new_node->data = data;
// Update the list size
list->cur_size++;
// Set the list head pointer to the new node
list->cur_head = new_node;
}
void *listDataAt(List *list, u64 pos) {
// Make sure our list isn't NULL or empty, if it is return NULL
if (list == NULL || list->cur_size == 0) {
QWARN("Null or empty list passed into listDataAt()");
return NULL;
}
// Next we want to make sure that our position is in range
if (pos < 1 || pos > list->cur_size) {
QERROR("Position given is out of range: %" PRId64, pos);
return NULL;
}
// This is the pointer to the node with the data we will be returning
Node *data_addr = list->cur_head;
// This is to keep track of what position in the list we are on
u64 counter = 1;
// While we arent at our position yet
while (counter != pos) {
// Get the next nodes address
data_addr = data_addr->next;
// And increment the counter
counter++;
}
// Return the data from the node
return data_addr->data;
}
void listInsertAt(List *list, u64 pos, void *data) {
// If our list is null return.
if (list == NULL) {
QWARN("A null list was passed into listInsertAt()");
return;
}
// Make sure we passed in a valid position
if (pos < 1 || pos > list->cur_size) {
// If we have elements in the list
if (list->cur_size != 0) {
// Then the position is actually out of bounds, so return.
QERROR("Position given is out of range: %" PRId64, pos);
return;
}
}
u64 counter = 1;
Node *insert_pos;
Node *prev_node;
Node *new_node = malloc(sizeof(Node));
if (list->cur_size == 0) {
insert_pos = new_node;
new_node->next = NULL;
new_node->prev = NULL;
pos = 1;
} else {
insert_pos = list->cur_head;
}
new_node->data = data;
while (counter != pos) {
insert_pos = insert_pos->next;
counter++;
}
if (insert_pos->prev != NULL)
prev_node = insert_pos->prev;
if (list->cur_size > 1) {
new_node->next = insert_pos;
new_node->prev = prev_node;
insert_pos->prev = new_node;
prev_node->next = new_node;
}
list->cur_size++;
}
void listRemoveAt(List *list, u64 pos) {
// If we were passed a null or empty list return
if (list == NULL || list->cur_size == 0) {
QWARN("A null list was passed into listRemoveAt()");
return;
}
// If we give a value that is outside of our list return
if (pos < 1 || pos > list->cur_size) {
QERROR("An invalid index was passed to listRemoveAt()");
return;
}
// This is the node we are going to be removing
Node *del_node = list->cur_head;
// This is a counter to keep our position in the list
u64 counter = 1;
// While we aren't at our position
while (counter != pos) {
// Set the node to the next node
del_node = del_node->next;
// And increase the counter
counter++;
}
// Now we are at the position we want to delete, so let's get the address of
// the next and previous nodes
Node *prev_node = del_node->prev;
Node *next_node = del_node->next;
// Now let's update their prev/next values accordingly
if (prev_node != NULL || next_node != NULL) {
prev_node->next = next_node;
next_node->prev = prev_node;
}
// Finally we can free del_node
free(del_node);
// Then we decrement the size of our list
list->cur_size--;
}

View File

@@ -0,0 +1,18 @@
#pragma once
#include "../defines.h"
typedef struct List List;
List *listCreate();
void listDestroy(List *list);
u64 listSize(const List *list);
void *listPeek(List *list);
void *listPop(List *list);
void listPush(List *list, void *data);
void *listPeekFromFront(List *list);
void *listPopFromFront(List *list);
void listPushFromFront(List *list, void *data);
void *listDataAt(List *list, u64 pos);
void listInsertAt(List *list, u64 pos, void *data);
void listRemoveAt(List *list, u64 pos);

View File

@@ -1,55 +1,35 @@
#include <defines.h>
#include <logger/logger.h>
#include <memory/zone.h>
#include <stdio.h>
int main() {
printf("Size of i16: %" PRId16 "\n", sizeof(i16));
printf("Size of u16: %" PRIu16 "\n", sizeof(u16));
printf("Size of i32: %" PRId32 "\n", sizeof(i32));
printf("Size of u32: %" PRIu32 "\n", sizeof(u32));
printf("Size of i64: %" PRId64 "\n", sizeof(i64));
printf("Size of u64: %" PRIu64 "\n", sizeof(u64));
printf("Size of f32: %lu\n", sizeof(f32));
printf("Size of f64: %lu\n", sizeof(f64));
QINFO("Size of i16: %" PRId16, sizeof(i16));
QINFO("Size of u16: %" PRIu16, sizeof(u16));
QINFO("Size of i32: %" PRId32, sizeof(i32));
QINFO("Size of u32: %" PRIu32, sizeof(u32));
QINFO("Size of i64: %" PRId64, sizeof(i64));
QINFO("Size of u64: %" PRIu64, sizeof(u64));
QINFO("Size of f32: %lu", sizeof(f32));
QINFO("Size of f64: %lu", sizeof(f64));
QFATAL("Test");
QERROR("Test");
QWARN("Test");
QINFO("Test");
QDEBUG("Test");
printf("\nCreating new zone 4K in size...\n");
Zone *test_zone = zoneCreate(4096);
void *test_alloc = zoneAlloc(test_zone, 4);
void *test_alloc2 = zoneAlloc(test_zone, 4);
u64 val1 = 420;
u32 val2 = 169;
u32 val3 = 80085;
printf("Address of test_zone: %p\n", (void *)test_zone);
printf("Address of test_alloc: %p\n", test_alloc);
printf("Address of test_alloc2: %p\n\n", test_alloc2);
u64 *zVal1 = (u64 *)zoneAlloc(test_zone, sizeof(val1));
*zVal1 = val1;
zoneClear(test_zone);
zoneFree(zVal1, test_zone, sizeof(zVal1));
u64 *test_free = zoneAlloc(test_zone, sizeof(u64));
u32 *zVal2 = (u32 *)zoneAlloc(test_zone, sizeof(val2));
u32 *zVal3 = (u32 *)zoneAlloc(test_zone, sizeof(val3));
printf("Address of test_free: %p\n", (void *)test_free);
printf("Freeing test_free...\n");
*zVal2 = val2;
*zVal3 = val3;
zoneFree(&test_free, sizeof(u64));
printf("Is test_free NULL: %s\n\n", test_free == NULL ? "true" : "false");
zoneDestroy(test_zone);
const u64 FOUR_GIGS = (u64)4 * 1024 * 1024 * 1024;
Zone *break_zone = zoneCreate(FOUR_GIGS);
while (zoneAlloc(break_zone, 1024 * 1024 * 1024) != NULL) {
}
zoneDestroy(break_zone);
void *dont_care = zoneAlloc(test_zone, 64);
return 0;
}