frugal_timeout 0.0.6 → 0.0.7

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.
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: