emit 0.1.0 → 0.2.0

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.
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