Skip to content

Commit

Permalink
Make Socket hold a reference to its Context (#229)
Browse files Browse the repository at this point in the history
This prevents the `Context` from being garbage collected while the `Socket` is
still alive, otherwise the `Socket` would be closed by the `Context`'s finalizer
while the `Socket` is potentially still in use.
  • Loading branch information
JamesWrigley authored May 20, 2024
1 parent d2edc88 commit f278afd
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/socket.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ A ZMQ socket.
"""
mutable struct Socket
data::Ptr{Cvoid}
context::Context
pollfd::FDWatcher

@doc """
Expand All @@ -15,7 +16,7 @@ mutable struct Socket
if p == C_NULL
throw(StateError(jl_zmq_error_str()))
end
socket = new(p)
socket = new(p, ctx)
setfield!(socket, :pollfd, FDWatcher(fd(socket), #=readable=#true, #=writable=#false))
finalizer(close, socket)
push!(getfield(ctx, :sockets), WeakRef(socket))
Expand Down
16 changes: 16 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,23 @@ using ZMQ, Test
@test_throws StateError Socket(ctx, PUB)
end

# This test is in its own function to keep it simple and try to trick Julia into
# thinking it can safely GC the Context.
function context_gc_test()
ctx = Context()
s = Socket(ctx, PUB)

# Force garbage collection to attempt to delete ctx
GC.gc()

# But it shouldn't be garbage collected since the socket should have a
# reference to it, so the socket should still be open.
@test isopen(s)
end

@testset "ZMQ sockets" begin
context_gc_test()

s=Socket(PUB)
@test s isa Socket
ZMQ.close(s)
Expand Down

0 comments on commit f278afd

Please sign in to comment.