rubysl-monitor 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []