concurrent-selectable 0.1

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