Skip to content

Commit

Permalink
Merge pull request #30 from badgeteam/mutex
Browse files Browse the repository at this point in the history
Simple spinlock mutexes.
  • Loading branch information
robotman2412 authored Aug 14, 2023
2 parents 63a1957 + 4da3f99 commit a8d2c7c
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 118 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ add_executable(${target}
${CMAKE_CURRENT_LIST_DIR}/src/log.c
${CMAKE_CURRENT_LIST_DIR}/src/main.c
${CMAKE_CURRENT_LIST_DIR}/src/malloc.c
${CMAKE_CURRENT_LIST_DIR}/src/mutex.c
${CMAKE_CURRENT_LIST_DIR}/src/num_to_str.c
${CMAKE_CURRENT_LIST_DIR}/src/scheduler.c
${CMAKE_CURRENT_LIST_DIR}/src/syscall.c
Expand Down
43 changes: 43 additions & 0 deletions include/mutex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

// SPDX-License-Identifier: MIT

#pragma once

#include "badge_err.h"
#include "time.h"

#include <stdatomic.h>

// Magic value for the magic field.
#define MUTEX_MAGIC (int)0xcafebabe

typedef struct {
// Magic value.
atomic_int magic;
// Mutex allows sharing.
bool is_shared;
// Share count and/or is locked.
atomic_int shares;
} mutex_t;

#define MUTEX_T_INIT ((mutex_t){MUTEX_MAGIC, 0, 0})
#define MUTEX_T_INIT_SHARED ((mutex_t){MUTEX_MAGIC, 1, 0})

// Initialise a mutex for unshared use.
void mutex_init(badge_err_t *ec, mutex_t *mutex);
// Initialise a mutex for shared use.
void mutex_init_shared(badge_err_t *ec, mutex_t *mutex);
// Clean up the mutex.
void mutex_destroy(badge_err_t *ec, mutex_t *mutex);
// Try to acquire `mutex` within `max_wait_us` microseconds.
// Returns true if the mutex was successully acquired.
bool mutex_acquire(badge_err_t *ec, mutex_t *mutex, timestamp_us_t max_wait_us);
// Release `mutex`, if it was initially acquired by this thread.
// Returns true if the mutex was successfully released.
bool mutex_release(badge_err_t *ec, mutex_t *mutex);
// Try to acquire a share in `mutex` within `max_wait_us` microseconds.
// Returns true if the share was successfully acquired.
bool mutex_acquire_shared(badge_err_t *ec, mutex_t *mutex, timestamp_us_t max_wait_us);
// Release `mutex`, if it was initially acquired by this thread.
// Returns true if the mutex was successfully released.
bool mutex_release_shared(badge_err_t *ec, mutex_t *mutex);
138 changes: 20 additions & 118 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,23 @@
// SPDX-License-Identifier: MIT

#include "assertions.h"
#include "attributes.h"
#include "cpu/riscv_pmp.h"
#include "gpio.h"
#include "log.h"
#include "malloc.h"
#include "memprotect.h"
#include "port/interrupt.h"
#include "rawprint.h"
#include "scheduler.h"
#include "syscall.h"
#include "time.h"

#include <stdint.h>

// Temporary kernel context until threading is implemented.
static kernel_ctx_t kctx;

static void led_blink_loop(void *);
static void uart_print_loop(void *);

struct led_config {
int pin;
uint64_t off_time;
uint64_t on_time;
};

static struct led_config led_pins[3] = {
{.pin = 19, .off_time = 300000, .on_time = 200000},
{.pin = 20, .off_time = 250000, .on_time = 350000},
{.pin = 21, .off_time = 500000, .on_time = 400000},
};
static uint8_t led_blink_stack[3][512] ALIGNED_TO(STACK_ALIGNMENT);
static uint8_t uart_print_stack[3][256] ALIGNED_TO(STACK_ALIGNMENT);


uint32_t userland_stack[1024];

static void userland_entry(void *ignored) {
asm(".option push\n"
".option norelax\n"
".global __global_pointer$\n"
".global userland_stack\n"
"la gp, __global_pointer$\n"
"la sp, userland_stack+4096\n"
".option pop");
logk(LOG_DEBUG, "This is a USER MESSAGE!");
while (1) syscall_thread_yield();
}
void debug_func(void *);
#define stack_size 1024
static uint8_t stack0[stack_size] ALIGNED_TO(STACK_ALIGNMENT);

// This is the entrypoint after the stack has been set up and the init functions
// have been run. Main is not allowed to return, so declare it noreturn.
Expand All @@ -68,104 +37,37 @@ void main() {
// called as early as possible.
time_init();

// Set up memory allocator.
kernel_heap_init();

// Test a log message.
logk(LOG_FATAL, "The ultimage log message test");
logk(LOG_ERROR, "The ultimage log message test");
logk(LOG_WARN, "The ultimage log message test");
logk(LOG_INFO, "The ultimage log message test");
logk(LOG_DEBUG, "The ultimage log message test");

// Test a GPIO.
io_mode(NULL, 22, IO_MODE_INPUT);
io_pull(NULL, 22, IO_PULL_UP);



// Set up multithreading.
sched_init(&err);
assert_always(badge_err_is_ok(&err));

for (size_t i = 0; i < 3; i++) {

sched_thread_t *const led_thread = sched_create_kernel_thread(
&err,
led_blink_loop,
&led_pins[i],
led_blink_stack[i],
sizeof led_blink_stack[i],
SCHED_PRIO_NORMAL
);
assert_always(badge_err_is_ok(&err));
assert_always(led_thread != NULL);

char thread_name[] = {'l', 'e', 'd', '-', '0' + i, 0};

sched_set_name(&err, led_thread, thread_name);
assert_always(badge_err_is_ok(&err));

sched_resume_thread(&err, led_thread);
assert_always(badge_err_is_ok(&err));
}

sched_thread_t *const print_thread = sched_create_kernel_thread(
&err,
uart_print_loop,
NULL,
uart_print_stack,
sizeof uart_print_stack,
SCHED_PRIO_NORMAL
);
// A debug thread.
sched_thread_t *const debug_thread_0 =
sched_create_kernel_thread(&err, debug_func, NULL, stack0, stack_size, SCHED_PRIO_NORMAL);
assert_always(badge_err_is_ok(&err));
assert_always(print_thread != NULL);

sched_set_name(&err, print_thread, "print");
sched_set_name(&err, debug_thread_0, "debug0");
assert_always(badge_err_is_ok(&err));

sched_resume_thread(&err, print_thread);
sched_resume_thread(&err, debug_thread_0);
assert_always(badge_err_is_ok(&err));


// Enter the scheduler
sched_exec();

__builtin_unreachable();
}

static void led_blink_loop(void *ptr) {
struct led_config *cfg = ptr;

logkf(LOG_INFO, "led thread %{d} (%{size;x})", cfg->pin, (size_t)cfg);

io_mode(NULL, cfg->pin, IO_MODE_OUTPUT);

int64_t next_blink = time_us();
while (1) {
io_write(NULL, cfg->pin, true);
next_blink += cfg->on_time;
while (time_us() < next_blink) {
sched_yield();
}

io_write(NULL, cfg->pin, false);
next_blink += cfg->off_time;
while (time_us() < next_blink) {
sched_yield();
}
}
}

static void uart_print_loop(void *) {

int loops = 0;

void debug_func(void *arg) {
(void)arg;
io_mode(NULL, 19, IO_MODE_OUTPUT);
timestamp_us_t t;
while (1) {
int64_t const now = time_us();


// Busy waiting loop to test preemptive multitasking.
while (time_us() < now + 700000)
;
logkf(LOG_INFO, "timer loop %{d}", ++loops);
io_write(NULL, 19, true);
t = time_us() + 500000;
while (time_us() < t) sched_yield();
io_write(NULL, 19, false);
t = time_us() + 500000;
while (time_us() < t) sched_yield();
}
}
Loading

0 comments on commit a8d2c7c

Please sign in to comment.