Skip to content

Recursive methods crash in Fiber/Thread due to stack size #12

@evnu

Description

@evnu

RubyTree uses recursion for methods such as each and detached_subtree_copy. This is ok for smaller well-balanced trees, but fails for unbalanced trees when Fiber or Threads are involved.

Constructing and Walking a Linear Tree

See the following example method to construct a linear tree:

#!/usr/bin/ruby
require "tree"

def run_test(depth=100)
    tree = Tree::TreeNode.new("/")
    current = tree
    depth.times do |i|
        new_node = Tree::TreeNode.new("#{i}")
        current << new_node
        current = new_node
    end
    tree.each{|n| nil}
end

This runs fine when executed in the main thread...

puts "Run test in the main thread"
run_test()

...but fails when a Fiber or Thread is involved:

puts "Run test in a fiber"
begin
    Fiber.new do
        run_test()
    end.resume
rescue SystemStackError
    puts "Fiber died."
end

puts "Run test in a thread"
begin
    Thread.abort_on_exception = true
    Thread.new do
        run_test(600) # 600 is not chosen arbitrary: this is the first number where it fails here.
    end
    sleep(3)
rescue SystemStackError
    puts "Thread died."
end

Note that the recursion depth between Fiber and Thread differs.

Demo Output

The example script above produces the following output with my machine:

% ./example.rb
Run test in the main thread
Run test in a fiber
Fiber died.
Run test in a thread
Thread died.

Possible Solution

This should be resolvable by replacing the recursion in each, detached_subtree_copy and elsewhere with the respective iterative representation. each could possibly be fixed like this:

module Tree
    class TreeNode
        def each(&blk)
            expand_nodes = [self]
            while expand_nodes != []
                current = expand_nodes.shift
                yield current
                expand_nodes = current.children.concat(expand_nodes)
            end
        end
    end

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions