cruby 0.0.1

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