timeout-interrupt 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|