itimer 3

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.
@@ -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: []