timeout-interrupt 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/VERSION +1 -1
- data/lib/timeout_interrupt.rb +145 -11
- data/timeout-interrupt.gemspec +4 -1
- metadata +27 -16
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -24,6 +24,7 @@ GEM
|
|
24
24
|
rake (10.0.3)
|
25
25
|
rdoc (4.0.0)
|
26
26
|
json (~> 1.4)
|
27
|
+
redcarpet (2.2.2)
|
27
28
|
shoulda (3.3.2)
|
28
29
|
shoulda-context (~> 1.0.1)
|
29
30
|
shoulda-matchers (~> 1.4.1)
|
@@ -45,6 +46,7 @@ DEPENDENCIES
|
|
45
46
|
ffi-libc
|
46
47
|
jeweler
|
47
48
|
rdoc
|
49
|
+
redcarpet
|
48
50
|
shoulda
|
49
51
|
simplecov
|
50
52
|
yard
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
data/lib/timeout_interrupt.rb
CHANGED
@@ -1,40 +1,107 @@
|
|
1
1
|
require 'ffi/libc'
|
2
2
|
require 'timeout'
|
3
3
|
|
4
|
+
# Provided by ffi-libc-lib and extended by this library, if needed.
|
5
|
+
# Older version of ffi-libc does not provide {FFI::LibC.alarm}
|
4
6
|
module FFI
|
5
7
|
module LibC
|
8
|
+
# @!method alarm(seconds)
|
9
|
+
# Sets an alarm. After `seconds` it will send an ALRM-signal to this process.
|
10
|
+
#
|
11
|
+
# Predefined alarm will be reset and will forget.
|
12
|
+
# @note Older implementations of ffi-libc does not provide {alarm}, but we need it.
|
13
|
+
# So we detect, if it is not provided and attach it.
|
14
|
+
# @param seconds [0] Clears alarm.
|
15
|
+
# @param seconds [Integer] How many seconds should be waited, before ALRM-signal should be send?
|
16
|
+
# @return (nil)
|
6
17
|
attach_function :alarm, [:uint], :uint unless FFI::LibC.respond_to? :alarm
|
7
18
|
end
|
8
19
|
end
|
9
20
|
|
21
|
+
# Helper module for `TimeoutInterrupt`
|
22
|
+
# @see TimeoutInterrupt
|
10
23
|
module TimeoutInterruptSingleton
|
11
24
|
class <<self
|
25
|
+
# Stores all timeouts.
|
26
|
+
#
|
27
|
+
# @param thread [nil] must be nil! Do not use it yet!
|
28
|
+
# @return [Hash< key(Integer): [at(Time), backtrace(Array<String>), exception(Exception)] >]
|
12
29
|
def timeouts thread = nil
|
13
|
-
@timeouts ||= Hash.new {|h,k| h[k] =
|
14
|
-
thread = Thread.current
|
30
|
+
@timeouts ||= Hash.new {|h,k| h[k] = {} }
|
31
|
+
thread = Thread.current unless thread.kind_of? Thread
|
15
32
|
thread ? @timeouts[thread] : @timeouts
|
16
33
|
end
|
17
34
|
|
35
|
+
# If there's a timed out timeout, it will raise its exception.
|
36
|
+
# Can be used for handling ALRM-signal.
|
37
|
+
# It will prepare the next timeout, too.
|
38
|
+
#
|
39
|
+
# The timeout will not removed from timeouts, because it is timed out, yet.
|
40
|
+
# First, if timeout-scope will be exit, it will be removed.
|
41
|
+
#
|
42
|
+
# @return [nil]
|
18
43
|
def alarm_trap sig
|
44
|
+
raise_if_sb_timed_out
|
45
|
+
setup
|
46
|
+
end
|
47
|
+
|
48
|
+
# There is a timed out timeout? It will raise it!
|
49
|
+
# You need not to check it yourself, it will do it for you.
|
50
|
+
#
|
51
|
+
# @return [nil]
|
52
|
+
def raise_if_sb_timed_out
|
53
|
+
return if self.timeouts.empty?
|
19
54
|
key, (at, bt, exception) = self.timeouts.min_by {|key,(at,bt,ex)| at }
|
20
55
|
return if Time.now < at
|
21
56
|
raise exception, 'execution expired', bt
|
22
57
|
end
|
23
58
|
|
59
|
+
# Prepares the next timeout. Sets the trap and the shortest timeout as alarm.
|
60
|
+
#
|
61
|
+
# @return [nil]
|
24
62
|
def setup
|
25
63
|
if timeouts.empty?
|
26
64
|
Signal.trap( 'ALRM') {}
|
27
65
|
FFI::LibC.alarm 0
|
28
66
|
else
|
29
|
-
|
30
|
-
secs = (at - Time.now)
|
31
|
-
alarm_trap 14 if 0 > secs
|
67
|
+
raise_if_sb_timed_out
|
32
68
|
Signal.trap 'ALRM', &method( :alarm_trap)
|
33
|
-
|
69
|
+
key, (at, bt) = timeouts.min_by {|key,(at,bt)| at }
|
70
|
+
FFI::LibC.alarm (at - Time.now).to_i + 1
|
34
71
|
end
|
72
|
+
nil
|
35
73
|
end
|
36
74
|
|
37
|
-
|
75
|
+
# Creates a timeout and calls your block, which has to finish before timeout occurs.
|
76
|
+
#
|
77
|
+
# @param seconds [Integer] In `seconds` Seconds, it should raise a timeout, if not finished.
|
78
|
+
# @param seconds [nil] Everything will be ignored and
|
79
|
+
# it will call {setup} for checking and preparing next known timeout.
|
80
|
+
# @param exception [Exception] which will be raised if timed out.
|
81
|
+
# @param exception [nil] `TimeoutInterrupt::Error` will be used to raise.
|
82
|
+
# @param block [Proc] Will be called and should finish its work before it timed out.
|
83
|
+
# @param block [nil] Nothing will happen, instead it will return a Proc,
|
84
|
+
# which can be called with a block to use the timeout.
|
85
|
+
# @return If block given, the returned value of your block.
|
86
|
+
# Or if not, it will return a Proc, which will expect a Proc if called.
|
87
|
+
# This Proc has no arguments and will prepare a timeout, like if you had given a block.
|
88
|
+
#
|
89
|
+
# You can rescue `Timeout::Error`, instead `TimeoutInterrupt::Error`, it will work too.
|
90
|
+
#
|
91
|
+
# It will call your given block, which has `seconds` seconds to end.
|
92
|
+
# If you want to prepare a timeout, which should be used many times,
|
93
|
+
# without giving `seconds` and `exception`, you can omit the block,
|
94
|
+
# so, `TimeoutInterruptSingleton#timeout` will return a `Proc`, which want to have the block.
|
95
|
+
#
|
96
|
+
# There is a problem with scoped timeouts. If you rescue a timeout in an other timeout,
|
97
|
+
# it's possible, that the other timeout will never timeout, because both are timed out at once.
|
98
|
+
# Than you need to call `TimeoutInterruptSingleton#timeout` without arguments.
|
99
|
+
# It will prepare the next timeout or it will raise it directy, if timed out.
|
100
|
+
#
|
101
|
+
# @see TimeoutInterrupt.timeout
|
102
|
+
# @see TimeoutInterrupt#timeout
|
103
|
+
# @raise exception
|
104
|
+
def timeout seconds = nil, exception = nil, &block
|
38
105
|
return setup if seconds.nil?
|
39
106
|
seconds = seconds.to_i
|
40
107
|
exception ||= TimeoutInterrupt::Error
|
@@ -59,15 +126,82 @@ module TimeoutInterruptSingleton
|
|
59
126
|
end
|
60
127
|
end
|
61
128
|
|
129
|
+
# Can be included, or used directly.
|
130
|
+
# In both cases, it provides {#timeout}.
|
131
|
+
#
|
132
|
+
# @see TimeoutInterruptSingleton
|
62
133
|
module TimeoutInterrupt
|
134
|
+
# The {TimeoutInterrupt::Error} is the default exception, which will be raised,
|
135
|
+
# if something will time out.
|
136
|
+
# Its base-class is {Timeout::Error}, so you can replace {Timeout} by {TimeoutInterrupt} without
|
137
|
+
# replacing your `rescue Timeout::Error`, but you can.
|
63
138
|
class Error < Timeout::Error
|
64
139
|
end
|
65
140
|
|
66
|
-
|
67
|
-
|
141
|
+
# Creates a timeout and calls your block, which has to finish before timeout occurs.
|
142
|
+
#
|
143
|
+
# @param seconds [Integer] In `seconds` Seconds, it should raise a timeout, if not finished.
|
144
|
+
# @param seconds [nil] Everything will be ignored and
|
145
|
+
# it will call {TimeoutInterruptSingleton.setup} for checking and preparing next known timeout.
|
146
|
+
# @param exception [Exception] which will be raised if timed out.
|
147
|
+
# @param exception [nil] `TimeoutInterrupt::Error` will be used to raise.
|
148
|
+
# @param block [Proc] Will be called and should finish its work before it timed out.
|
149
|
+
# @param block [nil] Nothing will happen, instead it will return a Proc,
|
150
|
+
# which can be called with a block to use the timeout.
|
151
|
+
# @return If block given, the returned value of your block.
|
152
|
+
# Or if not, it will return a Proc, which will expect a Proc if called.
|
153
|
+
# This Proc has no arguments and will prepare a timeout, like if you had given a block.
|
154
|
+
#
|
155
|
+
# You can rescue `Timeout::Error`, instead `TimeoutInterrupt::Error`, it will work too.
|
156
|
+
#
|
157
|
+
# It will call your given block, which has `seconds` seconds to end.
|
158
|
+
# If you want to prepare a timeout, which should be used many times,
|
159
|
+
# without giving `seconds` and `exception`, you can omit the block,
|
160
|
+
# so, `TimeoutInterruptSingleton#timeout` will return a `Proc`, which want to have the block.
|
161
|
+
#
|
162
|
+
# There is a problem with scoped timeouts. If you rescue a timeout in an other timeout,
|
163
|
+
# it's possible, that the other timeout will never timeout, because both are timed out at once.
|
164
|
+
# Than you need to call `TimeoutInterruptSingleton#timeout` without arguments.
|
165
|
+
# It will prepare the next timeout or it will raise it directy, if timed out.
|
166
|
+
#
|
167
|
+
# @see TimeoutInterrupt#timeout
|
168
|
+
# @see TimeoutInterruptSingleton.timeout
|
169
|
+
# @raise exception
|
170
|
+
def self.timeout seconds = nil, exception = nil, &block
|
171
|
+
TimeoutInterruptSingleton.timeout seconds, exception, &block
|
68
172
|
end
|
69
173
|
|
70
|
-
|
71
|
-
|
174
|
+
# Creates a timeout and calls your block, which has to finish before timeout occurs.
|
175
|
+
#
|
176
|
+
# @param seconds [Integer] In `seconds` Seconds, it should raise a timeout, if not finished.
|
177
|
+
# @param seconds [nil] Everything will be ignored and
|
178
|
+
# it will call {TimeoutInterruptSingleton.setup} for checking and preparing next known timeout.
|
179
|
+
# @param exception [Exception] which will be raised if timed out.
|
180
|
+
# @param exception [nil] `TimeoutInterrupt::Error` will be used to raise.
|
181
|
+
# @param block [Proc] Will be called and should finish its work before it timed out.
|
182
|
+
# @param block [nil] Nothing will happen, instead it will return a Proc,
|
183
|
+
# which can be called with a block to use the timeout.
|
184
|
+
# @return If block given, the returned value of your block.
|
185
|
+
# Or if not, it will return a Proc, which will expect a Proc if called.
|
186
|
+
# This Proc has no arguments and will prepare a timeout, like if you had given a block.
|
187
|
+
#
|
188
|
+
# You can rescue `Timeout::Error`, instead `TimeoutInterrupt::Error`, it will work too.
|
189
|
+
#
|
190
|
+
# It will call your given block, which has `seconds` seconds to end.
|
191
|
+
# If you want to prepare a timeout, which should be used many times,
|
192
|
+
# without giving `seconds` and `exception`, you can omit the block,
|
193
|
+
# so, `TimeoutInterruptSingleton#timeout` will return a `Proc`, which want to have the block.
|
194
|
+
#
|
195
|
+
# There is a problem with scoped timeouts. If you rescue a timeout in an other timeout,
|
196
|
+
# it's possible, that the other timeout will never timeout, because both are timed out at once.
|
197
|
+
# Than you need to call `TimeoutInterruptSingleton#timeout` without arguments.
|
198
|
+
# It will prepare the next timeout or it will raise it directy, if timed out.
|
199
|
+
#
|
200
|
+
# @note This method is useful, if you `include TimeoutInterrupt`. You can call it directly.
|
201
|
+
# @see TimeoutInterrupt.timeout
|
202
|
+
# @see TimeoutInterruptSingleton.timeout
|
203
|
+
# @raise exception
|
204
|
+
def timeout seconds = nil, exception = nil, &block
|
205
|
+
TimeoutInterruptSingleton.timeout seconds, exception, &block
|
72
206
|
end
|
73
207
|
end
|
data/timeout-interrupt.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "timeout-interrupt"
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Denis Knauf"]
|
@@ -42,6 +42,7 @@ Gem::Specification.new do |s|
|
|
42
42
|
s.add_runtime_dependency(%q<ffi-libc>, [">= 0"])
|
43
43
|
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
44
44
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
45
|
+
s.add_development_dependency(%q<redcarpet>, [">= 0"])
|
45
46
|
s.add_development_dependency(%q<rdoc>, [">= 0"])
|
46
47
|
s.add_development_dependency(%q<bundler>, [">= 0"])
|
47
48
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
@@ -50,6 +51,7 @@ Gem::Specification.new do |s|
|
|
50
51
|
s.add_dependency(%q<ffi-libc>, [">= 0"])
|
51
52
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
52
53
|
s.add_dependency(%q<yard>, [">= 0"])
|
54
|
+
s.add_dependency(%q<redcarpet>, [">= 0"])
|
53
55
|
s.add_dependency(%q<rdoc>, [">= 0"])
|
54
56
|
s.add_dependency(%q<bundler>, [">= 0"])
|
55
57
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
@@ -59,6 +61,7 @@ Gem::Specification.new do |s|
|
|
59
61
|
s.add_dependency(%q<ffi-libc>, [">= 0"])
|
60
62
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
61
63
|
s.add_dependency(%q<yard>, [">= 0"])
|
64
|
+
s.add_dependency(%q<redcarpet>, [">= 0"])
|
62
65
|
s.add_dependency(%q<rdoc>, [">= 0"])
|
63
66
|
s.add_dependency(%q<bundler>, [">= 0"])
|
64
67
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timeout-interrupt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2013-03-07 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi-libc
|
16
|
-
requirement: &
|
16
|
+
requirement: &78508080 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *78508080
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: shoulda
|
27
|
-
requirement: &
|
27
|
+
requirement: &78507820 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *78507820
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: yard
|
38
|
-
requirement: &
|
38
|
+
requirement: &78507570 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,21 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *78507570
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: redcarpet
|
49
|
+
requirement: &78507280 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *78507280
|
47
58
|
- !ruby/object:Gem::Dependency
|
48
59
|
name: rdoc
|
49
|
-
requirement: &
|
60
|
+
requirement: &78506950 !ruby/object:Gem::Requirement
|
50
61
|
none: false
|
51
62
|
requirements:
|
52
63
|
- - ! '>='
|
@@ -54,10 +65,10 @@ dependencies:
|
|
54
65
|
version: '0'
|
55
66
|
type: :development
|
56
67
|
prerelease: false
|
57
|
-
version_requirements: *
|
68
|
+
version_requirements: *78506950
|
58
69
|
- !ruby/object:Gem::Dependency
|
59
70
|
name: bundler
|
60
|
-
requirement: &
|
71
|
+
requirement: &78505780 !ruby/object:Gem::Requirement
|
61
72
|
none: false
|
62
73
|
requirements:
|
63
74
|
- - ! '>='
|
@@ -65,10 +76,10 @@ dependencies:
|
|
65
76
|
version: '0'
|
66
77
|
type: :development
|
67
78
|
prerelease: false
|
68
|
-
version_requirements: *
|
79
|
+
version_requirements: *78505780
|
69
80
|
- !ruby/object:Gem::Dependency
|
70
81
|
name: jeweler
|
71
|
-
requirement: &
|
82
|
+
requirement: &78505320 !ruby/object:Gem::Requirement
|
72
83
|
none: false
|
73
84
|
requirements:
|
74
85
|
- - ! '>='
|
@@ -76,10 +87,10 @@ dependencies:
|
|
76
87
|
version: '0'
|
77
88
|
type: :development
|
78
89
|
prerelease: false
|
79
|
-
version_requirements: *
|
90
|
+
version_requirements: *78505320
|
80
91
|
- !ruby/object:Gem::Dependency
|
81
92
|
name: simplecov
|
82
|
-
requirement: &
|
93
|
+
requirement: &78505050 !ruby/object:Gem::Requirement
|
83
94
|
none: false
|
84
95
|
requirements:
|
85
96
|
- - ! '>='
|
@@ -87,7 +98,7 @@ dependencies:
|
|
87
98
|
version: '0'
|
88
99
|
type: :development
|
89
100
|
prerelease: false
|
90
|
-
version_requirements: *
|
101
|
+
version_requirements: *78505050
|
91
102
|
description: Timeout-lib, which interrupts everything, also systemcalls. It uses libc-alarm.
|
92
103
|
email: Denis.Knauf@gmail.com
|
93
104
|
executables: []
|
@@ -122,7 +133,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
122
133
|
version: '0'
|
123
134
|
segments:
|
124
135
|
- 0
|
125
|
-
hash: -
|
136
|
+
hash: -241597663
|
126
137
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
138
|
none: false
|
128
139
|
requirements:
|