Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sleep support to win32 event loop #10605

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions spec/std/concurrent_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,22 @@ describe "concurrent" do
it "accepts method call with receiver" do
typeof(spawn String.new)
end

it "schedules intermitting sleeps" do
chan = Channel(Int32).new
spawn do
3.times do |i|
sleep 20.milliseconds
chan.send (i + 1)
end
end
spawn do
2.times do |i|
sleep 50.milliseconds
chan.send (i + 1) * 10
end
end

Array(Int32).new(5, 0).map! { chan.receive }.should eq [1, 2, 10, 3, 20]
end
end
39 changes: 25 additions & 14 deletions src/crystal/system/win32/event_loop_iocp.cr
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
require "crystal/system/print_error"

module Crystal::EventLoop
@@queue = Deque(Fiber).new
@@queue = Deque(Event).new

# Runs the event loop.
def self.run_once : Nil
next_fiber = @@queue.pop?
next_event = @@queue.min_by { |e| e.wake_at }

if next_fiber
Crystal::Scheduler.enqueue next_fiber
if next_event
sleep_time = next_event.wake_at - Time.monotonic

if sleep_time > Time::Span.zero
LibC.Sleep(sleep_time.milliseconds)
end

dequeue next_event

Crystal::Scheduler.enqueue next_event.fiber
else
Crystal::System.print_error "Warning: No runnables in scheduler. Exiting program.\n"
::exit
Expand All @@ -19,20 +27,18 @@ module Crystal::EventLoop
def self.after_fork : Nil
end

def self.enqueue(fiber : Fiber)
unless @@queue.includes?(fiber)
@@queue << fiber
def self.enqueue(event : Event)
unless @@queue.includes?(event)
@@queue << event
end
end

def self.dequeue(fiber : Fiber)
@@queue.delete(fiber)
def self.dequeue(event : Event)
@@queue.delete(event)
end

# Create a new resume event for a fiber.
def self.create_resume_event(fiber : Fiber) : Crystal::Event
enqueue(fiber)

Crystal::Event.new(fiber)
end

Expand All @@ -48,15 +54,20 @@ module Crystal::EventLoop
end

struct Crystal::Event
getter fiber
getter wake_at

def initialize(@fiber : Fiber)
@wake_at = Time.monotonic
end

# Frees the event
def free : Nil
Crystal::EventLoop.dequeue(@fiber)
Crystal::EventLoop.dequeue(self)
end

def add(time_span : Time::Span?) : Nil
Crystal::EventLoop.enqueue(@fiber)
def add(time_span : Time::Span) : Nil
@wake_at = Time.monotonic + time_span
Crystal::EventLoop.enqueue(self)
end
end
8 changes: 0 additions & 8 deletions src/windows_stubs.cr
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,3 @@ end
enum Signal
KILL = 0
end

def sleep(seconds : Number)
sleep(seconds.seconds)
end

def sleep(time : Time::Span)
LibC.Sleep(time.total_milliseconds)
end