Browse Source

Add files in core

Ginger Bill 8 years ago
parent
commit
19bde275a3
3 changed files with 284 additions and 0 deletions
  1. 100 0
      core/atomics.odin
  2. 93 0
      core/sync_linux.odin
  3. 91 0
      core/sync_windows.odin

+ 100 - 0
core/atomics.odin

@@ -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 - 0
core/sync_linux.odin

@@ -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 - 0
core/sync_windows.odin

@@ -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);
+		}
+	}
+}
+