-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement multithreading primitives on Windows (#11647)
- Loading branch information
1 parent
6acf031
commit a3f9199
Showing
18 changed files
with
286 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
class Thread | ||
class ConditionVariable | ||
# Creates a new condition variable. | ||
# def initialize | ||
|
||
# Unblocks one thread that is waiting on `self`. | ||
# def signal : Nil | ||
|
||
# Unblocks all threads that are waiting on `self`. | ||
# def broadcast : Nil | ||
|
||
# Causes the calling thread to wait on `self` and unlock the given *mutex* | ||
# atomically. | ||
# def wait(mutex : Thread::Mutex) : Nil | ||
|
||
# Causes the calling thread to wait on `self` and unlock the given *mutex* | ||
# atomically within the given *time* span. Yields to the given block if a | ||
# timeout occurs. | ||
# def wait(mutex : Thread::Mutex, time : Time::Span, & : ->) | ||
end | ||
end | ||
|
||
{% if flag?(:wasi) %} | ||
require "./wasi/thread_condition_variable" | ||
{% elsif flag?(:unix) %} | ||
require "./unix/pthread_condition_variable" | ||
{% elsif flag?(:win32) %} | ||
require "./win32/thread_condition_variable" | ||
{% else %} | ||
{% raise "thread condition variable not supported" %} | ||
{% end %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# TODO: Implement | ||
class Thread | ||
class ConditionVariable | ||
def signal : Nil | ||
end | ||
|
||
def broadcast : Nil | ||
end | ||
|
||
def wait(mutex : Thread::Mutex) : Nil | ||
end | ||
|
||
def wait(mutex : Thread::Mutex, time : Time::Span, &) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
require "c/synchapi" | ||
|
||
# :nodoc: | ||
class Thread | ||
# :nodoc: | ||
class ConditionVariable | ||
def initialize | ||
@cond = uninitialized LibC::CONDITION_VARIABLE | ||
LibC.InitializeConditionVariable(self) | ||
end | ||
|
||
def signal : Nil | ||
LibC.WakeConditionVariable(self) | ||
end | ||
|
||
def broadcast : Nil | ||
LibC.WakeAllConditionVariable(self) | ||
end | ||
|
||
def wait(mutex : Thread::Mutex) : Nil | ||
ret = LibC.SleepConditionVariableCS(self, mutex, LibC::INFINITE) | ||
raise RuntimeError.from_winerror("SleepConditionVariableCS") if ret == 0 | ||
end | ||
|
||
def wait(mutex : Thread::Mutex, time : Time::Span, & : ->) | ||
ret = LibC.SleepConditionVariableCS(self, mutex, time.total_milliseconds) | ||
return if ret != 0 | ||
|
||
error = WinError.value | ||
if error == WinError::ERROR_TIMEOUT | ||
yield | ||
else | ||
raise RuntimeError.from_os_error("SleepConditionVariableCS", error) | ||
end | ||
end | ||
|
||
def to_unsafe | ||
pointerof(@cond) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,61 @@ | ||
# TODO: Implement | ||
require "c/synchapi" | ||
|
||
# :nodoc: | ||
class Thread | ||
# :nodoc: | ||
# for Win32 condition variable interop we must use either a critical section | ||
# or a slim reader/writer lock, not a Win32 mutex | ||
# also note critical sections are reentrant; to match the behaviour in | ||
# `../unix/pthread_mutex.cr` we must do extra housekeeping ourselves | ||
class Mutex | ||
def initialize | ||
@cs = uninitialized LibC::CRITICAL_SECTION | ||
LibC.InitializeCriticalSectionAndSpinCount(self, 1000) | ||
end | ||
|
||
def lock : Nil | ||
LibC.EnterCriticalSection(self) | ||
if @cs.recursionCount > 1 | ||
LibC.LeaveCriticalSection(self) | ||
raise RuntimeError.new "Attempt to lock a mutex recursively (deadlock)" | ||
end | ||
end | ||
|
||
def try_lock : Bool | ||
if LibC.TryEnterCriticalSection(self) != 0 | ||
if @cs.recursionCount > 1 | ||
LibC.LeaveCriticalSection(self) | ||
false | ||
else | ||
true | ||
end | ||
else | ||
false | ||
end | ||
end | ||
|
||
def unlock : Nil | ||
# `owningThread` is declared as `LibC::HANDLE` for historical reasons, so | ||
# the following comparison is correct | ||
unless @cs.owningThread == LibC::HANDLE.new(LibC.GetCurrentThreadId) | ||
raise RuntimeError.new "Attempt to unlock a mutex locked by another thread" | ||
end | ||
LibC.LeaveCriticalSection(self) | ||
end | ||
|
||
def synchronize | ||
yield | ||
lock | ||
yield self | ||
ensure | ||
unlock | ||
end | ||
|
||
def finalize | ||
LibC.DeleteCriticalSection(self) | ||
end | ||
|
||
def to_unsafe | ||
pointerof(@cs) | ||
end | ||
end | ||
end |
Oops, something went wrong.