8484
8585function finalize_ref (r:: AbstractRemoteRef )
8686 if r. where > 0 # Handle the case of the finalizer having been called manually
87- if islocked (client_refs)
88- # delay finalizer for later, when it's not already locked
87+ if trylock (client_refs. lock) # trylock doesn't call wait which causes yields
88+ try
89+ delete! (client_refs. ht, r) # direct removal avoiding locks
90+ if isa (r, RemoteChannel)
91+ send_del_client_no_lock (r)
92+ else
93+ # send_del_client only if the reference has not been set
94+ r. v === nothing && send_del_client_no_lock (r)
95+ r. v = nothing
96+ end
97+ r. where = 0
98+ finally
99+ unlock (client_refs. lock)
100+ end
101+ else
89102 finalizer (finalize_ref, r)
90103 return nothing
91104 end
92- delete! (client_refs, r)
93- if isa (r, RemoteChannel)
94- send_del_client (r)
95- else
96- # send_del_client only if the reference has not been set
97- r. v === nothing && send_del_client (r)
98- r. v = nothing
99- end
100- r. where = 0
101105 end
102106 nothing
103107end
@@ -229,13 +233,18 @@ del_client(rr::AbstractRemoteRef) = del_client(remoteref_id(rr), myid())
229233del_client (id, client) = del_client (PGRP, id, client)
230234function del_client (pg, id, client)
231235 lock (client_refs) do
232- rv = get (pg. refs, id, false )
233- if rv != = false
234- delete! (rv. clientset, client)
235- if isempty (rv. clientset)
236- delete! (pg. refs, id)
237- # print("$(myid()) collected $id\n")
238- end
236+ _del_client (pg, id, client)
237+ end
238+ nothing
239+ end
240+
241+ function _del_client (pg, id, client)
242+ rv = get (pg. refs, id, false )
243+ if rv != = false
244+ delete! (rv. clientset, client)
245+ if isempty (rv. clientset)
246+ delete! (pg. refs, id)
247+ # print("$(myid()) collected $id\n")
239248 end
240249 end
241250 nothing
@@ -247,25 +256,67 @@ function del_clients(pairs::Vector)
247256 end
248257end
249258
250- const any_gc_flag = Condition ()
259+ # The task below is coalescing the `flush_gc_msgs` call
260+ # across multiple producers, see `send_del_client`,
261+ # and `send_add_client`.
262+ # XXX : Is this worth the additional complexity?
263+ # `flush_gc_msgs` has to iterate over all connected workers.
264+ const any_gc_flag = Threads. Condition ()
251265function start_gc_msgs_task ()
252- errormonitor (@async while true
253- wait (any_gc_flag)
254- flush_gc_msgs ()
255- end )
266+ errormonitor (
267+ Threads. @spawn begin
268+ while true
269+ lock (any_gc_flag) do
270+ # this might miss events
271+ wait (any_gc_flag)
272+ end
273+ flush_gc_msgs () # handles throws internally
274+ end
275+ end
276+ )
256277end
257278
279+ # Function can be called within a finalizer
258280function send_del_client (rr)
259281 if rr. where == myid ()
260282 del_client (rr)
261283 elseif id_in_procs (rr. where) # process only if a valid worker
262- w = worker_from_id (rr. where):: Worker
263- push! (w. del_msgs, (remoteref_id (rr), myid ()))
264- w. gcflag = true
284+ process_worker (rr)
285+ end
286+ end
287+
288+ function send_del_client_no_lock (rr)
289+ # for gc context to avoid yields
290+ if rr. where == myid ()
291+ _del_client (PGRP, remoteref_id (rr), myid ())
292+ elseif id_in_procs (rr. where) # process only if a valid worker
293+ process_worker (rr)
294+ end
295+ end
296+
297+ function publish_del_msg! (w:: Worker , msg)
298+ lock (w. msg_lock) do
299+ push! (w. del_msgs, msg)
300+ @atomic w. gcflag = true
301+ end
302+ lock (any_gc_flag) do
265303 notify (any_gc_flag)
266304 end
267305end
268306
307+ function process_worker (rr)
308+ w = worker_from_id (rr. where):: Worker
309+ msg = (remoteref_id (rr), myid ())
310+
311+ # Needs to aquire a lock on the del_msg queue
312+ T = Threads. @spawn begin
313+ publish_del_msg! ($ w, $ msg)
314+ end
315+ Base. errormonitor (T)
316+
317+ return
318+ end
319+
269320function add_client (id, client)
270321 lock (client_refs) do
271322 rv = lookup_ref (id)
@@ -288,9 +339,13 @@ function send_add_client(rr::AbstractRemoteRef, i)
288339 # to the processor that owns the remote ref. it will add_client
289340 # itself inside deserialize().
290341 w = worker_from_id (rr. where)
291- push! (w. add_msgs, (remoteref_id (rr), i))
292- w. gcflag = true
293- notify (any_gc_flag)
342+ lock (w. msg_lock) do
343+ push! (w. add_msgs, (remoteref_id (rr), i))
344+ @atomic w. gcflag = true
345+ end
346+ lock (any_gc_flag) do
347+ notify (any_gc_flag)
348+ end
294349 end
295350end
296351
0 commit comments