1 | #--
|
---|
2 | # = timeout.rb
|
---|
3 | #
|
---|
4 | # execution timeout
|
---|
5 | #
|
---|
6 | # = Copyright
|
---|
7 | #
|
---|
8 | # Copyright:: (C) 2000 Network Applied Communication Laboratory, Inc.
|
---|
9 | # Copyright:: (C) 2000 Information-technology Promotion Agency, Japan
|
---|
10 | #
|
---|
11 | #++
|
---|
12 | #
|
---|
13 | # = Description
|
---|
14 | #
|
---|
15 | # A way of performing a potentially long-running operation in a thread, and
|
---|
16 | # terminating it's execution if it hasn't finished within fixed amount of
|
---|
17 | # time.
|
---|
18 | #
|
---|
19 | # Previous versions of timeout didn't use a module for namespace. This version
|
---|
20 | # provides both Timeout.timeout, and a backwards-compatible #timeout.
|
---|
21 | #
|
---|
22 | # = Synopsis
|
---|
23 | #
|
---|
24 | # require 'timeout'
|
---|
25 | # status = Timeout::timeout(5) {
|
---|
26 | # # Something that should be interrupted if it takes too much time...
|
---|
27 | # }
|
---|
28 | #
|
---|
29 |
|
---|
30 | module Timeout
|
---|
31 |
|
---|
32 | ##
|
---|
33 | # Raised by Timeout#timeout when the block times out.
|
---|
34 |
|
---|
35 | class Error<Interrupt
|
---|
36 | end
|
---|
37 |
|
---|
38 | ##
|
---|
39 | # Executes the method's block. If the block execution terminates before +sec+
|
---|
40 | # seconds has passed, it returns true. If not, it terminates the execution
|
---|
41 | # and raises +exception+ (which defaults to Timeout::Error).
|
---|
42 | #
|
---|
43 | # Note that this is both a method of module Timeout, so you can 'include
|
---|
44 | # Timeout' into your classes so they have a #timeout method, as well as a
|
---|
45 | # module method, so you can call it directly as Timeout.timeout().
|
---|
46 |
|
---|
47 | def timeout(sec, exception=Error)
|
---|
48 | return yield if sec == nil or sec.zero?
|
---|
49 | raise ThreadError, "timeout within critical session" if Thread.critical
|
---|
50 | begin
|
---|
51 | x = Thread.current
|
---|
52 | y = Thread.start {
|
---|
53 | sleep sec
|
---|
54 | x.raise exception, "execution expired" if x.alive?
|
---|
55 | }
|
---|
56 | yield sec
|
---|
57 | # return true
|
---|
58 | ensure
|
---|
59 | y.kill if y and y.alive?
|
---|
60 | end
|
---|
61 | end
|
---|
62 |
|
---|
63 | module_function :timeout
|
---|
64 |
|
---|
65 | end
|
---|
66 |
|
---|
67 | ##
|
---|
68 | # Identical to:
|
---|
69 | #
|
---|
70 | # Timeout::timeout(n, e, &block).
|
---|
71 | #
|
---|
72 | # Defined for backwards compatibility with earlier versions of timeout.rb, see
|
---|
73 | # Timeout#timeout.
|
---|
74 |
|
---|
75 | def timeout(n, e=Timeout::Error, &block) # :nodoc:
|
---|
76 | Timeout::timeout(n, e, &block)
|
---|
77 | end
|
---|
78 |
|
---|
79 | ##
|
---|
80 | # Another name for Timeout::Error, defined for backwards compatibility with
|
---|
81 | # earlier versions of timeout.rb.
|
---|
82 |
|
---|
83 | TimeoutError = Timeout::Error # :nodoc:
|
---|
84 |
|
---|
85 | if __FILE__ == $0
|
---|
86 | p timeout(5) {
|
---|
87 | 45
|
---|
88 | }
|
---|
89 | p timeout(5, TimeoutError) {
|
---|
90 | 45
|
---|
91 | }
|
---|
92 | p timeout(nil) {
|
---|
93 | 54
|
---|
94 | }
|
---|
95 | p timeout(0) {
|
---|
96 | 54
|
---|
97 | }
|
---|
98 | p timeout(5) {
|
---|
99 | loop {
|
---|
100 | p 10
|
---|
101 | sleep 1
|
---|
102 | }
|
---|
103 | }
|
---|
104 | end
|
---|
105 |
|
---|