normandy 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dfc72d3679cf96efa105ddbb59286e2adec616f3
4
+ data.tar.gz: 9d6358833bbb0d8ae0316f21abc282c5f7e3874c
5
+ SHA512:
6
+ metadata.gz: 55bd93f35b6dd626873bf18c4978975fa1c405a48f3b77619486a8344e744b611bcc8768c98228bbfc87057fea9bc2401d9b08e9d67279b48194b6fce3e48c48
7
+ data.tar.gz: c0e4a3235b16b9bed94801bf635702da18b6b2b489baca71881092ce849f8188df8a0ba451997cb7df8f2c4f57833868434183f08b11049cf88962a1e4fc0856
@@ -0,0 +1,189 @@
1
+ class Channel
2
+ class Closed < StandardError; end
3
+
4
+ def initialize(size = nil)
5
+ @q = size ? SizedQueue.new(size) : Queue.new
6
+ @closed = false
7
+ @mutex = Mutex.new
8
+ @waiting = []
9
+ end
10
+
11
+ private def lock!(&block)
12
+ @mutex.synchronize(&block)
13
+ end
14
+
15
+ private def wait!
16
+ @waiting << Thread.current
17
+ @mutex.sleep
18
+ end
19
+
20
+ private def next!
21
+ loop do
22
+ thr = @waiting.shift
23
+ break if thr.nil?
24
+ next unless thr.alive?
25
+ break thr.wakeup
26
+ end
27
+ end
28
+
29
+ private def all!
30
+ @waiting.dup.each { next! }
31
+ end
32
+
33
+ def recv
34
+ lock! do
35
+ loop do
36
+ closed! if closed? && @q.empty?
37
+ wait! && next if @q.empty?
38
+ break @q.pop
39
+ end
40
+ end
41
+ end
42
+ alias_method :pop, :recv
43
+
44
+ def send(val)
45
+ lock! do
46
+ fail Closed if closed?
47
+ @q << val
48
+ next!
49
+ end
50
+ end
51
+ alias_method :push, :send
52
+ alias_method :<<, :push
53
+
54
+ def close
55
+ lock! do
56
+ return if closed?
57
+ @closed = true
58
+ all!
59
+ end
60
+ end
61
+
62
+ def closed?
63
+ @closed
64
+ end
65
+
66
+ private def closed!
67
+ fail Closed
68
+ end
69
+
70
+ def each
71
+ return enum_for(:each) unless block_given?
72
+
73
+ loop do
74
+ begin
75
+ e = recv
76
+ rescue Channel::Closed
77
+ return
78
+ else
79
+ yield e
80
+ end
81
+ end
82
+ end
83
+
84
+ def receive_only!
85
+ ReceiveOnly.new(self)
86
+ end
87
+ alias_method :r!, :receive_only!
88
+
89
+ def send_only!
90
+ SendOnly.new(self)
91
+ end
92
+ alias_method :s!, :send_only!
93
+
94
+ class << self
95
+ def select(*channels)
96
+ selector = new
97
+ threads = channels.map do |c|
98
+ Thread.new { selector << [c.recv, c] }
99
+ end
100
+ yield selector.recv
101
+ ensure
102
+ selector.close
103
+ threads.each(&:kill).each(&:join)
104
+ end
105
+ end
106
+
107
+ class Direction < StandardError; end
108
+ class Conversion < StandardError; end
109
+
110
+ class ReceiveOnly
111
+ def initialize(channel)
112
+ @channel = channel
113
+ end
114
+
115
+ def recv
116
+ @channel.recv
117
+ end
118
+ alias_method :pop, :recv
119
+
120
+ def send(_)
121
+ fail Direction, 'receive only'
122
+ end
123
+ alias_method :push, :send
124
+ alias_method :<<, :push
125
+
126
+ def close
127
+ @channel.close
128
+ end
129
+
130
+ def closed?
131
+ @channel.closed?
132
+ end
133
+
134
+ def receive_only!
135
+ self
136
+ end
137
+ alias_method :r!, :receive_only!
138
+
139
+ def send_only!
140
+ fail Conversion, 'receive only'
141
+ end
142
+ alias_method :s!, :send_only!
143
+
144
+ def hash
145
+ @channel.hash
146
+ end
147
+ end
148
+
149
+ class SendOnly
150
+ def initialize(channel)
151
+ @channel = channel
152
+ end
153
+
154
+ def recv
155
+ fail Direction, 'send only'
156
+ end
157
+ alias_method :pop, :recv
158
+
159
+ def send(val)
160
+ @channel.send(val)
161
+ end
162
+ alias_method :push, :send
163
+ alias_method :<<, :push
164
+
165
+ def close
166
+ @channel.close
167
+ end
168
+
169
+ def closed?
170
+ @channel.closed?
171
+ end
172
+
173
+ def receive_only!
174
+ fail Conversion, 'send only'
175
+ end
176
+ alias_method :r!, :receive_only!
177
+
178
+ def send_only!
179
+ self
180
+ end
181
+ alias_method :s!, :send_only!
182
+
183
+ def hash
184
+ @channel.hash
185
+ end
186
+ end
187
+ end
188
+
189
+ require 'channel/runtime'
@@ -0,0 +1,15 @@
1
+ require 'thread'
2
+
3
+ module Channel::Runtime
4
+ module_function
5
+
6
+ def go(prc, *args)
7
+ Thread.new { prc.call(*args) }
8
+ end
9
+ end
10
+
11
+ module Kernel
12
+ def go(prc, *args)
13
+ Channel::Runtime.go(prc, *args)
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ class Channel::Timer
2
+ attr_reader :channel
3
+
4
+ def initialize(delay)
5
+ @channel = Channel.new(1)
6
+ @prc = -> { sleep delay; channel << Time.now }
7
+ start
8
+ end
9
+
10
+ def start
11
+ Channel::Runtime.go @prc
12
+ end
13
+
14
+ def self.after(delay)
15
+ new(delay).channel
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ class WaitGroup
2
+ def initialize
3
+ @mutex = Mutex.new
4
+ @count = 0
5
+ @waiting = []
6
+ end
7
+
8
+ def add(delta)
9
+ sync! do
10
+ @count += delta
11
+ fail 'negative WaitGroup counter' if @count < 0
12
+ if @waiting.any? && delta > 0 && @count == delta
13
+ fail 'misuse: add called concurrently with wait'
14
+ end
15
+ wake!
16
+ end
17
+ end
18
+
19
+ def done
20
+ add(-1)
21
+ end
22
+
23
+ private def done?
24
+ @count == 0
25
+ end
26
+
27
+ def wait
28
+ sync! do
29
+ @waiting << Thread.current
30
+ @mutex.sleep until done?
31
+ end
32
+ end
33
+
34
+ private def wake!
35
+ @waiting.each { |t| t.wakeup if t.alive? }
36
+ end
37
+
38
+ private def sync!(&block)
39
+ @mutex.synchronize(&block)
40
+ end
41
+ end
@@ -0,0 +1 @@
1
+ require 'channel'
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: normandy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Loic Nageleisen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-02-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pry
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-unit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Share memory by communicating
70
+ email: loic.nageleisen@gmail.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - lib/channel.rb
76
+ - lib/channel/runtime.rb
77
+ - lib/channel/timer.rb
78
+ - lib/channel/waitgroup.rb
79
+ - lib/normandy.rb
80
+ homepage: https://github.com/lloeki/normandy
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.5.1
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Channels, CSP style
104
+ test_files: []