Skip to content

Commit

Permalink
Make Socket hold a reference to its Context
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 committed May 17, 2024
1 parent 9ec590e commit 9767ab3
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 @@ -19,6 +19,7 @@ Do-block constructor.
"""
mutable struct Socket
data::Ptr{Cvoid}
context::Context
pollfd::FDWatcher

"""
Expand All @@ -31,7 +32,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 @@ -13,7 +13,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 9767ab3

Please sign in to comment.