mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
300 lines
7.1 KiB
C
300 lines
7.1 KiB
C
#include "stdlib.h"
|
|
#include "syscall.h"
|
|
|
|
// Block allocator over sys_sbrk with coalescing and splitting
|
|
typedef struct BlockMeta {
|
|
size_t size;
|
|
int free;
|
|
struct BlockMeta *next;
|
|
struct BlockMeta *prev;
|
|
} BlockMeta;
|
|
|
|
#define META_SIZE sizeof(BlockMeta)
|
|
#define MIN_SPLIT_SIZE 64
|
|
#define ALIGN8(x) (((x) + 7) & ~(size_t)7)
|
|
|
|
static BlockMeta *heap_head = NULL;
|
|
static BlockMeta *heap_tail = NULL;
|
|
|
|
static BlockMeta *request_space(size_t size) {
|
|
BlockMeta *block = (BlockMeta *)sys_sbrk(0);
|
|
void *request = sys_sbrk(size + META_SIZE);
|
|
if (request == (void*)-1) return NULL;
|
|
|
|
block->size = size;
|
|
block->free = 0;
|
|
block->next = NULL;
|
|
block->prev = heap_tail;
|
|
|
|
if (heap_tail) heap_tail->next = block;
|
|
else heap_head = block;
|
|
heap_tail = block;
|
|
|
|
return block;
|
|
}
|
|
|
|
// Split a block if remainder is large enough
|
|
static void split_block(BlockMeta *block, size_t size) {
|
|
size_t remain = block->size - size - META_SIZE;
|
|
if (block->size < size + META_SIZE + MIN_SPLIT_SIZE) return;
|
|
|
|
BlockMeta *new_block = (BlockMeta *)((char *)(block + 1) + size);
|
|
new_block->size = remain;
|
|
new_block->free = 1;
|
|
new_block->next = block->next;
|
|
new_block->prev = block;
|
|
|
|
if (block->next) block->next->prev = new_block;
|
|
else heap_tail = new_block;
|
|
block->next = new_block;
|
|
block->size = size;
|
|
}
|
|
|
|
void *malloc(size_t size) {
|
|
if (size == 0) return NULL;
|
|
|
|
size = ALIGN8(size);
|
|
|
|
// First-fit search (faster than best-fit for large heaps)
|
|
BlockMeta *current = heap_head;
|
|
while (current) {
|
|
if (current->free && current->size >= size) {
|
|
split_block(current, size);
|
|
current->free = 0;
|
|
return (current + 1);
|
|
}
|
|
current = current->next;
|
|
}
|
|
|
|
// No suitable block found, request more space
|
|
BlockMeta *block = request_space(size);
|
|
if (!block) return NULL;
|
|
return (block + 1);
|
|
}
|
|
|
|
void free(void *ptr) {
|
|
if (!ptr) return;
|
|
|
|
BlockMeta *block = (BlockMeta *)ptr - 1;
|
|
block->free = 1;
|
|
|
|
// Coalesce with next block
|
|
if (block->next && block->next->free) {
|
|
block->size += META_SIZE + block->next->size;
|
|
block->next = block->next->next;
|
|
if (block->next) block->next->prev = block;
|
|
else heap_tail = block;
|
|
}
|
|
|
|
// Coalesce with previous block
|
|
if (block->prev && block->prev->free) {
|
|
block->prev->size += META_SIZE + block->size;
|
|
block->prev->next = block->next;
|
|
if (block->next) block->next->prev = block->prev;
|
|
else heap_tail = block->prev;
|
|
}
|
|
}
|
|
|
|
void *calloc(size_t nelem, size_t elsize) {
|
|
size_t size = nelem * elsize;
|
|
void *ptr = malloc(size);
|
|
if (ptr) {
|
|
char *p = ptr;
|
|
for (size_t i = 0; i < size; i++) {
|
|
p[i] = 0;
|
|
}
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
void *realloc(void *ptr, size_t size) {
|
|
if (!ptr) {
|
|
return malloc(size);
|
|
}
|
|
if (size == 0) {
|
|
free(ptr);
|
|
return NULL;
|
|
}
|
|
|
|
BlockMeta *block = (BlockMeta*)ptr - 1;
|
|
if (block->size >= size) {
|
|
return ptr;
|
|
}
|
|
|
|
void *new_ptr = malloc(size);
|
|
if (!new_ptr) {
|
|
return NULL;
|
|
}
|
|
|
|
char *src = ptr;
|
|
char *dst = new_ptr;
|
|
for (size_t i = 0; i < block->size; i++) {
|
|
dst[i] = src[i];
|
|
}
|
|
free(ptr);
|
|
return new_ptr;
|
|
}
|
|
|
|
void *memset(void *s, int c, size_t n) {
|
|
unsigned char *p = (unsigned char *)s;
|
|
while (n--) *p++ = (unsigned char)c;
|
|
return s;
|
|
}
|
|
|
|
void *memcpy(void *dest, const void *src, size_t n) {
|
|
unsigned char *d = (unsigned char *)dest;
|
|
const unsigned char *s = (const unsigned char *)src;
|
|
while (n--) *d++ = *s++;
|
|
return dest;
|
|
}
|
|
|
|
// String functions
|
|
size_t strlen(const char *s) {
|
|
size_t len = 0;
|
|
while (s[len]) len++;
|
|
return len;
|
|
}
|
|
|
|
int strcmp(const char *s1, const char *s2) {
|
|
while (*s1 && (*s1 == *s2)) {
|
|
s1++;
|
|
s2++;
|
|
}
|
|
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
|
|
}
|
|
|
|
char* strcpy(char *dest, const char *src) {
|
|
char *ret = dest;
|
|
while (*src) *dest++ = *src++;
|
|
*dest = 0;
|
|
return ret;
|
|
}
|
|
|
|
char* strcat(char *dest, const char *src) {
|
|
char *ret = dest;
|
|
while (*dest) dest++;
|
|
while (*src) *dest++ = *src++;
|
|
*dest = 0;
|
|
return ret;
|
|
}
|
|
|
|
int atoi(const char *nptr) {
|
|
int res = 0;
|
|
int sign = 1;
|
|
if (*nptr == '-') {
|
|
sign = -1;
|
|
nptr++;
|
|
}
|
|
while (*nptr >= '0' && *nptr <= '9') {
|
|
res = res * 10 + (*nptr - '0');
|
|
nptr++;
|
|
}
|
|
return sign * res;
|
|
}
|
|
|
|
void itoa(int n, char *buf) {
|
|
if (n == 0) {
|
|
buf[0] = '0'; buf[1] = 0; return;
|
|
}
|
|
int i = 0;
|
|
int sign = n < 0;
|
|
if (sign) n = -n;
|
|
while (n > 0) {
|
|
buf[i++] = (n % 10) + '0';
|
|
n /= 10;
|
|
}
|
|
if (sign) buf[i++] = '-';
|
|
buf[i] = 0;
|
|
// Reverse
|
|
for (int j = 0; j < i / 2; j++) {
|
|
char t = buf[j];
|
|
buf[j] = buf[i - 1 - j];
|
|
buf[i - 1 - j] = t;
|
|
}
|
|
}
|
|
|
|
// IO functions
|
|
void puts(const char *s) {
|
|
sys_write(1, s, strlen(s));
|
|
sys_write(1, "\n", 1);
|
|
}
|
|
|
|
void printf(const char *fmt, ...) {
|
|
__builtin_va_list args;
|
|
__builtin_va_start(args, fmt);
|
|
char buf[1024];
|
|
int buf_idx = 0;
|
|
|
|
while (*fmt) {
|
|
if (*fmt == '%') {
|
|
fmt++;
|
|
// Flush current buffer
|
|
if (buf_idx > 0) {
|
|
sys_write(1, buf, buf_idx);
|
|
buf_idx = 0;
|
|
}
|
|
|
|
if (*fmt == 's') {
|
|
char *s = __builtin_va_arg(args, char *);
|
|
if (s) sys_write(1, s, strlen(s));
|
|
else sys_write(1, "(null)", 6);
|
|
} else if (*fmt == 'd') {
|
|
int d = __builtin_va_arg(args, int);
|
|
char ibuf[32];
|
|
itoa(d, ibuf);
|
|
sys_write(1, ibuf, strlen(ibuf));
|
|
} else if (*fmt == 'X' || *fmt == 'x') {
|
|
uint32_t val = __builtin_va_arg(args, uint32_t);
|
|
char xbuf[16];
|
|
int xi = 0;
|
|
if (val == 0) xbuf[xi++] = '0';
|
|
else {
|
|
while (val > 0) {
|
|
uint32_t rem = val % 16;
|
|
xbuf[xi++] = (rem < 10) ? (rem + '0') : (rem - 10 + 'A');
|
|
val /= 16;
|
|
}
|
|
}
|
|
while (xi > 0) {
|
|
char c = xbuf[--xi];
|
|
sys_write(1, &c, 1);
|
|
}
|
|
} else if (*fmt == 'c') {
|
|
char c = (char)__builtin_va_arg(args, int);
|
|
sys_write(1, &c, 1);
|
|
} else if (*fmt == '%') {
|
|
char c = '%';
|
|
sys_write(1, &c, 1);
|
|
}
|
|
} else {
|
|
buf[buf_idx++] = *fmt;
|
|
if (buf_idx >= 1024) {
|
|
sys_write(1, buf, buf_idx);
|
|
buf_idx = 0;
|
|
}
|
|
}
|
|
fmt++;
|
|
}
|
|
if (buf_idx > 0) {
|
|
sys_write(1, buf, buf_idx);
|
|
}
|
|
__builtin_va_end(args);
|
|
}
|
|
|
|
// System/Process functions
|
|
int chdir(const char *path) {
|
|
return sys_chdir(path);
|
|
}
|
|
|
|
char* getcwd(char *buf, int size) {
|
|
if (sys_getcwd(buf, size) == 0) return buf;
|
|
return NULL;
|
|
}
|
|
|
|
void sleep(int ms) {
|
|
sys_system(46, ms, 0, 0, 0);
|
|
}
|
|
|
|
void exit(int status) {
|
|
sys_exit(status);
|
|
}
|