Skip to content

Commit

Permalink
Implement Fiber and Scheduler for win32
Browse files Browse the repository at this point in the history
The actual stack context switch is still missing.
  • Loading branch information
straight-shoota committed Oct 19, 2018
1 parent 838f9d0 commit f4e7ced
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 11 deletions.
2 changes: 2 additions & 0 deletions src/concurrent.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ require "channel"
require "crystal/scheduler"
require "./concurrent/*"

{% unless flag?(:win32) %}
# Blocks the current fiber for the specified number of seconds.
#
# While this fiber is waiting this time other ready-to-execute
Expand All @@ -22,6 +23,7 @@ end
def sleep(time : Time::Span)
Crystal::Scheduler.sleep(time)
end
{% end %}

# Blocks the current fiber forever.
#
Expand Down
27 changes: 24 additions & 3 deletions src/crystal/scheduler.cr
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,14 @@ class Crystal::Scheduler
if runnable = @runnables.shift?
runnable.resume
else
Crystal::EventLoop.resume
{% if flag?(:unix) %}
Crystal::EventLoop.resume
{% elsif flag?(:win32) %}
STDERR.puts "Warning: No runnables in scheduler. Exiting program."
::exit
{% else %}
{% raise "unsupported platform" %}
{% end %}
end
end

Expand All @@ -78,11 +85,25 @@ class Crystal::Scheduler
end

protected def yield : Nil
sleep(0.seconds)
{% if flag?(:unix) %}
sleep(0.seconds)
{% elsif flag?(:win32) %}
@runnables << @current
reschedule
{% else %}
{% raise "unsupported platform" %}
{% end %}
end

protected def yield(fiber : Fiber) : Nil
@current.resume_event.add(0.seconds)
{% if flag?(:unix) %}
@current.resume_event.add(0.seconds)
{% elsif flag?(:win32) %}
@runnables << fiber
{% else %}
{% raise "unsupported platform" %}
{% end %}

resume(fiber)
end
end
2 changes: 2 additions & 0 deletions src/crystal/system/fiber.cr
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ end

{% if flag?(:unix) %}
require "./unix/fiber"
{% elsif flag?(:win32) %}
require "./win32/fiber"
{% else %}
{% raise "fiber not supported" %}
{% end %}
27 changes: 27 additions & 0 deletions src/crystal/system/win32/fiber.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require "c/winbase"
require "c/winnt"
require "c/processthreadsapi"

module Crystal::System::Fiber
def self.allocate_stack(stack_size) : Void*
memory_pointer = LibC.VirtualAlloc(nil, stack_size, LibC::MEM_COMMIT | LibC::MEM_RESERVE, LibC::PAGE_READWRITE)

if memory_pointer.null?
raise WinError.new("VirtualAlloc")
end

memory_pointer
end

def self.free_stack(stack : Void*, stack_size) : Nil
if LibC.VirtualFree(stack, stack_size, LibC::MEM_RELEASE) == 0
raise WinError.new("VirtualFree")
end
end

def self.main_fiber_stack(stack_bottom : Void*) : Void*
LibC.GetCurrentThreadStackLimits(out lowLimit, out highLimit)

Pointer(Void).new(lowLimit)
end
end
8 changes: 8 additions & 0 deletions src/fiber.cr
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ class Fiber
@@stack_pool = [] of Void*

@stack : Void*

{% unless flag?(:win32) %}
@resume_event : Crystal::Event?
{% end %}

@stack_top = Pointer(Void).null
protected property stack_top : Void*
protected property stack_bottom : Void*
Expand Down Expand Up @@ -130,8 +134,10 @@ class Fiber
# Remove the current fiber from the linked list
@@fibers.delete(self)

{% unless flag?(:win32) %}
# Delete the resume event if it was used by `yield` or `sleep`
@resume_event.try &.free
{% end %}

Crystal::Scheduler.reschedule
end
Expand All @@ -144,10 +150,12 @@ class Fiber
Crystal::Scheduler.resume(self)
end

{% unless flag?(:win32) %}
# :nodoc:
def resume_event
@resume_event ||= Crystal::EventLoop.create_resume_event(self)
end
{% end %}

def self.yield
Crystal::Scheduler.yield
Expand Down
14 changes: 7 additions & 7 deletions src/kernel.cr
Original file line number Diff line number Diff line change
Expand Up @@ -470,15 +470,15 @@ class Process
end
end

{% unless flag?(:win32) %}
# Background loop to cleanup unused fiber stacks.
spawn do
loop do
sleep 5
Fiber.stack_pool_collect
end
# Background loop to cleanup unused fiber stacks.
spawn do
loop do
sleep 5
Fiber.stack_pool_collect
end
end

{% unless flag?(:win32) %}
Signal.setup_default_handlers
LibExt.setup_sigfault_handler
{% end %}
1 change: 1 addition & 0 deletions src/lib_c/x86_64-windows-msvc/c/basetsd.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ lib LibC
{% else %}
alias ULONG_PTR = ULong
{% end %}
alias PULONG_PTR = ULONG_PTR*
end
5 changes: 5 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/processthreadsapi.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require "./basetsd"

lib LibC
fun GetCurrentThreadStackLimits(lowLimit : PULONG_PTR, highLimit : PULONG_PTR) : Void
end
12 changes: 12 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/winbase.cr
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,16 @@ lib LibC
fun GetEnvironmentStringsW : LPWCH
fun FreeEnvironmentStringsW(lpszEnvironmentBlock : LPWCH) : BOOL
fun SetEnvironmentVariableW(lpName : LPWSTR, lpValue : LPWSTR) : BOOL

MEM_COMMIT = 0x00001000
MEM_RESERVE = 0x00002000
MEM_RESET = 0x00080000
MEM_RESET_UNDO = 0x01000000

fun VirtualAlloc(lpAddress : Void*, dwSize : SizeT, flAllocationType : DWORD, flProtect : DWORD) : Void*

MEM_DECOMMIT = 0x4000
MEM_RELEASE = 0x8000

fun VirtualFree(lpAddress : Void*, dwSize : SizeT, dwFreeType : DWORD) : BOOL
end
3 changes: 3 additions & 0 deletions src/lib_c/x86_64-windows-msvc/c/winnt.cr
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@ lib LibC
FILE_ATTRIBUTE_REPARSE_POINT = 0x400

FILE_READ_ATTRIBUTES = 0x80

# Memory protection constants
PAGE_READWRITE = 0x04
end
2 changes: 1 addition & 1 deletion src/prelude.cr
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ require "box"
require "char"
require "char/reader"
require "class"
no_win require "concurrent"
require "concurrent"
require "crystal/main"
require "deque"
require "dir"
Expand Down

0 comments on commit f4e7ced

Please sign in to comment.