Skip to content

Commit

Permalink
Add files in core
Browse files Browse the repository at this point in the history
  • Loading branch information
gingerBill committed May 1, 2017
1 parent 634ee45 commit 19bde27
Show file tree
Hide file tree
Showing 3 changed files with 284 additions and 0 deletions.
100 changes: 100 additions & 0 deletions core/atomics.odin
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// TODO(bill): Use assembly instead here to implement atomics
// Inline vs external file?

#import win32 "sys/windows.odin" when ODIN_OS == "windows";
_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version


yield_thread :: proc() { win32.mm_pause(); }
mfence :: proc() { win32.ReadWriteBarrier(); }
sfence :: proc() { win32.WriteBarrier(); }
lfence :: proc() { win32.ReadBarrier(); }


load :: proc(a: ^i32) -> i32 {
return a^;
}
store :: proc(a: ^i32, value: i32) {
a^ = value;
}
compare_exchange :: proc(a: ^i32, expected, desired: i32) -> i32 {
return win32.InterlockedCompareExchange(a, desired, expected);
}
exchanged :: proc(a: ^i32, desired: i32) -> i32 {
return win32.InterlockedExchange(a, desired);
}
fetch_add :: proc(a: ^i32, operand: i32) -> i32 {
return win32.InterlockedExchangeAdd(a, operand);

}
fetch_and :: proc(a: ^i32, operand: i32) -> i32 {
return win32.InterlockedAnd(a, operand);
}
fetch_or :: proc(a: ^i32, operand: i32) -> i32 {
return win32.InterlockedOr(a, operand);
}
spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange(a, 1, 0);
counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) {
counter++;
yield_thread();
old_value = compare_exchange(a, 1, 0);
mfence();
}
return old_value == 0;
}
spin_unlock :: proc(a: ^i32) {
store(a, 0);
mfence();
}
try_acquire_lock :: proc(a: ^i32) -> bool {
yield_thread();
old_value := compare_exchange(a, 1, 0);
mfence();
return old_value == 0;
}


load :: proc(a: ^i64) -> i64 {
return a^;
}
store :: proc(a: ^i64, value: i64) {
a^ = value;
}
compare_exchange :: proc(a: ^i64, expected, desired: i64) -> i64 {
return win32.InterlockedCompareExchange64(a, desired, expected);
}
exchanged :: proc(a: ^i64, desired: i64) -> i64 {
return win32.InterlockedExchange64(a, desired);
}
fetch_add :: proc(a: ^i64, operand: i64) -> i64 {
return win32.InterlockedExchangeAdd64(a, operand);
}
fetch_and :: proc(a: ^i64, operand: i64) -> i64 {
return win32.InterlockedAnd64(a, operand);
}
fetch_or :: proc(a: ^i64, operand: i64) -> i64 {
return win32.InterlockedOr64(a, operand);
}
spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default
old_value := compare_exchange(a, 1, 0);
counter := 0;
for old_value != 0 && (time_out < 0 || counter < time_out) {
counter++;
yield_thread();
old_value = compare_exchange(a, 1, 0);
mfence();
}
return old_value == 0;
}
spin_unlock :: proc(a: ^i64) {
store(a, 0);
mfence();
}
try_acquire_lock :: proc(a: ^i64) -> bool {
yield_thread();
old_value := compare_exchange(a, 1, 0);
mfence();
return old_value == 0;
}
93 changes: 93 additions & 0 deletions core/sync_linux.odin
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#import "atomics.odin";
#import "os.odin";

Semaphore :: struct {
// _handle: win32.Handle,
}

Mutex :: struct {
_semaphore: Semaphore,
_counter: i32,
_owner: i32,
_recursion: i32,
}

current_thread_id :: proc() -> i32 {
return i32(os.current_thread_id());
}

semaphore_init :: proc(s: ^Semaphore) {
// s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
}

semaphore_destroy :: proc(s: ^Semaphore) {
// win32.CloseHandle(s._handle);
}

semaphore_post :: proc(s: ^Semaphore, count: int) {
// win32.ReleaseSemaphore(s._handle, cast(i32)count, nil);
}

semaphore_release :: proc(s: ^Semaphore) #inline {
semaphore_post(s, 1);
}

semaphore_wait :: proc(s: ^Semaphore) {
// win32.WaitForSingleObject(s._handle, win32.INFINITE);
}


mutex_init :: proc(m: ^Mutex) {
atomics.store(&m._counter, 0);
atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore);
m._recursion = 0;
}
mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(&m._semaphore);
}
mutex_lock :: proc(m: ^Mutex) {
thread_id := current_thread_id();
if atomics.fetch_add(&m._counter, 1) > 0 {
if thread_id != atomics.load(&m._owner) {
semaphore_wait(&m._semaphore);
}
}
atomics.store(&m._owner, thread_id);
m._recursion++;
}
mutex_try_lock :: proc(m: ^Mutex) -> bool {
thread_id := current_thread_id();
if atomics.load(&m._owner) == thread_id {
atomics.fetch_add(&m._counter, 1);
} else {
expected: i32 = 0;
if atomics.load(&m._counter) != 0 {
return false;
}
if atomics.compare_exchange(&m._counter, expected, 1) == 0 {
return false;
}
atomics.store(&m._owner, thread_id);
}
m._recursion++;
return true;
}
mutex_unlock :: proc(m: ^Mutex) {
recursion: i32;
thread_id := current_thread_id();
assert(thread_id == atomics.load(&m._owner));

m._recursion--;
recursion = m._recursion;
if recursion == 0 {
atomics.store(&m._owner, thread_id);
}

if atomics.fetch_add(&m._counter, -1) > 1 {
if recursion == 0 {
semaphore_release(&m._semaphore);
}
}
}

91 changes: 91 additions & 0 deletions core/sync_windows.odin
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
#import "atomics.odin";

Semaphore :: struct {
_handle: win32.Handle,
}

Mutex :: struct {
_semaphore: Semaphore,
_counter: i32,
_owner: i32,
_recursion: i32,
}

current_thread_id :: proc() -> i32 {
return i32(win32.GetCurrentThreadId());
}

semaphore_init :: proc(s: ^Semaphore) {
s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil);
}

semaphore_destroy :: proc(s: ^Semaphore) {
win32.CloseHandle(s._handle);
}

semaphore_post :: proc(s: ^Semaphore, count: int) {
win32.ReleaseSemaphore(s._handle, i32(count), nil);
}

semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); }

semaphore_wait :: proc(s: ^Semaphore) {
win32.WaitForSingleObject(s._handle, win32.INFINITE);
}


mutex_init :: proc(m: ^Mutex) {
atomics.store(&m._counter, 0);
atomics.store(&m._owner, current_thread_id());
semaphore_init(&m._semaphore);
m._recursion = 0;
}
mutex_destroy :: proc(m: ^Mutex) {
semaphore_destroy(&m._semaphore);
}
mutex_lock :: proc(m: ^Mutex) {
thread_id := current_thread_id();
if atomics.fetch_add(&m._counter, 1) > 0 {
if thread_id != atomics.load(&m._owner) {
semaphore_wait(&m._semaphore);
}
}
atomics.store(&m._owner, thread_id);
m._recursion++;
}
mutex_try_lock :: proc(m: ^Mutex) -> bool {
thread_id := current_thread_id();
if atomics.load(&m._owner) == thread_id {
atomics.fetch_add(&m._counter, 1);
} else {
expected: i32 = 0;
if atomics.load(&m._counter) != 0 {
return false;
}
if atomics.compare_exchange(&m._counter, expected, 1) == 0 {
return false;
}
atomics.store(&m._owner, thread_id);
}
m._recursion++;
return true;
}
mutex_unlock :: proc(m: ^Mutex) {
recursion: i32;
thread_id := current_thread_id();
assert(thread_id == atomics.load(&m._owner));

m._recursion--;
recursion = m._recursion;
if recursion == 0 {
atomics.store(&m._owner, thread_id);
}

if atomics.fetch_add(&m._counter, -1) > 1 {
if recursion == 0 {
semaphore_release(&m._semaphore);
}
}
}

0 comments on commit 19bde27

Please sign in to comment.