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