cruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
File without changes
data/README ADDED
@@ -0,0 +1,7 @@
1
+ README for cruby
2
+ ================
3
+
4
+ CRubyはRuby上で並行プログラミングを実現するためのライブラリです。
5
+
6
+
7
+
@@ -0,0 +1,85 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/rdoctask'
8
+ require 'rake/contrib/rubyforgepublisher'
9
+ require 'fileutils'
10
+ include FileUtils
11
+ require File.join(File.dirname(__FILE__), 'lib', 'cruby', 'version')
12
+
13
+ AUTHOR = "hattori"
14
+ EMAIL = "hattori@isp.co.jp"
15
+ DESCRIPTION = "CRuby is a library that provids concurrent programming in Ruby"
16
+ RUBYFORGE_PROJECT = "cruby"
17
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
18
+ BIN_FILES = %w( )
19
+
20
+
21
+ NAME = "cruby"
22
+ REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
23
+ VERS = ENV['VERSION'] || (Cruby::VERSION::STRING + (REV ? ".#{REV}" : ""))
24
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config']
25
+ RDOC_OPTS = ['--quiet', '--title', "cruby documentation",
26
+ "--opname", "index.html",
27
+ "--line-numbers",
28
+ "--main", "README",
29
+ "--inline-source"]
30
+
31
+ desc "Packages up cruby gem."
32
+ task :default => [:test]
33
+ task :package => [:clean]
34
+
35
+ Rake::TestTask.new("test") { |t|
36
+ t.libs << "test"
37
+ t.pattern = "test/**/*_test.rb"
38
+ t.verbose = true
39
+ }
40
+
41
+ spec =
42
+ Gem::Specification.new do |s|
43
+ s.name = NAME
44
+ s.version = VERS
45
+ s.platform = Gem::Platform::RUBY
46
+ s.has_rdoc = true
47
+ s.extra_rdoc_files = ["README", "CHANGELOG"]
48
+ s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|extras)/']
49
+ s.summary = DESCRIPTION
50
+ s.description = DESCRIPTION
51
+ s.author = AUTHOR
52
+ s.email = EMAIL
53
+ s.homepage = HOMEPATH
54
+ s.executables = BIN_FILES
55
+ s.rubyforge_project = RUBYFORGE_PROJECT
56
+ s.bindir = "bin"
57
+ s.require_path = "lib"
58
+ s.autorequire = "cruby"
59
+
60
+ #s.add_dependency('activesupport', '>=1.3.1')
61
+ #s.required_ruby_version = '>= 1.8.2'
62
+
63
+ s.files = %w(README CHANGELOG Rakefile) +
64
+ Dir.glob("{bin,doc,test,lib,templates,generator,extras,website,script}/**/*") +
65
+ Dir.glob("ext/**/*.{h,c,rb}") +
66
+ Dir.glob("examples/**/*.rb") +
67
+ Dir.glob("tools/*.rb")
68
+
69
+ # s.extensions = FileList["ext/**/extconf.rb"].to_a
70
+ end
71
+
72
+ Rake::GemPackageTask.new(spec) do |p|
73
+ p.need_tar = true
74
+ p.gem_spec = spec
75
+ end
76
+
77
+ task :install do
78
+ name = "#{NAME}-#{VERS}.gem"
79
+ sh %{rake package}
80
+ sh %{sudo gem install pkg/#{name}}
81
+ end
82
+
83
+ task :uninstall => [:clean] do
84
+ sh %{sudo gem uninstall #{NAME}}
85
+ end
@@ -0,0 +1,148 @@
1
+ require 'socket'
2
+ require 'crbtk'
3
+
4
+ class EchoCtrl
5
+ # �R���g���[���Ŏg�p����C�x���g��`
6
+ EVT_CONNECT = 'EVT_CONNECT' # �ڑ��C�x���g
7
+ EVT_DISCONN = 'EVT_DISCONN' # �ؒf�C�x���g
8
+ EVT_SENDMSG = 'EVT_SENDMSG' # ���M�C�x���g
9
+
10
+ ECHO_PORT = 7
11
+
12
+ def initialize view
13
+ @view = view
14
+ @sock = nil
15
+ # �`���l���̏�����
16
+ @chSockIn = nil
17
+ @chSockOut = nil
18
+ @chConnect = TkChannel.new(EVT_CONNECT)
19
+ @chDisconn = TkChannel.new(EVT_DISCONN)
20
+ @chSendMsg = TkChannel.new(EVT_SENDMSG)
21
+ end
22
+
23
+ def loop
24
+ host = @chConnect.recv # �ڑ��v���҂�
25
+ @sock = TCPSocket.open(host, ECHO_PORT)
26
+ @chSockIn = IoChannel.new(@sock)
27
+ @chSockOut = IoChannel.new(@sock)
28
+
29
+ def innerLoop
30
+ Event.choose[
31
+ @chSendMsg.recvEvt.wrap{|m| # ���M�v���҂�
32
+ @chSockOut.send(m) # ���b�Z�[�W���M
33
+ m = @chSockIn.recv # ���b�Z�[�W��M�҂�
34
+ @view.set_recv(m)
35
+ innerLoop
36
+ },
37
+ @chDiscon.recvEvt.wrap{ @sock.close }].sync
38
+ end
39
+ loop
40
+ end
41
+
42
+ end
43
+
44
+ #
45
+ # �\���n
46
+ #
47
+ class EchoView
48
+
49
+ # �ڑ��{�^���������̏���
50
+ def connect
51
+ @host_e.background 'gray'
52
+ @host_e.state 'disabled'
53
+ @conn_b.text '�ؒf'
54
+ @conn_b.command { disconnect }
55
+ @mesg_e.background 'white'
56
+ @mesg_e.state 'normal'
57
+ @send_b.state 'normal'
58
+
59
+ CRubyTk.send(EchoCtrl::CONNECT, @host_e.value)
60
+ end
61
+
62
+ # �ؒf�{�^���������̏���
63
+ def disconnect
64
+ @host_e.background 'white'
65
+ @host_e.state 'normal'
66
+ @conn_b.text '�ڑ�'
67
+ @conn_b.command { connect }
68
+ @mesg_e.background 'gray'
69
+ @mesg_e.state 'disabled'
70
+ @send_b.state 'disabled'
71
+
72
+ CRubyTk.send(EchoCtrl::DISCONN)
73
+ end
74
+
75
+ def initialize
76
+ root = TkRoot.new { title "EchoClient" }
77
+ top = TkFrame.new(root) { background "white" }
78
+
79
+ #
80
+ # �z�X�g���F[ ][�ڑ�]
81
+ #
82
+ TkLabel.new(top) {
83
+ background "white"
84
+ text '�z�X�g��:'
85
+ grid('row'=>0, 'column'=>0, 'sticky'=>'w')
86
+ }
87
+ @host_e = TkEntry.new(top) {
88
+ grid('row'=>0, 'column'=>1, 'sticky'=>'ns', 'padx'=>5,'pady'=>5)
89
+ }
90
+ @conn_b = TkButton.new(top) {
91
+ grid('row'=>0, 'column'=>2, 'sticky'=>'e')
92
+ }
93
+
94
+ #
95
+ # ���́F[ ][���M]
96
+ #
97
+ TkLabel.new(top) {
98
+ background "white"
99
+ text '����:'
100
+ grid('row'=>1, 'column'=>0, 'sticky'=>'w')
101
+ }
102
+ @mesg_e = TkEntry.new(top) {
103
+ grid('row'=>1, 'column'=>1, 'sticky'=>'ns', 'padx'=>5,'pady'=>5)
104
+ }
105
+ @send_b = TkButton.new(top) {
106
+ text '���M'
107
+ grid('row'=>1, 'column'=>2, 'sticky'=>'e')
108
+ }
109
+
110
+ #
111
+ # �����F[ ]
112
+ #
113
+ TkLabel.new(top) {
114
+ background "white"
115
+ text '����:'
116
+ grid('row'=>2, 'column'=>0, 'sticky'=>'w')
117
+ }
118
+ @recv_m = TkMessage.new(top) {
119
+ background "white"
120
+ relief 'ridge'
121
+ aspect 1000
122
+ grid('row'=>2, 'column'=>1, 'columnspan'=>2, 'sticky'=>'news')
123
+ }
124
+ def set_recv mesg
125
+ # �����ƂƂ��ɕ\������
126
+ @recv_m.text = Time.now.to_s + ":" + mesg
127
+ end
128
+ #
129
+ # [�I��]
130
+ #
131
+ exit_b = TkButton.new(top) {
132
+ text '�I��'
133
+ grid('row'=>3, 'column'=>1, 'sticky'=>'news')
134
+ }
135
+
136
+ top.pack('fill' => 'both', 'side' => 'top')
137
+
138
+ # �e�{�^���ɑ΂���A�N�V������ݒ�
139
+ @send_b.command { CRubyTk.send(EchoCtrol::SENDMSG, @mesg_e.value) }
140
+ exit_b.command { exit }
141
+
142
+ disconnect # �������
143
+ end
144
+
145
+ end
146
+
147
+ # EchoCtrl.new(EchoView.new)
148
+ # CRubyTk.mainloop
@@ -0,0 +1,18 @@
1
+ require 'socket'
2
+ require '../lib/cruby'
3
+
4
+ def echod sch
5
+ while true
6
+ (sch.recvEvt.wrap {|ch| CRuby::Coroutine.spawn {echoProc(ch)}}).sync
7
+ end
8
+ end
9
+ def echoProc ch
10
+ while true
11
+ ch.send(ch.recv) rescue return
12
+ end
13
+ end
14
+
15
+
16
+ gs = TCPServer.open(10007)
17
+ echod(CRuby::TcpServerChannel.new(gs))
18
+
@@ -0,0 +1,45 @@
1
+ #
2
+ # Fibプロセスネットワーク
3
+ #
4
+ require 'cruby'
5
+
6
+ # 加算器
7
+ def add (inCh1,inCh2,outCh)
8
+ outCh.send(inCh1.recv+inCh2.recv)
9
+ add(inCh1,inCh2,outCh)
10
+ end
11
+
12
+ def add (inCh1,inCh2,outCh)
13
+ outCh.send(inCh1.recv+inCh2.recv)
14
+ add(inCh1,inCh2,outCh)
15
+ end
16
+
17
+ def copy (inCh,outCh1,outCh2)
18
+ x = inCh.recv
19
+ outCh1.send(x); outCh2.send(x)
20
+ copy(inCh,outCh1,outCh2)
21
+ end
22
+
23
+ def delay (n,inCh,outCh)
24
+ outCh.send(n)
25
+ delay(inCh.recv,inCh,outCh)
26
+ end
27
+
28
+ def fib
29
+ outCh = CRuby::Channel.new()
30
+ c1 = CRuby::Channel.new()
31
+ c2 = CRuby::Channel.new()
32
+ c3 = CRuby::Channel.new()
33
+ c4 = CRuby::Channel.new()
34
+ c5 = CRuby::Channel.new()
35
+ CRuby::Coroutine.spawn{delay(0,c4,c5)}
36
+ CRuby::Coroutine.spawn{copy(c2,c3,c4)}
37
+ CRuby::Coroutine.spawn{add(c3,c5,c1)}
38
+ CRuby::Coroutine.spawn{copy(c1,c2,outCh)}
39
+ c1.send(1)
40
+ outCh
41
+ end
42
+
43
+ ch = fib
44
+ 20.times { p ch.recv }
45
+
@@ -0,0 +1,40 @@
1
+ #
2
+ # n,n+1,n+2,...を送信するチャネルを返す
3
+ #
4
+ require 'cruby'
5
+
6
+ def counter (n, ch)
7
+ ch.send(n); counter(n+1,ch)
8
+ end
9
+
10
+ def filter (p, inCh, outCh)
11
+ i = inCh.recv()
12
+ if i % p != 0 then
13
+ outCh.send(i)
14
+ end
15
+ filter(p,inCh,outCh)
16
+ end
17
+
18
+ #
19
+ # 篩にかける
20
+ #
21
+ def sieve (inCh, outCh)
22
+ ch = CRuby::Channel.new()
23
+ p = inCh.recv(); outCh.send(p)
24
+ CRuby::Coroutine.spawn { filter(p,inCh,ch) }
25
+ sieve(ch,outCh)
26
+ end
27
+
28
+ def primes n
29
+ nCh = CRuby::Channel.new()
30
+ CRuby::Coroutine.spawn { counter(2,nCh) }
31
+ pCh = CRuby::Channel.new()
32
+ CRuby::Coroutine.spawn { sieve(nCh,pCh) }
33
+
34
+ for i in 1..n
35
+ p pCh.recv()
36
+ end
37
+
38
+ end
39
+
40
+ primes(50)
@@ -0,0 +1,77 @@
1
+ require 'tk'
2
+ require 'cruby'
3
+
4
+ # ���荞�ݗp�̗�O��`
5
+ class InterruptException < Exception
6
+ attr_reader :evtnam, :param
7
+ def initialize(evtnam,param)
8
+ @evtnam = evtnam
9
+ @param = param
10
+ end
11
+ end
12
+
13
+ module Coroutine
14
+ def Coroutine.dispatch
15
+ while true
16
+ k = @@rdyQ.dequeue
17
+ k.call if k != nil
18
+
19
+ begin
20
+ @@io.call if @@io != nil
21
+ Coroutine.interruptible true
22
+ sleep
23
+ rescue InterruptException
24
+ Coroutine.interruptible false
25
+ # �C�x���g�z������
26
+ EventChannel.setEvent($!.evtnam, $!.param)
27
+ end
28
+ end
29
+ assert false
30
+ end
31
+ end
32
+
33
+ class CRubyTk
34
+ def self.mainloop
35
+ @@thread = Thread.current
36
+ Thread.new {
37
+ while true
38
+ Tk.do_one_event(Tk::EventFlag::ALL)
39
+ end
40
+ }
41
+ Coroutine.dispatch
42
+ end
43
+
44
+ # �R�[���o�b�N�̕�������Ă΂��
45
+ def self.send(evtnam, param = nil)
46
+ Coroutine.interrupt
47
+ @@thread.raise InterruptException.new(evtnam, param)
48
+ end
49
+
50
+ end
51
+
52
+ class EventChannel < Channel
53
+ @@evtTbl = Hash.new # �C�x���g�����L�[�Ƃ���e�[�u��
54
+
55
+ def initialize(evtnam)
56
+ super()
57
+ @evtnam = evtnam
58
+ @@evtTbl[evtnam] = self
59
+ end
60
+
61
+ def self.setEvent(evtnam, param)
62
+ # �C�x���g�L���[����`���l������Ž��o��
63
+ ch = @@evtTbl[evtnam]
64
+ p
65
+ callcc {|k| ch.input(param,k) }
66
+ end
67
+
68
+ def input(mesg, ret)
69
+ # �`���l���̎�M�҂��L���[�̃v���Z�X�����o��
70
+ item = @recvQ.dequeue
71
+ if item
72
+ item['flg'][0] = true
73
+ callcc {|k| Coroutine.enqueue(k); ret.call}
74
+ item['cont'].call(mesg) rescue p $!
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,2 @@
1
+ module CRuby; end
2
+ Dir[File.join(File.dirname(__FILE__), 'cruby/**/*.rb')].sort.each { |lib| require lib }
@@ -0,0 +1,197 @@
1
+ class CRuby::Channel
2
+
3
+ def initialize
4
+ @sendQ = CRuby::Queue.new()
5
+ @recvQ = CRuby::Queue.new()
6
+ end
7
+
8
+ def send msg
9
+ sendEvt(msg).sync
10
+ end
11
+
12
+ def recv
13
+ recvEvt.sync
14
+ end
15
+
16
+ # 送信イベントを生成する
17
+ def sendEvt msg
18
+ pollFn = Proc.new { @recvQ.poll }
19
+ doFn = Proc.new {
20
+ callcc {|k|
21
+ item = @recvQ.dequeue
22
+ item['flg'][0] = true
23
+ CRuby::Coroutine.enqueue(k)
24
+ item['cont'].call(msg)
25
+ }
26
+ }
27
+ blockFn = Proc.new {|flg,k| @sendQ.enqueue({'flg'=>flg,'msg'=>msg,'cont'=>k}) }
28
+ CRuby::Event.new([CRuby::Event::BEvt.new(pollFn, doFn, blockFn)])
29
+ end
30
+
31
+ # 受信イベントを生成する
32
+ def recvEvt
33
+ pollFn = Proc.new { @sendQ.poll }
34
+ doFn = Proc.new {
35
+ item = @sendQ.dequeue
36
+ item['flg'][0] = true
37
+ CRuby::Coroutine.enqueue(item['cont'])
38
+ item['msg']
39
+ }
40
+ blockFn = Proc.new {|flg,k| @recvQ.enqueue({'flg'=>flg,'cont'=>k}) }
41
+ CRuby::Event.new([CRuby::Event::BEvt.new(pollFn, doFn, blockFn)])
42
+ end
43
+
44
+ end
45
+
46
+ # 入出力とタイマー処理
47
+ module IOT
48
+ @@inTbl = Hash.new {[]} # 入力IOをキーとするテーブル
49
+ @@outTbl = Hash.new {[]} # 出力IOをキーとするテーブル
50
+ @@timerQ = []
51
+
52
+ def IOT.input io
53
+ # IOキューから入力チャネルを一つ取り出す
54
+ ich = @@inTbl[io].shift
55
+ # キューが空になればエントリを削除
56
+ if @@inTbl[io].empty? then
57
+ @@inTbl.delete(io)
58
+ end
59
+ ich.input
60
+ end
61
+
62
+ def IOT.output io
63
+ # IOキューから出力チャネルを一つ取り出す
64
+ och = @@outTbl[io].shift
65
+ # キューが空になればエントリを削除
66
+ if @@outTbl[io].empty? then
67
+ @@outTbl.delete(io)
68
+ end
69
+ och.output
70
+ end
71
+
72
+ def IOT.exec
73
+ tm = nil
74
+ # IOキューを調べる
75
+ rds = @@inTbl.keys
76
+ wds = @@outTbl.keys
77
+ nxt = @@timerQ.first
78
+
79
+ # どちらも空の場合
80
+ if rds.empty? && wds.empty? && nxt == nil then
81
+ return nil
82
+ end
83
+ if nxt then
84
+ tm = nxt[:time] - Time.now
85
+ if tm < 0 then
86
+ tm = 0
87
+ end
88
+ end
89
+
90
+ CRuby::Coroutine.interruptible true # 割り込み可能にセット
91
+ ds = select(rds,wds,nil,tm)
92
+ CRuby::Coroutine.interruptible false # もとに戻す
93
+ if (ds == nil)
94
+ @@timerQ.shift
95
+ nxt[:chan].timeout
96
+ else
97
+ # 入力処理
98
+ ds[0].each {|io| input(io) }
99
+ # 出力処理
100
+ ds[1].each {|io| output(io) }
101
+ end
102
+ CRuby::Coroutine.dispatch
103
+ end
104
+ end
105
+
106
+ class CRuby::IoChannel < CRuby::Channel
107
+ include IOT
108
+
109
+ attr_reader :io
110
+
111
+ def initialize io
112
+ super()
113
+ @io = io
114
+ end
115
+
116
+ # 送信イベントを生成する
117
+ def sendEvt msg
118
+ pollFn = Proc.new { false }
119
+ blockFn = Proc.new {|flg,k|
120
+ if flg[0] == true then
121
+ CRuby::Coroutine.dispatch
122
+ end
123
+ @@outTbl[@io] <<= self
124
+ @sendQ.enqueue({'flg'=>flg,'msg'=>msg,'cont'=>k})
125
+ }
126
+ CRuby::Event.new([CRuby::Event::BEvt.new(pollFn, nil, blockFn)])
127
+ end
128
+
129
+ # 受信イベントを生成する
130
+ def recvEvt
131
+ pollFn = Proc.new { false }
132
+ blockFn = Proc.new {|flg,k|
133
+ if flg[0] == true then
134
+ CRuby::Coroutine.dispatch
135
+ end
136
+ @@inTbl[@io] <<= self
137
+ @recvQ.enqueue({'flg'=>flg,'cont'=>k})
138
+ }
139
+ CRuby::Event.new([CRuby::Event::BEvt.new(pollFn, nil, blockFn)])
140
+ end
141
+
142
+ # 入力処理を行う
143
+ def input
144
+ # EOFの処理
145
+ msg = @io.readpartial(4096)
146
+ # チャネルの受信待ちキューのプロセスを取り出す
147
+ item = @recvQ.dequeue
148
+ item['flg'][0] = true
149
+ item['cont'].call(msg)
150
+ end
151
+
152
+ # 出力処理を行う
153
+ def output
154
+ # チャネルの送信待ちキューのプロセスを取り出す
155
+ item = @sendQ.dequeue
156
+ item['flg'][0] = true
157
+ CRuby::Coroutine.enqueue(item['cont'])
158
+ io.write(item['msg'])
159
+ end
160
+
161
+ end
162
+
163
+ class CRuby::TimerChannel < CRuby::Channel
164
+ include IOT
165
+
166
+ # 送信イベントを生成する
167
+ def sendEvt msg
168
+ pollFn = Proc.new { false }
169
+ blockFn = Proc.new {|flg,k|
170
+ if flg[0] == true then
171
+ CRuby::Coroutine.dispatch
172
+ end
173
+ @@timerQ <<= {:time=>Time.now+msg,:chan=>self}
174
+ @@timerQ.sort! {|a,b| a[:time]<=>b[:time]}
175
+ @sendQ.enqueue({'flg'=>flg,'msg'=>msg,'cont'=>k})
176
+ }
177
+ CRuby::Event.new([CRuby::Event::BEvt.new(pollFn, nil, blockFn)])
178
+ end
179
+
180
+ def timeout
181
+ item = @sendQ.dequeue
182
+ item['flg'][0] = true
183
+ CRuby::Coroutine.enqueue(item['cont'])
184
+ end
185
+ end
186
+
187
+ class CRuby::TcpServerChannel < CRuby::IoChannel
188
+ include IOT
189
+
190
+ def input
191
+ s = @io.accept
192
+ # チャネルの受信待ちキューのプロセスを取り出す
193
+ item = @recvQ.dequeue
194
+ item['flg'][0] = true
195
+ item['cont'].call(CRuby::IoChannel.new(s))
196
+ end
197
+ end
@@ -0,0 +1,87 @@
1
+ require 'thread'
2
+
3
+ class CRuby::Queue
4
+
5
+ def initialize
6
+ @queue = []
7
+ end
8
+
9
+ def empty?
10
+ @queue == []
11
+ end
12
+
13
+ def enqueue val
14
+ @queue.push val
15
+ end
16
+
17
+ def dequeue
18
+ return @queue.shift
19
+ end
20
+
21
+ # このメソッドは別のクラスに移すべき
22
+ def poll
23
+ # dirtyなエントリを削除
24
+ @queue.delete_if {|item| item['flg']==[true] }
25
+ not empty?
26
+ end
27
+
28
+ end
29
+
30
+ module CRuby::Coroutine
31
+ @@rdyQ = CRuby::Queue.new
32
+
33
+ @@flag = false # 割り込み可能フラグ
34
+ @@mutex = Mutex.new
35
+ @@condv = ConditionVariable.new
36
+
37
+ def self.rdyq
38
+ p @@rdyQ
39
+ end
40
+
41
+ # メインスレッドに割り込みをかける
42
+ def self.interrupt
43
+ # 割り込み可能になるまで待つ
44
+ @@mutex.synchronize {
45
+ while not @@flag
46
+ @@condv.wait(@@mutex)
47
+ end
48
+ }
49
+ end
50
+
51
+ # 割り込み可能フラグをセットする
52
+ def self.interruptible flag
53
+ @@mutex.synchronize {
54
+ if flag
55
+ @@condv.signal
56
+ end
57
+ @@flag = flag
58
+ }
59
+ end
60
+
61
+ def self.empty?
62
+ @@rdyQ.empty?
63
+ end
64
+
65
+ def self.dispatch
66
+ k = @@rdyQ.dequeue
67
+ if k != nil then
68
+ k.call
69
+ assert false
70
+ end
71
+ IOT.exec
72
+ end
73
+
74
+ def self.spawn &f
75
+ callcc {|parentK|
76
+ @@rdyQ.enqueue(parentK)
77
+ f.call # 例外捕捉する必要あり
78
+ CRuby::Coroutine.dispatch
79
+ }
80
+ end
81
+
82
+ def self.enqueue k
83
+ @@rdyQ.enqueue(k)
84
+ end
85
+
86
+ end
87
+
@@ -0,0 +1,51 @@
1
+ class CRuby::Event
2
+ attr_reader :evts
3
+
4
+ class BEvt
5
+ attr_reader :pollFn, :doFn, :blockFn
6
+ def initialize (pollFn, doFn, blockFn)
7
+ @pollFn = pollFn
8
+ @doFn = doFn
9
+ @blockFn = blockFn
10
+ end
11
+ end
12
+
13
+ def initialize bevts
14
+ @evts = bevts
15
+ end
16
+
17
+ def sync
18
+ bevt = @evts.find {|evt| evt.pollFn.call() }
19
+ if bevt then
20
+ bevt.doFn.call()
21
+ else
22
+ callcc {|k|
23
+ flag = [false]
24
+ @evts.each {|evt| evt.blockFn.call(flag,k) }
25
+ CRuby::Coroutine.dispatch()
26
+ }
27
+ end
28
+ end
29
+
30
+ # 新しいイベントを生成する
31
+ def wrap &f
32
+ CRuby::Event.new(@evts.map {|evt|
33
+ doFn = Proc.new { f.call(evt.doFn.call()) }
34
+ blockFn = Proc.new {|flg,k| # k はsync実行後の継続
35
+ callcc {|kk| # kk はblockFn実行後の継続
36
+ k.call(f.call(callcc {|kkk| # kkk は元のblockFn実行後の継続
37
+ kk.call(evt.blockFn.call(flg,kkk))
38
+ }))}}
39
+ BEvt.new(evt.pollFn,doFn,blockFn)
40
+ })
41
+ end
42
+
43
+ # イベントを選択する
44
+ def self.choose evts
45
+ CRuby::Event.new((evts.map {|ev| ev.evts}).flatten)
46
+ end
47
+
48
+ def self.select evts
49
+ CRuby::Event.choose(evts).sync
50
+ end
51
+ end
@@ -0,0 +1,9 @@
1
+ module Cruby #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 1
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,56 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class CrubyTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def test_truth
9
+ assert true
10
+ end
11
+
12
+ def test_cruby_queue
13
+ q = CRuby::Queue.new
14
+ assert(q.empty?)
15
+
16
+ q.enqueue("foo")
17
+ assert(!q.empty?)
18
+ assert_equal("foo", q.dequeue)
19
+ assert(q.empty?)
20
+ end
21
+
22
+ def test_cruby_coroutine
23
+ CRuby::Coroutine.spawn { assert(true) }
24
+ end
25
+
26
+ def test_cruby_channel
27
+ ch = CRuby::Channel.new
28
+
29
+ CRuby::Coroutine.spawn { ch.send("hello"); assert(true) }
30
+ assert_equal("hello", ch.recv)
31
+ end
32
+
33
+ def test_cruby_select
34
+ ch1 = CRuby::Channel.new
35
+ ch2 = CRuby::Channel.new
36
+ CRuby::Coroutine.spawn { ch2.send("hello") }
37
+ assert_equal("hello",
38
+ CRuby::Event.select([
39
+ ch1.recvEvt.wrap {|m| assert(false); m},
40
+ ch2.recvEvt.wrap {|m| assert(true); m}
41
+ ])
42
+ )
43
+ end
44
+
45
+ def test_cruby_timer
46
+ timer = CRuby::TimerChannel.new
47
+ timer.send(0.5)
48
+ assert(true)
49
+ end
50
+
51
+ def test_cruby_stdout
52
+ chout = CRuby::IoChannel.new(STDOUT)
53
+ chout.send("\nhoge\n")
54
+ assert(true)
55
+ end
56
+ end
@@ -0,0 +1,2 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/cruby'
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0
3
+ specification_version: 1
4
+ name: cruby
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2006-11-08 00:00:00 +09:00
8
+ summary: CRuby is a library that provids concurrent programming in Ruby
9
+ require_paths:
10
+ - lib
11
+ email: hattori@isp.co.jp
12
+ homepage: http://cruby.rubyforge.org
13
+ rubyforge_project: cruby
14
+ description: CRuby is a library that provids concurrent programming in Ruby
15
+ autorequire: cruby
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
+ post_install_message:
29
+ authors:
30
+ - hattori
31
+ files:
32
+ - README
33
+ - CHANGELOG
34
+ - Rakefile
35
+ - test/cruby_test.rb
36
+ - test/test_helper.rb
37
+ - lib/crbtk.rb
38
+ - lib/cruby
39
+ - lib/cruby.rb
40
+ - lib/cruby/version.rb
41
+ - lib/cruby/coroutine.rb
42
+ - lib/cruby/event.rb
43
+ - lib/cruby/channel.rb
44
+ - examples/prime.rb
45
+ - examples/fib.rb
46
+ - examples/echoc.rb
47
+ - examples/echod.rb
48
+ test_files: []
49
+
50
+ rdoc_options:
51
+ - --quiet
52
+ - --title
53
+ - cruby documentation
54
+ - --opname
55
+ - index.html
56
+ - --line-numbers
57
+ - --main
58
+ - README
59
+ - --inline-source
60
+ - --exclude
61
+ - ^(examples|extras)/
62
+ extra_rdoc_files:
63
+ - README
64
+ - CHANGELOG
65
+ executables: []
66
+
67
+ extensions: []
68
+
69
+ requirements: []
70
+
71
+ dependencies: []
72
+