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

Introduce Crystal::EventLoop namespace #15226

Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{% skip_file unless Crystal.has_constant?(:Evented) %}
{% skip_file unless Crystal::EventLoop.has_constant?(:Polling) %}

require "spec"

describe Crystal::Evented::Arena do
describe Crystal::EventLoop::Polling::Arena do
describe "#allocate_at?" do
it "yields block when not allocated" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)
pointer = nil
index = nil
called = 0
Expand All @@ -31,8 +31,8 @@ describe Crystal::Evented::Arena do
end

it "allocates up to capacity" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
indexes = [] of Crystal::Evented::Arena::Index
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)
indexes = [] of Crystal::EventLoop::Polling::Arena::Index

indexes = 32.times.map do |i|
arena.allocate_at?(i) { |ptr, _| ptr.value = i }
Expand All @@ -49,15 +49,15 @@ describe Crystal::Evented::Arena do
end

it "checks bounds" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)
expect_raises(IndexError) { arena.allocate_at?(-1) { } }
expect_raises(IndexError) { arena.allocate_at?(33) { } }
end
end

describe "#get" do
it "returns previously allocated object" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)
pointer = nil

index = arena.allocate_at(30) do |ptr|
Expand All @@ -77,15 +77,15 @@ describe Crystal::Evented::Arena do
end

it "can't access unallocated object" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)

expect_raises(RuntimeError) do
arena.get(Crystal::Evented::Arena::Index.new(10, 0)) { }
arena.get(Crystal::EventLoop::Polling::Arena::Index.new(10, 0)) { }
end
end

it "checks generation" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)
called = 0

index1 = arena.allocate_at(2) { called += 1 }
Expand All @@ -102,15 +102,15 @@ describe Crystal::Evented::Arena do
end

it "checks out of bounds" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
expect_raises(IndexError) { arena.get(Crystal::Evented::Arena::Index.new(-1, 0)) { } }
expect_raises(IndexError) { arena.get(Crystal::Evented::Arena::Index.new(33, 0)) { } }
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)
expect_raises(IndexError) { arena.get(Crystal::EventLoop::Polling::Arena::Index.new(-1, 0)) { } }
expect_raises(IndexError) { arena.get(Crystal::EventLoop::Polling::Arena::Index.new(33, 0)) { } }
end
end

describe "#get?" do
it "returns previously allocated object" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)
pointer = nil

index = arena.allocate_at(30) do |ptr|
Expand All @@ -131,16 +131,16 @@ describe Crystal::Evented::Arena do
end

it "can't access unallocated index" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)

called = 0
ret = arena.get?(Crystal::Evented::Arena::Index.new(10, 0)) { called += 1 }
ret = arena.get?(Crystal::EventLoop::Polling::Arena::Index.new(10, 0)) { called += 1 }
ret.should be_false
called.should eq(0)
end

it "checks generation" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)
called = 0

old_index = arena.allocate_at(2) { }
Expand All @@ -166,19 +166,19 @@ describe Crystal::Evented::Arena do
end

it "checks out of bounds" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)
called = 0

arena.get?(Crystal::Evented::Arena::Index.new(-1, 0)) { called += 1 }.should be_false
arena.get?(Crystal::Evented::Arena::Index.new(33, 0)) { called += 1 }.should be_false
arena.get?(Crystal::EventLoop::Polling::Arena::Index.new(-1, 0)) { called += 1 }.should be_false
arena.get?(Crystal::EventLoop::Polling::Arena::Index.new(33, 0)) { called += 1 }.should be_false

called.should eq(0)
end
end

describe "#free" do
it "deallocates the object" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)

index1 = arena.allocate_at(3) { |ptr| ptr.value = 123 }
arena.free(index1) { }
Expand All @@ -192,7 +192,7 @@ describe Crystal::Evented::Arena do
end

it "checks generation" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)

called = 0
old_index = arena.allocate_at(1) { }
Expand All @@ -214,19 +214,19 @@ describe Crystal::Evented::Arena do
end

it "checks out of bounds" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)
called = 0

arena.free(Crystal::Evented::Arena::Index.new(-1, 0)) { called += 1 }
arena.free(Crystal::Evented::Arena::Index.new(33, 0)) { called += 1 }
arena.free(Crystal::EventLoop::Polling::Arena::Index.new(-1, 0)) { called += 1 }
arena.free(Crystal::EventLoop::Polling::Arena::Index.new(33, 0)) { called += 1 }

called.should eq(0)
end
end

it "#each_index" do
arena = Crystal::Evented::Arena(Int32, 96).new(32)
indices = [] of {Int32, Crystal::Evented::Arena::Index}
arena = Crystal::EventLoop::Polling::Arena(Int32, 96).new(32)
indices = [] of {Int32, Crystal::EventLoop::Polling::Arena::Index}

arena.each_index { |i, index| indices << {i, index} }
indices.should be_empty
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{% skip_file unless Crystal.has_constant?(:Evented) %}
{% skip_file unless Crystal::EventLoop.has_constant?(:Polling) %}

require "spec"

class Crystal::Evented::FakeLoop < Crystal::Evented::EventLoop
getter operations = [] of {Symbol, Int32, Crystal::Evented::Arena::Index | Bool}
class Crystal::EventLoop::FakeLoop < Crystal::EventLoop::Polling
getter operations = [] of {Symbol, Int32, Arena::Index | Bool}

private def system_run(blocking : Bool, & : Fiber ->) : Nil
end
Expand All @@ -27,13 +27,13 @@ class Crystal::Evented::FakeLoop < Crystal::Evented::EventLoop
end
end

describe Crystal::Evented::Waiters do
describe Crystal::EventLoop::Polling::Waiters do
describe "#take_ownership" do
it "associates a poll descriptor to an evloop instance" do
fd = Int32::MAX
pd = Crystal::Evented::PollDescriptor.new
index = Crystal::Evented::Arena::Index.new(fd, 0)
evloop = Crystal::Evented::FakeLoop.new
pd = Crystal::EventLoop::Polling::PollDescriptor.new
index = Crystal::EventLoop::Polling::Arena::Index.new(fd, 0)
evloop = Crystal::EventLoop::Polling::FakeLoop.new

pd.take_ownership(evloop, fd, index)
pd.@event_loop.should be(evloop)
Expand All @@ -45,11 +45,11 @@ describe Crystal::Evented::Waiters do

it "moves a poll descriptor to another evloop instance" do
fd = Int32::MAX
pd = Crystal::Evented::PollDescriptor.new
index = Crystal::Evented::Arena::Index.new(fd, 0)
pd = Crystal::EventLoop::Polling::PollDescriptor.new
index = Crystal::EventLoop::Polling::Arena::Index.new(fd, 0)

evloop1 = Crystal::Evented::FakeLoop.new
evloop2 = Crystal::Evented::FakeLoop.new
evloop1 = Crystal::EventLoop::Polling::FakeLoop.new
evloop2 = Crystal::EventLoop::Polling::FakeLoop.new

pd.take_ownership(evloop1, fd, index)
pd.take_ownership(evloop2, fd, index)
Expand All @@ -67,26 +67,26 @@ describe Crystal::Evented::Waiters do

it "can't move to the current evloop" do
fd = Int32::MAX
pd = Crystal::Evented::PollDescriptor.new
index = Crystal::Evented::Arena::Index.new(fd, 0)
pd = Crystal::EventLoop::Polling::PollDescriptor.new
index = Crystal::EventLoop::Polling::Arena::Index.new(fd, 0)

evloop = Crystal::Evented::FakeLoop.new
evloop = Crystal::EventLoop::Polling::FakeLoop.new

pd.take_ownership(evloop, fd, index)
expect_raises(Exception) { pd.take_ownership(evloop, fd, index) }
end

it "can't move with pending waiters" do
fd = Int32::MAX
pd = Crystal::Evented::PollDescriptor.new
index = Crystal::Evented::Arena::Index.new(fd, 0)
event = Crystal::Evented::Event.new(:io_read, Fiber.current)
pd = Crystal::EventLoop::Polling::PollDescriptor.new
index = Crystal::EventLoop::Polling::Arena::Index.new(fd, 0)
event = Crystal::EventLoop::Polling::Event.new(:io_read, Fiber.current)

evloop1 = Crystal::Evented::FakeLoop.new
evloop1 = Crystal::EventLoop::Polling::FakeLoop.new
pd.take_ownership(evloop1, fd, index)
[email protected](pointerof(event))

evloop2 = Crystal::Evented::FakeLoop.new
evloop2 = Crystal::EventLoop::Polling::FakeLoop.new
expect_raises(RuntimeError) { pd.take_ownership(evloop2, fd, index) }

pd.@event_loop.should be(evloop1)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{% skip_file unless Crystal.has_constant?(:Evented) %}
{% skip_file unless Crystal::EventLoop.has_constant?(:Polling) %}

require "spec"

describe Crystal::Evented::Timers do
describe Crystal::EventLoop::Polling::Timers do
it "#empty?" do
timers = Crystal::Evented::Timers.new
timers = Crystal::EventLoop::Polling::Timers.new
timers.empty?.should be_true

event = Crystal::Evented::Event.new(:sleep, Fiber.current, timeout: 7.seconds)
event = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current, timeout: 7.seconds)
timers.add(pointerof(event))
timers.empty?.should be_false

Expand All @@ -17,13 +17,13 @@ describe Crystal::Evented::Timers do

it "#next_ready?" do
# empty
timers = Crystal::Evented::Timers.new
timers = Crystal::EventLoop::Polling::Timers.new
timers.next_ready?.should be_nil

# with events
event1s = Crystal::Evented::Event.new(:sleep, Fiber.current, timeout: 1.second)
event3m = Crystal::Evented::Event.new(:sleep, Fiber.current, timeout: 3.minutes)
event5m = Crystal::Evented::Event.new(:sleep, Fiber.current, timeout: 5.minutes)
event1s = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current, timeout: 1.second)
event3m = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current, timeout: 3.minutes)
event5m = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current, timeout: 5.minutes)

timers.add(pointerof(event5m))
timers.next_ready?.should eq(event5m.wake_at?)
Expand All @@ -36,24 +36,24 @@ describe Crystal::Evented::Timers do
end

it "#dequeue_ready" do
timers = Crystal::Evented::Timers.new
timers = Crystal::EventLoop::Polling::Timers.new

event1 = Crystal::Evented::Event.new(:sleep, Fiber.current, timeout: 0.seconds)
event2 = Crystal::Evented::Event.new(:sleep, Fiber.current, timeout: 0.seconds)
event3 = Crystal::Evented::Event.new(:sleep, Fiber.current, timeout: 1.minute)
event1 = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current, timeout: 0.seconds)
event2 = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current, timeout: 0.seconds)
event3 = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current, timeout: 1.minute)

# empty
called = 0
timers.dequeue_ready { called += 1 }
called.should eq(0)

# add events in non chronological order
timers = Crystal::Evented::Timers.new
timers = Crystal::EventLoop::Polling::Timers.new
timers.add(pointerof(event1))
timers.add(pointerof(event3))
timers.add(pointerof(event2))

events = [] of Crystal::Evented::Event*
events = [] of Crystal::EventLoop::Polling::Event*
timers.dequeue_ready { |event| events << event }

events.should eq([
Expand All @@ -64,12 +64,12 @@ describe Crystal::Evented::Timers do
end

it "#add" do
timers = Crystal::Evented::Timers.new
timers = Crystal::EventLoop::Polling::Timers.new

event0 = Crystal::Evented::Event.new(:sleep, Fiber.current)
event1 = Crystal::Evented::Event.new(:sleep, Fiber.current, timeout: 0.seconds)
event2 = Crystal::Evented::Event.new(:sleep, Fiber.current, timeout: 2.minutes)
event3 = Crystal::Evented::Event.new(:sleep, Fiber.current, timeout: 1.minute)
event0 = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current)
event1 = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current, timeout: 0.seconds)
event2 = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current, timeout: 2.minutes)
event3 = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current, timeout: 1.minute)

# add events in non chronological order
timers.add(pointerof(event1)).should be_true # added to the head (next ready)
Expand All @@ -81,13 +81,13 @@ describe Crystal::Evented::Timers do
end

it "#delete" do
event1 = Crystal::Evented::Event.new(:sleep, Fiber.current, timeout: 0.seconds)
event2 = Crystal::Evented::Event.new(:sleep, Fiber.current, timeout: 0.seconds)
event3 = Crystal::Evented::Event.new(:sleep, Fiber.current, timeout: 1.minute)
event4 = Crystal::Evented::Event.new(:sleep, Fiber.current, timeout: 4.minutes)
event1 = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current, timeout: 0.seconds)
event2 = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current, timeout: 0.seconds)
event3 = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current, timeout: 1.minute)
event4 = Crystal::EventLoop::Polling::Event.new(:sleep, Fiber.current, timeout: 4.minutes)

# add events in non chronological order
timers = Crystal::Evented::Timers.new
timers = Crystal::EventLoop::Polling::Timers.new
timers.add(pointerof(event1))
timers.add(pointerof(event3))
timers.add(pointerof(event2))
Expand Down
Loading
Loading