cool.io 1.4.1-x64-mingw32
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.
- checksums.yaml +7 -0
- data/.gitignore +29 -0
- data/.rspec +3 -0
- data/.travis.yml +13 -0
- data/CHANGES.md +229 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +166 -0
- data/Rakefile +79 -0
- data/cool.io.gemspec +29 -0
- data/examples/callbacked_echo_server.rb +24 -0
- data/examples/dslified_echo_client.rb +34 -0
- data/examples/dslified_echo_server.rb +24 -0
- data/examples/echo_client.rb +38 -0
- data/examples/echo_server.rb +27 -0
- data/examples/google.rb +9 -0
- data/ext/cool.io/.gitignore +5 -0
- data/ext/cool.io/cool.io.h +59 -0
- data/ext/cool.io/cool.io_ext.c +25 -0
- data/ext/cool.io/ev_wrap.h +10 -0
- data/ext/cool.io/extconf.rb +61 -0
- data/ext/cool.io/iowatcher.c +189 -0
- data/ext/cool.io/libev.c +8 -0
- data/ext/cool.io/loop.c +261 -0
- data/ext/cool.io/stat_watcher.c +269 -0
- data/ext/cool.io/timer_watcher.c +219 -0
- data/ext/cool.io/utils.c +122 -0
- data/ext/cool.io/watcher.c +264 -0
- data/ext/cool.io/watcher.h +71 -0
- data/ext/iobuffer/extconf.rb +9 -0
- data/ext/iobuffer/iobuffer.c +767 -0
- data/ext/libev/Changes +507 -0
- data/ext/libev/LICENSE +37 -0
- data/ext/libev/README +58 -0
- data/ext/libev/README.embed +3 -0
- data/ext/libev/ev.c +5054 -0
- data/ext/libev/ev.h +853 -0
- data/ext/libev/ev_epoll.c +282 -0
- data/ext/libev/ev_kqueue.c +214 -0
- data/ext/libev/ev_poll.c +148 -0
- data/ext/libev/ev_port.c +185 -0
- data/ext/libev/ev_select.c +362 -0
- data/ext/libev/ev_vars.h +204 -0
- data/ext/libev/ev_win32.c +163 -0
- data/ext/libev/ev_wrap.h +200 -0
- data/ext/libev/ruby_gil.patch +97 -0
- data/ext/libev/test_libev_win32.c +123 -0
- data/ext/libev/win_select.patch +115 -0
- data/lib/.gitignore +2 -0
- data/lib/cool.io.rb +34 -0
- data/lib/cool.io/async_watcher.rb +43 -0
- data/lib/cool.io/custom_require.rb +9 -0
- data/lib/cool.io/dns_resolver.rb +219 -0
- data/lib/cool.io/dsl.rb +139 -0
- data/lib/cool.io/io.rb +194 -0
- data/lib/cool.io/iowatcher.rb +17 -0
- data/lib/cool.io/listener.rb +99 -0
- data/lib/cool.io/loop.rb +122 -0
- data/lib/cool.io/meta.rb +49 -0
- data/lib/cool.io/server.rb +75 -0
- data/lib/cool.io/socket.rb +230 -0
- data/lib/cool.io/timer_watcher.rb +17 -0
- data/lib/cool.io/version.rb +7 -0
- data/lib/coolio.rb +2 -0
- data/spec/async_watcher_spec.rb +57 -0
- data/spec/dns_spec.rb +43 -0
- data/spec/iobuffer_spec.rb +147 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/stat_watcher_spec.rb +77 -0
- data/spec/tcp_server_spec.rb +225 -0
- data/spec/tcp_socket_spec.rb +185 -0
- data/spec/timer_watcher_spec.rb +59 -0
- data/spec/udp_socket_spec.rb +58 -0
- data/spec/unix_listener_spec.rb +25 -0
- data/spec/unix_server_spec.rb +27 -0
- metadata +182 -0
data/Rakefile
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rake/clean'
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
RSpec::Core::RakeTask.new
|
6
|
+
|
7
|
+
RSpec::Core::RakeTask.new(:rcov) do |task|
|
8
|
+
task.rcov = true
|
9
|
+
end
|
10
|
+
|
11
|
+
task :default => %w(compile spec)
|
12
|
+
|
13
|
+
require 'rdoc/task'
|
14
|
+
Rake::RDocTask.new do |rdoc|
|
15
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
16
|
+
|
17
|
+
rdoc.rdoc_dir = 'rdoc'
|
18
|
+
rdoc.title = "cool.io #{version}"
|
19
|
+
rdoc.rdoc_files.include('README*')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'rake/extensiontask'
|
24
|
+
|
25
|
+
spec = eval(File.read("cool.io.gemspec"))
|
26
|
+
|
27
|
+
def configure_cross_compilation(ext)
|
28
|
+
unless RUBY_PLATFORM =~ /mswin|mingw/
|
29
|
+
ext.cross_compile = true
|
30
|
+
ext.cross_platform = ['x86-mingw32', 'x64-mingw32']
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Rake::ExtensionTask.new('iobuffer_ext', spec) do |ext|
|
35
|
+
ext.ext_dir = 'ext/iobuffer'
|
36
|
+
configure_cross_compilation(ext)
|
37
|
+
end
|
38
|
+
|
39
|
+
Rake::ExtensionTask.new('cool.io_ext', spec) do |ext|
|
40
|
+
ext.ext_dir = 'ext/cool.io'
|
41
|
+
configure_cross_compilation(ext)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Note that this rake-compiler-dock rake task dose not support bundle install(1) --path option.
|
45
|
+
# Please use bundle install instead when you execute this rake task.
|
46
|
+
namespace :build do
|
47
|
+
desc 'Build gems for Windows per rake-compiler-dock'
|
48
|
+
task :windows do
|
49
|
+
require 'rake_compiler_dock'
|
50
|
+
RakeCompilerDock.sh <<-CROSS
|
51
|
+
bundle
|
52
|
+
rake cross native gem RUBY_CC_VERSION='2.0.0:2.1.6:2.2.2'
|
53
|
+
CROSS
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# adapted from http://flavoriffic.blogspot.com/2009/06/easily-valgrind-gdb-your-ruby-c.html
|
58
|
+
def specs_command
|
59
|
+
require "find"
|
60
|
+
files = []
|
61
|
+
Find.find("spec") do |f|
|
62
|
+
files << f if File.basename(f) =~ /.*spec.*\.rb$/
|
63
|
+
end
|
64
|
+
cmdline = "#{RUBY} -I.:lib:ext:spec \
|
65
|
+
-e '%w[#{files.join(' ')}].each { |f| require f }'"
|
66
|
+
end
|
67
|
+
|
68
|
+
namespace :spec do
|
69
|
+
desc "run specs with valgrind"
|
70
|
+
task :valgrind => :compile do
|
71
|
+
system "valgrind --num-callers=15 \
|
72
|
+
--partial-loads-ok=yes --undef-value-errors=no \
|
73
|
+
--tool=memcheck --leak-check=yes --track-fds=yes \
|
74
|
+
--show-reachable=yes #{specs_command}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
CLEAN.include "**/*.rbc", "**/*.o", "**/*.so", "**/*.bundle"
|
79
|
+
CLEAN.exclude "vendor/**/*.rbc", "vendor/**/*.o", "vendor/**/*.so", "vendor/**/*.bundle"
|
data/cool.io.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "cool.io/version"
|
4
|
+
|
5
|
+
module Cool
|
6
|
+
# Allow Coolio module to be referenced as Cool.io
|
7
|
+
def self.io; Coolio; end
|
8
|
+
end
|
9
|
+
|
10
|
+
Gem::Specification.new do |s|
|
11
|
+
s.name = "cool.io"
|
12
|
+
s.version = Coolio::VERSION
|
13
|
+
s.authors = ["Tony Arcieri", "Masahiro Nakagawa"]
|
14
|
+
s.email = ["tony.arcieri@gmail.com", "repeatedly@gmail.com"]
|
15
|
+
s.homepage = "http://coolio.github.com"
|
16
|
+
s.summary = "A cool framework for doing high performance I/O in Ruby"
|
17
|
+
s.description = "Cool.io provides a high performance event framework for Ruby which uses the libev C library"
|
18
|
+
s.extensions = ["ext/cool.io/extconf.rb", "ext/iobuffer/extconf.rb"]
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
|
25
|
+
s.add_development_dependency "rake-compiler", "~> 0.9.5"
|
26
|
+
s.add_development_dependency "rake-compiler-dock", "~> 0.4.3"
|
27
|
+
s.add_development_dependency "rspec", ">= 2.13.0"
|
28
|
+
s.add_development_dependency "rdoc", ">= 3.6.0"
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'cool.io'
|
5
|
+
|
6
|
+
ADDR = '127.0.0.1'
|
7
|
+
PORT = 4321
|
8
|
+
|
9
|
+
event_loop = Cool.io::Loop.default
|
10
|
+
server = Cool.io::TCPServer.new(ADDR, PORT) do |connection|
|
11
|
+
puts "#{connection.remote_addr}:#{connection.remote_port} connected"
|
12
|
+
|
13
|
+
connection.on_close do
|
14
|
+
puts "#{connection.remote_addr}:#{connection.remote_port} disconnected"
|
15
|
+
end
|
16
|
+
|
17
|
+
connection.on_read do |data|
|
18
|
+
connection.write data
|
19
|
+
end
|
20
|
+
end
|
21
|
+
server.attach(event_loop)
|
22
|
+
|
23
|
+
puts "Echo server listening on #{ADDR}:#{PORT}"
|
24
|
+
event_loop.run
|
@@ -0,0 +1,34 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'cool.io'
|
5
|
+
|
6
|
+
ADDR = '127.0.0.1'
|
7
|
+
PORT = 4321
|
8
|
+
|
9
|
+
cool.io.connect ADDR, PORT do
|
10
|
+
on_connect do
|
11
|
+
puts "Connected to #{remote_host}:#{remote_port}"
|
12
|
+
write "bounce this back to me"
|
13
|
+
end
|
14
|
+
|
15
|
+
on_close do
|
16
|
+
puts "Disconnected from #{remote_host}:#{remote_port}"
|
17
|
+
end
|
18
|
+
|
19
|
+
on_read do |data|
|
20
|
+
puts "Got: #{data}"
|
21
|
+
close
|
22
|
+
end
|
23
|
+
|
24
|
+
on_resolve_failed do
|
25
|
+
puts "Error: Couldn't resolve #{remote_host}"
|
26
|
+
end
|
27
|
+
|
28
|
+
on_connect_failed do
|
29
|
+
puts "Error: Connection refused to #{remote_host}:#{remote_port}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
puts "Echo client connecting to #{ADDR}:#{PORT}..."
|
34
|
+
cool.io.run
|
@@ -0,0 +1,24 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'cool.io'
|
5
|
+
|
6
|
+
ADDR = '127.0.0.1'
|
7
|
+
PORT = 4321
|
8
|
+
|
9
|
+
cool.io.server ADDR, PORT do
|
10
|
+
on_connect do
|
11
|
+
puts "#{remote_addr}:#{remote_port} connected"
|
12
|
+
end
|
13
|
+
|
14
|
+
on_close do
|
15
|
+
puts "#{remote_addr}:#{remote_port} disconnected"
|
16
|
+
end
|
17
|
+
|
18
|
+
on_read do |data|
|
19
|
+
write data
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
puts "Echo server listening on #{ADDR}:#{PORT}"
|
24
|
+
cool.io.run
|
@@ -0,0 +1,38 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'cool.io'
|
5
|
+
|
6
|
+
ADDR = '127.0.0.1'
|
7
|
+
PORT = 4321
|
8
|
+
|
9
|
+
class ClientConnection < Cool.io::TCPSocket
|
10
|
+
def on_connect
|
11
|
+
puts "#{remote_addr}:#{remote_port} connected"
|
12
|
+
write "bounce this back to me"
|
13
|
+
end
|
14
|
+
|
15
|
+
def on_close
|
16
|
+
puts "#{remote_addr}:#{remote_port} disconnected"
|
17
|
+
end
|
18
|
+
|
19
|
+
def on_read(data)
|
20
|
+
print "got #{data}"
|
21
|
+
close
|
22
|
+
end
|
23
|
+
|
24
|
+
def on_resolve_failed
|
25
|
+
print "DNS resolve failed"
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_connect_failed
|
29
|
+
print "connect failed, meaning our connection to their port was rejected"
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
event_loop = Cool.io::Loop.default
|
35
|
+
client = ClientConnection.connect(ADDR, PORT)
|
36
|
+
client.attach(event_loop)
|
37
|
+
puts "Echo client connecting to #{ADDR}:#{PORT}..."
|
38
|
+
event_loop.run
|
@@ -0,0 +1,27 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'cool.io'
|
5
|
+
|
6
|
+
ADDR = '127.0.0.1'
|
7
|
+
PORT = 4321
|
8
|
+
|
9
|
+
class EchoServerConnection < Cool.io::TCPSocket
|
10
|
+
def on_connect
|
11
|
+
puts "#{remote_addr}:#{remote_port} connected"
|
12
|
+
end
|
13
|
+
|
14
|
+
def on_close
|
15
|
+
puts "#{remote_addr}:#{remote_port} disconnected"
|
16
|
+
end
|
17
|
+
|
18
|
+
def on_read(data)
|
19
|
+
write data
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
event_loop = Cool.io::Loop.default
|
24
|
+
Cool.io::TCPServer.new(ADDR, PORT, EchoServerConnection).attach(event_loop)
|
25
|
+
|
26
|
+
puts "Echo server listening on #{ADDR}:#{PORT}"
|
27
|
+
event_loop.run
|
data/examples/google.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (C) 2007-10 Tony Arcieri
|
3
|
+
* You may redistribute this under the terms of the Ruby license.
|
4
|
+
* See LICENSE for details
|
5
|
+
*/
|
6
|
+
|
7
|
+
#ifndef COOLIO_H
|
8
|
+
#define COOLIO_H
|
9
|
+
|
10
|
+
#include "ruby.h"
|
11
|
+
#include "rubyio.h"
|
12
|
+
|
13
|
+
#ifdef GetReadFile
|
14
|
+
#define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
|
15
|
+
#else
|
16
|
+
|
17
|
+
#if !HAVE_RB_IO_T || (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
|
18
|
+
#define FPTR_TO_FD(fptr) fileno(fptr->f)
|
19
|
+
#else
|
20
|
+
#define FPTR_TO_FD(fptr) fptr->fd
|
21
|
+
#endif
|
22
|
+
|
23
|
+
#endif
|
24
|
+
|
25
|
+
struct Coolio_Event
|
26
|
+
{
|
27
|
+
/* These values are used to extract events from libev callbacks */
|
28
|
+
VALUE watcher;
|
29
|
+
int revents;
|
30
|
+
};
|
31
|
+
|
32
|
+
struct Coolio_Loop
|
33
|
+
{
|
34
|
+
struct ev_loop *ev_loop;
|
35
|
+
struct ev_timer timer; /* for timeouts */
|
36
|
+
|
37
|
+
int running;
|
38
|
+
int events_received;
|
39
|
+
int eventbuf_size;
|
40
|
+
struct Coolio_Event *eventbuf;
|
41
|
+
};
|
42
|
+
|
43
|
+
struct Coolio_Watcher
|
44
|
+
{
|
45
|
+
union {
|
46
|
+
struct ev_io ev_io;
|
47
|
+
struct ev_timer ev_timer;
|
48
|
+
struct ev_stat ev_stat;
|
49
|
+
} event_types;
|
50
|
+
|
51
|
+
int enabled;
|
52
|
+
VALUE loop;
|
53
|
+
|
54
|
+
void (*dispatch_callback)(VALUE self, int revents);
|
55
|
+
};
|
56
|
+
|
57
|
+
void Coolio_Loop_process_event(VALUE watcher, int revents);
|
58
|
+
|
59
|
+
#endif
|
@@ -0,0 +1,25 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (C) 2007-10 Tony Arcieri
|
3
|
+
* You may redistribute this under the terms of the Ruby license.
|
4
|
+
* See LICENSE for details
|
5
|
+
*/
|
6
|
+
|
7
|
+
|
8
|
+
#include "ruby.h"
|
9
|
+
|
10
|
+
#include "ev_wrap.h"
|
11
|
+
#include "cool.io.h"
|
12
|
+
|
13
|
+
static VALUE mCoolio = Qnil;
|
14
|
+
|
15
|
+
/* Initialize the coolness */
|
16
|
+
void Init_cool()
|
17
|
+
{
|
18
|
+
/* Initializers for other modules */
|
19
|
+
Init_coolio_loop();
|
20
|
+
Init_coolio_watcher();
|
21
|
+
Init_coolio_iowatcher();
|
22
|
+
Init_coolio_timer_watcher();
|
23
|
+
Init_coolio_stat_watcher();
|
24
|
+
Init_coolio_utils();
|
25
|
+
}
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
libs = []
|
4
|
+
|
5
|
+
$defs << "-DRUBY_VERSION_CODE=#{RUBY_VERSION.gsub(/\D/, '')}"
|
6
|
+
|
7
|
+
have_func('rb_thread_blocking_region')
|
8
|
+
have_func('rb_thread_call_without_gvl')
|
9
|
+
have_func('rb_thread_alone')
|
10
|
+
have_func('rb_str_set_len')
|
11
|
+
have_library('rt', 'clock_gettime')
|
12
|
+
|
13
|
+
if have_header('sys/select.h')
|
14
|
+
$defs << '-DEV_USE_SELECT'
|
15
|
+
end
|
16
|
+
|
17
|
+
if have_header('poll.h')
|
18
|
+
$defs << '-DEV_USE_POLL'
|
19
|
+
end
|
20
|
+
|
21
|
+
if have_header('sys/epoll.h')
|
22
|
+
$defs << '-DEV_USE_EPOLL'
|
23
|
+
end
|
24
|
+
|
25
|
+
if have_header('sys/event.h') and have_header('sys/queue.h')
|
26
|
+
$defs << '-DEV_USE_KQUEUE'
|
27
|
+
end
|
28
|
+
|
29
|
+
if have_header('port.h')
|
30
|
+
$defs << '-DEV_USE_PORT'
|
31
|
+
end
|
32
|
+
|
33
|
+
have_header('sys/resource.h')
|
34
|
+
|
35
|
+
# ncpu detection specifics
|
36
|
+
case RUBY_PLATFORM
|
37
|
+
when /linux/
|
38
|
+
$defs << '-DHAVE_LINUX_PROCFS'
|
39
|
+
else
|
40
|
+
if have_func('sysctlbyname', ['sys/param.h', 'sys/sysctl.h'])
|
41
|
+
$defs << '-DHAVE_SYSCTLBYNAME'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
$LIBS << ' ' << libs.join(' ')
|
46
|
+
|
47
|
+
dir_config('cool.io_ext')
|
48
|
+
create_makefile('cool.io_ext')
|
49
|
+
|
50
|
+
# win32 needs to link in "just the right order" for some reason or ioctlsocket will be mapped to an [inverted] ruby specific version. See libev mailing list for (not so helpful discussion--true cause I'm not sure, but this overcomes the symptom)
|
51
|
+
if RUBY_PLATFORM =~ /mingw|mswin/
|
52
|
+
makefile_contents = File.read 'Makefile'
|
53
|
+
|
54
|
+
# "Init_cool could not be found" when loading cool.io.so.
|
55
|
+
# I'm not sure why this is needed. But this line causes "1114 A dynamic link library (DLL) initialization routine failed." So I commented out this line.
|
56
|
+
#makefile_contents.gsub! 'DLDFLAGS = ', 'DLDFLAGS = -export-all '
|
57
|
+
|
58
|
+
makefile_contents.gsub! /LIBS = (.*) (\S*ws2_32\S*)/i, 'LIBS = \\2 \\1'
|
59
|
+
File.open('Makefile', 'w') { |f| f.write makefile_contents }
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,189 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (C) 2007-10 Tony Arcieri
|
3
|
+
* You may redistribute this under the terms of the Ruby license.
|
4
|
+
* See LICENSE for details
|
5
|
+
*/
|
6
|
+
|
7
|
+
#include "ruby.h"
|
8
|
+
#include "rubyio.h"
|
9
|
+
|
10
|
+
#include "ev_wrap.h"
|
11
|
+
|
12
|
+
#include "cool.io.h"
|
13
|
+
#include "watcher.h"
|
14
|
+
|
15
|
+
static VALUE mCoolio = Qnil;
|
16
|
+
static VALUE cCoolio_Watcher = Qnil;
|
17
|
+
static VALUE cCoolio_Loop = Qnil;
|
18
|
+
static VALUE cCoolio_IOWatcher = Qnil;
|
19
|
+
|
20
|
+
static VALUE Coolio_IOWatcher_initialize(int argc, VALUE *argv, VALUE self);
|
21
|
+
static VALUE Coolio_IOWatcher_attach(VALUE self, VALUE loop);
|
22
|
+
static VALUE Coolio_IOWatcher_detach(VALUE self);
|
23
|
+
static VALUE Coolio_IOWatcher_enable(VALUE self);
|
24
|
+
static VALUE Coolio_IOWatcher_disable(VALUE self);
|
25
|
+
static VALUE Coolio_IOWatcher_on_readable(VALUE self);
|
26
|
+
static VALUE Coolio_IOWatcher_on_writable(VALUE self);
|
27
|
+
|
28
|
+
static void Coolio_IOWatcher_libev_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents);
|
29
|
+
static void Coolio_IOWatcher_dispatch_callback(VALUE self, int revents);
|
30
|
+
|
31
|
+
/*
|
32
|
+
* Coolio::IOWatcher monitors Ruby IO objects for readability or writability.
|
33
|
+
* This allows your application to block while the kernel is writing out
|
34
|
+
* data and fill the read or write buffer whenever there is space available.
|
35
|
+
*/
|
36
|
+
void Init_coolio_iowatcher()
|
37
|
+
{
|
38
|
+
mCoolio = rb_define_module("Coolio");
|
39
|
+
cCoolio_Watcher = rb_define_class_under(mCoolio, "Watcher", rb_cObject);
|
40
|
+
cCoolio_IOWatcher = rb_define_class_under(mCoolio, "IOWatcher", cCoolio_Watcher);
|
41
|
+
cCoolio_Loop = rb_define_class_under(mCoolio, "Loop", rb_cObject);
|
42
|
+
|
43
|
+
rb_define_method(cCoolio_IOWatcher, "initialize", Coolio_IOWatcher_initialize, -1);
|
44
|
+
rb_define_method(cCoolio_IOWatcher, "attach", Coolio_IOWatcher_attach, 1);
|
45
|
+
rb_define_method(cCoolio_IOWatcher, "detach", Coolio_IOWatcher_detach, 0);
|
46
|
+
rb_define_method(cCoolio_IOWatcher, "enable", Coolio_IOWatcher_enable, 0);
|
47
|
+
rb_define_method(cCoolio_IOWatcher, "disable", Coolio_IOWatcher_disable, 0);
|
48
|
+
rb_define_method(cCoolio_IOWatcher, "on_readable", Coolio_IOWatcher_on_readable, 0);
|
49
|
+
rb_define_method(cCoolio_IOWatcher, "on_writable", Coolio_IOWatcher_on_writable, 0);
|
50
|
+
}
|
51
|
+
|
52
|
+
/**
|
53
|
+
* call-seq:
|
54
|
+
* Coolio::IOWatcher.initialize(IO, events = 'r') -> Coolio::IOWatcher
|
55
|
+
*
|
56
|
+
* Create a new Coolio::IOWatcher for the given IO object and add it to the given Coolio::Loop
|
57
|
+
*/
|
58
|
+
static VALUE Coolio_IOWatcher_initialize(int argc, VALUE *argv, VALUE self)
|
59
|
+
{
|
60
|
+
VALUE io, flags;
|
61
|
+
char *flags_str;
|
62
|
+
int events;
|
63
|
+
struct Coolio_Watcher *watcher_data;
|
64
|
+
#if HAVE_RB_IO_T
|
65
|
+
rb_io_t *fptr;
|
66
|
+
#else
|
67
|
+
OpenFile *fptr;
|
68
|
+
#endif
|
69
|
+
|
70
|
+
rb_scan_args(argc, argv, "11", &io, &flags);
|
71
|
+
|
72
|
+
if(flags != Qnil)
|
73
|
+
flags_str = RSTRING_PTR(rb_String(flags));
|
74
|
+
else
|
75
|
+
flags_str = "r";
|
76
|
+
|
77
|
+
if(!strcmp(flags_str, "r"))
|
78
|
+
events = EV_READ;
|
79
|
+
else if(!strcmp(flags_str, "w"))
|
80
|
+
events = EV_WRITE;
|
81
|
+
else if(!strcmp(flags_str, "rw"))
|
82
|
+
events = EV_READ | EV_WRITE;
|
83
|
+
else
|
84
|
+
rb_raise(rb_eArgError, "invalid event type: '%s' (must be 'r', 'w', or 'rw')", flags_str);
|
85
|
+
|
86
|
+
Data_Get_Struct(self, struct Coolio_Watcher, watcher_data);
|
87
|
+
GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
|
88
|
+
|
89
|
+
watcher_data->dispatch_callback = Coolio_IOWatcher_dispatch_callback;
|
90
|
+
ev_io_init(&watcher_data->event_types.ev_io, Coolio_IOWatcher_libev_callback, FPTR_TO_FD(fptr), events);
|
91
|
+
watcher_data->event_types.ev_io.data = (void *)self;
|
92
|
+
|
93
|
+
return Qnil;
|
94
|
+
}
|
95
|
+
|
96
|
+
/**
|
97
|
+
* call-seq:
|
98
|
+
* Coolio::IOWatcher.attach(loop) -> Coolio::IOWatcher
|
99
|
+
*
|
100
|
+
* Attach the IO watcher to the given Coolio::Loop. If the watcher is already attached
|
101
|
+
* to a loop, detach it from the old one and attach it to the new one.
|
102
|
+
*/
|
103
|
+
static VALUE Coolio_IOWatcher_attach(VALUE self, VALUE loop)
|
104
|
+
{
|
105
|
+
Watcher_Attach(io, Coolio_IOWatcher_detach, self, loop);
|
106
|
+
|
107
|
+
return self;
|
108
|
+
}
|
109
|
+
|
110
|
+
/**
|
111
|
+
* call-seq:
|
112
|
+
* Coolio::IOWatcher.detach -> Coolio::IOWatcher
|
113
|
+
*
|
114
|
+
* Detach the IO watcher from its current Coolio::Loop.
|
115
|
+
*/
|
116
|
+
static VALUE Coolio_IOWatcher_detach(VALUE self)
|
117
|
+
{
|
118
|
+
Watcher_Detach(io, self);
|
119
|
+
|
120
|
+
return self;
|
121
|
+
}
|
122
|
+
|
123
|
+
/**
|
124
|
+
* call-seq:
|
125
|
+
* Coolio::IOWatcher.enable -> Coolio::IOWatcher
|
126
|
+
*
|
127
|
+
* Re-enable an IO watcher which has been temporarily disabled. See the
|
128
|
+
* disable method for a more thorough explanation.
|
129
|
+
*/
|
130
|
+
static VALUE Coolio_IOWatcher_enable(VALUE self)
|
131
|
+
{
|
132
|
+
Watcher_Enable(io, self);
|
133
|
+
|
134
|
+
return self;
|
135
|
+
}
|
136
|
+
|
137
|
+
/**
|
138
|
+
* call-seq:
|
139
|
+
* Coolio::IOWatcher.disable -> Coolio::IOWatcher
|
140
|
+
*
|
141
|
+
* Temporarily disable an IO watcher which is attached to a loop.
|
142
|
+
* This is useful if you wish to toggle event monitoring on and off.
|
143
|
+
*/
|
144
|
+
static VALUE Coolio_IOWatcher_disable(VALUE self)
|
145
|
+
{
|
146
|
+
Watcher_Disable(io, self);
|
147
|
+
|
148
|
+
return self;
|
149
|
+
}
|
150
|
+
|
151
|
+
/**
|
152
|
+
* call-seq:
|
153
|
+
* Coolio::IOWatcher#on_readable -> nil
|
154
|
+
*
|
155
|
+
* Called whenever the IO object associated with the IOWatcher is readable
|
156
|
+
*/
|
157
|
+
static VALUE Coolio_IOWatcher_on_readable(VALUE self)
|
158
|
+
{
|
159
|
+
return Qnil;
|
160
|
+
}
|
161
|
+
|
162
|
+
/**
|
163
|
+
* call-seq:
|
164
|
+
* Coolio::IOWatcher#on_writable -> nil
|
165
|
+
*
|
166
|
+
* Called whenever the IO object associated with the IOWatcher is writable
|
167
|
+
*/
|
168
|
+
|
169
|
+
static VALUE Coolio_IOWatcher_on_writable(VALUE self)
|
170
|
+
{
|
171
|
+
return Qnil;
|
172
|
+
}
|
173
|
+
|
174
|
+
/* libev callback */
|
175
|
+
static void Coolio_IOWatcher_libev_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents)
|
176
|
+
{
|
177
|
+
Coolio_Loop_process_event((VALUE)io->data, revents);
|
178
|
+
}
|
179
|
+
|
180
|
+
/* Coolio::Loop dispatch callback */
|
181
|
+
static void Coolio_IOWatcher_dispatch_callback(VALUE self, int revents)
|
182
|
+
{
|
183
|
+
if(revents & EV_READ)
|
184
|
+
rb_funcall(self, rb_intern("on_readable"), 0, 0);
|
185
|
+
else if(revents & EV_WRITE)
|
186
|
+
rb_funcall(self, rb_intern("on_writable"), 0, 0);
|
187
|
+
else
|
188
|
+
rb_raise(rb_eRuntimeError, "unknown revents value for ev_io: %d", revents);
|
189
|
+
}
|