green 0.0.1 → 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +17 -1
- data/Gemfile.lock +61 -8
- data/README.md +46 -1
- data/green.gemspec +24 -5
- data/lib/active_record/connection_adapters/green_mysql2_adapter.rb +92 -0
- data/lib/green/activerecord.rb +21 -0
- data/lib/green/connection_pool.rb +72 -0
- data/lib/green/event.rb +3 -7
- data/lib/green/ext.rb +10 -2
- data/lib/green/group.rb +20 -6
- data/lib/green/hub/em.rb +49 -9
- data/lib/green/hub/nio4r.rb +147 -0
- data/lib/green/hub.rb +12 -3
- data/lib/green/monkey.rb +11 -13
- data/lib/green/mysql2.rb +16 -0
- data/lib/green/semaphore.rb +136 -6
- data/lib/green/socket.rb +124 -0
- data/lib/green/zmq.rb +92 -0
- data/lib/green-em/em-http.rb +3 -4
- data/lib/green.rb +92 -33
- data/spec/green/activerecord_spec.rb +100 -0
- data/spec/green/connection_pool_spec.rb +45 -0
- data/spec/green/event_spec.rb +24 -0
- data/spec/green/group_spec.rb +68 -0
- data/spec/green/monkey_spec.rb +22 -0
- data/spec/green/mysql2_spec.rb +52 -0
- data/spec/green/semaphore_spec.rb +169 -0
- data/spec/green/socket_spec.rb +26 -0
- data/spec/green/tcpsocket_spec.rb +417 -0
- data/spec/green/zmq_spec.rb +121 -0
- data/spec/green_spec.rb +37 -0
- data/spec/helpers.rb +0 -0
- data/spec/spec_helper.rb +32 -0
- metadata +56 -9
- data/Readme.md +0 -55
- data/lib/green/tcp_socket.rb +0 -25
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'nio'
|
2
|
+
require 'algorithms'
|
3
|
+
|
4
|
+
class Green
|
5
|
+
class Hub
|
6
|
+
class Nio4r < Hub
|
7
|
+
class SocketWaiter < Green::SocketWaiter
|
8
|
+
attr_reader :reactor
|
9
|
+
def initialize(reactor, socket)
|
10
|
+
super socket
|
11
|
+
@reactor = reactor
|
12
|
+
end
|
13
|
+
|
14
|
+
def wait_read
|
15
|
+
make_monitor :r
|
16
|
+
end
|
17
|
+
|
18
|
+
def wait_write
|
19
|
+
make_monitor :w
|
20
|
+
end
|
21
|
+
|
22
|
+
def make_monitor(interest)
|
23
|
+
m = reactor.selector.register(socket, interest)
|
24
|
+
g = Green.current
|
25
|
+
m.value = proc { g.switch }
|
26
|
+
Green.hub.switch
|
27
|
+
ensure
|
28
|
+
reactor.selector.deregister socket
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Timer
|
33
|
+
attr_reader :reactor, :fire_at, :clb
|
34
|
+
def initialize(reactor, fire_at, &clb)
|
35
|
+
@reactor, @fire_at, @clb = reactor, fire_at, clb
|
36
|
+
end
|
37
|
+
|
38
|
+
def run
|
39
|
+
@runned = true
|
40
|
+
clb.call
|
41
|
+
end
|
42
|
+
|
43
|
+
def green_cancel
|
44
|
+
return if @canceled || @runned
|
45
|
+
@canceled = true
|
46
|
+
reactor.cancel_timer self
|
47
|
+
end
|
48
|
+
|
49
|
+
def <=>(v)
|
50
|
+
@fire_at <=> v.fire_at
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
MIN_TIMEOUT = 0.0001
|
55
|
+
MAX_TIMEOUT = 0.01
|
56
|
+
|
57
|
+
attr_reader :callbacks, :timers, :cancel_timers
|
58
|
+
def initialize(*args)
|
59
|
+
@callbacks = []
|
60
|
+
@timers = Containers::MinHeap.new
|
61
|
+
@cancel_timers = {}
|
62
|
+
super
|
63
|
+
end
|
64
|
+
|
65
|
+
def reactor_running?
|
66
|
+
@reactor_running
|
67
|
+
end
|
68
|
+
|
69
|
+
def run
|
70
|
+
@reactor_running = true
|
71
|
+
@selector = NIO::Selector.new
|
72
|
+
while @reactor_running
|
73
|
+
run_callbacks
|
74
|
+
run_timers
|
75
|
+
@selector.select(time_till_first_event) do |m|
|
76
|
+
m.value.call
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def run_timers
|
82
|
+
now = Time.now
|
83
|
+
while (t = @timers.next)
|
84
|
+
if t.fire_at <= now
|
85
|
+
@timers.pop
|
86
|
+
if @cancel_timers[t]
|
87
|
+
@cancel_timers.delete t
|
88
|
+
else
|
89
|
+
t.run
|
90
|
+
end
|
91
|
+
else
|
92
|
+
break
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def run_callbacks
|
98
|
+
jobs, @callbacks = @callbacks, []
|
99
|
+
begin
|
100
|
+
i = 0
|
101
|
+
while i < jobs.size
|
102
|
+
job = jobs[i]
|
103
|
+
jobs[i] = nil
|
104
|
+
job.call
|
105
|
+
i += 1
|
106
|
+
end
|
107
|
+
ensure
|
108
|
+
@callbacks[0...0] = jobs[i..-1] if i < jobs.size
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def time_till_first_event
|
113
|
+
if @callbacks.size > 0
|
114
|
+
MIN_TIMEOUT
|
115
|
+
elsif @timers.size > 0
|
116
|
+
@timers.next.fire_at - Time.now + MIN_TIMEOUT
|
117
|
+
else
|
118
|
+
MAX_TIMEOUT
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def selector
|
123
|
+
@selector
|
124
|
+
end
|
125
|
+
|
126
|
+
def cancel_timer(timer)
|
127
|
+
@cancel_timers[timer] = true
|
128
|
+
end
|
129
|
+
|
130
|
+
def timer(n, &blk)
|
131
|
+
@timers << Timer.new(self, Time.now + n, &blk)
|
132
|
+
end
|
133
|
+
|
134
|
+
def callback(cb=nil, &blk)
|
135
|
+
@callbacks << (cb || blk)
|
136
|
+
end
|
137
|
+
|
138
|
+
def socket_waiter(socket)
|
139
|
+
SocketWaiter.new self, socket
|
140
|
+
end
|
141
|
+
|
142
|
+
def stop
|
143
|
+
@reactor_running = false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
data/lib/green/hub.rb
CHANGED
@@ -14,17 +14,18 @@ class Green
|
|
14
14
|
g.switch
|
15
15
|
end
|
16
16
|
|
17
|
-
def wait(
|
17
|
+
def wait(proc = nil, &cancel_clb)
|
18
18
|
switch
|
19
19
|
rescue => e
|
20
|
-
|
20
|
+
(proc || cancel_clb).call
|
21
21
|
raise e
|
22
22
|
end
|
23
23
|
|
24
24
|
def sleep(n)
|
25
25
|
g = Green.current
|
26
26
|
t = timer(n) { g.switch }
|
27
|
-
wait t
|
27
|
+
wait { t.green_cancel }
|
28
|
+
t
|
28
29
|
end
|
29
30
|
|
30
31
|
def run
|
@@ -38,5 +39,13 @@ class Green
|
|
38
39
|
def callback(&blk)
|
39
40
|
raise "override"
|
40
41
|
end
|
42
|
+
|
43
|
+
def socket_waiter(socket)
|
44
|
+
raise "override"
|
45
|
+
end
|
46
|
+
|
47
|
+
def stop
|
48
|
+
raise "override"
|
49
|
+
end
|
41
50
|
end
|
42
51
|
end
|
data/lib/green/monkey.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
end
|
1
|
+
require 'green/socket'
|
2
|
+
|
3
|
+
original_verbosity = $VERBOSE
|
4
|
+
$VERBOSE = nil
|
5
|
+
|
6
|
+
Socket = Green::Socket
|
7
|
+
TCPSocket = Green::TCPSocket
|
8
|
+
TCPServer = Green::TCPServer
|
9
|
+
|
10
|
+
|
11
|
+
$VERBOSE = original_verbosity
|
data/lib/green/mysql2.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'mysql2'
|
2
|
+
class Green
|
3
|
+
module Mysql2
|
4
|
+
class Client < ::Mysql2::Client
|
5
|
+
def query(sql, opts={})
|
6
|
+
super(sql, opts.merge(:async => true))
|
7
|
+
green_waiter.wait_read
|
8
|
+
async_result
|
9
|
+
end
|
10
|
+
|
11
|
+
def green_waiter
|
12
|
+
@green_waiter ||= Green.hub.socket_waiter(Socket.for_fd(self.socket))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/green/semaphore.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
class Green
|
2
2
|
class Semaphore
|
3
|
-
|
4
|
-
attr_accessor :counter
|
3
|
+
attr_accessor :counter, :value
|
5
4
|
def initialize(value = 1)
|
5
|
+
@value = value
|
6
6
|
@counter = value
|
7
7
|
@links = []
|
8
8
|
end
|
9
9
|
|
10
|
+
def wait_links
|
11
|
+
@wait_links ||= []
|
12
|
+
end
|
13
|
+
|
10
14
|
def acquire
|
11
15
|
if counter > 0
|
12
16
|
self.counter -= 1
|
@@ -14,7 +18,7 @@ class Green
|
|
14
18
|
else
|
15
19
|
g = Green.current
|
16
20
|
clb = rawlink { g.switch }
|
17
|
-
Green.hub.wait
|
21
|
+
Green.hub.wait { unlink clb }
|
18
22
|
self.counter -= 1
|
19
23
|
true
|
20
24
|
end
|
@@ -22,10 +26,11 @@ class Green
|
|
22
26
|
|
23
27
|
def release
|
24
28
|
self.counter += 1
|
29
|
+
wait_links.dup.each(&:call)
|
25
30
|
if @links.size > 0
|
26
31
|
l = @links.pop
|
27
32
|
Green.hub.callback { l.call }
|
28
|
-
end
|
33
|
+
end
|
29
34
|
end
|
30
35
|
|
31
36
|
def rawlink(&clb)
|
@@ -37,8 +42,133 @@ class Green
|
|
37
42
|
@links.delete clb
|
38
43
|
end
|
39
44
|
|
40
|
-
def
|
41
|
-
|
45
|
+
def wait(v = value)
|
46
|
+
if counter >= v
|
47
|
+
return counter
|
48
|
+
else
|
49
|
+
g = Green.current
|
50
|
+
clb = proc do
|
51
|
+
if counter >= v && @links.size == 0
|
52
|
+
wait_links.delete clb
|
53
|
+
Green.hub.callback { g.switch }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
wait_links << clb
|
57
|
+
Green.hub.wait { wait_links.delete clb }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def wait_avaliable
|
62
|
+
wait value - 1
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# With Ruby compatible API
|
67
|
+
class Mutex < Semaphore
|
68
|
+
def initialize
|
69
|
+
super 1
|
70
|
+
@slept = {}
|
71
|
+
end
|
72
|
+
|
73
|
+
def synchronize
|
74
|
+
lock
|
75
|
+
yield
|
76
|
+
ensure
|
77
|
+
unlock
|
78
|
+
end
|
79
|
+
|
80
|
+
def lock
|
81
|
+
if Green.current.locals["mutex_locked_#{self.object_id}"]
|
82
|
+
Green.current.locals.delete "mutex_locked_#{self.object_id}"
|
83
|
+
raise Green::GreenError.new
|
84
|
+
end
|
85
|
+
Green.current.locals["mutex_locked_#{self.object_id}"] = true
|
86
|
+
acquire
|
87
|
+
end
|
88
|
+
|
89
|
+
def unlock
|
90
|
+
raise Green::GreenError.new unless Green.current.locals["mutex_locked_#{self.object_id}"]
|
91
|
+
Green.current.locals.delete "mutex_locked_#{self.object_id}"
|
92
|
+
release
|
93
|
+
end
|
94
|
+
|
95
|
+
def _wakeup(green)
|
96
|
+
if @slept.delete(green)
|
97
|
+
Green.hub.callback { green.switch }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def sleep(timeout = nil)
|
102
|
+
unlock
|
103
|
+
beg = Time.now
|
104
|
+
current = Green.current
|
105
|
+
@slept[current] = true
|
106
|
+
begin
|
107
|
+
if timeout
|
108
|
+
t = Green.hub.timer(timeout) { _wakeup(current) }
|
109
|
+
Green.hub.switch
|
110
|
+
t.green_cancel
|
111
|
+
else
|
112
|
+
Green.hub.switch
|
113
|
+
end
|
114
|
+
ensure
|
115
|
+
@slept.delete current
|
116
|
+
end
|
117
|
+
yield if block_given?
|
118
|
+
lock
|
119
|
+
Time.now - beg
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class ConditionVariable
|
124
|
+
def initialize
|
125
|
+
@waiters = []
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup.
|
130
|
+
#
|
131
|
+
# If +timeout+ is given, this method returns after +timeout+ seconds passed,
|
132
|
+
# even if no other thread doesn't signal.
|
133
|
+
#
|
134
|
+
def wait(mutex, timeout=nil)
|
135
|
+
current = Green.current
|
136
|
+
pair = [mutex, current]
|
137
|
+
@waiters << pair
|
138
|
+
mutex.sleep timeout do
|
139
|
+
@waiters.delete pair
|
140
|
+
end
|
141
|
+
self
|
142
|
+
end
|
143
|
+
|
144
|
+
def _wakeup(mutex, green)
|
145
|
+
if alive = green.alive?
|
146
|
+
Green.hub.callback {
|
147
|
+
mutex._wakeup(green)
|
148
|
+
}
|
149
|
+
end
|
150
|
+
alive
|
151
|
+
end
|
152
|
+
|
153
|
+
#
|
154
|
+
# Wakes up the first thread in line waiting for this lock.
|
155
|
+
#
|
156
|
+
def signal
|
157
|
+
while (pair = @waiters.shift)
|
158
|
+
break if _wakeup(*pair)
|
159
|
+
end
|
160
|
+
self
|
161
|
+
end
|
162
|
+
|
163
|
+
#
|
164
|
+
# Wakes up all threads waiting for this lock.
|
165
|
+
#
|
166
|
+
def broadcast
|
167
|
+
@waiters.each do |mutex, green|
|
168
|
+
_wakeup(mutex, green)
|
169
|
+
end
|
170
|
+
@waiters.clear
|
171
|
+
self
|
42
172
|
end
|
43
173
|
end
|
44
174
|
end
|
data/lib/green/socket.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
require "fcntl"
|
2
|
+
require 'socket'
|
3
|
+
require 'kgio'
|
4
|
+
|
5
|
+
class Green
|
6
|
+
|
7
|
+
ERRORS = Errno::constants.each_with_object({}) do |c, h|
|
8
|
+
const = Errno.const_get(c)
|
9
|
+
h[const::Errno] = const
|
10
|
+
end
|
11
|
+
|
12
|
+
# TODO puts
|
13
|
+
class Socket < ::Socket
|
14
|
+
READ_BUFFER_SIZE = 65536
|
15
|
+
|
16
|
+
include Kgio::SocketMethods
|
17
|
+
|
18
|
+
def write(str)
|
19
|
+
kgio_write(str)
|
20
|
+
str.bytesize
|
21
|
+
end
|
22
|
+
|
23
|
+
def read(length = nil, buffer = nil)
|
24
|
+
res = []
|
25
|
+
readed = 0
|
26
|
+
begin # begin ... while
|
27
|
+
need_read = if length
|
28
|
+
length - readed
|
29
|
+
else
|
30
|
+
READ_BUFFER_SIZE
|
31
|
+
end
|
32
|
+
data = kgio_read(need_read)
|
33
|
+
if data.nil? && length.nil? && readed == 0
|
34
|
+
return ''
|
35
|
+
elsif data.nil? && readed == 0
|
36
|
+
return nil
|
37
|
+
elsif data.nil?
|
38
|
+
return buffer ? buffer.replace(res * '') : res * ''
|
39
|
+
else
|
40
|
+
readed += data.size
|
41
|
+
res << data
|
42
|
+
end
|
43
|
+
end while length != readed
|
44
|
+
return buffer ? buffer.replace(res * '') : res * ''
|
45
|
+
end
|
46
|
+
|
47
|
+
def recv(maxlen, flags = 0)
|
48
|
+
recv_nonblock(maxlen)
|
49
|
+
rescue Errno::EAGAIN
|
50
|
+
waiter.wait_read
|
51
|
+
retry
|
52
|
+
end
|
53
|
+
|
54
|
+
def send(mesg, flags, dest_sockaddr = nil)
|
55
|
+
# FIXME
|
56
|
+
write mesg
|
57
|
+
end
|
58
|
+
|
59
|
+
def kgio_wait_readable
|
60
|
+
waiter.wait_write
|
61
|
+
end
|
62
|
+
|
63
|
+
def kgio_wait_readable
|
64
|
+
waiter.wait_read
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.accept_socket_class
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def accept
|
72
|
+
s, a = accept_nonblock
|
73
|
+
[self.class.accept_socket_class.for_fd(s.fileno), a]
|
74
|
+
rescue Errno::EAGAIN
|
75
|
+
waiter.wait_read
|
76
|
+
retry
|
77
|
+
end
|
78
|
+
|
79
|
+
def connect(sock_addr)
|
80
|
+
connect_nonblock(sock_addr)
|
81
|
+
rescue Errno::EINPROGRESS
|
82
|
+
error, = getsockopt(::Socket::SOL_SOCKET, ::Socket::SO_ERROR).unpack('i')
|
83
|
+
if error != 0
|
84
|
+
raise ERRORS[error]
|
85
|
+
else
|
86
|
+
waiter.wait_write
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def waiter
|
91
|
+
@waiter ||= Green.hub.socket_waiter(self)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class TCPSocket < Socket
|
96
|
+
def initialize(remote_host, remote_port, local_host = nil, local_port = nil)
|
97
|
+
addrinfo = Addrinfo.tcp(remote_host, remote_port)
|
98
|
+
super(addrinfo.ipv4? ? :INET : :INET6, :STREAM, 0)
|
99
|
+
if local_host && local_port
|
100
|
+
bind(Addrinfo.tcp(local_host, local_port))
|
101
|
+
end
|
102
|
+
connect addrinfo
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class TCPServer < Socket
|
107
|
+
def initialize(host, port)
|
108
|
+
addrinfo = Addrinfo.tcp(host, port)
|
109
|
+
super(addrinfo.ipv4? ? :INET : :INET6, :STREAM, 0)
|
110
|
+
setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
|
111
|
+
bind(addrinfo)
|
112
|
+
listen(5)
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def self.accept_socket_class
|
117
|
+
TCPSocket
|
118
|
+
end
|
119
|
+
|
120
|
+
def accept
|
121
|
+
super[0]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/lib/green/zmq.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'green'
|
2
|
+
require 'ffi-rzmq'
|
3
|
+
|
4
|
+
class Green
|
5
|
+
module ZMQ
|
6
|
+
class Waiter
|
7
|
+
attr_reader :socket_waiter, :waiters
|
8
|
+
def initialize(fd)
|
9
|
+
@socket_waiter = Green.hub.socket_waiter(Socket.for_fd(fd))
|
10
|
+
@waiters = []
|
11
|
+
@notifier = Green.spawn do
|
12
|
+
while true
|
13
|
+
@socket_waiter.wait_read
|
14
|
+
wake
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def lock
|
20
|
+
g = Green.current
|
21
|
+
@waiters << g
|
22
|
+
Green.hub.wait { @waiters.delete g }
|
23
|
+
end
|
24
|
+
|
25
|
+
def wake
|
26
|
+
w = @waiters.shift
|
27
|
+
Green.hub.callback { w.switch } if w
|
28
|
+
end
|
29
|
+
|
30
|
+
def cancel
|
31
|
+
@notifier.kill
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module ZMQ
|
38
|
+
class Context
|
39
|
+
alias :original_terminate :terminate
|
40
|
+
def terminate
|
41
|
+
Green.hub.callback do
|
42
|
+
original_terminate
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Socket
|
48
|
+
def initialize(*args)
|
49
|
+
super
|
50
|
+
fd, = [].tap { |a| getsockopt(ZMQ::FD, a) }
|
51
|
+
@waiter = Green::ZMQ::Waiter.new fd
|
52
|
+
end
|
53
|
+
|
54
|
+
alias :bsendmsg :sendmsg
|
55
|
+
def sendmsg(message, flags = 0)
|
56
|
+
return bsendmsg(message, flags) if (flags & ZMQ::NonBlocking) != 0
|
57
|
+
flags |= ZMQ::NonBlocking
|
58
|
+
loop do
|
59
|
+
rc = bsendmsg message, flags
|
60
|
+
if rc == -1 && ZMQ::Util.errno == EAGAIN
|
61
|
+
@waiter.lock
|
62
|
+
else
|
63
|
+
@waiter.wake
|
64
|
+
return rc
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
alias :brecvmsg :recvmsg
|
70
|
+
def recvmsg(message, flags = 0)
|
71
|
+
return brecvmsg(message, flags) if (flags & ZMQ::NonBlocking) != 0
|
72
|
+
flags |= ZMQ::NonBlocking
|
73
|
+
loop do
|
74
|
+
rc = brecvmsg message, flags
|
75
|
+
if rc == -1 && ZMQ::Util.errno == EAGAIN
|
76
|
+
@waiter.lock
|
77
|
+
else
|
78
|
+
@waiter.wake
|
79
|
+
return rc
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
alias :original_close :close
|
85
|
+
def close
|
86
|
+
@waiter.cancel
|
87
|
+
Green.hub.callback do
|
88
|
+
original_close
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/green-em/em-http.rb
CHANGED
@@ -12,15 +12,14 @@ module EventMachine
|
|
12
12
|
alias :a#{type} :#{type}
|
13
13
|
def #{type}(options = {}, &blk)
|
14
14
|
g = Green.current
|
15
|
-
|
16
15
|
conn = setup_request(:#{type}, options, &blk)
|
17
16
|
if conn.error.nil?
|
18
17
|
conn.callback { g.switch(conn) }
|
19
|
-
conn.errback { g.throw(HTTPException.new
|
18
|
+
conn.errback { g.throw(HTTPException.new) }
|
20
19
|
|
21
|
-
Green.hub.wait
|
20
|
+
Green.hub.wait { conn.green_cancel }
|
22
21
|
else
|
23
|
-
raise HTTPException.new
|
22
|
+
raise HTTPException.new
|
24
23
|
end
|
25
24
|
end
|
26
25
|
]
|