-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
spec/std/channel_spec.cr
gets stuck on Windows with -Dpreview_mt
#14222
Comments
It looks like all the worker threads eventually got stuck on the |
All threads waiting on FiberChannel means all threads "parked" themselves but they shouldn't be blocked on it, but blocked on the EventLoop (waiting for completions). So yeah, suspicious. Note: with Executioncontext the FiberChannel is no longer used. |
With two changes I now manage to get the OP snippet and the specs passing: module Crystal::System::FileDescriptor
def self.pipe(read_blocking, write_blocking)
# ...
r = IO::FileDescriptor.new(r_pipe.address, read_blocking)
w = IO::FileDescriptor.new(w_pipe.address, write_blocking)
r.read_buffering = false # disable buffering on the read end
w.sync = true
{r, w}
end
end
lib LibC
fun PeekNamedPipe(hNamedPipe : HANDLE, lpBuffer : Void*, nBufferSize : DWORD, lpBytesRead : DWORD*, lpTotalBytesAvail : DWORD*, lpBytesLeftThisMessage : DWORD*) : BOOL
end
struct Crystal::FiberChannel
def receive
# explicitly peek the pipe until there is data available
while true
LibC.PeekNamedPipe(LibC::HANDLE.new(@worker_out.fd), nil, 0, nil, out bytes_avail, nil)
break if bytes_avail >= sizeof(UInt64)
Fiber.yield
end
oid = @worker_out.read_bytes(UInt64)
Pointer(Fiber).new(oid).as(Fiber)
end
end What's interesting is both ends of the struct Crystal::FiberChannel
@lock = Crystal::SpinLock.new
def initialize
@queue = Deque(Fiber).new
end
def send(fiber : Fiber)
@lock.sync { @queue << fiber }
end
def receive
while true
fiber = @lock.sync { @queue.shift? }
return fiber if fiber
Fiber.yield
end
end
end And eventually: class Crystal::Scheduler
{% flag?(:preview_mt) %}
def run_loop
spawn_stack_pool_collector
loop do
@lock.lock
if runnable = @runnables.shift?
@runnables << Fiber.current
@lock.unlock
resume(runnable)
else
@lock.unlock
Fiber.yield
end
end
end
def send_fiber(fiber : Fiber)
@lock.sync { @runnables << fiber }
end
{% end %}
end Has the codebase changed so much in these years that we don't need On the other hand, I wonder if this also implies |
Running that spec file will block at the
raises if channel was closed
test. IncreasingCRYSTAL_WORKERS
from the default 4 makes two more specs run and pass, but after that theawakes all waiting selects
test still blocks.This reduction, probably the first Windows-specific one we have, similarly blocks at the
CRYSTAL_WORKERS + 1
-th loop:The snippet doesn't block if run without
-Dpreview_mt
or run on Linux.The text was updated successfully, but these errors were encountered: