Skip to content

Commit 455df09

Browse files
committed
Wrap LibC.open in syscall(&) in the polling event loops
1 parent 8544bea commit 455df09

File tree

3 files changed

+27
-10
lines changed

3 files changed

+27
-10
lines changed

spec/std/file_spec.cr

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require "./spec_helper"
22
require "../support/thread"
3+
require "wait_group"
34

45
private def it_raises_on_null_byte(operation, file = __FILE__, line = __LINE__, end_line = __END_LINE__, &block)
56
it "errors on #{operation}", file, line, end_line do
@@ -94,19 +95,31 @@ describe "File" do
9495
ret = LibC.mkfifo(path, File::DEFAULT_CREATE_PERMISSIONS)
9596
raise RuntimeError.from_errno("mkfifo") unless ret == 0
9697

97-
# FIXME: open(2) will block when opening a fifo file until another
98-
# thread or process also opened the file; we should pass
99-
# O_NONBLOCK to the open(2) call itself, not afterwards
100-
file = nil
101-
new_thread { file = File.new(path, "w", blocking: nil) }
98+
# open(2) will block when opening a fifo file until another thread or
99+
# process also opened the file; we should pass O_NONBLOCK to the
100+
# open(2) call itself, not afterwards
101+
w = nil
102102

103103
begin
104-
File.open(path, "r", blocking: false) do |file|
105-
file.blocking.should be_false
104+
WaitGroup.wait do |wg|
105+
{% if flag?(:execution_context) %}
106+
# the fiber may block on open(2) (depending on the event loop)
107+
# but the execution context must notice and replace the thread
108+
wg.spawn(name: "fifo:write") { w = File.new(path, "w", blocking: nil) }
109+
{% else %}
110+
# must explicitly start a thread
111+
new_thread { w = File.new(path, "w", blocking: nil) }
112+
{% end %}
113+
114+
wg.spawn(name: "fifo:read") do
115+
File.open(path, "r", blocking: false) do |r|
116+
r.blocking.should be_false
117+
end
118+
end
106119
end
107120
ensure
108121
File.delete(path)
109-
file.try(&.close)
122+
w.try(&.close)
110123
end
111124
end
112125
{% end %}

src/crystal/event_loop/libevent.cr

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,9 @@ class Crystal::EventLoop::LibEvent < Crystal::EventLoop
127127
def open(path : String, flags : Int32, permissions : File::Permissions, blocking : Bool?) : {System::FileDescriptor::Handle, Bool} | Errno
128128
path.check_no_null_byte
129129

130-
fd = LibC.open(path, flags | LibC::O_CLOEXEC, permissions)
130+
fd = ::Fiber.syscall do
131+
LibC.open(path, flags | LibC::O_CLOEXEC, permissions)
132+
end
131133
return Errno.value if fd == -1
132134

133135
blocking = !System::File.special_type?(fd) if blocking.nil?

src/crystal/event_loop/polling.cr

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,9 @@ abstract class Crystal::EventLoop::Polling < Crystal::EventLoop
173173
def open(path : String, flags : Int32, permissions : File::Permissions, blocking : Bool?) : {System::FileDescriptor::Handle, Bool} | Errno
174174
path.check_no_null_byte
175175

176-
fd = LibC.open(path, flags | LibC::O_CLOEXEC, permissions)
176+
fd = ::Fiber.syscall do
177+
LibC.open(path, flags | LibC::O_CLOEXEC, permissions)
178+
end
177179
return Errno.value if fd == -1
178180

179181
blocking = !System::File.special_type?(fd) if blocking.nil?

0 commit comments

Comments
 (0)