mirror of https://github.com/flysand7/ciabatta.git
116 lines
3.5 KiB
C
116 lines
3.5 KiB
C
|
|
||
|
#include <stdatomic.h>
|
||
|
#include <threads.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#if 1
|
||
|
enum memory_order store_memory_order = memory_order_acquire;
|
||
|
enum memory_order load_memory_order = memory_order_release;
|
||
|
#else
|
||
|
enum memory_order store_memory_order = memory_order_seq_cst;
|
||
|
enum memory_order load_memory_order = memory_order_seq_cst;
|
||
|
#endif
|
||
|
|
||
|
// Scheduler on linux has too coarse granularity
|
||
|
// to allow a thread to a very tiny bit of work
|
||
|
// before switching to another thread. If we
|
||
|
// introduce an arbitrary delay, the threads will
|
||
|
// be able to be run in a random order better.
|
||
|
// Without it, the threads seem to be run as they are
|
||
|
// created, i.e. the scheduling is too convenient and
|
||
|
// hides a potential bug that we're testing for here
|
||
|
#define delay_that_works 1000000
|
||
|
#define arbitrary_delay(n) for(volatile int i = 0; i < n; ++i)
|
||
|
|
||
|
// This is all the explicit shared state between threads.
|
||
|
struct Shared_State typedef Shared_State;
|
||
|
struct Shared_State {
|
||
|
_Atomic(int) x;
|
||
|
_Atomic(int) y;
|
||
|
_Atomic(int) cnt;
|
||
|
};
|
||
|
static Shared_State g_shared_state = {0};
|
||
|
|
||
|
// Sets the atomic flag x
|
||
|
int tx(void *ctx) {
|
||
|
arbitrary_delay(delay_that_works);
|
||
|
Shared_State *ss = ctx;
|
||
|
char msg[] = "Thread tx running\n";
|
||
|
fwrite(msg, 1, sizeof msg, stdout);
|
||
|
atomic_store_explicit(&ss->x, 1, store_memory_order);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// Set the atomic flag y
|
||
|
int ty(void *ctx) {
|
||
|
arbitrary_delay(delay_that_works);
|
||
|
Shared_State *ss = ctx;
|
||
|
char msg[] = "Thread ty running\n";
|
||
|
fwrite(msg, 1, sizeof msg, stdout);
|
||
|
atomic_store_explicit(&ss->y, 1, store_memory_order);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// Spinlock until flag x is set, if y is also set, add 1 to cnt
|
||
|
int t1(void *ctx) {
|
||
|
arbitrary_delay(delay_that_works);
|
||
|
Shared_State *ss = ctx;
|
||
|
char msg[] = "Thread t1 running\n";
|
||
|
fwrite(msg, 1, sizeof msg, stdout);
|
||
|
while(atomic_load_explicit(&ss->x, load_memory_order) == 0)
|
||
|
;
|
||
|
if(atomic_load_explicit(&ss->y, load_memory_order) == 1) {
|
||
|
atomic_fetch_add_explicit(&ss->cnt, 1, memory_order_relaxed);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// Spinlock until flag y is set, if x is also set, add 1 to cnt
|
||
|
int t2(void *ctx) {
|
||
|
arbitrary_delay(delay_that_works);
|
||
|
Shared_State *ss = ctx;
|
||
|
char msg[] = "Thread t2 running\n";
|
||
|
fwrite(msg, 1, sizeof msg, stdout);
|
||
|
while(atomic_load_explicit(&ss->y, load_memory_order) == 0)
|
||
|
;
|
||
|
if(atomic_load_explicit(&ss->x, load_memory_order) == 1) {
|
||
|
atomic_fetch_add_explicit(&ss->cnt, 1, memory_order_relaxed);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int main() {
|
||
|
// TODO: rewrite this to run in a loop after I
|
||
|
// fix stack leaking on thread destruction
|
||
|
thrd_start_t thread_funcs[4] = {tx,ty,t1,t2};
|
||
|
thrd_t threads[4];
|
||
|
// Spawn the threads
|
||
|
for(int i = 0; i < 4; ++i) {
|
||
|
int status = thrd_create(&threads[i], thread_funcs[i], &g_shared_state);
|
||
|
if(status != thrd_success) {
|
||
|
char msg[] = "Thread unable to start\n";
|
||
|
fwrite(msg, 1, sizeof msg, stdout);
|
||
|
}
|
||
|
}
|
||
|
// Wait for threads to complete
|
||
|
for(int i = 0; i < 4; ++i) {
|
||
|
int _exit_code;
|
||
|
thrd_join(threads[i], &_exit_code);
|
||
|
}
|
||
|
// Check to see the cnt variable
|
||
|
int result = atomic_load_explicit(&g_shared_state.cnt, memory_order_relaxed);
|
||
|
if(result == 0) {
|
||
|
char msg[] = "Result was 0\n";
|
||
|
fwrite(msg, 1, sizeof msg, stdout);
|
||
|
}
|
||
|
else if(result == 1) {
|
||
|
char msg[] = "Result was 1\n";
|
||
|
fwrite(msg, 1, sizeof msg, stdout);
|
||
|
}
|
||
|
else {
|
||
|
char msg[] = "Result was 2\n";
|
||
|
fwrite(msg, 1, sizeof msg, stdout);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|