1#!/usr/local/bin/ruby
2# TupleSpace
3# Copyright (c) 1999-2000 Masatoshi SEKI
4# You can redistribute it and/or modify it under the same terms as Ruby.
5
6require 'thread'
7
8class TupleSpace
9  class Template
10    def initialize(list)
11      @list = list
12      @check_idx = []
13      @list.each_with_index do |x, i|
14	@check_idx.push i if x
15      end
16      @size = @list.size
17    end
18
19    attr :size
20    alias length size
21
22    def match(tuple)
23      return nil if tuple.size != self.size
24      @check_idx.each do |i|
25	unless @list[i] === tuple[i]
26	  return false
27	end
28      end
29      return true
30    end
31  end
32
33  def initialize
34    @que = {}
35    @waiting = {}
36    @que.taint		# enable tainted comunication
37    @waiting.taint
38    self.taint
39  end
40
41  def wakeup_waiting(tuple)
42    sz = tuple.length
43    return nil unless @waiting[sz]
44
45    x = nil
46    i = -1
47    found = false
48    @waiting[sz] = @waiting[sz].find_all { |x|
49      if x[0].match(tuple)
50	begin
51	  x[1].wakeup
52	rescue ThreadError
53	end
54	false
55      else
56	true
57      end
58    }
59  end
60
61  def put_waiting(template, thread)
62    sz = template.length
63    @waiting[sz] = [] unless @waiting[sz]
64    @waiting[sz].push([Template.new(template), thread])
65  end
66  private :wakeup_waiting
67  private :put_waiting
68
69  def get_que(template)
70    sz = template.length
71    return nil unless @que[sz]
72
73    template = Template.new(template)
74
75    x = nil
76    i = -1
77    found = false
78    @que[sz].each_with_index do |x, i|
79      if template.match(x)
80	found = true
81	break
82      end
83    end
84    return nil unless found
85
86    @que[sz].delete_at(i)
87
88    return x
89  end
90
91  def put_que(tuple)
92    sz = tuple.length
93    @que[sz] = [] unless @que[sz]
94    @que[sz].push tuple
95  end
96  private :get_que
97  private :put_que
98
99  def out(*tuples)
100    tuples.each do |tuple|
101      Thread.critical = true
102      put_que(tuple)
103      wakeup_waiting(tuple)
104      Thread.critical = false
105    end
106  end
107  alias put out
108  alias write out
109
110  def in(template, non_block=false)
111    begin
112      loop do
113	Thread.critical = true
114	tuple = get_que(template)
115	unless tuple
116	  if non_block
117	    raise ThreadError, "queue empty"
118	  end
119	  put_waiting(template, Thread.current)
120	  Thread.stop
121	else
122	  return tuple
123	end
124      end
125    ensure
126      Thread.critical = false
127    end
128  end
129  alias get in
130  alias take in
131
132  def rd(template, non_block=false)
133    tuple = self.in(template, non_block)
134    out(tuple)
135    tuple
136  end
137  alias read rd
138
139  def mv(dest, template, non_block=false)
140    tuple = self.in(template, non_block)
141    begin
142      dest.out(tuple)
143    rescue
144      self.out(tuple)
145    end
146  end
147  alias move mv
148end
149
150if __FILE__ == $0
151  ts = TupleSpace.new
152  clients = []
153  servers = []
154
155  def server(ts, id)
156    Thread.start {
157      loop do
158	req = ts.in(['req', nil, nil])
159	ac = req[1]
160	num = req[2]
161	sleep id
162	ts.out([ac, id, num, num * num])
163      end
164    }
165  end
166
167  def client(ts, n)
168    Thread.start {
169      ac = Object.new
170      tuples = (1..10).collect { |i|
171	['req', ac, i * 10 + n]
172      }
173      ts.out(*tuples)
174      ts.out(tuples[0])
175      puts "out: #{n}"
176      11.times do |i|
177	ans = ts.in([ac, nil, nil, nil])
178	puts "client(#{n}) server(#{ans[1]}) #{ans[2]} #{ans[3]}"
179      end
180    }
181  end
182
183  def watcher(ts)
184    Thread.start {
185      loop do
186	begin
187	  sleep 1
188	  p ts.rd(['req', nil, nil], true)
189	rescue ThreadError
190	  puts "'req' not found."
191	end
192      end
193    }
194  end
195
196  (0..3).each do |n|
197    servers.push(server(ts, n))
198  end
199
200  (1..6).each do |n|
201    clients.push(client(ts, n))
202  end
203
204  (1..3).each do
205    watcher(ts)
206  end
207
208  clients.each do |t|
209    t.join
210  end
211end
212
213
214
215