瀏覽代碼

Reimplement sync2.Sema on windows with WaitOnAddress primitives

gingerBill 4 年之前
父節點
當前提交
96b60d8779

+ 3 - 22
core/sync/sync2/primitives.odin

@@ -153,33 +153,14 @@ cond_broadcast :: proc(c: ^Cond) {
 //
 // A Sema must not be copied after first use
 Sema :: struct {
-	// TODO(bill): Is this implementation too lazy?
-	// Can this be made to work on all OSes without construction and destruction, i.e. Zero is Initialized
-
-	mutex: Mutex,
-	cond:  Cond,
-	count: int,
+	impl: _Sema,
 }
 
 
 sema_wait :: proc(s: ^Sema) {
-	mutex_lock(&s.mutex);
-	defer mutex_unlock(&s.mutex);
-
-	for s.count == 0 {
-		cond_wait(&s.cond, &s.mutex);
-	}
-
-	s.count -= 1;
-	if s.count > 0 {
-		cond_signal(&s.cond);
-	}
+	_sema_wait(s);
 }
 
 sema_post :: proc(s: ^Sema, count := 1) {
-	mutex_lock(&s.mutex);
-	defer mutex_unlock(&s.mutex);
-
-	s.count += count;
-	cond_signal(&s.cond);
+	_sema_post(s, count);
 }

+ 30 - 0
core/sync/sync2/primitives_atomic.odin

@@ -240,5 +240,35 @@ _cond_broadcast :: proc(c: ^Cond) {
 	}
 }
 
+_Sema :: struct {
+	mutex: Mutex,
+	cond:  Cond,
+	count: int,
+}
+
+_sema_wait :: proc(s: ^Sema) {
+	mutex_lock(&s.impl.mutex);
+	defer mutex_unlock(&s.impl.mutex);
+
+	for s.impl.count == 0 {
+		cond_wait(&s.impl.cond, &s.impl.mutex);
+	}
+
+	s.impl.count -= 1;
+	if s.impl.count > 0 {
+		cond_signal(&s.impl.cond);
+	}
+}
+
+_sema_post :: proc(s: ^Sema, count := 1) {
+	mutex_lock(&s.impl.mutex);
+	defer mutex_unlock(&s.impl.mutex);
+
+	s.impl.count += count;
+	cond_signal(&s.impl.cond);
+}
+
+
+
 
 } // !ODIN_SYNC_USE_PTHREADS

+ 29 - 0
core/sync/sync2/primitives_pthreads.odin

@@ -150,5 +150,34 @@ _cond_broadcast :: proc(c: ^Cond) {
 	assert(err == 0);
 }
 
+_Sema :: struct {
+	mutex: Mutex,
+	cond:  Cond,
+	count: int,
+}
+
+_sema_wait :: proc(s: ^Sema) {
+	mutex_lock(&s.impl.mutex);
+	defer mutex_unlock(&s.impl.mutex);
+
+	for s.impl.count == 0 {
+		cond_wait(&s.impl.cond, &s.impl.mutex);
+	}
+
+	s.impl.count -= 1;
+	if s.impl.count > 0 {
+		cond_signal(&s.impl.cond);
+	}
+}
+
+_sema_post :: proc(s: ^Sema, count := 1) {
+	mutex_lock(&s.impl.mutex);
+	defer mutex_unlock(&s.impl.mutex);
+
+	s.impl.count += count;
+	cond_signal(&s.impl.cond);
+}
+
+
 
 } // ODIN_SYNC_USE_PTHREADS

+ 32 - 0
core/sync/sync2/primitives_windows.odin

@@ -71,3 +71,35 @@ _cond_signal :: proc(c: ^Cond) {
 _cond_broadcast :: proc(c: ^Cond) {
 	win32.WakeAllConditionVariable(&c.impl.cond);
 }
+
+
+_Sema :: struct {
+	count: int,
+}
+
+_sema_wait :: proc(s: ^Sema) {
+	for {
+		original_count := s.impl.count;
+		for original_count == 0 {
+			win32.WaitOnAddress(
+				&s.impl.count,
+				&original_count,
+				size_of(original_count),
+				win32.INFINITE,
+			);
+			original_count = s.impl.count;
+		}
+		if original_count == atomic_cxchg(&s.impl.count, original_count-1, original_count) {
+			return;
+		}
+	}
+}
+
+_sema_post :: proc(s: ^Sema, count := 1) {
+	atomic_add(&s.impl.count, count);
+	if count == 1 {
+		win32.WakeByAddressSingle(&s.impl.count);
+	} else {
+		win32.WakeByAddressAll(&s.impl.count);
+	}
+}