@@ -166,11 +166,21 @@ end
166166 elseif field === :exception
167167 # TODO : this field name should be deprecated in 2.0
168168 return t. _isexception ? t. result : nothing
169+ elseif field === :sticky
170+ return getfield (t, :sticky_count ) != 0
169171 else
170172 return getfield (t, field)
171173 end
172174end
173175
176+ function setproperty! (t:: Task , field:: Symbol , x)
177+ if field === :sticky
178+ t. sticky_count = convert (Bool, x)
179+ else
180+ setfield! (t, field, convert (fieldtype (Task, field), x))
181+ end
182+ end
183+
174184"""
175185 istaskdone(t::Task) -> Bool
176186
@@ -611,6 +621,9 @@ function __preinit_threads__()
611621 nothing
612622end
613623
624+ # Factored out so that the behavior after saturation can be tested:
625+ is_sticky_count_saturated (t:: Task ) = t. sticky_count === typemax (t. sticky_count)
626+
614627function enq_work (t:: Task )
615628 (t. _state === task_state_runnable && t. queue === nothing ) || error (" schedule: Task not runnable" )
616629 tid = Threads. threadid (t)
@@ -625,8 +638,30 @@ function enq_work(t::Task)
625638 # t.sticky && tid == 0 is a task that needs to be co-scheduled with
626639 # the parent task. If the parent (current_task) is not sticky we must
627640 # set it to be sticky.
628- # XXX : Ideally we would be able to unset this
629- current_task (). sticky = true
641+ parent_task = current_task ()
642+ if t. sticky && ! is_sticky_count_saturated (parent_task)
643+ parent_task. sticky_count += 1
644+ original_code = t. code
645+ t. code = function wrapper_code ()
646+ try
647+ original_code ()
648+ finally
649+ if ! is_sticky_count_saturated (parent_task)
650+ # Once `parent_task.sticky_count` hits the typemax (which
651+ # practically never happens), we stop un-sticking the parent
652+ # task. This only affects the performance in rare cases (which
653+ # already torturing the scheulder anyway) and does not
654+ # sacrifice the correctness. Checking saturation should be done
655+ # for all tasks includding those started with
656+ # `parent_task.sticky_count < typemax -1` since there may be
657+ # sticky tasks started realying on that the coutner is
658+ # saturated.
659+ parent_task. sticky_count -= 1
660+ end
661+ end
662+ end
663+ end
664+
630665 tid = Threads. threadid ()
631666 ccall (:jl_set_task_tid , Cvoid, (Any, Cint), t, tid- 1 )
632667 end
0 commit comments