vio 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +40 -0
- data/Rakefile +75 -0
- data/bench/patched_logger.rb +30 -0
- data/bench/read.rb +22 -0
- data/bench/write.rb +38 -0
- data/ext/vio/Makefile +187 -0
- data/ext/vio/extconf.rb +13 -0
- data/ext/vio/mkmf.log +62 -0
- data/ext/vio/vio.bundle +0 -0
- data/ext/vio/vio.c +164 -0
- data/ext/vio/vio.o +0 -0
- data/test/fixtures/fix.txt +1 -0
- data/test/fixtures/writable.txt +0 -0
- data/test/helper.rb +13 -0
- data/test/test_vio.rb +54 -0
- data/vio.gemspec +16 -0
- metadata +80 -0
data/README
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
Vectored I/O for Ruby MRI
|
2
|
+
(c) 2009 Lourens Naudé (methodmissing)
|
3
|
+
|
4
|
+
http://github.com/methodmissing/vio
|
5
|
+
|
6
|
+
Vectored I/O ?
|
7
|
+
|
8
|
+
POSIX 1003.1-2001 introduces reading or writing data into multiple buffers with a single procedure call.See http://en.wikipedia.org/wiki/Vectored_I/O for an overview.
|
9
|
+
|
10
|
+
Use cases :
|
11
|
+
|
12
|
+
* Write non-sequentially placed data in memory to disk with a single write operation.This fits very well with custom database/record formats for writing out indexes and data at once.
|
13
|
+
* Reducing syscall overheads
|
14
|
+
* Reading structured data (protocol dumps,db records) into distinct buffers
|
15
|
+
|
16
|
+
Examples :
|
17
|
+
|
18
|
+
8=FIX.4.49=4535=049=TW56=ISLD34=352=20000426-12:05:0610=220
|
19
|
+
|
20
|
+
>>io = File.open('/path/to/fix.txt'))
|
21
|
+
=> #<File://path/to/fix.txt>
|
22
|
+
>>io.read(9, 5, 5, 6, 8, 26, 8)
|
23
|
+
=> ["8=FIX.4.4","\x019=45", "\x0135=0", "\x0149=TW", "\x0156=ISLD",
|
24
|
+
"\x0134=3\x0152=20000426-12:05:06", "\x0110=220\x01"]
|
25
|
+
|
26
|
+
Installation
|
27
|
+
|
28
|
+
sudo gem install methodmissing-vio
|
29
|
+
|
30
|
+
Todo :
|
31
|
+
|
32
|
+
* Error handling for rewind + sockets don't support lseek
|
33
|
+
|
34
|
+
To run the test suite:
|
35
|
+
|
36
|
+
rake
|
37
|
+
|
38
|
+
To run the benchmarks:
|
39
|
+
|
40
|
+
rake bench
|
data/Rakefile
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/clean'
|
4
|
+
$:.unshift(File.expand_path('lib'))
|
5
|
+
VIO_ROOT = 'ext/vio'
|
6
|
+
|
7
|
+
desc 'Default: test'
|
8
|
+
task :default => :test
|
9
|
+
|
10
|
+
desc 'Run VIO tests.'
|
11
|
+
Rake::TestTask.new(:test) do |t|
|
12
|
+
t.libs = [VIO_ROOT]
|
13
|
+
t.pattern = 'test/test_*.rb'
|
14
|
+
t.verbose = true
|
15
|
+
end
|
16
|
+
task :test => :build
|
17
|
+
|
18
|
+
namespace :build do
|
19
|
+
file "#{VIO_ROOT}/vio.c"
|
20
|
+
file "#{VIO_ROOT}/extconf.rb"
|
21
|
+
file "#{VIO_ROOT}/Makefile" => %W(#{VIO_ROOT}/vio.c #{VIO_ROOT}/extconf.rb) do
|
22
|
+
Dir.chdir(VIO_ROOT) do
|
23
|
+
ruby 'extconf.rb'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "generate makefile"
|
28
|
+
task :makefile => %W(#{VIO_ROOT}/Makefile #{VIO_ROOT}/vio.c)
|
29
|
+
|
30
|
+
dlext = Config::CONFIG['DLEXT']
|
31
|
+
file "#{VIO_ROOT}/vio.#{dlext}" => %W(#{VIO_ROOT}/Makefile #{VIO_ROOT}/vio.c) do
|
32
|
+
Dir.chdir(VIO_ROOT) do
|
33
|
+
sh 'make' # TODO - is there a config for which make somewhere?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "compile vio extension"
|
38
|
+
task :compile => "#{VIO_ROOT}/vio.#{dlext}"
|
39
|
+
|
40
|
+
task :clean do
|
41
|
+
Dir.chdir(VIO_ROOT) do
|
42
|
+
sh 'make clean'
|
43
|
+
end if File.exists?("#{VIO_ROOT}/Makefile")
|
44
|
+
end
|
45
|
+
|
46
|
+
CLEAN.include("#{VIO_ROOT}/Makefile")
|
47
|
+
CLEAN.include("#{VIO_ROOT}/vio.#{dlext}")
|
48
|
+
end
|
49
|
+
|
50
|
+
task :clean => %w(build:clean)
|
51
|
+
|
52
|
+
desc "compile"
|
53
|
+
task :build => %w(build:compile)
|
54
|
+
|
55
|
+
task :install do |t|
|
56
|
+
Dir.chdir(VIO_ROOT) do
|
57
|
+
sh 'sudo make install'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "clean build install"
|
62
|
+
task :setup => %w(clean build install)
|
63
|
+
|
64
|
+
namespace :bench do |t|
|
65
|
+
desc "bench reads"
|
66
|
+
task :read do
|
67
|
+
ruby "bench/read.rb"
|
68
|
+
end
|
69
|
+
|
70
|
+
desc "bench writes"
|
71
|
+
task :write do
|
72
|
+
ruby "bench/write.rb"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
task :bench => :build
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Logger
|
2
|
+
def addv(msgs)
|
3
|
+
unless @logdev.nil?
|
4
|
+
@logdev.writev(msgs)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
def blank_slate
|
9
|
+
@logdev.blank_slate
|
10
|
+
end
|
11
|
+
|
12
|
+
class LogDevice
|
13
|
+
def writev(messages)
|
14
|
+
@mutex.synchronize do
|
15
|
+
if @shift_age and @dev.respond_to?(:stat)
|
16
|
+
begin
|
17
|
+
check_shift_log
|
18
|
+
rescue
|
19
|
+
raise Logger::ShiftingError.new("Shifting failed. #{$!}")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
@dev.writev(*messages)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def blank_slate
|
27
|
+
@dev.truncate(0)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/bench/read.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
$:.unshift "."
|
2
|
+
def relative(path)
|
3
|
+
File.dirname(__FILE__) + path
|
4
|
+
end
|
5
|
+
|
6
|
+
require relative('/../ext/vio/vio')
|
7
|
+
require "benchmark"
|
8
|
+
|
9
|
+
FILE = relative("/../test/fixtures/fix.txt")
|
10
|
+
SEP = "\x01".freeze
|
11
|
+
|
12
|
+
source = File.open(FILE)
|
13
|
+
TESTS = 100_000
|
14
|
+
begin
|
15
|
+
puts "* Bench reads ..."
|
16
|
+
Benchmark.bmbm do |results|
|
17
|
+
results.report("IO.readv") { TESTS.times{ source.readv(9, 5, 5, 6, 8, 26, 8) } }
|
18
|
+
results.report("IO.read") { TESTS.times{ source.read.split(SEP) } }
|
19
|
+
end
|
20
|
+
ensure
|
21
|
+
source.close
|
22
|
+
end
|
data/bench/write.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
$:.unshift "."
|
2
|
+
def relative(path)
|
3
|
+
File.dirname(__FILE__) + path
|
4
|
+
end
|
5
|
+
|
6
|
+
require relative('/../ext/vio/vio')
|
7
|
+
require "benchmark"
|
8
|
+
require "logger"
|
9
|
+
require relative('/patched_logger')
|
10
|
+
|
11
|
+
PAYLOAD = ['a' * 100,
|
12
|
+
'b' * 200,
|
13
|
+
'c' * 300,
|
14
|
+
'd' * 400,
|
15
|
+
'e' * 500,
|
16
|
+
'f' * 600,
|
17
|
+
'g' * 700,
|
18
|
+
'h' * 800,
|
19
|
+
'i' * 900,
|
20
|
+
'j' * 1000]
|
21
|
+
|
22
|
+
FILE = relative("/../test/fixtures/writable.txt")
|
23
|
+
|
24
|
+
logger = Logger.new(FILE)
|
25
|
+
logger.blank_slate
|
26
|
+
|
27
|
+
TESTS = 100_000
|
28
|
+
begin
|
29
|
+
puts "* Bench log writes ..."
|
30
|
+
Benchmark.bmbm do |results|
|
31
|
+
results.report("IO.writev") { TESTS.times{ logger.addv(PAYLOAD) } }
|
32
|
+
logger.blank_slate
|
33
|
+
results.report("IO.write") { TESTS.times{ logger << PAYLOAD.join } }
|
34
|
+
end
|
35
|
+
ensure
|
36
|
+
logger.blank_slate
|
37
|
+
logger.close
|
38
|
+
end
|
data/ext/vio/Makefile
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
|
2
|
+
SHELL = /bin/sh
|
3
|
+
|
4
|
+
#### Start of system configuration section. ####
|
5
|
+
|
6
|
+
srcdir = .
|
7
|
+
topdir = /Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1
|
8
|
+
hdrdir = /Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1
|
9
|
+
arch_hdrdir = /Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1/$(arch)
|
10
|
+
VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
|
11
|
+
prefix = $(DESTDIR)/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1
|
12
|
+
rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
|
13
|
+
exec_prefix = $(prefix)
|
14
|
+
vendorhdrdir = $(rubyhdrdir)/vendor_ruby
|
15
|
+
sitehdrdir = $(rubyhdrdir)/site_ruby
|
16
|
+
rubyhdrdir = $(includedir)/$(RUBY_BASE_NAME)-$(ruby_version)
|
17
|
+
vendordir = $(rubylibprefix)/vendor_ruby
|
18
|
+
sitedir = $(rubylibprefix)/site_ruby
|
19
|
+
ridir = $(datarootdir)/$(RI_BASE_NAME)
|
20
|
+
mandir = $(datarootdir)/man
|
21
|
+
localedir = $(datarootdir)/locale
|
22
|
+
libdir = $(exec_prefix)/lib
|
23
|
+
psdir = $(docdir)
|
24
|
+
pdfdir = $(docdir)
|
25
|
+
dvidir = $(docdir)
|
26
|
+
htmldir = $(docdir)
|
27
|
+
infodir = $(datarootdir)/info
|
28
|
+
docdir = $(datarootdir)/doc/$(PACKAGE)
|
29
|
+
oldincludedir = $(DESTDIR)/usr/include
|
30
|
+
includedir = $(prefix)/include
|
31
|
+
localstatedir = $(prefix)/var
|
32
|
+
sharedstatedir = $(prefix)/com
|
33
|
+
sysconfdir = $(prefix)/etc
|
34
|
+
datadir = $(datarootdir)
|
35
|
+
datarootdir = $(prefix)/share
|
36
|
+
libexecdir = $(exec_prefix)/libexec
|
37
|
+
sbindir = $(exec_prefix)/sbin
|
38
|
+
bindir = $(exec_prefix)/bin
|
39
|
+
rubylibdir = $(rubylibprefix)/$(ruby_version)
|
40
|
+
archdir = $(rubylibdir)/$(arch)
|
41
|
+
sitelibdir = $(sitedir)/$(ruby_version)
|
42
|
+
sitearchdir = $(sitelibdir)/$(sitearch)
|
43
|
+
vendorlibdir = $(vendordir)/$(ruby_version)
|
44
|
+
vendorarchdir = $(vendorlibdir)/$(sitearch)
|
45
|
+
|
46
|
+
CC = gcc
|
47
|
+
CXX = g++
|
48
|
+
LIBRUBY = $(LIBRUBY_SO)
|
49
|
+
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
50
|
+
LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
|
51
|
+
LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
|
52
|
+
OUTFLAG = -o
|
53
|
+
COUTFLAG = -o
|
54
|
+
|
55
|
+
RUBY_EXTCONF_H =
|
56
|
+
cflags = $(optflags) $(debugflags) $(warnflags)
|
57
|
+
optflags = -O3
|
58
|
+
debugflags = -ggdb
|
59
|
+
warnflags = -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long
|
60
|
+
CFLAGS = -fno-common $(cflags) -fno-common -pipe
|
61
|
+
INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
|
62
|
+
DEFS =
|
63
|
+
CPPFLAGS = -DHAVE_RB_THREAD_BLOCKING_REGION -DRUBY19 -pedantic -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE $(DEFS) $(cppflags)
|
64
|
+
CXXFLAGS = $(CFLAGS) $(cxxflags)
|
65
|
+
ldflags = -L. -L/usr/local/lib
|
66
|
+
dldflags = -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress -Wl,-flat_namespace
|
67
|
+
ARCH_FLAG =
|
68
|
+
DLDFLAGS = $(ldflags) $(dldflags)
|
69
|
+
LDSHARED = $(CC) -dynamic -bundle
|
70
|
+
LDSHAREDXX = $(CXX) -dynamic -bundle
|
71
|
+
AR = ar
|
72
|
+
EXEEXT =
|
73
|
+
|
74
|
+
RUBY_BASE_NAME = ruby
|
75
|
+
RUBY_INSTALL_NAME = ruby
|
76
|
+
RUBY_SO_NAME = ruby.1.9.1
|
77
|
+
arch = x86_64-darwin10.4.0
|
78
|
+
sitearch = $(arch)
|
79
|
+
ruby_version = 1.9.1
|
80
|
+
ruby = /Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/bin/ruby
|
81
|
+
RUBY = $(ruby)
|
82
|
+
RM = rm -f
|
83
|
+
RM_RF = $(RUBY) -run -e rm -- -rf
|
84
|
+
RMDIRS = $(RUBY) -run -e rmdir -- -p
|
85
|
+
MAKEDIRS = mkdir -p
|
86
|
+
INSTALL = /usr/bin/install -c
|
87
|
+
INSTALL_PROG = $(INSTALL) -m 0755
|
88
|
+
INSTALL_DATA = $(INSTALL) -m 644
|
89
|
+
COPY = cp
|
90
|
+
|
91
|
+
#### End of system configuration section. ####
|
92
|
+
|
93
|
+
preload =
|
94
|
+
|
95
|
+
libpath = . $(libdir)
|
96
|
+
LIBPATH = -L. -L$(libdir)
|
97
|
+
DEFFILE =
|
98
|
+
|
99
|
+
CLEANFILES = mkmf.log
|
100
|
+
DISTCLEANFILES =
|
101
|
+
DISTCLEANDIRS =
|
102
|
+
|
103
|
+
extout =
|
104
|
+
extout_prefix =
|
105
|
+
target_prefix =
|
106
|
+
LOCAL_LIBS =
|
107
|
+
LIBS = $(LIBRUBYARG_SHARED) -lpthread -ldl -lobjc
|
108
|
+
SRCS = vio.c
|
109
|
+
OBJS = vio.o
|
110
|
+
TARGET = vio
|
111
|
+
DLLIB = $(TARGET).bundle
|
112
|
+
EXTSTATIC =
|
113
|
+
STATIC_LIB =
|
114
|
+
|
115
|
+
BINDIR = $(bindir)
|
116
|
+
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
117
|
+
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
118
|
+
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
119
|
+
HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
|
120
|
+
ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
|
121
|
+
|
122
|
+
TARGET_SO = $(DLLIB)
|
123
|
+
CLEANLIBS = $(TARGET).bundle
|
124
|
+
CLEANOBJS = *.o *.bak
|
125
|
+
|
126
|
+
all: $(DLLIB)
|
127
|
+
static: $(STATIC_LIB)
|
128
|
+
.PHONY: all install static install-so install-rb
|
129
|
+
.PHONY: clean clean-so clean-rb
|
130
|
+
|
131
|
+
clean-rb-default::
|
132
|
+
clean-rb::
|
133
|
+
clean-so::
|
134
|
+
clean: clean-so clean-rb-default clean-rb
|
135
|
+
@-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
|
136
|
+
|
137
|
+
distclean-rb-default::
|
138
|
+
distclean-rb::
|
139
|
+
distclean-so::
|
140
|
+
distclean: clean distclean-so distclean-rb-default distclean-rb
|
141
|
+
@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
|
142
|
+
@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
143
|
+
@-$(RMDIRS) $(DISTCLEANDIRS)
|
144
|
+
|
145
|
+
realclean: distclean
|
146
|
+
install: install-so install-rb
|
147
|
+
|
148
|
+
install-so: $(RUBYARCHDIR)
|
149
|
+
install-so: $(RUBYARCHDIR)/$(DLLIB)
|
150
|
+
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
|
151
|
+
@-$(MAKEDIRS) $(@D)
|
152
|
+
$(INSTALL_PROG) $(DLLIB) $(@D)
|
153
|
+
install-rb: pre-install-rb install-rb-default
|
154
|
+
install-rb-default: pre-install-rb-default
|
155
|
+
pre-install-rb: Makefile
|
156
|
+
pre-install-rb-default: Makefile
|
157
|
+
$(RUBYARCHDIR):
|
158
|
+
$(MAKEDIRS) $@
|
159
|
+
|
160
|
+
site-install: site-install-so site-install-rb
|
161
|
+
site-install-so: install-so
|
162
|
+
site-install-rb: install-rb
|
163
|
+
|
164
|
+
.SUFFIXES: .c .m .cc .cxx .cpp .C .o
|
165
|
+
|
166
|
+
.cc.o:
|
167
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
168
|
+
|
169
|
+
.cxx.o:
|
170
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
171
|
+
|
172
|
+
.cpp.o:
|
173
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
174
|
+
|
175
|
+
.C.o:
|
176
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
177
|
+
|
178
|
+
.c.o:
|
179
|
+
$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
|
180
|
+
|
181
|
+
$(DLLIB): $(OBJS) Makefile
|
182
|
+
@-$(RM) $(@)
|
183
|
+
$(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
$(OBJS): $(hdrdir)/ruby.h $(hdrdir)/ruby/defines.h $(arch_hdrdir)/ruby/config.h
|
data/ext/vio/extconf.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
def add_define(name)
|
4
|
+
$defs.push("-D#{name}")
|
5
|
+
end
|
6
|
+
|
7
|
+
dir_config('vio')
|
8
|
+
add_define 'RUBY19' if have_func('rb_thread_blocking_region') and have_macro('RUBY_UBF_IO', 'ruby.h')
|
9
|
+
add_define 'RUBY18' if have_var('rb_trap_immediate', ['ruby.h', 'rubysig.h'])
|
10
|
+
|
11
|
+
$defs.push("-pedantic")
|
12
|
+
|
13
|
+
create_makefile('vio')
|
data/ext/vio/mkmf.log
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
have_func: checking for rb_thread_blocking_region()... -------------------- yes
|
2
|
+
|
3
|
+
"gcc -o conftest -I/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1/x86_64-darwin10.4.0 -I/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1/ruby/backward -I/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long -fno-common -pipe conftest.c -L. -L/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/lib -L. -L/usr/local/lib -lruby.1.9.1-static -lpthread -ldl -lobjc "
|
4
|
+
checked program was:
|
5
|
+
/* begin */
|
6
|
+
1: #include "ruby.h"
|
7
|
+
2:
|
8
|
+
3: int main() {return 0;}
|
9
|
+
/* end */
|
10
|
+
|
11
|
+
"gcc -o conftest -I/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1/x86_64-darwin10.4.0 -I/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1/ruby/backward -I/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long -fno-common -pipe conftest.c -L. -L/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/lib -L. -L/usr/local/lib -lruby.1.9.1-static -lpthread -ldl -lobjc "
|
12
|
+
checked program was:
|
13
|
+
/* begin */
|
14
|
+
1: #include "ruby.h"
|
15
|
+
2:
|
16
|
+
3: /*top*/
|
17
|
+
4: int main() {return 0;}
|
18
|
+
5: int t() { void ((*volatile p)()); p = (void ((*)()))rb_thread_blocking_region; return 0; }
|
19
|
+
/* end */
|
20
|
+
|
21
|
+
--------------------
|
22
|
+
|
23
|
+
have_macro: checking for RUBY_UBF_IO in ruby.h... -------------------- yes
|
24
|
+
|
25
|
+
"gcc -I/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1/x86_64-darwin10.4.0 -I/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1/ruby/backward -I/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long -fno-common -pipe -c conftest.c"
|
26
|
+
checked program was:
|
27
|
+
/* begin */
|
28
|
+
1: #include "ruby.h"
|
29
|
+
2:
|
30
|
+
3: #include <ruby.h>
|
31
|
+
4: /*top*/
|
32
|
+
5: #ifndef RUBY_UBF_IO
|
33
|
+
6: # error
|
34
|
+
7: >>>>>> RUBY_UBF_IO undefined <<<<<<
|
35
|
+
8: #endif
|
36
|
+
/* end */
|
37
|
+
|
38
|
+
--------------------
|
39
|
+
|
40
|
+
have_var: checking for rb_trap_immediate in ruby.h,rubysig.h... -------------------- no
|
41
|
+
|
42
|
+
"gcc -I/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1/x86_64-darwin10.4.0 -I/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1/ruby/backward -I/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long -fno-common -pipe -c conftest.c"
|
43
|
+
In file included from conftest.c:4:
|
44
|
+
/Users/lourens/.rvm/rubies/ruby-1.9.2-rc1/include/ruby-1.9.1/ruby/backward/rubysig.h:14:2: warning: #warning rubysig.h is obsolete
|
45
|
+
conftest.c: In function ‘t’:
|
46
|
+
conftest.c:8: error: ‘rb_trap_immediate’ undeclared (first use in this function)
|
47
|
+
conftest.c:8: error: (Each undeclared identifier is reported only once
|
48
|
+
conftest.c:8: error: for each function it appears in.)
|
49
|
+
checked program was:
|
50
|
+
/* begin */
|
51
|
+
1: #include "ruby.h"
|
52
|
+
2:
|
53
|
+
3: #include <ruby.h>
|
54
|
+
4: #include <rubysig.h>
|
55
|
+
5:
|
56
|
+
6: /*top*/
|
57
|
+
7: int main() {return 0;}
|
58
|
+
8: int t() { const volatile void *volatile p; p = &(&rb_trap_immediate)[0]; return 0; }
|
59
|
+
/* end */
|
60
|
+
|
61
|
+
--------------------
|
62
|
+
|
data/ext/vio/vio.bundle
ADDED
Binary file
|
data/ext/vio/vio.c
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include <sys/types.h>
|
3
|
+
#include <sys/uio.h>
|
4
|
+
#include <unistd.h>
|
5
|
+
|
6
|
+
#ifndef RSTRING_PTR
|
7
|
+
#define RSTRING_PTR(obj) RSTRING(obj)->ptr
|
8
|
+
#endif
|
9
|
+
|
10
|
+
#ifndef RSTRING_LEN
|
11
|
+
#define RSTRING_LEN(obj) RSTRING(obj)->len
|
12
|
+
#endif
|
13
|
+
|
14
|
+
#ifndef RARRAY_PTR
|
15
|
+
#define RARRAY_PTR(obj) RARRAY(obj)->ptr
|
16
|
+
#endif
|
17
|
+
|
18
|
+
#ifndef RARRAY_LEN
|
19
|
+
#define RARRAY_LEN(obj) RARRAY(obj)->len
|
20
|
+
#endif
|
21
|
+
|
22
|
+
#ifdef RUBY19
|
23
|
+
#include "ruby/io.h"
|
24
|
+
#define TRAP_BEG
|
25
|
+
#define TRAP_END
|
26
|
+
#define declare_fptr \
|
27
|
+
rb_io_t *fptr;
|
28
|
+
#define declare_fd \
|
29
|
+
fd = fptr->fd;
|
30
|
+
#else
|
31
|
+
#include "rubysig.h"
|
32
|
+
#include "rubyio.h"
|
33
|
+
#define declare_fptr \
|
34
|
+
OpenFile *fptr;
|
35
|
+
#define declare_fd \
|
36
|
+
fd = fileno(fptr->f);
|
37
|
+
#endif
|
38
|
+
|
39
|
+
#define vio_error(err) \
|
40
|
+
rb_raise(rb_eIOError, err);
|
41
|
+
|
42
|
+
static void
|
43
|
+
vio_read_error()
|
44
|
+
{
|
45
|
+
switch(errno){
|
46
|
+
case EAGAIN:
|
47
|
+
vio_error("The file was marked for non-blocking I/O, and no data were ready to be read.");
|
48
|
+
case EBADF:
|
49
|
+
vio_error("File descriptor is not a valid file or socket descriptor open for reading.");
|
50
|
+
case EFAULT:
|
51
|
+
vio_error("Buffer points outside the allocated address space.");
|
52
|
+
case EINTR:
|
53
|
+
vio_error("A read from a slow device was interrupted before any data arrived by the delivery of a signal.");
|
54
|
+
case EINVAL:
|
55
|
+
vio_error("The pointer associated with file descriptor was negative.");
|
56
|
+
case EIO:
|
57
|
+
vio_error("An I/O error occurred while reading from the file system.");
|
58
|
+
case EISDIR:
|
59
|
+
vio_error("An attempt is made to read a directory.");
|
60
|
+
case ENOBUFS:
|
61
|
+
vio_error("An attempt to allocate a memory buffer fails.");
|
62
|
+
case ENOMEM:
|
63
|
+
vio_error("Insufficient memory is available.");
|
64
|
+
case ENXIO:
|
65
|
+
vio_error("An action is requested of a device that does not exist.");
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
static void
|
70
|
+
vio_write_error()
|
71
|
+
{
|
72
|
+
switch(errno){
|
73
|
+
case EDQUOT:
|
74
|
+
vio_error("The user's quota of disk blocks on the file system containing the file is exhausted.");
|
75
|
+
case EFAULT:
|
76
|
+
vio_error("Buffer points outside the allocated address space.");
|
77
|
+
case EWOULDBLOCK:
|
78
|
+
vio_error("The file descriptor is for a socket, is marked O_NONBLOCK, and write would block.");
|
79
|
+
case EDESTADDRREQ:
|
80
|
+
vio_error("The destination is no longer available when writing to a UNIX domain datagram socket on which connect(2) had been used to set a destination address.");
|
81
|
+
case EINVAL:
|
82
|
+
vio_error("Iov count is less than or equal to 0, or greater than MAX_IOV");
|
83
|
+
case ENOBUFS:
|
84
|
+
vio_error("The mbuf pool has been completely exhausted when writing to a socket.");
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
static VALUE
|
89
|
+
vio_read(VALUE io, VALUE iov)
|
90
|
+
{
|
91
|
+
int fd, i, size, bytes_read, cnt;
|
92
|
+
int expected = 0;
|
93
|
+
struct iovec iovs[IOV_MAX];
|
94
|
+
VALUE results;
|
95
|
+
declare_fptr;
|
96
|
+
if (RARRAY_LEN(iov) == 0) vio_error("No buffer offsets given");
|
97
|
+
GetOpenFile(io, fptr);
|
98
|
+
rb_io_check_readable(fptr);
|
99
|
+
declare_fd;
|
100
|
+
/* XXX Todo: Error handling */
|
101
|
+
lseek(fd, 0L, SEEK_SET);
|
102
|
+
fptr->lineno = 0;
|
103
|
+
cnt = RARRAY_LEN(iov);
|
104
|
+
results = rb_ary_new2(cnt);
|
105
|
+
for (i=0; i < cnt; i++) {
|
106
|
+
VALUE size_el = RARRAY_PTR(iov)[i];
|
107
|
+
Check_Type(size_el, T_FIXNUM);
|
108
|
+
size = FIX2INT(size_el);
|
109
|
+
expected = expected + size;
|
110
|
+
iovs[i].iov_len = size;
|
111
|
+
iovs[i].iov_base = calloc(1,size);
|
112
|
+
}
|
113
|
+
retry:
|
114
|
+
TRAP_BEG;
|
115
|
+
bytes_read = readv(fd,iovs,cnt);
|
116
|
+
TRAP_END;
|
117
|
+
if (bytes_read < expected && bytes_read > 0) goto retry;
|
118
|
+
vio_read_error();
|
119
|
+
for (i=0; i < cnt; i++) {
|
120
|
+
rb_ary_push(results, rb_tainted_str_new((char *)iovs[i].iov_base, iovs[i].iov_len));
|
121
|
+
}
|
122
|
+
return results;
|
123
|
+
}
|
124
|
+
|
125
|
+
static VALUE
|
126
|
+
vio_write(VALUE io, VALUE iov)
|
127
|
+
{
|
128
|
+
int i, size, bytes_written, fd, cnt;
|
129
|
+
int expected = 0;
|
130
|
+
VALUE results;
|
131
|
+
struct iovec iovs[IOV_MAX];
|
132
|
+
declare_fptr;
|
133
|
+
Check_Type(iov, T_ARRAY);
|
134
|
+
cnt = RARRAY_LEN(iov);
|
135
|
+
if (cnt == 0) vio_error("No buffers to write given");
|
136
|
+
GetOpenFile(io, fptr);
|
137
|
+
rb_io_check_writable(fptr);
|
138
|
+
declare_fd;
|
139
|
+
results = rb_ary_new2(cnt);
|
140
|
+
for (i=0; i < cnt; i++) {
|
141
|
+
VALUE str = RARRAY_PTR(iov)[i];
|
142
|
+
Check_Type(str, T_STRING);
|
143
|
+
size = RSTRING_LEN(str);
|
144
|
+
expected = expected + size;
|
145
|
+
iovs[i].iov_len = size;
|
146
|
+
iovs[i].iov_base = RSTRING_PTR(str);
|
147
|
+
}
|
148
|
+
retry:
|
149
|
+
TRAP_BEG;
|
150
|
+
bytes_written = writev(fd,iovs,cnt);
|
151
|
+
TRAP_END;
|
152
|
+
if (bytes_written < expected && bytes_written > 0) goto retry;
|
153
|
+
vio_write_error();
|
154
|
+
for (i=0; i < cnt; i++) {
|
155
|
+
rb_ary_push(results, INT2FIX(iovs[i].iov_len));
|
156
|
+
}
|
157
|
+
return results;
|
158
|
+
}
|
159
|
+
|
160
|
+
void Init_vio()
|
161
|
+
{
|
162
|
+
rb_define_method(rb_cIO, "readv", vio_read, -2);
|
163
|
+
rb_define_method(rb_cIO, "writev", vio_write, -2);
|
164
|
+
}
|
data/ext/vio/vio.o
ADDED
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
8=FIX.4.49=4535=049=TW56=ISLD34=352=20000426-12:05:0610=220
|
File without changes
|
data/test/helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'vio'
|
4
|
+
|
5
|
+
FIXTURES = File.dirname(__FILE__) + "/fixtures"
|
6
|
+
|
7
|
+
def fixtures(*files)
|
8
|
+
files.map{|f| File.join(FIXTURES,f) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def fixture(file)
|
12
|
+
file =~ /\// ? file : fixtures(*file).first
|
13
|
+
end
|
data/test/test_vio.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
$:.unshift "."
|
2
|
+
require File.dirname(__FILE__) + '/helper'
|
3
|
+
|
4
|
+
class TestVectoredIO < Test::Unit::TestCase
|
5
|
+
CONTENT = [ "8=FIX.4.4", "\x019=45", "\x0135=0", "\x0149=TW", "\x0156=ISLD",
|
6
|
+
"\x0134=3\x0152=20000426-12:05:06", "\x0110=220\x01" ]
|
7
|
+
LENGTHS = [9, 5, 5, 6, 8, 26, 8]
|
8
|
+
|
9
|
+
def test_readv_arguments
|
10
|
+
io = File.open(fixture('fix.txt'))
|
11
|
+
assert_raises TypeError do
|
12
|
+
io.readv nil
|
13
|
+
end
|
14
|
+
assert_raises TypeError do
|
15
|
+
io.readv 'string'
|
16
|
+
end
|
17
|
+
assert_raises IOError do
|
18
|
+
io.readv
|
19
|
+
end
|
20
|
+
assert_raises IOError do
|
21
|
+
io.readv -2
|
22
|
+
end
|
23
|
+
io.close
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_readv
|
27
|
+
io = File.open(fixture('fix.txt'))
|
28
|
+
expected = CONTENT
|
29
|
+
assert_equal expected, io.readv(*LENGTHS)
|
30
|
+
io.close
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_writev_arguments
|
34
|
+
io = File.open(fixture('writable.txt'), 'w')
|
35
|
+
assert_raises TypeError do
|
36
|
+
io.writev nil
|
37
|
+
end
|
38
|
+
assert_raises TypeError do
|
39
|
+
io.writev 2
|
40
|
+
end
|
41
|
+
assert_raises IOError do
|
42
|
+
io.writev
|
43
|
+
end
|
44
|
+
io.close
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_writev
|
48
|
+
io = File.open(fixture('writable.txt'), 'w')
|
49
|
+
expected = LENGTHS
|
50
|
+
assert_equal expected, io.writev(*CONTENT.dup)
|
51
|
+
io.truncate(0)
|
52
|
+
io.close
|
53
|
+
end
|
54
|
+
end
|
data/vio.gemspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "vio"
|
3
|
+
s.version = "0.3.0"
|
4
|
+
s.date = "2009-09-19"
|
5
|
+
s.summary = "Vectored I/O extension for Ruby"
|
6
|
+
s.email = "lourens@methodmissing.com"
|
7
|
+
s.homepage = "http://github.com/methodmissing/vio"
|
8
|
+
s.description = "Vectored I/O extension for Ruby MRI (1.8.{6,7} and 1.9.2)"
|
9
|
+
s.has_rdoc = true
|
10
|
+
s.authors = ["Lourens Naudé (methodmissing)"]
|
11
|
+
s.platform = Gem::Platform::RUBY
|
12
|
+
s.files = Dir.glob("{bench,ext,test}/**/*") + %w[README Rakefile ext/vio/extconf.rb ext/vio/vio.c vio.gemspec]
|
13
|
+
s.rdoc_options = ["--main", "README"]
|
14
|
+
s.extra_rdoc_files = ["README"]
|
15
|
+
s.extensions << "ext/vio/extconf.rb"
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vio
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 3
|
8
|
+
- 0
|
9
|
+
version: 0.3.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- "Lourens Naud\xC3\xA9 (methodmissing)"
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2009-09-19 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Vectored I/O extension for Ruby MRI (1.8.{6,7} and 1.9.2)
|
22
|
+
email: lourens@methodmissing.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions:
|
26
|
+
- ext/vio/extconf.rb
|
27
|
+
extra_rdoc_files:
|
28
|
+
- README
|
29
|
+
files:
|
30
|
+
- bench/patched_logger.rb
|
31
|
+
- bench/read.rb
|
32
|
+
- bench/write.rb
|
33
|
+
- ext/vio/extconf.rb
|
34
|
+
- ext/vio/Makefile
|
35
|
+
- ext/vio/mkmf.log
|
36
|
+
- ext/vio/vio.bundle
|
37
|
+
- ext/vio/vio.c
|
38
|
+
- ext/vio/vio.o
|
39
|
+
- test/fixtures/fix.txt
|
40
|
+
- test/fixtures/writable.txt
|
41
|
+
- test/helper.rb
|
42
|
+
- test/test_vio.rb
|
43
|
+
- README
|
44
|
+
- Rakefile
|
45
|
+
- vio.gemspec
|
46
|
+
has_rdoc: true
|
47
|
+
homepage: http://github.com/methodmissing/vio
|
48
|
+
licenses: []
|
49
|
+
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options:
|
52
|
+
- --main
|
53
|
+
- README
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 1.3.7
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Vectored I/O extension for Ruby
|
79
|
+
test_files: []
|
80
|
+
|