Skip to content

Commit 9b87ee9

Browse files
vtjnashLilithHafner
authored andcommitted
[Serialization] support AbstractLock and GenericCondition (JuliaLang#43325)
Locks should be unlocked when serialized, and GenericCondition should drop their waiters. Otherwise, we may try to serialize a running Task (the user should normally be holding the lock around the data they are intending to serialize), which will fail and error.
1 parent ac80528 commit 9b87ee9

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

base/deepcopy.jl

+18
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,21 @@ function deepcopy_internal(x::Union{Dict,IdDict}, stackdict::IdDict)
126126
end
127127
dest
128128
end
129+
130+
function deepcopy_internal(x::AbstractLock, stackdict::IdDict)
131+
if haskey(stackdict, x)
132+
return stackdict[x]
133+
end
134+
y = typeof(x)()
135+
stackdict[x] = y
136+
return y
137+
end
138+
139+
function deepcopy_internal(x::GenericCondition, stackdict::IdDict)
140+
if haskey(stackdict, x)
141+
return stackdict[x]
142+
end
143+
y = typeof(x)(deepcopy_internal(x.lock))
144+
stackdict[x] = y
145+
return y
146+
end

stdlib/Serialization/src/Serialization.jl

+26
Original file line numberDiff line numberDiff line change
@@ -1528,4 +1528,30 @@ function deserialize(s::AbstractSerializer, ::Type{Base.StackTraces.StackFrame})
15281528
return Base.StackTraces.StackFrame(func, file, line, nothing, from_c, inlined, pointer)
15291529
end
15301530

1531+
function serialize(s::AbstractSerializer, lock::Base.AbstractLock)
1532+
# assert_havelock(lock)
1533+
serialize_cycle_header(s, lock)
1534+
nothing
1535+
end
1536+
1537+
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.AbstractLock
1538+
lock = T()
1539+
deserialize_cycle(s, lock)
1540+
return lock
1541+
end
1542+
1543+
function serialize(s::AbstractSerializer, cond::Base.GenericCondition)
1544+
serialize_cycle_header(s, cond) && return
1545+
serialize(s, cond.lock)
1546+
nothing
1547+
end
1548+
1549+
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.GenericCondition
1550+
lock = deserialize(s)
1551+
cond = T(lock)
1552+
deserialize_cycle(s, cond)
1553+
return cond
1554+
end
1555+
1556+
15311557
end

stdlib/Serialization/test/runtests.jl

+18
Original file line numberDiff line numberDiff line change
@@ -624,3 +624,21 @@ end
624624
@test_broken f(1) == 2
625625
end
626626
end
627+
628+
let c1 = Threads.Condition()
629+
c2 = Threads.Condition(c1.lock)
630+
lock(c2)
631+
t = @task nothing
632+
Base._wait2(c1, t)
633+
c3, c4 = deserialize(IOBuffer(sprint(serialize, [c1, c2])))::Vector{Threads.Condition}
634+
@test c3.lock === c4.lock
635+
@test islocked(c1)
636+
@test !islocked(c3)
637+
@test !isempty(c1.waitq)
638+
@test isempty(c2.waitq)
639+
@test isempty(c3.waitq)
640+
@test isempty(c4.waitq)
641+
notify(c1)
642+
unlock(c2)
643+
wait(t)
644+
end

0 commit comments

Comments
 (0)