rubysl-monitor 1.0.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0611fdd2b6a1443e13577664e38ea505b906bfab
4
+ data.tar.gz: fcf2eaf0f16be03c284b10166cc33c658922d93e
5
+ SHA512:
6
+ metadata.gz: 942b331aab1098f3a7de9f8e3295bbec7e550507473f941861e37766ae2a699a428e25011a7aef8e51e52db7653a5d0bd9382315e1ec9e279990f8d93233e910
7
+ data.tar.gz: ad8e8567390e5a64d68ddeeeccad617e77a66cd540f13d33eb9a3aad4546da8d60aa2f5946bcd9b56e3c9d2fe2ec92db5185b8bb41ed1be632584123f6e226a9
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ env:
3
+ - RUBYLIB=lib
4
+ script: bundle exec mspec
5
+ rvm:
6
+ - 1.8.7
7
+ - rbx-nightly-18mode
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rubysl-monitor.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2013, Brian Shirai
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ 3. Neither the name of the library nor the names of its contributors may be
13
+ used to endorse or promote products derived from this software without
14
+ specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
20
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Rubysl::Monitor
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rubysl-monitor'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rubysl-monitor
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/lib/monitor.rb ADDED
@@ -0,0 +1 @@
1
+ require "rubysl/monitor"
@@ -0,0 +1,2 @@
1
+ require "rubysl/monitor/version"
2
+ require "rubysl/monitor/monitor"
@@ -0,0 +1,341 @@
1
+ =begin
2
+
3
+ = monitor.rb
4
+
5
+ Copyright (C) 2001 Shugo Maeda <shugo@ruby-lang.org>
6
+ Copyright (C) 2008 MenTaLguY <mental@rydia.net>
7
+
8
+ This library is distributed under the terms of the Ruby license.
9
+ You can freely distribute/modify this library.
10
+
11
+ == example
12
+
13
+ This is a simple example.
14
+
15
+ require 'monitor.rb'
16
+
17
+ buf = []
18
+ buf.extend(MonitorMixin)
19
+ empty_cond = buf.new_cond
20
+
21
+ # consumer
22
+ Thread.start do
23
+ loop do
24
+ buf.synchronize do
25
+ empty_cond.wait_while { buf.empty? }
26
+ print buf.shift
27
+ end
28
+ end
29
+ end
30
+
31
+ # producer
32
+ while line = ARGF.gets
33
+ buf.synchronize do
34
+ buf.push(line)
35
+ empty_cond.signal
36
+ end
37
+ end
38
+
39
+ The consumer thread waits for the producer thread to push a line
40
+ to buf while buf.empty?, and the producer thread (main thread)
41
+ reads a line from ARGF and push it to buf, then call
42
+ empty_cond.signal.
43
+
44
+ =end
45
+
46
+ require 'thread'
47
+
48
+ #
49
+ # Adds monitor functionality to an arbitrary object by mixing the module with
50
+ # +include+. For example:
51
+ #
52
+ # require 'monitor.rb'
53
+ #
54
+ # buf = []
55
+ # buf.extend(MonitorMixin)
56
+ # empty_cond = buf.new_cond
57
+ #
58
+ # # consumer
59
+ # Thread.start do
60
+ # loop do
61
+ # buf.synchronize do
62
+ # empty_cond.wait_while { buf.empty? }
63
+ # print buf.shift
64
+ # end
65
+ # end
66
+ # end
67
+ #
68
+ # # producer
69
+ # while line = ARGF.gets
70
+ # buf.synchronize do
71
+ # buf.push(line)
72
+ # empty_cond.signal
73
+ # end
74
+ # end
75
+ #
76
+ # The consumer thread waits for the producer thread to push a line
77
+ # to buf while buf.empty?, and the producer thread (main thread)
78
+ # reads a line from ARGF and push it to buf, then call
79
+ # empty_cond.signal.
80
+ #
81
+ module MonitorMixin
82
+ #
83
+ # FIXME: This isn't documented in Nutshell.
84
+ #
85
+ # Since MonitorMixin.new_cond returns a ConditionVariable, and the example
86
+ # above calls while_wait and signal, this class should be documented.
87
+ #
88
+ class ConditionVariable
89
+ # Create a new timer with the argument timeout, and add the
90
+ # current thread to the list of waiters. Then the thread is
91
+ # stopped. It will be resumed when a corresponding #signal
92
+ # occurs.
93
+ def wait(timeout = nil)
94
+ condition = @condition
95
+ @monitor.instance_eval { mon_wait_for_cond(condition, timeout) }
96
+ end
97
+
98
+ # call #wait while the supplied block returns +true+.
99
+ def wait_while
100
+ while yield
101
+ wait
102
+ end
103
+ end
104
+
105
+ # call #wait until the supplied block returns +true+.
106
+ def wait_until
107
+ until yield
108
+ wait
109
+ end
110
+ end
111
+
112
+ # Wake up and run the next waiter
113
+ def signal
114
+ condition = @condition
115
+ @monitor.instance_eval { mon_signal_cond(condition) }
116
+ nil
117
+ end
118
+
119
+ # Wake up all the waiters.
120
+ def broadcast
121
+ condition = @condition
122
+ @monitor.instance_eval { mon_broadcast_cond(condition) }
123
+ nil
124
+ end
125
+
126
+ def count_waiters
127
+ condition = @condition
128
+ @monitor.instance_eval { mon_count_cond_waiters(condition) }
129
+ end
130
+
131
+ private
132
+
133
+ def initialize(monitor, condition)
134
+ @monitor = monitor
135
+ @condition = condition
136
+ end
137
+ end
138
+
139
+ def self.extend_object(obj)
140
+ super(obj)
141
+ obj.instance_eval {mon_initialize()}
142
+ end
143
+
144
+ #
145
+ # Attempts to enter exclusive section. Returns +false+ if lock fails.
146
+ #
147
+ def mon_try_enter
148
+ @mon_mutex.synchronize do
149
+ @mon_owner = Thread.current unless @mon_owner
150
+ if @mon_owner == Thread.current
151
+ @mon_count += 1
152
+ true
153
+ else
154
+ false
155
+ end
156
+ end
157
+ end
158
+ # For backward compatibility
159
+ alias try_mon_enter mon_try_enter
160
+
161
+ #
162
+ # Enters exclusive section.
163
+ #
164
+ def mon_enter
165
+ @mon_mutex.synchronize do
166
+ mon_acquire(@mon_entering_cond)
167
+ @mon_count += 1
168
+ end
169
+ end
170
+
171
+ #
172
+ # Leaves exclusive section.
173
+ #
174
+ def mon_exit
175
+ @mon_mutex.synchronize do
176
+ mon_check_owner
177
+ @mon_count -= 1
178
+ mon_release if @mon_count.zero?
179
+ nil
180
+ end
181
+ end
182
+
183
+ #
184
+ # Enters exclusive section and executes the block. Leaves the exclusive
185
+ # section automatically when the block exits. See example under
186
+ # +MonitorMixin+.
187
+ #
188
+ def mon_synchronize
189
+ mon_enter
190
+ begin
191
+ yield
192
+ ensure
193
+ mon_exit
194
+ end
195
+ end
196
+ alias synchronize mon_synchronize
197
+
198
+ #
199
+ # FIXME: This isn't documented in Nutshell.
200
+ #
201
+ # Create a new condition variable for this monitor.
202
+ # This facilitates control of the monitor with #signal and #wait.
203
+ #
204
+ def new_cond
205
+ condition = ::ConditionVariable.new
206
+ condition.instance_eval { @mon_n_waiters = 0 }
207
+ return ConditionVariable.new(self, condition)
208
+ end
209
+
210
+ private
211
+
212
+ def initialize(*args)
213
+ super
214
+ mon_initialize
215
+ end
216
+
217
+ # called by initialize method to set defaults for instance variables.
218
+ def mon_initialize
219
+ @mon_mutex = Mutex.new
220
+ @mon_owner = nil
221
+ @mon_count = 0
222
+ @mon_total_waiting = 0
223
+ @mon_entering_cond = ::ConditionVariable.new
224
+ @mon_waiting_cond = ::ConditionVariable.new
225
+ self
226
+ end
227
+
228
+ # Throw a ThreadError exception if the current thread
229
+ # does't own the monitor
230
+ def mon_check_owner
231
+ # called with @mon_mutex held
232
+ if @mon_owner != Thread.current
233
+ raise ThreadError, "current thread not owner"
234
+ end
235
+ end
236
+
237
+ def mon_acquire(condition)
238
+ # called with @mon_mutex held
239
+ while @mon_owner && @mon_owner != Thread.current
240
+ condition.wait @mon_mutex
241
+ end
242
+ @mon_owner = Thread.current
243
+ end
244
+
245
+ def mon_release
246
+ # called with @mon_mutex held
247
+ @mon_owner = nil
248
+ if @mon_total_waiting.nonzero?
249
+ @mon_waiting_cond.signal
250
+ else
251
+ @mon_entering_cond.signal
252
+ end
253
+ end
254
+
255
+ def mon_wait_for_cond(condition, timeout)
256
+ @mon_mutex.synchronize do
257
+ mon_check_owner
258
+ count = @mon_count
259
+ @mon_count = 0
260
+ condition.instance_eval { @mon_n_waiters += 1 }
261
+ begin
262
+ mon_release
263
+ if timeout
264
+ condition.wait(@mon_mutex, timeout)
265
+ else
266
+ condition.wait(@mon_mutex)
267
+ true
268
+ end
269
+ ensure
270
+ @mon_total_waiting += 1
271
+ # TODO: not interrupt-safe
272
+ mon_acquire(@mon_waiting_cond)
273
+ @mon_total_waiting -= 1
274
+ @mon_count = count
275
+ condition.instance_eval { @mon_n_waiters -= 1 }
276
+ end
277
+ end
278
+ end
279
+
280
+ def mon_signal_cond(condition)
281
+ @mon_mutex.synchronize do
282
+ mon_check_owner
283
+ condition.signal
284
+ end
285
+ end
286
+
287
+ def mon_broadcast_cond(condition)
288
+ @mon_mutex.synchronize do
289
+ mon_check_owner
290
+ condition.broadcast
291
+ end
292
+ end
293
+
294
+ def mon_count_cond_waiters(condition)
295
+ @mon_mutex.synchronize do
296
+ condition.instance_eval { @mon_n_waiters }
297
+ end
298
+ end
299
+ end
300
+
301
+ # Monitors provide means of mutual exclusion for Thread programming.
302
+ # A critical region is created by means of the synchronize method,
303
+ # which takes a block.
304
+ # The condition variables (created with #new_cond) may be used
305
+ # to control the execution of a monitor with #signal and #wait.
306
+ #
307
+ # the Monitor class wraps MonitorMixin, and provides aliases
308
+ # alias try_enter try_mon_enter
309
+ # alias enter mon_enter
310
+ # alias exit mon_exit
311
+ # to access its methods more concisely.
312
+ class Monitor
313
+ include MonitorMixin
314
+ alias try_enter try_mon_enter
315
+ alias enter mon_enter
316
+ alias exit mon_exit
317
+ end
318
+
319
+
320
+ # Documentation comments:
321
+ # - All documentation comes from Nutshell.
322
+ # - MonitorMixin.new_cond appears in the example, but is not documented in
323
+ # Nutshell.
324
+ # - All the internals (internal modules Accessible and Initializable, class
325
+ # ConditionVariable) appear in RDoc. It might be good to hide them, by
326
+ # making them private, or marking them :nodoc:, etc.
327
+ # - The entire example from the RD section at the top is replicated in the RDoc
328
+ # comment for MonitorMixin. Does the RD section need to remain?
329
+ # - RDoc doesn't recognise aliases, so we have mon_synchronize documented, but
330
+ # not synchronize.
331
+ # - mon_owner is in Nutshell, but appears as an accessor in a separate module
332
+ # here, so is hard/impossible to RDoc. Some other useful accessors
333
+ # (mon_count and some queue stuff) are also in this module, and don't appear
334
+ # directly in the RDoc output.
335
+ # - in short, it may be worth changing the code layout in this file to make the
336
+ # documentation easier
337
+
338
+ # Local variables:
339
+ # mode: Ruby
340
+ # tab-width: 8
341
+ # End:
@@ -0,0 +1,5 @@
1
+ module RubySL
2
+ module Monitor
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ require './lib/rubysl/monitor/version'
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "rubysl-monitor"
6
+ spec.version = RubySL::Monitor::VERSION
7
+ spec.authors = ["Brian Shirai"]
8
+ spec.email = ["brixen@gmail.com"]
9
+ spec.description = %q{Ruby standard library Monitor.}
10
+ spec.summary = %q{Ruby standard library Monitor.}
11
+ spec.homepage = "https://github.com/rubysl/rubysl-monitor"
12
+ spec.license = "BSD"
13
+
14
+ spec.files = `git ls-files`.split($/)
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.3"
20
+ spec.add_development_dependency "rake", "~> 10.0"
21
+ spec.add_development_dependency "mspec", "~> 1.5"
22
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubysl-monitor
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Brian Shirai
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.5'
55
+ description: Ruby standard library Monitor.
56
+ email:
57
+ - brixen@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - .travis.yml
64
+ - Gemfile
65
+ - LICENSE
66
+ - README.md
67
+ - Rakefile
68
+ - lib/monitor.rb
69
+ - lib/rubysl/monitor.rb
70
+ - lib/rubysl/monitor/monitor.rb
71
+ - lib/rubysl/monitor/version.rb
72
+ - rubysl-monitor.gemspec
73
+ homepage: https://github.com/rubysl/rubysl-monitor
74
+ licenses:
75
+ - BSD
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 2.0.7
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Ruby standard library Monitor.
97
+ test_files: []