mirror of https://github.com/flysand7/ciabatta.git
broken mutex
This commit is contained in:
parent
fa1f9ec0e6
commit
35a760e54e
5
cia.c
5
cia.c
|
@ -9,6 +9,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <threads.h>
|
#include <threads.h>
|
||||||
#include <cia/mem.h>
|
#include <cia/mem.h>
|
||||||
|
#include <cia/sync.h>
|
||||||
|
|
||||||
// Module cia_memory
|
// Module cia_memory
|
||||||
#include "src/cia-mem/util.c"
|
#include "src/cia-mem/util.c"
|
||||||
|
@ -16,6 +17,9 @@
|
||||||
#include "src/cia-mem/arena.c"
|
#include "src/cia-mem/arena.c"
|
||||||
#include "src/cia-mem/pool.c"
|
#include "src/cia-mem/pool.c"
|
||||||
|
|
||||||
|
// Module cia_sync
|
||||||
|
#include "src/cia-sync/mutex.c"
|
||||||
|
|
||||||
// Module stdlib_program
|
// Module stdlib_program
|
||||||
#include "src/stdlib-program/program.c"
|
#include "src/stdlib-program/program.c"
|
||||||
|
|
||||||
|
@ -24,3 +28,4 @@
|
||||||
|
|
||||||
// Module stdlib_file
|
// Module stdlib_file
|
||||||
#include "src/stdlib-file/file.c"
|
#include "src/stdlib-file/file.c"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,17 @@
|
||||||
|
|
||||||
#pragma once
|
#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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct timespec {
|
||||||
|
time_t tv_sec;
|
||||||
|
long tv_nsec;
|
||||||
|
};
|
|
@ -1,13 +1,15 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Common errors
|
#include <cia/def.h>
|
||||||
|
|
||||||
|
// Common status
|
||||||
#define _RT_STATUS_OK 0 // No errors
|
#define _RT_STATUS_OK 0 // No errors
|
||||||
#define _RT_ERROR_NOT_IMPLEMENTED -1 // Function not implemented
|
#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_BAD_PARAM -2 // One of the function parameters was wrong
|
||||||
#define _RT_ERROR_GENERIC -3 // Just any random error
|
#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_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_NO_SPACE 2 // Storage device has no space for the file
|
||||||
#define _RT_STATUS_FILE_EXISTS 3 // File exists when shouldn't
|
#define _RT_STATUS_FILE_EXISTS 3 // File exists when shouldn't
|
||||||
|
@ -30,6 +32,9 @@
|
||||||
#define _RT_FILE_EXCLUSIVE 0x08
|
#define _RT_FILE_EXCLUSIVE 0x08
|
||||||
#define _RT_FILE_TRUNCATE 0x10
|
#define _RT_FILE_TRUNCATE 0x10
|
||||||
|
|
||||||
|
// Sync API sleep constant
|
||||||
|
#define _RT_SYNC_WAIT_INFINITE 0xffffffffffffffffULL
|
||||||
|
|
||||||
typedef i32 _RT_Status;
|
typedef i32 _RT_Status;
|
||||||
|
|
||||||
// API implementation flags (managed and used by the layers on top of tinyrt)
|
// 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
|
// Memory API
|
||||||
static _RT_Status _rt_mem_alloc(void *optional_desired_addr, u64 size, void **out_addr);
|
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);
|
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);
|
|
@ -1,10 +1,12 @@
|
||||||
|
|
||||||
#include <cia/def.h>
|
#include <cia/def.h>
|
||||||
|
|
||||||
#include <bin/elf.h>
|
#include <bin/elf.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
|
|
||||||
|
#include <futex.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <linux/futex.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
|
@ -151,3 +151,32 @@ static _RT_Status _rt_mem_free(void *ptr, u64 len) {
|
||||||
}
|
}
|
||||||
return _RT_STATUS_OK;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <threads.h>
|
#include <threads.h>
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
|
#include <cia/sync.h>
|
||||||
|
|
||||||
static void print_string_n(char *str, u64 len) {
|
static void print_string_n(char *str, u64 len) {
|
||||||
fwrite(str, 1, len, stdout);
|
fwrite(str, 1, len, stdout);
|
||||||
|
@ -33,22 +34,39 @@ static void print_int(i64 number) {
|
||||||
print_string(p);
|
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) {
|
int thrd_func(void *arg) {
|
||||||
print_string("child thread: ok!\n");
|
print_string("child thread: ok!\n");
|
||||||
for(int i = 0; i < 100000; ++i) {
|
for(int i = 0; i < 100000; ++i) {
|
||||||
|
cia_mutex_lock(&g_mutex);
|
||||||
counter += 1;
|
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_string("child thread: counter = ");
|
||||||
print_int(counter);
|
print_int(counter);
|
||||||
print_char('\n');
|
print_char('\n');
|
||||||
for(;;);
|
cia_mutex_unlock(&g_print_mutex);
|
||||||
|
exit(1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
print_string("main thread: before\n");
|
print_string("main thread: before\n");
|
||||||
|
cia_mutex_init(&g_mutex);
|
||||||
|
cia_mutex_init(&g_print_mutex);
|
||||||
thrd_t thrd;
|
thrd_t thrd;
|
||||||
int status = thrd_create(&thrd, thrd_func, NULL);
|
int status = thrd_create(&thrd, thrd_func, NULL);
|
||||||
if(status == thrd_error) {
|
if(status == thrd_error) {
|
||||||
|
@ -57,10 +75,22 @@ int main() {
|
||||||
}
|
}
|
||||||
print_string("main thread: after!\n");
|
print_string("main thread: after!\n");
|
||||||
for(int i = 0; i < 100000; ++i) {
|
for(int i = 0; i < 100000; ++i) {
|
||||||
|
cia_mutex_lock(&g_mutex);
|
||||||
counter += 1;
|
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_string("main thread: counter = ");
|
||||||
print_int(counter);
|
print_int(counter);
|
||||||
print_char('\n');
|
print_char('\n');
|
||||||
|
cia_mutex_unlock(&g_print_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue