mm: make malloc and free system calls
This is required because the heap is shared among all tasks and protected using a mutex which only works in kernel space.
This commit is contained in:
parent
040b5af5d6
commit
fb9ec2a8bc
20 changed files with 214 additions and 72 deletions
|
@ -3,13 +3,32 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#include <toolchain.h>
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
# define __breakpoint __asm__ volatile("bkpt")
|
# define __breakpoint __asm__ volatile("bkpt")
|
||||||
#else
|
#else
|
||||||
# define __breakpoint
|
# define __breakpoint
|
||||||
|
# define NDEBUG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define __breakpoint
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__always_inline int __is_kernel(void) {
|
||||||
|
int psr_val;
|
||||||
|
|
||||||
|
__asm__ volatile(
|
||||||
|
" mrs %0, psr \n"
|
||||||
|
: "=&r" (psr_val)
|
||||||
|
);
|
||||||
|
|
||||||
|
return psr_val & 0x01ff; /* bits 8-0 hold ISR_NUMBER */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of Ardix.
|
* This file is part of Ardix.
|
||||||
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
|
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#define ARCH_SYS_read 0
|
#define ARCH_SYS_read 0
|
||||||
#define ARCH_SYS_write 1
|
#define ARCH_SYS_write 1
|
||||||
#define ARCH_SYS_sleep 2
|
#define ARCH_SYS_sleep 2
|
||||||
|
#define ARCH_SYS_malloc 3
|
||||||
|
#define ARCH_SYS_free 4
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of Ardix.
|
* This file is part of Ardix.
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <toolchain.h>
|
#include <toolchain.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup malloc Memory Management
|
* @defgroup kmalloc Kernel Memory Management
|
||||||
*
|
*
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
@ -15,18 +15,18 @@
|
||||||
* @brief Allocate `size` bytes of memory *w/out initializing it*.
|
* @brief Allocate `size` bytes of memory *w/out initializing it*.
|
||||||
*
|
*
|
||||||
* This method may block if an allocation is already taking place.
|
* This method may block if an allocation is already taking place.
|
||||||
* Use `atomic_malloc()` if you are in kernel space and in atomic context.
|
* Use `atomic_kmalloc()` if you are in kernel space and in atomic context.
|
||||||
*
|
*
|
||||||
* @param size The amount of bytes to allocate.
|
* @param size The amount of bytes to allocate.
|
||||||
* @return A pointer to the beginning of the memory area, or `NULL` if
|
* @return A pointer to the beginning of the memory area, or `NULL` if
|
||||||
* `size` was 0 or there is not enough free memory left.
|
* `size` was 0 or there is not enough free memory left.
|
||||||
*/
|
*/
|
||||||
__shared __malloc(free, 1) void *malloc(size_t size);
|
__malloc(kfree, 1) void *kmalloc(size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Allocate `size` bytes of memory *w/out initializing it*.
|
* @brief Allocate `size` bytes of memory *w/out initializing it*.
|
||||||
*
|
*
|
||||||
* Unlike `malloc()`, this method is guaranteed not to sleep. It does this by
|
* Unlike `kmalloc()`, this method is guaranteed not to sleep. It does this by
|
||||||
* using a completely separate, smaller heap. Only use this if you already are
|
* using a completely separate, smaller heap. Only use this if you already are
|
||||||
* in atomic context, like when in an irq.
|
* in atomic context, like when in an irq.
|
||||||
*
|
*
|
||||||
|
@ -34,18 +34,7 @@ __shared __malloc(free, 1) void *malloc(size_t size);
|
||||||
* @return A pointer to the beginning of the memory area, or `NULL` if
|
* @return A pointer to the beginning of the memory area, or `NULL` if
|
||||||
* `size` was 0 or there is not enough free memory left.
|
* `size` was 0 or there is not enough free memory left.
|
||||||
*/
|
*/
|
||||||
__malloc(free, 1) void *atomic_malloc(size_t size);
|
__malloc(kfree, 1) void *atomic_kmalloc(size_t size);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Allocate an array and initialize the memory to zeroes.
|
|
||||||
* The allocated size will be at least `nmemb * size`.
|
|
||||||
* If the multiplication would overflow, the allocation fails.
|
|
||||||
*
|
|
||||||
* @param nmemb The amount of members.
|
|
||||||
* @param size The size of an individual member.
|
|
||||||
* @return A pointer to the zeroed-out memory, or `NULL` if OOM.
|
|
||||||
*/
|
|
||||||
__shared __malloc(free, 1) void *calloc(size_t nmemb, size_t size);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Free a previously allocated memory region.
|
* @brief Free a previously allocated memory region.
|
||||||
|
@ -53,12 +42,12 @@ __shared __malloc(free, 1) void *calloc(size_t nmemb, size_t size);
|
||||||
*
|
*
|
||||||
* @param ptr The pointer, as returned by `malloc`/`calloc`.
|
* @param ptr The pointer, as returned by `malloc`/`calloc`.
|
||||||
*/
|
*/
|
||||||
__shared void free(void *ptr);
|
void kfree(void *ptr);
|
||||||
|
|
||||||
/** @} */
|
|
||||||
|
|
||||||
/** Initialize the memory allocator, this is only called by the bootloader on early bootstrap. */
|
/** Initialize the memory allocator, this is only called by the bootloader on early bootstrap. */
|
||||||
void malloc_init(void *heap, size_t size);
|
void kmalloc_init(void *heap, size_t size);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of Ardix.
|
* This file is part of Ardix.
|
||||||
|
|
|
@ -13,6 +13,8 @@ enum syscall {
|
||||||
SYS_read = ARCH_SYS_read,
|
SYS_read = ARCH_SYS_read,
|
||||||
SYS_write = ARCH_SYS_write,
|
SYS_write = ARCH_SYS_write,
|
||||||
SYS_sleep = ARCH_SYS_sleep,
|
SYS_sleep = ARCH_SYS_sleep,
|
||||||
|
SYS_malloc = ARCH_SYS_malloc,
|
||||||
|
SYS_free = ARCH_SYS_free,
|
||||||
NSYSCALLS
|
NSYSCALLS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
24
include/stdassert.h
Normal file
24
include/stdassert.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/* See the end of this file for copyright, license, and warranty information. */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <arch/debug.h>
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
# define assert(expr)
|
||||||
|
#else
|
||||||
|
# define assert(expr) if (!(expr)) { __breakpoint; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Ardix.
|
||||||
|
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
|
||||||
|
*
|
||||||
|
* Ardix is non-violent software: you may only use, redistribute,
|
||||||
|
* and/or modify it under the terms of the CNPLv6+ as found in
|
||||||
|
* the LICENSE file in the source code root directory or at
|
||||||
|
* <https://git.pixie.town/thufie/CNPL>.
|
||||||
|
*
|
||||||
|
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||||
|
* permitted by applicable law. See the CNPLv6+ for details.
|
||||||
|
*/
|
58
include/stdlib.h
Normal file
58
include/stdlib.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/* See the end of this file for copyright, license, and warranty information. */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ardix/types.h>
|
||||||
|
#include <toolchain.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup malloc Memory Management
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate `size` bytes of memory *w/out initializing it*.
|
||||||
|
*
|
||||||
|
* This method may block if an allocation is already taking place.
|
||||||
|
* Use `atomickmalloc()` if you are in kernel space and in atomic context.
|
||||||
|
*
|
||||||
|
* @param size The amount of bytes to allocate.
|
||||||
|
* @return A pointer to the beginning of the memory area, or `NULL` if
|
||||||
|
* `size` was 0 or there is not enough free memory left.
|
||||||
|
*/
|
||||||
|
__shared __malloc(free, 1) void *malloc(size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate an array and initialize the memory to zeroes.
|
||||||
|
* The allocated size will be at least `nmemb * size`.
|
||||||
|
* If the multiplication would overflow, the allocation fails.
|
||||||
|
*
|
||||||
|
* @param nmemb The amount of members.
|
||||||
|
* @param size The size of an individual member.
|
||||||
|
* @return A pointer to the zeroed-out memory, or `NULL` if OOM.
|
||||||
|
*/
|
||||||
|
__malloc(free, 1) void *calloc(size_t nmemb, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free a previously allocated memory region.
|
||||||
|
* Passing `NULL` has no effect.
|
||||||
|
*
|
||||||
|
* @param ptr The pointer, as returned by `malloc`/`calloc`.
|
||||||
|
*/
|
||||||
|
__shared void free(void *ptr);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Ardix.
|
||||||
|
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
|
||||||
|
*
|
||||||
|
* Ardix is non-violent software: you may only use, redistribute,
|
||||||
|
* and/or modify it under the terms of the CNPLv6+ as found in
|
||||||
|
* the LICENSE file in the source code root directory or at
|
||||||
|
* <https://git.pixie.town/thufie/CNPL>.
|
||||||
|
*
|
||||||
|
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||||
|
* permitted by applicable law. See the CNPLv6+ for details.
|
||||||
|
*/
|
|
@ -15,6 +15,7 @@ target_sources(ardix_kernel PRIVATE
|
||||||
kent.c
|
kent.c
|
||||||
kevent.c
|
kevent.c
|
||||||
main.c
|
main.c
|
||||||
|
mm.c
|
||||||
mutex.c
|
mutex.c
|
||||||
ringbuf.c
|
ringbuf.c
|
||||||
sched.c
|
sched.c
|
||||||
|
|
|
@ -14,7 +14,7 @@ struct kent *devices_kent = NULL;
|
||||||
static void devices_destroy(struct kent *kent)
|
static void devices_destroy(struct kent *kent)
|
||||||
{
|
{
|
||||||
/* should never be executed because the root devices kent is immortal */
|
/* should never be executed because the root devices kent is immortal */
|
||||||
free(kent);
|
kfree(kent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Initialize the devices subsystem. */
|
/** Initialize the devices subsystem. */
|
||||||
|
@ -23,7 +23,7 @@ int devices_init(void)
|
||||||
if (devices_kent != NULL)
|
if (devices_kent != NULL)
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
|
|
||||||
devices_kent = malloc(sizeof(*devices_kent));
|
devices_kent = kmalloc(sizeof(*devices_kent));
|
||||||
if (devices_kent == NULL)
|
if (devices_kent == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ int devices_init(void)
|
||||||
static void device_destroy(struct kent *kent)
|
static void device_destroy(struct kent *kent)
|
||||||
{
|
{
|
||||||
struct device *dev = kent_to_device(kent);
|
struct device *dev = kent_to_device(kent);
|
||||||
free(dev);
|
kfree(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
int device_init(struct device *dev)
|
int device_init(struct device *dev)
|
||||||
|
@ -54,12 +54,12 @@ static void device_kevent_destroy(struct kent *kent)
|
||||||
{
|
{
|
||||||
struct kevent *event = container_of(kent, struct kevent, kent);
|
struct kevent *event = container_of(kent, struct kevent, kent);
|
||||||
struct device_kevent *device_kevent = container_of(event, struct device_kevent, kevent);
|
struct device_kevent *device_kevent = container_of(event, struct device_kevent, kevent);
|
||||||
free(device_kevent);
|
kfree(device_kevent);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct device_kevent *device_kevent_create(struct device *device, enum device_kevent_flags flags)
|
struct device_kevent *device_kevent_create(struct device *device, enum device_kevent_flags flags)
|
||||||
{
|
{
|
||||||
struct device_kevent *event = atomic_malloc(sizeof(*event));
|
struct device_kevent *event = atomic_kmalloc(sizeof(*event));
|
||||||
if (event == NULL)
|
if (event == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ struct device_kevent *device_kevent_create(struct device *device, enum device_ke
|
||||||
event->kevent.kent.destroy = device_kevent_destroy;
|
event->kevent.kent.destroy = device_kevent_destroy;
|
||||||
int err = kent_init(&event->kevent.kent);
|
int err = kent_init(&event->kevent.kent);
|
||||||
if (err) {
|
if (err) {
|
||||||
free(event);
|
kfree(event);
|
||||||
event = NULL;
|
event = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
static void dmabuf_destroy(struct kent *kent)
|
static void dmabuf_destroy(struct kent *kent)
|
||||||
{
|
{
|
||||||
struct dmabuf *buf = kent_to_dmabuf(kent);
|
struct dmabuf *buf = kent_to_dmabuf(kent);
|
||||||
free(buf);
|
kfree(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dmabuf *dmabuf_create(struct device *dev, size_t len)
|
struct dmabuf *dmabuf_create(struct device *dev, size_t len)
|
||||||
|
@ -22,7 +22,7 @@ struct dmabuf *dmabuf_create(struct device *dev, size_t len)
|
||||||
* allocation needs to be atomic because the buffer might be
|
* allocation needs to be atomic because the buffer might be
|
||||||
* free()d from within an irq handler which cannot sleep
|
* free()d from within an irq handler which cannot sleep
|
||||||
*/
|
*/
|
||||||
struct dmabuf *buf = atomic_malloc(sizeof(*buf) + len);
|
struct dmabuf *buf = atomic_kmalloc(sizeof(*buf) + len);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ struct dmabuf *dmabuf_create(struct device *dev, size_t len)
|
||||||
|
|
||||||
err = kent_init(&buf->kent);
|
err = kent_init(&buf->kent);
|
||||||
if (err) {
|
if (err) {
|
||||||
free(buf);
|
kfree(buf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ static void file_destroy(struct kent *kent)
|
||||||
fdtab[file->fd] = NULL;
|
fdtab[file->fd] = NULL;
|
||||||
mutex_unlock(&fdtab_lock);
|
mutex_unlock(&fdtab_lock);
|
||||||
|
|
||||||
free(file);
|
kfree(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct file *file_create(struct device *device, enum file_type type, int *err)
|
struct file *file_create(struct device *device, enum file_type type, int *err)
|
||||||
|
@ -41,7 +41,7 @@ struct file *file_create(struct device *device, enum file_type type, int *err)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
f = malloc(sizeof(*f));
|
f = kmalloc(sizeof(*f));
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
*err = -ENOMEM;
|
*err = -ENOMEM;
|
||||||
mutex_unlock(&fdtab_lock);
|
mutex_unlock(&fdtab_lock);
|
||||||
|
@ -102,7 +102,7 @@ static int io_device_kevent_listener(struct kevent *event, void *_extra)
|
||||||
return KEVENT_CB_NONE;
|
return KEVENT_CB_NONE;
|
||||||
|
|
||||||
extra->task->state = TASK_QUEUE;
|
extra->task->state = TASK_QUEUE;
|
||||||
free(extra);
|
kfree(extra);
|
||||||
file_put(extra->file);
|
file_put(extra->file);
|
||||||
kent_put(&extra->task->kent);
|
kent_put(&extra->task->kent);
|
||||||
return KEVENT_CB_LISTENER_DEL | KEVENT_CB_STOP;
|
return KEVENT_CB_LISTENER_DEL | KEVENT_CB_STOP;
|
||||||
|
@ -114,7 +114,7 @@ static int iowait_device(struct file *file, enum device_kevent_flags flags)
|
||||||
kent_get(¤t->kent);
|
kent_get(¤t->kent);
|
||||||
|
|
||||||
/* this must be atomic because event listeners can't sleep but need to call free() */
|
/* this must be atomic because event listeners can't sleep but need to call free() */
|
||||||
struct io_device_kevent_extra *extra = atomic_malloc(sizeof(*extra));
|
struct io_device_kevent_extra *extra = atomic_kmalloc(sizeof(*extra));
|
||||||
if (extra == NULL)
|
if (extra == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -201,12 +201,12 @@ static void file_kevent_destroy(struct kent *kent)
|
||||||
{
|
{
|
||||||
struct kevent *kevent = container_of(kent, struct kevent, kent);
|
struct kevent *kevent = container_of(kent, struct kevent, kent);
|
||||||
struct file_kevent *file_kevent = container_of(kevent, struct file_kevent, kevent);
|
struct file_kevent *file_kevent = container_of(kevent, struct file_kevent, kevent);
|
||||||
free(file_kevent);
|
kfree(file_kevent);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct file_kevent *file_kevent_create(struct file *f, enum file_kevent_flags flags)
|
struct file_kevent *file_kevent_create(struct file *f, enum file_kevent_flags flags)
|
||||||
{
|
{
|
||||||
struct file_kevent *event = atomic_malloc(sizeof(*event));
|
struct file_kevent *event = atomic_kmalloc(sizeof(*event));
|
||||||
if (event == NULL)
|
if (event == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ struct file_kevent *file_kevent_create(struct file *f, enum file_kevent_flags fl
|
||||||
event->kevent.kent.destroy = file_kevent_destroy;
|
event->kevent.kent.destroy = file_kevent_destroy;
|
||||||
int err = kent_init(&event->kevent.kent);
|
int err = kent_init(&event->kevent.kent);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
free(event);
|
kfree(event);
|
||||||
event = NULL;
|
event = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ long sys_read(int fd, __user void *buf, size_t len)
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
copy = malloc(len);
|
copy = kmalloc(len);
|
||||||
if (copy == NULL)
|
if (copy == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ long sys_read(int fd, __user void *buf, size_t len)
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
ret = copy_to_user(buf, copy, ret);
|
ret = copy_to_user(buf, copy, ret);
|
||||||
|
|
||||||
free(copy);
|
kfree(copy);
|
||||||
file_put(f);
|
file_put(f);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ long sys_write(int fd, __user const void *buf, size_t len)
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
copy = malloc(len);
|
copy = kmalloc(len);
|
||||||
if (copy == NULL) {
|
if (copy == NULL) {
|
||||||
file_put(f);
|
file_put(f);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -27,7 +27,7 @@ long sys_write(int fd, __user const void *buf, size_t len)
|
||||||
len = copy_from_user(copy, buf, len);
|
len = copy_from_user(copy, buf, len);
|
||||||
ret = file_write(f, copy, len);
|
ret = file_write(f, copy, len);
|
||||||
|
|
||||||
free(copy);
|
kfree(copy);
|
||||||
file_put(f);
|
file_put(f);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ static inline void process_single_queue(struct kevent_queue *queue, struct list_
|
||||||
|
|
||||||
if (cb_ret & KEVENT_CB_LISTENER_DEL) {
|
if (cb_ret & KEVENT_CB_LISTENER_DEL) {
|
||||||
list_delete(&listener->link);
|
list_delete(&listener->link);
|
||||||
free(listener);
|
kfree(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cb_ret & KEVENT_CB_STOP)
|
if (cb_ret & KEVENT_CB_STOP)
|
||||||
|
@ -102,7 +102,6 @@ void kevents_process(void)
|
||||||
process_single_queue(&kev_queues[i], &kev_listeners[i]);
|
process_single_queue(&kev_queues[i], &kev_listeners[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called from irq context only */
|
|
||||||
void kevent_dispatch(struct kevent *event)
|
void kevent_dispatch(struct kevent *event)
|
||||||
{
|
{
|
||||||
struct kevent_queue *queue = &kev_queues[event->kind];
|
struct kevent_queue *queue = &kev_queues[event->kind];
|
||||||
|
@ -138,7 +137,7 @@ struct kevent_listener *kevent_listener_add(enum kevent_kind kind,
|
||||||
int (*cb)(struct kevent *, void *),
|
int (*cb)(struct kevent *, void *),
|
||||||
void *extra)
|
void *extra)
|
||||||
{
|
{
|
||||||
struct kevent_listener *listener = malloc(sizeof(*listener));
|
struct kevent_listener *listener = kmalloc(sizeof(*listener));
|
||||||
|
|
||||||
if (listener != NULL) {
|
if (listener != NULL) {
|
||||||
listener->cb = cb;
|
listener->cb = cb;
|
||||||
|
@ -158,7 +157,7 @@ void kevent_listener_del(struct kevent_listener *listener)
|
||||||
list_delete(&listener->link);
|
list_delete(&listener->link);
|
||||||
mutex_unlock(&kev_listeners_lock);
|
mutex_unlock(&kev_listeners_lock);
|
||||||
|
|
||||||
free(listener);
|
kfree(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
* header containing its size w/out overhead; free blocks additionally have a
|
* header containing its size w/out overhead; free blocks additionally have a
|
||||||
* `struct list_head` after that in order to keep track of where the free blocks
|
* `struct list_head` after that in order to keep track of where the free blocks
|
||||||
* are. This list is ordered by size ascendingly, so we can directly take the
|
* are. This list is ordered by size ascendingly, so we can directly take the
|
||||||
* first sufficiently sized block when iterating over the list in `malloc()`.
|
* first sufficiently sized block when iterating over the list in kmalloc()`.
|
||||||
*
|
*
|
||||||
* Additionally, the effective block size is copied to the very end of the block
|
* Additionally, the effective block size is copied to the very end of the block
|
||||||
* (directly after the last usable address) in order to be able to find a
|
* (directly after the last usable address) in order to be able to find a
|
||||||
|
@ -106,7 +106,7 @@ struct memblk {
|
||||||
/** @brief If the block is allocated, this will be overwritten */
|
/** @brief If the block is allocated, this will be overwritten */
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
|
||||||
/** @brief Used as the return value for `malloc()` */
|
/** @brief Used as the return value for kmalloc()` */
|
||||||
uint8_t data[0];
|
uint8_t data[0];
|
||||||
/** @brief Used to get the copy of the size field at the end of the block */
|
/** @brief Used to get the copy of the size field at the end of the block */
|
||||||
size_t endsz[0];
|
size_t endsz[0];
|
||||||
|
@ -164,7 +164,18 @@ static struct memblk *blk_try_merge(struct list_head *heap, struct memblk *blk);
|
||||||
/** @brief Cut a slice from a free block and return the slice. */
|
/** @brief Cut a slice from a free block and return the slice. */
|
||||||
static struct memblk *blk_slice(struct list_head *heap, struct memblk *bottom, size_t bottom_size);
|
static struct memblk *blk_slice(struct list_head *heap, struct memblk *bottom, size_t bottom_size);
|
||||||
|
|
||||||
void malloc_init(void *heap, size_t size)
|
long sys_malloc(size_t size)
|
||||||
|
{
|
||||||
|
void *ptr = kmalloc(size);
|
||||||
|
return *(long *)&ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sys_free(void *ptr)
|
||||||
|
{
|
||||||
|
kfree(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void kmalloc_init(void *heap, size_t size)
|
||||||
{
|
{
|
||||||
memset(heap, 0, size);
|
memset(heap, 0, size);
|
||||||
|
|
||||||
|
@ -191,7 +202,7 @@ void malloc_init(void *heap, size_t size)
|
||||||
atomic_heap_free = blk_get_size(atomic_block);
|
atomic_heap_free = blk_get_size(atomic_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *malloc(size_t size)
|
void *kmalloc(size_t size)
|
||||||
{
|
{
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return NULL; /* as per POSIX */
|
return NULL; /* as per POSIX */
|
||||||
|
@ -230,7 +241,7 @@ void *malloc(size_t size)
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *atomic_malloc(size_t size)
|
void *atomic_kmalloc(size_t size)
|
||||||
{
|
{
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -260,23 +271,7 @@ void *atomic_malloc(size_t size)
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *calloc(size_t nmemb, size_t size)
|
void kfree(void *ptr)
|
||||||
{
|
|
||||||
size_t total = nmemb * size;
|
|
||||||
|
|
||||||
/* check for overflow as mandated by POSIX */
|
|
||||||
if (size != 0 && total / size != nmemb)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
void *ptr = malloc(total);
|
|
||||||
|
|
||||||
if (ptr != NULL)
|
|
||||||
memset(ptr, 0, total);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free(void *ptr)
|
|
||||||
{
|
{
|
||||||
if (ptr == NULL)
|
if (ptr == NULL)
|
||||||
return; /* as per POSIX.1-2008 */
|
return; /* as per POSIX.1-2008 */
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
struct ringbuf *ringbuf_create(size_t size)
|
struct ringbuf *ringbuf_create(size_t size)
|
||||||
{
|
{
|
||||||
struct ringbuf *buf = malloc(sizeof(*buf) + size);
|
struct ringbuf *buf = kmalloc(sizeof(*buf) + size);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ struct ringbuf *ringbuf_create(size_t size)
|
||||||
|
|
||||||
inline void ringbuf_destroy(struct ringbuf *buf)
|
inline void ringbuf_destroy(struct ringbuf *buf)
|
||||||
{
|
{
|
||||||
free(buf);
|
kfree(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ringbuf_read(void *dest, struct ringbuf *buf, size_t len)
|
size_t ringbuf_read(void *dest, struct ringbuf *buf, size_t len)
|
||||||
|
|
|
@ -57,7 +57,7 @@ static void task_destroy(struct kent *kent)
|
||||||
{
|
{
|
||||||
struct task *task = container_of(kent, struct task, kent);
|
struct task *task = container_of(kent, struct task, kent);
|
||||||
tasks[task->pid] = NULL;
|
tasks[task->pid] = NULL;
|
||||||
free(task);
|
kfree(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sched_init(void)
|
int sched_init(void)
|
||||||
|
|
|
@ -13,6 +13,8 @@ long (*const sys_table[NSYSCALLS])(sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
|
||||||
sys_table_entry(SYS_read, sys_read),
|
sys_table_entry(SYS_read, sys_read),
|
||||||
sys_table_entry(SYS_write, sys_write),
|
sys_table_entry(SYS_write, sys_write),
|
||||||
sys_table_entry(SYS_sleep, sys_sleep),
|
sys_table_entry(SYS_sleep, sys_sleep),
|
||||||
|
sys_table_entry(SYS_malloc, sys_malloc),
|
||||||
|
sys_table_entry(SYS_free, sys_free),
|
||||||
};
|
};
|
||||||
|
|
||||||
long sys_stub(void)
|
long sys_stub(void)
|
||||||
|
|
|
@ -10,8 +10,8 @@ target_sources(ardix_lib PRIVATE
|
||||||
ctype.c
|
ctype.c
|
||||||
errno.c
|
errno.c
|
||||||
list.c
|
list.c
|
||||||
malloc.c
|
|
||||||
printf.c
|
printf.c
|
||||||
|
stdlib.c
|
||||||
string.c
|
string.c
|
||||||
unistd.c
|
unistd.c
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
/* See the end of this file for copyright, license, and warranty information. */
|
/* See the end of this file for copyright, license, and warranty information. */
|
||||||
|
|
||||||
#include <ardix/malloc.h>
|
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
/* Using GCC's stdarg.h is recommended even with -nodefaultlibs and -fno-builtin */
|
/* Using GCC's stdarg.h is recommended even with -nodefaultlibs and -fno-builtin */
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
52
lib/stdlib.c
Normal file
52
lib/stdlib.c
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/* See the end of this file for copyright, license, and warranty information. */
|
||||||
|
|
||||||
|
#include <ardix/syscall.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kmalloc() and free() are system calls in Ardix because the heap is shared
|
||||||
|
* among all tasks and locked using a mutex. If the lock is already claimed,
|
||||||
|
* the `mutex_lock()` routine will suspend the current task until the lock
|
||||||
|
* becomes available to the current process. However, this can only happen
|
||||||
|
* when we already are in kernel space.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void *malloc(size_t size)
|
||||||
|
{
|
||||||
|
if (size == 0) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
long int intptr = syscall(SYS_malloc, (sysarg_t)size);
|
||||||
|
return *(void **)&intptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *calloc(size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
size_t total = nmemb * size;
|
||||||
|
if (nmemb != 0 && total / nmemb != size)
|
||||||
|
return NULL; /* overflow check as mandated by POSIX.1 */
|
||||||
|
long int intptr = syscall(SYS_malloc, (sysarg_t)total);
|
||||||
|
return *(void **)&intptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr != NULL)
|
||||||
|
syscall(SYS_free, (sysarg_t)ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Ardix.
|
||||||
|
* Copyright (c) 2020, 2021 Felix Kopp <owo@fef.moe>.
|
||||||
|
*
|
||||||
|
* Ardix is non-violent software: you may only use, redistribute,
|
||||||
|
* and/or modify it under the terms of the CNPLv6+ as found in
|
||||||
|
* the LICENSE file in the source code root directory or at
|
||||||
|
* <https://git.pixie.town/thufie/CNPL>.
|
||||||
|
*
|
||||||
|
* Ardix comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||||
|
* permitted by applicable law. See the CNPLv6+ for details.
|
||||||
|
*/
|
Loading…
Reference in a new issue