Skip to content

Commit

Permalink
No finalizer (#189)
Browse files Browse the repository at this point in the history
* Option to not use finalizer

* Fix to disambiguate Socket call

* Add tests for context/socket resource management
  • Loading branch information
joelfrederico authored and stevengj committed Dec 10, 2018
1 parent 360f80c commit c071980
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/ZMQ.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ export
include("constants.jl")
include("optutil.jl")
include("error.jl")
include("context.jl")
include("socket.jl")
include("sockopts.jl")
include("context.jl")
include("message.jl")
include("comm.jl")

Expand Down
9 changes: 9 additions & 0 deletions src/context.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ mutable struct Context
end
end

function Context(f::Function, args...)
ctx = Context(args...)
try
f(ctx)
finally
close(ctx)
end
end

Base.unsafe_convert(::Type{Ptr{Cvoid}}, c::Context) = getfield(c, :data)

# define a global context that is initialized lazily
Expand Down
14 changes: 11 additions & 3 deletions src/socket.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ mutable struct Socket
data::Ptr{Cvoid}
pollfd::_FDWatcher

# ctx should be ::Context, but forward type references are not allowed
function Socket(ctx, typ::Integer)
function Socket(ctx::Context, typ::Integer)
p = ccall((:zmq_socket, libzmq), Ptr{Cvoid}, (Ptr{Cvoid}, Cint), ctx, typ)
if p == C_NULL
throw(StateError(jl_zmq_error_str()))
Expand All @@ -18,6 +17,15 @@ mutable struct Socket
Socket(typ::Integer) = Socket(context(), typ)
end

function Socket(f::Function, args...)
socket = Socket(args...)
try
f(socket)
finally
close(socket)
end
end

Base.unsafe_convert(::Type{Ptr{Cvoid}}, s::Socket) = getfield(s, :data)

Base.isopen(socket::Socket) = getfield(socket, :data) != C_NULL
Expand Down Expand Up @@ -56,4 +64,4 @@ function Sockets.connect(socket::Socket, endpoint::AbstractString)
if rc != 0
throw(StateError(jl_zmq_error_str()))
end
end
end
30 changes: 30 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,33 @@ end
# ZMQ.close(s1); ZMQ.close(s2) # should happen when context is closed
ZMQ.close(ZMQ._context) # immediately close global context rather than waiting for exit
end

@testset "ZMQ resource management" begin
local leaked_req_socket, leaked_rep_socket
ZMQ.Socket(ZMQ.REQ) do req_socket
leaked_req_socket = req_socket

ZMQ.Socket(ZMQ.REP) do rep_socket
leaked_rep_socket = rep_socket

ZMQ.bind(rep_socket, "inproc://tester")
ZMQ.connect(req_socket, "inproc://tester")

ZMQ.send(req_socket, "Mr. Watson, come here, I want to see you.")
@test unsafe_string(ZMQ.recv(rep_socket)) == "Mr. Watson, come here, I want to see you."
ZMQ.send(rep_socket, "Coming, Mr. Bell.")
@test unsafe_string(ZMQ.recv(req_socket)) == "Coming, Mr. Bell."
end

@test !ZMQ.isopen(leaked_rep_socket)
end
@test !ZMQ.isopen(leaked_req_socket)

local leaked_ctx
ZMQ.Context() do ctx
leaked_ctx = ctx

@test isopen(ctx)
end
@test !isopen(leaked_ctx)
end

0 comments on commit c071980

Please sign in to comment.