frugal_timeout 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/frugal_timeout.rb +42 -14
  2. metadata +19 -2
@@ -1,5 +1,6 @@
1
1
  # Copyright (C) 2013 by Dmitry Maksyoma <ledestin@gmail.com>
2
2
 
3
+ require 'hitimes'
3
4
  require 'thread'
4
5
  require 'timeout'
5
6
 
@@ -32,6 +33,20 @@ module FrugalTimeout
32
33
  # {{{1 Error
33
34
  class Error < Timeout::Error; end # :nodoc:
34
35
 
36
+ # {{{1 MonotonicTime
37
+ class MonotonicTime
38
+ NANOS_IN_SECOND = 1_000_000_000
39
+
40
+ def self.measure
41
+ start = now
42
+ yield
43
+ now - start
44
+ end
45
+
46
+ def self.now
47
+ Hitimes::Interval.now.start_instant.to_f/NANOS_IN_SECOND
48
+ end
49
+ end
35
50
  # {{{1 Request
36
51
  class Request # :nodoc:
37
52
  include Comparable
@@ -64,32 +79,44 @@ module FrugalTimeout
64
79
  class SleeperNotifier # :nodoc:
65
80
  def initialize notifyQueue
66
81
  @notifyQueue = notifyQueue
67
- @delays, @mutex = Queue.new, Mutex.new
82
+ @latestDelay, @mutex = nil, Mutex.new
68
83
 
69
84
  @thread = Thread.new {
70
85
  loop {
71
- sleepFor = nil
72
- @mutex.synchronize {
73
- sleepFor = @delays.shift until @delays.empty?
74
- }
75
- start = Time.now
76
- sleepFor ? sleep(sleepFor) : sleep
77
- @mutex.synchronize {
78
- @notifyQueue.push :expired \
79
- if sleepFor && Time.now - start >= sleepFor
86
+ unless sleepFor = latestDelay
87
+ sleep
88
+ else
89
+ sleptFor = MonotonicTime.measure { sleep(sleepFor) }
90
+ end
91
+ synchronize {
92
+ @notifyQueue.push :expired if sleepFor && sleptFor >= sleepFor
80
93
  }
81
94
  }
82
95
  }
83
96
  ObjectSpace.define_finalizer self, proc { @thread.kill }
84
97
  end
85
98
 
99
+ def latestDelay
100
+ synchronize {
101
+ tmp = @latestDelay
102
+ @latestDelay = nil
103
+ tmp
104
+ }
105
+ end
106
+ private :latestDelay
107
+
86
108
  def notifyAfter sec
87
- @mutex.synchronize {
109
+ synchronize {
88
110
  sleep 0.01 until @thread.status == 'sleep'
89
- @delays.push sec
111
+ @latestDelay = sec
90
112
  @thread.wakeup
91
113
  }
92
114
  end
115
+
116
+ def synchronize &b
117
+ @mutex.synchronize &b
118
+ end
119
+ private :synchronize
93
120
  end
94
121
 
95
122
  # {{{1 Main code
@@ -101,7 +128,7 @@ module FrugalTimeout
101
128
  nearestTimeout, requests = nil, []
102
129
  loop {
103
130
  request = @in.shift
104
- now = Time.now
131
+ now = MonotonicTime.now
105
132
 
106
133
  if request == :expired
107
134
  # Enforce all expired timeouts.
@@ -157,7 +184,8 @@ module FrugalTimeout
157
184
  def self.timeout sec, klass=nil
158
185
  return yield sec if sec == nil || sec <= 0
159
186
 
160
- @in.push request = Request.new(Thread.current, Time.now + sec, klass)
187
+ @in.push request = Request.new(Thread.current, MonotonicTime.now + sec,
188
+ klass)
161
189
  begin
162
190
  yield sec
163
191
  ensure
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: frugal_timeout
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-09-07 00:00:00.000000000 Z
12
+ date: 2013-10-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -27,6 +27,22 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: '2.13'
30
+ - !ruby/object:Gem::Dependency
31
+ name: hitimes
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.2'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.2'
30
46
  description: Timeout.timeout replacement that uses only 2 threads
31
47
  email: ledestin@gmail.com
32
48
  executables: []
@@ -59,3 +75,4 @@ signing_key:
59
75
  specification_version: 3
60
76
  summary: Timeout.timeout replacement
61
77
  test_files: []
78
+ has_rdoc: