-
-
Notifications
You must be signed in to change notification settings - Fork 105
Expand file tree
/
Copy pathko1.rb
More file actions
executable file
·143 lines (125 loc) · 2.53 KB
/
ko1.rb
File metadata and controls
executable file
·143 lines (125 loc) · 2.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env ruby
require 'fiber'
require 'io/nonblock'
require 'open-uri'
class Scheduler
def initialize
@ready = []
@waiting = [] # [[f, type, opts], ...]
end
def now
Process.clock_gettime(Process::CLOCK_MONOTONIC)
end
def wait_readable_fd(fd)
wait_readable(::IO.for_fd(fd, autoclose: false))
end
def wait_readable(io)
p wait_readable: io
Fiber.yield :wait_readable, io
true
end
def wait_any(io, events, timeout)
p [:wait_any, io, events, timeout]
case events
when IO::WAIT_READABLE
Fiber.yield :wait_readable, io
when IO::WAIT_WRITABLE
Fiber.yield :wait_writable, io
when IO::WAIT_READABLE | IO::WAIT_WRITABLE
Fiber.yield :wait_any, io
end
true
end
# Wrapper for rb_wait_for_single_fd(int) C function.
def wait_for_single_fd(fd, events, duration)
wait_any(::IO.for_fd(fd, autoclose: false), events, duration)
end
# Sleep the current task for the specified duration, or forever if not
# specified.
# @param duration [#to_f] the amount of time to sleep.
def wait_sleep(duration = nil)
Fiber.yield :sleep, self.now + duration
end
def fiber
@ready << f = Fiber.new(blocking: false){
yield
:exit
}
f
end
def schedule_ready
while f = @ready.shift
wait, opts = f.resume
case wait
when :exit
# ok
else
@waiting << [f, wait, opts]
end
end
end
def run
until @ready.empty? && @waiting.empty?
schedule_ready
next if @waiting.empty?
p @waiting
wakeup_time = nil
wakeup_fiber = nil
rs = []
ws = []
now = self.now
@waiting.each{|f, type, opt|
case type
when :sleep
t = opt
if !wakeup_time || wakeup_time > t
wakeup_time = t
wakeup_fiber = f
end
when :wait_readable
io = opt
rs << io
when :wait_writable
io = opt
ws << io
when :wait_any
io = opt
rs << io
ws << io
end
}
if wakeup_time
if wakeup_time > now
dur = wakeup_time - self.now
else
@ready << wakeup_fiber
@waiting.delete_if{|f,| f == wakeup_fiber}
end
end
pp dur
rs, ws, es = IO.select rs, ws, nil, dur
pp selected: [rs, ws, es]
[*rs, *ws].each{|io|
@waiting.delete_if{|f, type, opt|
if opt == io
p [:ready, f, io]
@ready << f
true
end
}
}
pp after: @waiting
end
end
def enter_blocking_region
#pp caller(0)
end
def exit_blocking_region
#pp caller(0)
end
end
Thread.current.scheduler = Scheduler.new
Fiber do
URI.open('http://www.ruby-lang.org/'){|f| p f.gets}
end
Thread.current.scheduler.run