concurrent-selectable 0.1

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.
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/gempackagetask'
5
+ require 'rake/clean'
6
+
7
+ GEM_VERSION = "0.1"
8
+
9
+ Rake::RDocTask.new do |task|
10
+ task.rdoc_files.add [ 'lib/**/*.rb' ]
11
+ end
12
+
13
+ task :clobber => [ :clean ]
14
+
15
+ Rake::TestTask.new do |task|
16
+ task.ruby_opts << '-rrubygems'
17
+ task.libs << 'lib'
18
+ task.libs << 'test'
19
+ task.test_files = [ "test/test_all.rb" ]
20
+ task.verbose = true
21
+ end
22
+
23
+ gemspec = Gem::Specification.new do |gemspec|
24
+ gemspec.name = "concurrent-selectable"
25
+ gemspec.version = GEM_VERSION
26
+ gemspec.author = "MenTaLguY <mental@rydia.net>"
27
+ gemspec.summary = "Synchronization primitives with selectable IO channels"
28
+ gemspec.test_file = 'test/test_all.rb'
29
+ gemspec.files = FileList[ 'Rakefile', 'test/*.rb', 'lib/**/*.rb' ]
30
+ gemspec.require_paths = [ 'lib' ]
31
+ gemspec.has_rdoc = true
32
+ gemspec.platform = Gem::Platform::RUBY
33
+ end
34
+
35
+ task :package => [ :clean, :test ]
36
+ Rake::GemPackageTask.new( gemspec ) do |task|
37
+ task.gem_spec = gemspec
38
+ task.need_tar = true
39
+ end
40
+
41
+ task :default => [ :clean, :test ]
42
+
@@ -0,0 +1,33 @@
1
+ # concurrent/selectable - Synchronization primitives supporting IO.select
2
+ #
3
+ # Copyright 2008 MenTaLguY <mental@rydia.net>
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ #
10
+ # * Redistributions of source code must retain the above copyright notice,
11
+ # this list of conditions and the following disclaimer.
12
+ # * Redistributions in binary form must reproduce the above copyright notice
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ # * The names of the authors may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ # POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ require 'concurrent/selectable/channel'
31
+ require 'concurrent/selectable/latch'
32
+ require 'concurrent/selectable/semaphore'
33
+
@@ -0,0 +1,86 @@
1
+ # concurrent/selectable/channel - IO-Selectable channel
2
+ #
3
+ # Copyright 2008 MenTaLguY <mental@rydia.net>
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ #
10
+ # * Redistributions of source code must retain the above copyright notice,
11
+ # this list of conditions and the following disclaimer.
12
+ # * Redistributions in binary form must reproduce the above copyright notice
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ # * The names of the authors may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ # POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ require 'thread'
31
+ begin
32
+ require 'fastthread'
33
+ rescue LoadError
34
+ end
35
+
36
+ require 'concurrent/selectable/common'
37
+
38
+ module Concurrent
39
+ module Selectable
40
+
41
+ # A thread-safe FIFO channel of Ruby objects which can be selected on as if it
42
+ # were an IO object.
43
+ class Channel < Base
44
+ def initialize
45
+ super()
46
+ @lock = ::Mutex.new
47
+ @channel = ::Queue.new
48
+ end
49
+
50
+ # Attempts to get a value from the channel and returns it, blocking if none
51
+ # is available and +blocking+ is true. If +blocking+ is false, then
52
+ # +default_value+ is returned if no value is currently available.
53
+ def get(blocking=true, default_value=nil)
54
+ loop do
55
+ @lock.synchronize do
56
+ size = @channel.size
57
+ if size.nonzero?
58
+ value = @channel.deq
59
+ internal_reset if size == 1 # i.e. if we removed the last remaining
60
+ return value
61
+ end
62
+ end
63
+ return default_value unless blocking
64
+ wait
65
+ end
66
+ end
67
+
68
+ # Places +value+ on the channel.
69
+ def put(value)
70
+ @lock.synchronize do
71
+ internal_set if @channel.empty?
72
+ @channel.enq value
73
+ end
74
+ end
75
+ alias_method :<<, :put
76
+
77
+ # Returns true if the channel is currently empty (additional external
78
+ # synchronization is normally required if other threads can manipulate
79
+ # the channel)
80
+ def empty?
81
+ @channel.empty?
82
+ end
83
+ end
84
+
85
+ end
86
+ end
@@ -0,0 +1,78 @@
1
+ # concurrent/selectable/common - Common bits for IO-Selectable synchronization
2
+ #
3
+ # Copyright 2008 MenTaLguY <mental@rydia.net>
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ #
10
+ # * Redistributions of source code must retain the above copyright notice,
11
+ # this list of conditions and the following disclaimer.
12
+ # * Redistributions in binary form must reproduce the above copyright notice
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ # * The names of the authors may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ # POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ require 'thread'
31
+ begin
32
+ require 'fastthread'
33
+ rescue LoadError
34
+ end
35
+
36
+ module Concurrent
37
+ module Selectable
38
+
39
+ # Raised if a wait exceeds a given timeout
40
+ class TimeoutError < RuntimeError
41
+ end
42
+
43
+ # Base class for selectable primitives
44
+ class Base
45
+ def initialize #:nodoc:
46
+ @read, @write = IO.pipe
47
+ end
48
+
49
+ # Waits for the primitive to become available/signaled, with the given
50
+ # +timeout+ (see IO.select). If +timeout+ is given and is not +nil+, then
51
+ # TimeoutError will be raised if the timeout is exceeded.
52
+ def wait(timeout=nil)
53
+ ready = IO.select([@read], nil, nil, timeout)
54
+ raise TimeoutError, "wait timed out" unless ready
55
+ self
56
+ end
57
+
58
+ # Converts the primitive to an IO object; the object is only safe to
59
+ # test whether it is ready for reading; DO NOT read from the returned
60
+ # IO object yourself.
61
+ def to_io
62
+ @read
63
+ end
64
+
65
+ private
66
+ def internal_set
67
+ @write.write 'x'
68
+ self
69
+ end
70
+
71
+ def internal_reset
72
+ @read.read 1
73
+ self
74
+ end
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,80 @@
1
+ # concurrent/selectable/latch - IO-Selectable latch
2
+ #
3
+ # Copyright 2008 MenTaLguY <mental@rydia.net>
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ #
10
+ # * Redistributions of source code must retain the above copyright notice,
11
+ # this list of conditions and the following disclaimer.
12
+ # * Redistributions in binary form must reproduce the above copyright notice
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ # * The names of the authors may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ # POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ require 'thread'
31
+ begin
32
+ require 'fastthread'
33
+ rescue LoadError
34
+ end
35
+
36
+ require 'concurrent/selectable/common'
37
+
38
+ module Concurrent
39
+ module Selectable
40
+
41
+ # A latch is a toggle which starts out unset. Threads can wait for the
42
+ # latch to become set by calling Latch#wait (inherited from Base). The
43
+ # latch can be reset to its intial state using Latch#reset.
44
+ class Latch < Base
45
+ def initialize
46
+ super()
47
+ @lock = ::Mutex.new
48
+ @set = false
49
+ end
50
+
51
+ # Sets the latch, allowing any current and future waiting threads to
52
+ # continue
53
+ def set
54
+ @lock.synchronize do
55
+ internal_set unless @set
56
+ @set = true
57
+ end
58
+ self
59
+ end
60
+
61
+ # Non-blocking test whether the latch is currently set (additional
62
+ # external synchronization will usually be required if the latch can be
63
+ # set or reset by other threads)
64
+ def set?
65
+ @lock.synchronize { @set }
66
+ end
67
+
68
+ # Resets the latch, blocking any subsequent waiting threads until the
69
+ # latch is set again
70
+ def reset
71
+ @lock.synchronize do
72
+ internal_reset if @set
73
+ @set = false
74
+ end
75
+ self
76
+ end
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,91 @@
1
+ # concurrent/selectable/semaphore - IO-Selectable semaphore
2
+ #
3
+ # Copyright 2008 MenTaLguY <mental@rydia.net>
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ #
10
+ # * Redistributions of source code must retain the above copyright notice,
11
+ # this list of conditions and the following disclaimer.
12
+ # * Redistributions in binary form must reproduce the above copyright notice
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ # * The names of the authors may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ # POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ require 'thread'
31
+ begin
32
+ require 'fastthread'
33
+ rescue LoadError
34
+ end
35
+
36
+ require 'concurrent/selectable/common'
37
+
38
+ module Concurrent
39
+ module Selectable
40
+
41
+ # A Semaphore is a counter which can be atomically incremented and decremented;
42
+ # attempts to decrement the counter below zero will block.
43
+ class Semaphore < Base
44
+ # Creates a semaphore with the given initial +count+
45
+ def initialize(count=0)
46
+ super()
47
+ @lock = ::Mutex.new
48
+ @count = count
49
+ end
50
+
51
+ # Decrements the semaphore, blocking if its count is already zero and
52
+ # +blocking+ is true.
53
+ def get(blocking=true)
54
+ loop do
55
+ @lock.synchronize do
56
+ if @count.nonzero?
57
+ @count -= 1
58
+ internal_reset if @count.zero?
59
+ return self
60
+ end
61
+ end
62
+ return nil unless blocking
63
+ wait
64
+ end
65
+ end
66
+
67
+ # Increments the semaphore
68
+ def put
69
+ @lock.synchronize do
70
+ internal_set if @count.zero?
71
+ @count += 1
72
+ end
73
+ end
74
+
75
+ # Returns true if the count is currently zero (additional external
76
+ # synchronization is usually required if other threads can modify the
77
+ # semaphore)
78
+ def zero?
79
+ @lock.synchronize { @count.zero? }
80
+ end
81
+
82
+ # Returns true if the count is currently nonzero (additional external
83
+ # synchronization is usually required if other threads can modify the
84
+ # semaphore)
85
+ def nonzero?
86
+ @lock.synchronize { @count.nonzero? }
87
+ end
88
+ end
89
+
90
+ end
91
+ end
data/test/test_all.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'test_channel.rb'
2
+ require 'test_latch.rb'
3
+ require 'test_semaphore.rb'
@@ -0,0 +1,23 @@
1
+ require 'test/unit'
2
+ require 'concurrent/selectable/channel'
3
+
4
+ SChannel = Concurrent::Selectable::Channel
5
+
6
+ class TestChannel < Test::Unit::TestCase
7
+ def test_to_io
8
+ channel = SChannel.new
9
+ assert_instance_of IO, channel.to_io
10
+ end
11
+
12
+ def test_select
13
+ channel = SChannel.new
14
+ ready = IO.select([channel], nil, nil, 0.01)
15
+ assert !ready
16
+ channel.put :blah
17
+ ready = IO.select([channel], nil, nil, 0.01)
18
+ assert ready
19
+ channel.get
20
+ ready = IO.select([channel], nil, nil, 0.01)
21
+ assert !ready
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ require 'test/unit'
2
+ require 'concurrent/selectable/latch'
3
+
4
+ Latch = Concurrent::Selectable::Latch
5
+
6
+ class TestLatch < Test::Unit::TestCase
7
+ def test_to_io
8
+ latch = Latch.new
9
+ assert_instance_of IO, latch.to_io
10
+ end
11
+
12
+ def test_select
13
+ latch = Latch.new
14
+ ready = IO.select([latch], nil, nil, 0.01)
15
+ assert !ready
16
+ latch.set
17
+ ready = IO.select([latch], nil, nil, 0.01)
18
+ assert ready
19
+ latch.reset
20
+ ready = IO.select([latch], nil, nil, 0.01)
21
+ assert !ready
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ require 'test/unit'
2
+ require 'concurrent/selectable/semaphore'
3
+
4
+ Semaphore = Concurrent::Selectable::Semaphore
5
+
6
+ class TestSemaphore < Test::Unit::TestCase
7
+ def test_to_io
8
+ semaphore = Semaphore.new
9
+ assert_instance_of IO, semaphore.to_io
10
+ end
11
+
12
+ def test_select
13
+ semaphore = Semaphore.new
14
+ ready = IO.select([semaphore], nil, nil, 0.01)
15
+ assert !ready
16
+ semaphore.put
17
+ ready = IO.select([semaphore], nil, nil, 0.01)
18
+ assert ready
19
+ semaphore.get
20
+ ready = IO.select([semaphore], nil, nil, 0.01)
21
+ assert !ready
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: concurrent-selectable
5
+ version: !ruby/object:Gem::Version
6
+ version: "0.1"
7
+ date: 2008-01-27 00:00:00 -05:00
8
+ summary: Synchronization primitives with selectable IO channels
9
+ require_paths:
10
+ - lib
11
+ email:
12
+ homepage:
13
+ rubyforge_project:
14
+ description:
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors:
29
+ - MenTaLguY <mental@rydia.net>
30
+ files:
31
+ - Rakefile
32
+ - test/test_latch.rb
33
+ - test/test_all.rb
34
+ - test/test_semaphore.rb
35
+ - test/test_channel.rb
36
+ - lib/concurrent/selectable.rb
37
+ - lib/concurrent/selectable/latch.rb
38
+ - lib/concurrent/selectable/common.rb
39
+ - lib/concurrent/selectable/semaphore.rb
40
+ - lib/concurrent/selectable/channel.rb
41
+ test_files:
42
+ - test/test_all.rb
43
+ rdoc_options: []
44
+
45
+ extra_rdoc_files: []
46
+
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ requirements: []
52
+
53
+ dependencies: []
54
+