itimer 3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,80 @@
1
+ # Itimer [![Build Status](https://secure.travis-ci.org/nearbuy/ruby-itimer.png?branch=master)]
2
+
3
+ Drop-in replacement for stdlib Timeout that uses POSIX interval timers instead of threads. Not as portable but much lighter weight. Also includes low-level wrappers for setitimer and getitimer.
4
+
5
+ ## Examples
6
+
7
+ ``` ruby
8
+ require 'itimer'
9
+
10
+ begin
11
+ Itimer.timeout(1) { sleep 5 }
12
+ rescue Itimer::Timeout
13
+ puts 'Time expired'
14
+ end
15
+ ```
16
+
17
+ ``` ruby
18
+ require 'itimer/compat'
19
+
20
+ begin
21
+ Timeout::timeout(1) { sleep 5 }
22
+ rescue Timeout::Error
23
+ puts 'Time expired'
24
+ end
25
+ ```
26
+
27
+ ``` ruby
28
+ require 'itimer'
29
+
30
+ Signal.trap('VTALRM') { raise Itimer::Timeout }
31
+
32
+ begin
33
+ # set :real, :virtual and :prof
34
+ Itimer.set(:virtual, 1)
35
+ do\_expensive\_computation()
36
+ rescue Itimer::Timeout
37
+ puts 'Execution time expired'
38
+ end
39
+
40
+ Signal.trap('ALRM') { print '.' }
41
+
42
+ Itimer.set\_interval(:real, 0.5)
43
+ do\_expensive\_computation()
44
+ puts 'Done'
45
+ ```
46
+
47
+ ## Support
48
+
49
+ Please report issues at https://github.com/nearbuy/ruby-itimer/issues
50
+
51
+ ## See Also
52
+
53
+ getitimer(2), setitimer(2)
54
+
55
+ ## Authors
56
+
57
+ * Nate Mueller ([natemueller](https://github.com/natemueller))
58
+
59
+ ## License
60
+
61
+ Copyright (c) 2011 Nearbuy Systems
62
+
63
+ Permission is hereby granted, free of charge, to any person obtaining
64
+ a copy of this software and associated documentation files (the
65
+ "Software"), to deal in the Software without restriction, including
66
+ without limitation the rights to use, copy, modify, merge, publish,
67
+ distribute, sublicense, and/or sell copies of the Software, and to
68
+ permit persons to whom the Software is furnished to do so, subject to
69
+ the following conditions:
70
+
71
+ The above copyright notice and this permission notice shall be
72
+ included in all copies or substantial portions of the Software.
73
+
74
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
75
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
76
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
77
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
78
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
79
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
80
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,12 @@
1
+ require 'rake/testtask'
2
+ require 'rake/extensiontask'
3
+
4
+ Rake::ExtensionTask.new('itimer_native') do |ext|
5
+ ext.ext_dir = 'ext'
6
+ end
7
+
8
+ Rake::TestTask.new do |t|
9
+ t.test_files = FileList['test/*.rb']
10
+ end
11
+
12
+ task :test => :compile
@@ -0,0 +1,7 @@
1
+ require 'mkmf'
2
+
3
+ $CFLAGS = "-g -O2 -Wall -Werror"
4
+
5
+ if have_header('sys/time.h')
6
+ create_makefile 'itimer_native'
7
+ end
@@ -0,0 +1,81 @@
1
+ #include <math.h>
2
+ #include <ruby.h>
3
+ #include <sys/time.h>
4
+
5
+ VALUE itimer_real;
6
+ VALUE itimer_virtual;
7
+ VALUE itimer_prof;
8
+
9
+ int which_from_val(VALUE which_val) {
10
+ return which_val == itimer_real
11
+ ? ITIMER_REAL
12
+ : which_val == itimer_virtual
13
+ ? ITIMER_VIRTUAL
14
+ : ITIMER_PROF;
15
+ }
16
+
17
+ VALUE rb_itimer_get(VALUE self, VALUE which_val) {
18
+ struct itimerval value;
19
+ getitimer(which_from_val(which_val), &value);
20
+
21
+ return DBL2NUM(value.it_value.tv_sec + (double)value.it_value.tv_usec/1000000);
22
+ }
23
+
24
+ VALUE rb_itimer_get_interval(VALUE self, VALUE which_val) {
25
+ struct itimerval value;
26
+ getitimer(which_from_val(which_val), &value);
27
+
28
+ return DBL2NUM(value.it_interval.tv_sec + (double)value.it_interval.tv_usec/1000000);
29
+ }
30
+
31
+ VALUE rb_itimer_set(VALUE self, VALUE which_val, VALUE new_value) {
32
+ struct itimerval value;
33
+ getitimer(which_from_val(which_val), &value);
34
+
35
+ double dbl_value = NUM2DBL(new_value);
36
+
37
+ value.it_value.tv_sec = (int)floor(dbl_value);
38
+ value.it_value.tv_usec = (dbl_value - floor(dbl_value)) * 1000000;
39
+
40
+ int ret = setitimer(which_from_val(which_val), &value, NULL);
41
+ if (ret != 0) {
42
+ rb_sys_fail(0);
43
+ } else {
44
+ return Qtrue;
45
+ }
46
+ }
47
+
48
+ VALUE rb_itimer_set_interval(VALUE self, VALUE which_val, VALUE new_value) {
49
+ struct itimerval value;
50
+ getitimer(which_from_val(which_val), &value);
51
+
52
+ double dbl_value = NUM2DBL(new_value);
53
+
54
+ value.it_interval.tv_sec = (int)floor(dbl_value);
55
+ value.it_interval.tv_usec = (dbl_value - floor(dbl_value)) * 1000000;
56
+
57
+ if (value.it_value.tv_sec == 0 && value.it_value.tv_usec == 0) {
58
+ value.it_value.tv_sec = (int)floor(dbl_value);
59
+ value.it_value.tv_usec = (dbl_value - floor(dbl_value)) * 1000000;
60
+ }
61
+
62
+ int ret = setitimer(which_from_val(which_val), &value, NULL);
63
+ if (ret != 0) {
64
+ rb_sys_fail(0);
65
+ } else {
66
+ return Qtrue;
67
+ }
68
+ }
69
+
70
+ void Init_itimer_native(void) {
71
+ VALUE itimer_module = rb_const_get(rb_cObject, rb_intern("Itimer"));
72
+
73
+ rb_define_singleton_method(itimer_module, "get", rb_itimer_get, 1);
74
+ rb_define_singleton_method(itimer_module, "get_interval", rb_itimer_get_interval, 1);
75
+ rb_define_singleton_method(itimer_module, "set", rb_itimer_set, 2);
76
+ rb_define_singleton_method(itimer_module, "set_interval", rb_itimer_set_interval, 2);
77
+
78
+ itimer_real = ID2SYM(rb_intern("real"));
79
+ itimer_virtual = ID2SYM(rb_intern("virtual"));
80
+ itimer_prof = ID2SYM(rb_intern("prof"));
81
+ }
@@ -0,0 +1,18 @@
1
+ module Itimer
2
+ require 'itimer_native'
3
+
4
+ class Timeout < RuntimeError
5
+ end
6
+
7
+ def self.timeout(seconds, klass=Timeout)
8
+ Signal.trap 'ALRM' do
9
+ raise klass
10
+ end
11
+
12
+ set(:real, seconds)
13
+ ret = yield
14
+ set(:real, 0)
15
+
16
+ return ret
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ require 'itimer'
2
+
3
+ module Timeout
4
+ class Error < RuntimeError
5
+ end
6
+
7
+ def timeout(sec, klass=Error, &block)
8
+ return Itimer.timeout(sec, klass, &block)
9
+ end
10
+
11
+ module_function :timeout
12
+ end
@@ -0,0 +1,93 @@
1
+ require 'itimer'
2
+ require 'test/unit'
3
+ require 'itimer/compat'
4
+
5
+ class ItimerTest < Test::Unit::TestCase
6
+ def test_itimer
7
+ Signal.trap 'ALRM' do
8
+ raise Exception.new('ALRM')
9
+ end
10
+
11
+ Signal.trap 'VTALRM' do
12
+ raise Exception.new('VTALRM')
13
+ end
14
+
15
+ Signal.trap 'PROF' do
16
+ raise Exception.new('PROF')
17
+ end
18
+
19
+ assert_equal( 0, Itimer.get(:real) )
20
+ assert_equal( 0, Itimer.get(:virtual) )
21
+ assert_equal( 0, Itimer.get(:prof) )
22
+
23
+ assert_equal( 0, Itimer.get_interval(:real) )
24
+ assert_equal( 0, Itimer.get_interval(:virtual) )
25
+ assert_equal( 0, Itimer.get_interval(:prof) )
26
+
27
+ Itimer.set(:real, 5)
28
+ Itimer.set(:virtual, 4)
29
+ Itimer.set(:prof, 0.5)
30
+
31
+ sleep 0.5
32
+ assert_in_delta( 4.5, Itimer.get(:real), 0.1 )
33
+ assert_in_delta( 4, Itimer.get(:virtual), 0.1 )
34
+ assert_in_delta( 0.5, Itimer.get(:prof), 0.1 )
35
+
36
+ assert_raises( Errno::EINVAL) { Itimer.set(:real, 2**32) }
37
+
38
+ Itimer.set(:real, 0)
39
+ Itimer.set(:virtual, 0)
40
+ Itimer.set(:prof, 0)
41
+
42
+ wait_for_sig = lambda do
43
+ signal = nil
44
+ begin
45
+ sleep 2
46
+ rescue Exception
47
+ signal = $!.message
48
+ end
49
+
50
+ signal
51
+ end
52
+
53
+ start = Time.now
54
+ Itimer.set(:real, 1)
55
+ assert_equal( 'ALRM', wait_for_sig.call )
56
+ assert_in_delta( Time.now-start, 1, 0.1 )
57
+
58
+ start = Time.now
59
+ Itimer.set_interval(:real, 1.2)
60
+ Itimer.set(:real, 0.5)
61
+ assert_in_delta( 1.2, Itimer.get_interval(:real), 0.1 )
62
+ assert_equal( 'ALRM', wait_for_sig.call )
63
+ assert_in_delta( Time.now-start, 0.5, 0.1 )
64
+ assert_in_delta( Itimer.get(:real), 1.2, 0.1 )
65
+
66
+ start = Time.now
67
+ assert_equal( 'ALRM', wait_for_sig.call )
68
+ assert_in_delta( Time.now-start, 1.2, 0.1 )
69
+ Itimer.set_interval(:real, 0)
70
+ end
71
+
72
+ def test_timeout
73
+ start = Time.now
74
+ assert_raises( Itimer::Timeout ) do
75
+ Itimer.timeout(1) { sleep 5 }
76
+ end
77
+ assert_in_delta( Time.now-start, 1, 0.1 )
78
+
79
+ start = Time.now
80
+ assert_raises( RuntimeError ) do
81
+ Itimer.timeout(0.25, RuntimeError) { sleep 5 }
82
+ end
83
+ assert_in_delta( Time.now-start, 0.25, 0.1 )
84
+ end
85
+
86
+ def test_compat
87
+ start = Time.now
88
+ assert_raises( Timeout::Error ) do
89
+ Timeout::timeout(0.25) { sleep 5 }
90
+ end
91
+ assert_in_delta( Time.now-start, 0.25, 0.1 )
92
+ end
93
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: itimer
3
+ version: !ruby/object:Gem::Version
4
+ version: '3'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nate Mueller
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-10 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake-compiler
16
+ requirement: &70188994886360 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.8.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70188994886360
25
+ description: Drop-in replacement for stdlib Timeout that uses POSIX interval timers
26
+ instead of threads. Not as portable but much lighter weight. Also includes low-level
27
+ wrappers for setitimer and getitimer.
28
+ email: hackers@nearbuysystems.com
29
+ executables: []
30
+ extensions:
31
+ - ext/extconf.rb
32
+ extra_rdoc_files: []
33
+ files:
34
+ - README.md
35
+ - Rakefile
36
+ - lib/itimer.rb
37
+ - lib/itimer/compat.rb
38
+ - test/itimer.rb
39
+ - ext/extconf.rb
40
+ - ext/itimer_native.c
41
+ homepage: http://github.com/nearbuy/ruby-itimer
42
+ licenses: []
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: 1.9.2
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 1.8.17
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Timeout replacement using POSIX interval timers
65
+ test_files: []