license, tests, lib.

master
Denis Knauf 2013-03-06 11:58:38 +01:00
parent c3dbaa7b71
commit 9f3eca6171
3 changed files with 121 additions and 0 deletions

50
Gemfile.lock Normal file
View File

@ -0,0 +1,50 @@
GEM
remote: http://rubygems.org/
specs:
activesupport (3.2.12)
i18n (~> 0.6)
multi_json (~> 1.0)
bourne (1.1.2)
mocha (= 0.10.5)
ffi (1.1.0)
ffi-libc (0.0.5)
ffi (>= 0.6.0, <= 1.1.0)
git (1.2.5)
i18n (0.6.4)
jeweler (1.8.4)
bundler (~> 1.0)
git (>= 1.2.5)
rake
rdoc
json (1.7.7)
metaclass (0.0.1)
mocha (0.10.5)
metaclass (~> 0.0.1)
multi_json (1.6.1)
rake (10.0.3)
rdoc (4.0.0)
json (~> 1.4)
shoulda (3.3.2)
shoulda-context (~> 1.0.1)
shoulda-matchers (~> 1.4.1)
shoulda-context (1.0.2)
shoulda-matchers (1.4.2)
activesupport (>= 3.0.0)
bourne (~> 1.1.2)
simplecov (0.7.1)
multi_json (~> 1.0)
simplecov-html (~> 0.7.1)
simplecov-html (0.7.1)
yard (0.8.5.2)
PLATFORMS
ruby
DEPENDENCIES
bundler
ffi-libc
jeweler
rdoc
shoulda
simplecov
yard

22
README.md Normal file
View File

@ -0,0 +1,22 @@
ruby-timeout-interrupt
======================
Description goes here.
Contributing to ruby-timeout-interrupt
======================================
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
* Fork the project.
* Start a feature/bugfix branch.
* Commit and push until you are happy with your contribution.
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
Copyright
=========
Copyright (c) 2013 Denis Knauf. See LICENSE.txt for
further details.

49
lib/timeout_interrupt.rb Normal file
View File

@ -0,0 +1,49 @@
require 'ffi/libc'
require 'timeout'
module FFI
module LibC
attach_function :alarm, [:uint], :uint unless FFI::LibC.respond_to? :alarm
end
end
module TimeoutInterrupt
def self.timeouts
@timeouts ||= {}
end
def self.alarm_trap sig
key, (at, bt) = TimeoutInterrupt.timeouts.min_by {|key,(at,bt)| at }
return if Time.now < at
raise Timeout::Error, 'execution expired', bt
end
def self.setup_timeout
if TimeoutInterrupt.timeouts.empty?
Signal.trap( 'ALRM') {}
FFI::LibC.alarm 0
else
key, (at, bt) = TimeoutInterrupt.timeouts.min_by {|key,(at,bt)| at }
secs = (at - Time.now).to_i+1
TimeoutInterrupt.alarm_trap if 1 > secs
Signal.trap 'ALRM', &TimeoutInterrupt.method( :alarm_trap)
FFI::LibC.alarm secs
end
end
def self.timeout seconds
seconds = seconds.to_i
raise Timeout::Error, "Timeout must be longer than '0' seconds." unless 0 < seconds
return lambda {|&e| self.timeout seconds, &e } unless block_given?
at = Time.now + seconds
key, bt = Random.rand( 2**64-1), Kernel.caller
begin
TimeoutInterrupt.timeouts[key] = [at, bt]
TimeoutInterrupt.setup_timeout
yield
ensure
TimeoutInterrupt.timeouts.delete key
TimeoutInterrupt.setup_timeout
end
end
end