Path: | lib/bundler/safe_catch.rb |
Last Update: | Tue Apr 01 14:31:10 +0000 2014 |
SafeCatch provides a mechanism to safely deepen the stack, performing stack-unrolling similar to catch/throw, but using Fiber or Thread to avoid deepening the stack too quickly.
The API is the same as that of catch/throw: SafeCatch#safe_catch takes a "tag" to be rescued when some code deeper in the process raises it. If the catch block completes successfully, that value is returned. If the tag is "thrown" by safe_throw, the tag‘s value is returned. Other exceptions propagate out as normal.
The implementation, however, uses fibers or threads along with raise/rescue to handle "deepening" the stack and unrolling it. On implementations where Fiber is available, it will be used. If Fiber is not available, Thread will be used. If neither of these classes are available, Proc will be used, effectively deepening the stack for each recursion as in normal catch/throw.
In order to avoid causing a new issue of creating too many fibers or threads, especially on implementations where fibers are actually backed by native threads, the "safe" recursion mechanism is only used every 20 recursions. Based on experiments with JRuby (which seems to suffer the most from excessively deep stacks), this appears to be a sufficient granularity to prevent stack overflow without spinning up excessive numbers of fibers or threads. This value can be adjusted with the BUNDLER_SAFE_RECURSE_EVERY env var; setting it to zero effectively disables safe recursion.