mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
f2a91397fd
If uplevel keyword is given, the warning message is prepended with caller file and line information and the string "warning: ". The use of the uplevel keyword makes Kernel#warn format output similar to how rb_warn formats output. This patch modifies net/ftp and net/imap to use Kernel#warn instead of $stderr.puts or $stderr.printf, since they are used for printing warnings. This makes lib/cgi/core and tempfile use $stderr.puts instead of warn for debug logging, since they are used for debug printing and not for warning. This does not modify bundler, rubygems, or rdoc, as those are maintained outside of ruby and probably wish to remain backwards compatible with older ruby versions. rb_warn_m code is originally from nobu, but I've changed it so that it only includes the path and lineno from uplevel (not the method), and also prepends the string "warning: ", to make it more similar to rb_warn. From: Jeremy Evans code@jeremyevans.net Signed-off-by: Urabe Shyouhei shyouhei@ruby-lang.org git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61155 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
130 lines
3.8 KiB
Ruby
130 lines
3.8 KiB
Ruby
# frozen_string_literal: false
|
|
# Timeout long-running blocks
|
|
#
|
|
# == Synopsis
|
|
#
|
|
# require 'timeout'
|
|
# status = Timeout::timeout(5) {
|
|
# # Something that should be interrupted if it takes more than 5 seconds...
|
|
# }
|
|
#
|
|
# == Description
|
|
#
|
|
# Timeout provides a way to auto-terminate a potentially long-running
|
|
# operation if it hasn't finished in a fixed amount of time.
|
|
#
|
|
# Previous versions didn't use a module for namespacing, however
|
|
# #timeout is provided for backwards compatibility. You
|
|
# should prefer Timeout.timeout instead.
|
|
#
|
|
# == Copyright
|
|
#
|
|
# Copyright:: (C) 2000 Network Applied Communication Laboratory, Inc.
|
|
# Copyright:: (C) 2000 Information-technology Promotion Agency, Japan
|
|
|
|
module Timeout
|
|
# Raised by Timeout.timeout when the block times out.
|
|
class Error < RuntimeError
|
|
attr_reader :thread
|
|
|
|
def self.catch(*args)
|
|
exc = new(*args)
|
|
exc.instance_variable_set(:@thread, Thread.current)
|
|
::Kernel.catch(exc) {yield exc}
|
|
end
|
|
|
|
def exception(*)
|
|
# TODO: use Fiber.current to see if self can be thrown
|
|
if self.thread == Thread.current
|
|
bt = caller
|
|
begin
|
|
throw(self, bt)
|
|
rescue UncaughtThrowError
|
|
end
|
|
end
|
|
self
|
|
end
|
|
end
|
|
|
|
# :stopdoc:
|
|
THIS_FILE = /\A#{Regexp.quote(__FILE__)}:/o
|
|
CALLER_OFFSET = ((c = caller[0]) && THIS_FILE =~ c) ? 1 : 0
|
|
private_constant :THIS_FILE, :CALLER_OFFSET
|
|
# :startdoc:
|
|
|
|
# Perform an operation in a block, raising an error if it takes longer than
|
|
# +sec+ seconds to complete.
|
|
#
|
|
# +sec+:: Number of seconds to wait for the block to terminate. Any number
|
|
# may be used, including Floats to specify fractional seconds. A
|
|
# value of 0 or +nil+ will execute the block without any timeout.
|
|
# +klass+:: Exception Class to raise if the block fails to terminate
|
|
# in +sec+ seconds. Omitting will use the default, Timeout::Error
|
|
# +message+:: Error message to raise with Exception Class.
|
|
# Omitting will use the default, "execution expired"
|
|
#
|
|
# Returns the result of the block *if* the block completed before
|
|
# +sec+ seconds, otherwise throws an exception, based on the value of +klass+.
|
|
#
|
|
# The exception thrown to terminate the given block cannot be rescued inside
|
|
# the block unless +klass+ is given explicitly.
|
|
#
|
|
# Note that this is both a method of module Timeout, so you can <tt>include
|
|
# Timeout</tt> into your classes so they have a #timeout method, as well as
|
|
# a module method, so you can call it directly as Timeout.timeout().
|
|
def timeout(sec, klass = nil, message = nil) #:yield: +sec+
|
|
return yield(sec) if sec == nil or sec.zero?
|
|
message ||= "execution expired".freeze
|
|
from = "from #{caller_locations(1, 1)[0]}" if $DEBUG
|
|
e = Error
|
|
bl = proc do |exception|
|
|
begin
|
|
x = Thread.current
|
|
y = Thread.start {
|
|
Thread.current.name = from
|
|
begin
|
|
sleep sec
|
|
rescue => e
|
|
x.raise e
|
|
else
|
|
x.raise exception, message
|
|
end
|
|
}
|
|
return yield(sec)
|
|
ensure
|
|
if y
|
|
y.kill
|
|
y.join # make sure y is dead.
|
|
end
|
|
end
|
|
end
|
|
if klass
|
|
begin
|
|
bl.call(klass)
|
|
rescue klass => e
|
|
bt = e.backtrace
|
|
end
|
|
else
|
|
bt = Error.catch(message, &bl)
|
|
end
|
|
level = -caller(CALLER_OFFSET).size-2
|
|
while THIS_FILE =~ bt[level]
|
|
bt.delete_at(level)
|
|
end
|
|
raise(e, message, bt)
|
|
end
|
|
|
|
module_function :timeout
|
|
end
|
|
|
|
def timeout(*args, &block)
|
|
warn "Object##{__method__} is deprecated, use Timeout.timeout instead.", uplevel: 1
|
|
Timeout.timeout(*args, &block)
|
|
end
|
|
|
|
# Another name for Timeout::Error, defined for backwards compatibility with
|
|
# earlier versions of timeout.rb.
|
|
TimeoutError = Timeout::Error
|
|
class Object
|
|
deprecate_constant :TimeoutError
|
|
end
|