class Async::Node
A node in a tree, used for implementing the task hierarchy.
def add_child child
def add_child child ||= Children.new .insert(child) _parent(self)
def annotate(annotation)
def annotate(annotation) if block_given? previous_annotation = @annotation @annotation = annotation yield @annotation = previous_annotation else @annotation = annotation end end
def backtrace(*arguments)
def backtrace(*arguments) nil end
def children?
def children? @children != nil && !@children.empty? end
def consume
If the node has a parent, and is {finished?}, then remove this node from
def consume if parent = @parent and finished? parent.delete_child(self) if @children @children.each do |child| if child.finished? delete_child(child) else # In theory we don't need to do this... because we are throwing away the list. However, if you don't correctly update the list when moving the child to the parent, it foobars the enumeration, and subsequent nodes will be skipped, or in the worst case you might start enumerating the parents nodes. delete_child(child) parent.add_child(child) end end @children = nil end parent.consume end end
def delete_child(child)
def delete_child(child) .delete(child) _parent(nil)
def description
def description @object_name ||= "#{self.class}:#{format '%#018x', object_id}#{@transient ? ' transient' : nil}" if @annotation "#{@object_name} #{@annotation}" elsif line = self.backtrace(0, 1)&.first "#{@object_name} #{line}" else @object_name end end
def finished?
children set is empty.
Whether the node can be consumed safely. By default, checks if the
def finished? @children.nil? || @children.finished? end
def initialize(parent = nil, annotation: nil, transient: false)
Create a new node in the tree.
def initialize(parent = nil, annotation: nil, transient: false) @parent = nil @children = nil @annotation = annotation @object_name = nil @transient = transient @head = nil @tail = nil if parent parent.add_child(self) end end
def parent=(parent)
@parameter parent [Node | Nil] the parent to attach to, or nil to detach.
Change the parent of this node.
def parent=(parent) return if @parent.equal?(parent) if @parent @parent.delete_child(self) @parent = nil end if parent parent.add_child(self) end return self end
def print_backtrace(out, indent, node)
def print_backtrace(out, indent, node) if backtrace = node.backtrace backtrace.each_with_index do |line, index| out.puts "#{indent}#{index.zero? ? "→ " : " "}#{line}" end end end
def print_hierarchy(out = $stdout, backtrace: true)
def print_hierarchy(out = $stdout, backtrace: true) self.traverse do |node, level| indent = "\t" * level out.puts "#{indent}#{node}" print_backtrace(out, indent, node) if backtrace end end
def root
def root @parent&.root || self end
def set_parent parent
def set_parent parent parent
def stop(later = false)
Invokes {#stop_children} to stop all children.
Attempt to stop the current node immediately, including all non-transient children.
def stop(later = false) # The implementation of this method may defer calling `stop_children`. stop_children(later) end
def stop_children(later = false)
def stop_children(later = false) en&.each do |child| stop(later) unless child.transient?
def stopped?
def stopped? @children.nil? end
def terminate
Immediately terminate all children tasks, including transient tasks.
def terminate # Attempt to stop the current task immediately, and all children: stop(false) # If that doesn't work, take more serious action: @children&.each do |child| child.terminate end end
def to_s
def to_s "\#<#{self.description}>" end
def transient?
def transient? @transient end
def traverse(level = 0, &block)
Traverse the tree.
def traverse(level = 0, &block) yield self, level @children&.each do |child| child.traverse(level + 1, &block) end end