emit 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f7f3459190a3ae6b0f8d872f97e14cbe8524468e
4
- data.tar.gz: 417ad5f6609d7ec63cabab3c0349e854842e2888
3
+ metadata.gz: a43400e02ac71c9a0c9568be319833e69c9e0b18
4
+ data.tar.gz: b28b6b8e6a01ef1b84e6e5fa797e5c404e387012
5
5
  SHA512:
6
- metadata.gz: 8755bc73dd138ba8ea36a02613e7a6c99ea4a9ad0d5e3f9542ad2a592a398b7e18bf6f9a027b536f692ebf147de2c4a248a7aeda4cfed0967777c4cadb2e0e40
7
- data.tar.gz: ab3bce60704fe9de7b22af564721704ea9fcb6f088bce47373085f9decab9aaca23c60172e73636b448394567dc89b2f4831117ae3928a376a97189e1b0cbd08
6
+ metadata.gz: c0597efaa0e69f35a94244698b5b038788e5210c780166af65068e254c04e47c3fa6717d215e680dde058167f63b7b264d2ab0de00a6b9b344974d0109023609
7
+ data.tar.gz: 68af9bef63afdce8f990890fd4a55dae5e3fe6cf0df86449d17a4c17bd8c603d962b5b0cb922d6851de3f84f36ea8b62cc5f40ee4602459b2754e720a391b0f8
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
  Gemfile.lock
10
+ emit-*.gem
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Emit
2
2
 
3
3
  [![Build Status](https://travis-ci.org/omegahm/emit.svg?branch=master)](https://travis-ci.org/omegahm/emit)
4
+ [![Gem Version](https://badge.fury.io/rb/emit.svg)](https://badge.fury.io/rb/emit)
4
5
 
5
6
  Emit is an implementation of Hoare's CSP in Ruby.
6
7
 
@@ -0,0 +1,22 @@
1
+ require "emit"
2
+
3
+ $result = []
4
+
5
+ def selector(cin1, cin2, n)
6
+ n.times do
7
+ _, msg = Emit.choice(cin1, cin2)
8
+ $result << msg
9
+ end
10
+ end
11
+
12
+ ch1 = Emit.channel
13
+ ch2 = Emit.channel
14
+
15
+ n = 100
16
+ Emit.parallel(
17
+ Emit.process { n.times { -ch1 << 0 } },
18
+ Emit.process { n.times { -ch2 << 1 } },
19
+ Emit.selector(+ch1, +ch2, 2*n)
20
+ )
21
+
22
+ puts $result.inspect
@@ -40,7 +40,7 @@ def consumer(cin, n)
40
40
  end
41
41
 
42
42
  n = 3
43
- comms = 500
43
+ comms = 125_000
44
44
  n.times do |i|
45
45
  puts "Running with #{4*comms} communications"
46
46
  puts
@@ -0,0 +1,14 @@
1
+ require "emit"
2
+
3
+ def deadlock_process(cout, cin)
4
+ cout << 1
5
+ cin.()
6
+ end
7
+
8
+ c = Emit.channel
9
+ d = Emit.channel
10
+
11
+ Emit.parallel(
12
+ Emit.deadlock_process(-c, +d),
13
+ Emit.deadlock_process(-d, +c)
14
+ )
@@ -4,16 +4,14 @@ c = Emit.channel
4
4
  d = Emit.channel
5
5
 
6
6
  def p(cout, cin)
7
- puts "START"
8
7
  cout << 1
9
- puts "WRITE"
8
+ cout << 1
10
9
  cin.()
11
- puts "DONE"
12
10
  end
13
11
 
14
12
  def q(cout, cin)
15
- cout << 1
16
13
  cin.()
14
+ cout << 1
17
15
  end
18
16
 
19
17
  Emit.parallel(
@@ -16,11 +16,10 @@ require "emit/input_guard"
16
16
  require "emit/output_guard"
17
17
 
18
18
  require "emit/alternation"
19
- require "emit/choice"
20
19
 
21
20
  module Emit
22
21
  class << self
23
- def parallel(*processes)
22
+ def parallel(*processes, run: true)
24
23
  processes.flatten!
25
24
 
26
25
  processes.each do |process|
@@ -28,8 +27,10 @@ module Emit
28
27
  Scheduler.enqueue(process)
29
28
  end
30
29
 
31
- Scheduler.join(processes)
32
- processes.map(&:return_value)
30
+ if run
31
+ Scheduler.join(processes)
32
+ processes.map(&:return_value)
33
+ end
33
34
  end
34
35
 
35
36
  def sequence(*processes)
@@ -52,8 +53,8 @@ module Emit
52
53
  channel_ends.each(&:retire)
53
54
  end
54
55
 
55
- def select(*guards)
56
- Alternation.new(guards.map(&:guard_action)).execute
56
+ def choice(*guards)
57
+ Alternation.new(guards).execute
57
58
  end
58
59
 
59
60
  def method_missing(name, *args, **kwargs)
@@ -1,30 +1,26 @@
1
1
  module Emit
2
2
  class Alternation
3
3
  def initialize(guards)
4
- @guards = guards
4
+ @guards = guards.map do |guard|
5
+ case guard
6
+ when InputGuard then guard
7
+ when OutputGuard then guard
8
+ else
9
+ InputGuard.new(guard)
10
+ end
11
+ end
5
12
  end
6
13
 
7
14
  def execute
8
15
  idx, request, channel, operation = choose
9
16
 
10
17
  if @guards[idx]
11
- action = @guards[idx].last[:action]
18
+ action = @guards[idx].action
19
+ fail "Failed executing action in alternation." unless [Proc, Method].include?(action.class)
12
20
 
13
- case action
14
- when Choice
15
- case operation
16
- when :write then action.invoke_on_output
17
- when :read then action.invoke_on_input(request.message)
18
- end
19
- when Proc, Method
20
- case operation
21
- when :write then action.()
22
- when :read then action.(message: request.message)
23
- end
24
- when nil
25
- # no-op
26
- else
27
- fail "Failed executing action: #{action}."
21
+ case operation
22
+ when :write then action.()
23
+ when :read then action.(request.message)
28
24
  end
29
25
  end
30
26
 
@@ -36,29 +32,25 @@ module Emit
36
32
  def choose
37
33
  requests = {}
38
34
  act = nil
39
- poison = false
40
- retire = false
41
35
 
42
36
  Scheduler.current.state = :active
43
37
 
44
38
  begin
45
39
  idx = 0
46
40
  @guards.each do |guard|
47
- if guard.size == 3 # write
41
+ if OutputGuard === guard
48
42
  operation = :write
49
- channel, message, action = guard
50
- request = ChannelRequest.new(Scheduler.current, message)
51
- channel.send(:post_write, request)
52
- elsif guard.size == 2 # read
43
+ request = ChannelRequest.new(Scheduler.current, guard.message)
44
+ guard.channel_end.send(:post_write, request)
45
+ elsif InputGuard === guard
53
46
  operation = :read
54
- channel, action = guard
55
47
  request = ChannelRequest.new(Scheduler.current)
56
- channel.send(:post_read, request)
48
+ guard.channel_end.send(:post_read, request)
57
49
  else
58
50
  fail "Guard was neither write or read."
59
51
  end
60
52
 
61
- requests[request] = [idx, channel, operation]
53
+ requests[request] = [idx, guard.channel_end, operation]
62
54
  idx += 1
63
55
  end
64
56
  rescue ChannelPoisonedException, ChannelRetiredException
@@ -1,13 +1,22 @@
1
1
  module Emit
2
2
  class InputGuard
3
- attr_reader :guard_action
3
+ attr_reader :channel_end, :action
4
4
 
5
- def initialize(channel_end, action=nil)
6
- if ChannelEndRead === channel_end
7
- @guard_action = [channel_end, action]
5
+ def initialize(argument, action=->(msg) {msg})
6
+ case argument
7
+ when InputGuard
8
+ @channel_end, @action = argument.channel_end, argument.action
9
+ when ChannelEndRead
10
+ @channel_end, @action = argument, action
11
+ when Array
12
+ fail "Wrong number of arguments" unless argument.size == 2
13
+ @channel_end, @action = argument
8
14
  else
9
- fail "InputGuard must have a reading channel end."
15
+ fail "Unknown input guard type"
10
16
  end
17
+
18
+ fail "InputGuard must have a reading channel end." unless ChannelEndRead === @channel_end
19
+ fail "InputGuard action cannot be nil" if @action.nil?
11
20
  end
12
21
  end
13
22
  end
@@ -1,13 +1,22 @@
1
1
  module Emit
2
- class GuardGuard
3
- attr_reader :guard_action
2
+ class OutputGuard
3
+ attr_reader :channel_end, :message, :action
4
4
 
5
- def initialize(channel_end, message, action=nil)
6
- if ChannelEndWrite === channel_end
7
- @guard_action = [channel_end, message, action]
5
+ def initialize(argument, message, action=nil)
6
+ case argument
7
+ when OutputGuard
8
+ @channel_end, @message, @action = argument.channel_end, argument.message, argument.action
9
+ when ChannelEndWrite
10
+ @channel_end, @message, @action = argument, message, action
11
+ when Array
12
+ fail "Wrong number of arguments" unless argument.size == 3
13
+ @channel_end, @message, @action = argument
8
14
  else
9
- fail "OutputGuard must have a writing channel end."
15
+ fail "Unknown output guard type"
10
16
  end
17
+
18
+ fail "OutputGuard must have a writing channel end." unless ChannelEndWrite === channel_end
19
+ fail "OutputGuard action cannot be nil" if @action.nil?
11
20
  end
12
21
  end
13
22
  end
@@ -1,3 +1,3 @@
1
1
  module Emit
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: emit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mads Ohm Larsen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-09 00:00:00.000000000 Z
11
+ date: 2018-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,10 +66,11 @@ files:
66
66
  - LICENSE.txt
67
67
  - README.md
68
68
  - Rakefile
69
+ - benchmarks/choice.rb
69
70
  - benchmarks/commstime.rb
71
+ - benchmarks/deadlock.rb
70
72
  - benchmarks/many_processes.rb
71
73
  - benchmarks/montecarlopi.rb
72
- - benchmarks/select.rb
73
74
  - benchmarks/starvation.rb
74
75
  - bin/console
75
76
  - bin/setup
@@ -81,7 +82,6 @@ files:
81
82
  - lib/emit/channel_end_read.rb
82
83
  - lib/emit/channel_end_write.rb
83
84
  - lib/emit/channel_request.rb
84
- - lib/emit/choice.rb
85
85
  - lib/emit/exceptions.rb
86
86
  - lib/emit/input_guard.rb
87
87
  - lib/emit/output_guard.rb
@@ -1,30 +0,0 @@
1
- require "emit"
2
-
3
- @result = []
4
- def action(message: nil)
5
- @result << message
6
- end
7
-
8
- def p1(cout, n)
9
- n.times { |i| cout << i }
10
- end
11
-
12
- def p2(cin1, cin2, n)
13
- n.times do
14
- Emit.select(
15
- Emit::InputGuard.new(cin1, action: method(:action)),
16
- Emit::InputGuard.new(cin2, action: method(:action))
17
- )
18
- end
19
- end
20
-
21
- ch1 = Emit.channel
22
- ch2 = Emit.channel
23
-
24
- Emit.parallel(
25
- Emit.process(-ch1, 50, &method(:p1)),
26
- Emit.process(-ch2, 50, &method(:p1)),
27
- Emit.process(+ch1, +ch2, 100, &method(:p2))
28
- )
29
-
30
- puts @result.inspect
@@ -1,18 +0,0 @@
1
- module Emit
2
- class Choice
3
- def initialize(*args, **kwargs, &block)
4
- @block = block
5
- @args = args
6
- @kwargs = kwargs
7
- end
8
-
9
- def invoke_on_output
10
- @block.call(*@args, **@kwargs)
11
- end
12
-
13
- def invoke_on_input(message)
14
- @kwargs[:message] = message
15
- @block.call(*@args, **@kwargs)
16
- end
17
- end
18
- end