broken mutex

This commit is contained in:
flysand7 2023-08-27 13:51:35 +11:00
parent fa1f9ec0e6
commit 35a760e54e
11 changed files with 213 additions and 5 deletions

5
cia.c
View File

@ -9,6 +9,7 @@
#include <stdio.h>
#include <threads.h>
#include <cia/mem.h>
#include <cia/sync.h>
// Module cia_memory
#include "src/cia-mem/util.c"
@ -16,6 +17,9 @@
#include "src/cia-mem/arena.c"
#include "src/cia-mem/pool.c"
// Module cia_sync
#include "src/cia-sync/mutex.c"
// Module stdlib_program
#include "src/stdlib-program/program.c"
@ -24,3 +28,4 @@
// Module stdlib_file
#include "src/stdlib-file/file.c"

View File

@ -1,4 +1,17 @@
#pragma once
#include <stdatomic.h>
int cia_wait(u32 *addr, u32 compare_with, u64 time);
int cia_wake_one(u32 *addr, u32 *n_woken);
int cia_wake_all(u32 *addr, u32 *n_woken);
struct Cia_Mutex typedef Cia_Mutex;
struct Cia_Mutex {
u32 tag;
};
void cia_mutex_init(Cia_Mutex *mutex);
void cia_mutex_lock(Cia_Mutex *mutex);
void cia_mutex_unlock(Cia_Mutex *mutex);

77
include/linux/futex.h Normal file
View File

@ -0,0 +1,77 @@
#pragma once
#include <cia/def.h>
#define FUTEX_WAIT 0
#define FUTEX_WAKE 1
#define FUTEX_FD 2
#define FUTEX_REQUEUE 3
#define FUTEX_CMP_REQUEUE 4
#define FUTEX_WAKE_OP 5
#define FUTEX_LOCK_PI 6
#define FUTEX_UNLOCK_PI 7
#define FUTEX_TRYLOCK_PI 8
#define FUTEX_WAIT_BITSET 9
#define FUTEX_WAKE_BITSET 10
#define FUTEX_WAIT_REQUEUE_PI 11
#define FUTEX_CMP_REQUEUE_PI 12
#define FUTEX_LOCK_PI2 13
#define FUTEX_PRIVATE_FLAG 128
#define FUTEX_CLOCK_REALTIME 256
#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
#define FUTEX_WAIT_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_WAIT)
#define FUTEX_WAKE_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_WAKE)
#define FUTEX_REQUEUE_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_REQUEUE)
#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE)
#define FUTEX_WAKE_OP_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_WAKE_OP)
#define FUTEX_LOCK_PI_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_LOCK_PI)
#define FUTEX_LOCK_PI2_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_LOCK_PI2)
#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_UNLOCK_PI)
#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_TRYLOCK_PI)
#define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_WAIT_BITSET)
#define FUTEX_WAKE_BITSET_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_WAKE_BITSET)
#define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_WAIT_REQUEUE_PI)
#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE_PI)
#define FUTEX_32 2
#define FUTEX_WAITV_MAX 128
struct futex_waitv {
u64 val;
u64 uaddr;
u32 flags;
u32 __reserved;
};
struct robust_list {
struct robust_list *next;
};
struct robust_list_head {
struct robust_list list;
long futex_offset;
struct robust_list *list_op_pending;
};
#define FUTEX_WAITERS 0x80000000
#define FUTEX_OWNER_DIED 0x40000000
#define FUTEX_TID_MASK 0x3fffffff
#define ROBUST_LIST_LIMIT 2048
#define FUTEX_BITSET_MATCH_ANY 0xffffffff
#define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */
#define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */
#define FUTEX_OP_OR 2 /* *(int *)UADDR2 |= OPARG; */
#define FUTEX_OP_ANDN 3 /* *(int *)UADDR2 &= ~OPARG; */
#define FUTEX_OP_XOR 4 /* *(int *)UADDR2 ^= OPARG; */
#define FUTEX_OP_OPARG_SHIFT 8 /* Use (1 << OPARG) instead of OPARG. */
#define FUTEX_OP_CMP_EQ 0 /* if (oldval == CMPARG) wake */
#define FUTEX_OP_CMP_NE 1 /* if (oldval != CMPARG) wake */
#define FUTEX_OP_CMP_LT 2 /* if (oldval < CMPARG) wake */
#define FUTEX_OP_CMP_LE 3 /* if (oldval <= CMPARG) wake */
#define FUTEX_OP_CMP_GT 4 /* if (oldval > CMPARG) wake */
#define FUTEX_OP_CMP_GE 5 /* if (oldval >= CMPARG) wake */

7
include/time.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
struct timespec {
time_t tv_sec;
long tv_nsec;
};

View File

@ -1,13 +1,15 @@
#pragma once
// Common errors
#include <cia/def.h>
// Common status
#define _RT_STATUS_OK 0 // No errors
#define _RT_ERROR_NOT_IMPLEMENTED -1 // Function not implemented
#define _RT_ERROR_BAD_PARAM -2 // One of the function parameters was wrong
#define _RT_ERROR_GENERIC -3 // Just any random error
// File API errors
// File API status
#define _RT_STATUS_FILE_ACCESS 1 // No access to the file
#define _RT_STATUS_FILE_NO_SPACE 2 // Storage device has no space for the file
#define _RT_STATUS_FILE_EXISTS 3 // File exists when shouldn't
@ -30,6 +32,9 @@
#define _RT_FILE_EXCLUSIVE 0x08
#define _RT_FILE_TRUNCATE 0x10
// Sync API sleep constant
#define _RT_SYNC_WAIT_INFINITE 0xffffffffffffffffULL
typedef i32 _RT_Status;
// API implementation flags (managed and used by the layers on top of tinyrt)
@ -82,3 +87,8 @@ static _RT_Status _rt_file_close(_RT_File *file);
// Memory API
static _RT_Status _rt_mem_alloc(void *optional_desired_addr, u64 size, void **out_addr);
static _RT_Status _rt_mem_free(void *ptr, u64 size);
// Synchronization API
static _RT_Status _rt_sync_wait(u32 *addr, u32 compare_with, u64 time);
static _RT_Status _rt_sync_wake_one(u32 *addr, u32 *n_woken);
static _RT_Status _rt_sync_wake_all(u32 *addr, u32 *n_woken);

View File

@ -1,10 +1,12 @@
#include <cia/def.h>
#include <bin/elf.h>
#include <sys/syscall.h>
#include <stdarg.h>
#include "loader.h"
#include <futex.h>
#include <sys/mman.h>
#include <sched.h>
#include <errno.h>

View File

@ -1,6 +1,7 @@
#pragma once
#include <linux/futex.h>
#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>

View File

@ -150,4 +150,33 @@ static _RT_Status _rt_mem_free(void *ptr, u64 len) {
return _RT_ERROR_GENERIC;
}
return _RT_STATUS_OK;
}
}
static _RT_Status _rt_sync_wait(u32 *addr, u32 compare_with, u64 sleep) {
i64 result = syscall(SYS_futex, addr, FUTEX_WAIT_PRIVATE, compare_with, NULL, 0, 0);
if(-result == EAGAIN) {
return _RT_STATUS_OK;
}
else if(-result > 0) {
return _RT_ERROR_GENERIC;
}
return _RT_STATUS_OK;
}
static _RT_Status _rt_sync_wake_one(u32 *addr, u32 *n_woken) {
i64 result = syscall(SYS_futex, addr, FUTEX_WAKE_PRIVATE, 1, NULL, 0, 0);
if(result < 0) {
return _RT_ERROR_GENERIC;
}
*n_woken = (u32)result;
return _RT_STATUS_OK;
}
static _RT_Status _rt_sync_wake_all(u32 *addr, u32 *n_woken) {
i64 result = syscall(SYS_futex, addr, FUTEX_WAKE_PRIVATE, 0x7fffffff, NULL, 0, 0);
if(result < 0) {
return _RT_ERROR_GENERIC;
}
*n_woken = (u32)result;
return _RT_STATUS_OK;
}

13
src/cia-sync/futex.c Normal file
View File

@ -0,0 +1,13 @@
int cia_wait(u32 *addr, u32 compare_with, u64 time) {
_rt_sync_wait(addr, compare_with, time);
}
int cia_wake_one(u32 *addr, u32 *n_woken) {
_rt_sync_wake_one(addr, n_woken);
}
int cia_wake_all(u32 *addr, u32 *n_woken) {
_rt_sync_wake_all(addr, n_woken);
}

21
src/cia-sync/mutex.c Normal file
View File

@ -0,0 +1,21 @@
#define _CIA_MUTEX_TAG_UNLOCKED 0x00000000
#define _CIA_MUTEX_TAG_LOCKED 0x00000001
void cia_mutex_init(Cia_Mutex *mutex) {
mutex->tag = _CIA_MUTEX_TAG_UNLOCKED;
}
void cia_mutex_lock(Cia_Mutex *mutex) {
do {
_rt_sync_wait(&mutex->tag, _CIA_MUTEX_TAG_LOCKED, _RT_SYNC_WAIT_INFINITE);
} while(mutex->tag == _CIA_MUTEX_TAG_LOCKED);
mutex->tag = _CIA_MUTEX_TAG_LOCKED;
}
void cia_mutex_unlock(Cia_Mutex *mutex) {
mutex->tag = _CIA_MUTEX_TAG_UNLOCKED;
u32 woken = 0;
_rt_sync_wake_one(&mutex->tag, &woken);
}

View File

@ -3,6 +3,7 @@
#include <stdlib.h>
#include <threads.h>
#include <stdatomic.h>
#include <cia/sync.h>
static void print_string_n(char *str, u64 len) {
fwrite(str, 1, len, stdout);
@ -33,22 +34,39 @@ static void print_int(i64 number) {
print_string(p);
}
volatile _Atomic i64 counter = 0;
static Cia_Mutex g_print_mutex;
static Cia_Mutex g_mutex;
static volatile _Atomic i64 n_completed = 0;
static volatile i64 counter = 0;
int thrd_func(void *arg) {
print_string("child thread: ok!\n");
for(int i = 0; i < 100000; ++i) {
cia_mutex_lock(&g_mutex);
counter += 1;
print_int(counter);
print_char('\n');
cia_mutex_unlock(&g_mutex);
}
atomic_fetch_add(&n_completed, 1);
for(;;) {
if(n_completed == 2) {
break;
}
}
cia_mutex_lock(&g_print_mutex);
print_string("child thread: counter = ");
print_int(counter);
print_char('\n');
for(;;);
cia_mutex_unlock(&g_print_mutex);
exit(1);
return 0;
}
int main() {
print_string("main thread: before\n");
cia_mutex_init(&g_mutex);
cia_mutex_init(&g_print_mutex);
thrd_t thrd;
int status = thrd_create(&thrd, thrd_func, NULL);
if(status == thrd_error) {
@ -57,10 +75,22 @@ int main() {
}
print_string("main thread: after!\n");
for(int i = 0; i < 100000; ++i) {
cia_mutex_lock(&g_mutex);
counter += 1;
print_int(counter);
print_char('\n');
cia_mutex_unlock(&g_mutex);
}
atomic_fetch_add(&n_completed, 1);
for(;;) {
if(n_completed == 2) {
break;
}
}
cia_mutex_lock(&g_print_mutex);
print_string("main thread: counter = ");
print_int(counter);
print_char('\n');
cia_mutex_unlock(&g_print_mutex);
return 0;
}