methodmissing-rb_aio 0.1.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 +6 -0
- data/Rakefile +69 -0
- data/aio.gemspec +24 -0
- data/bench/read.rb +28 -0
- data/bench/write.rb +32 -0
- data/ext/aio/aio.c +851 -0
- data/ext/aio/extconf.rb +15 -0
- metadata +62 -0
data/README
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/clean'
|
4
|
+
$:.unshift(File.expand_path('lib'))
|
5
|
+
AIO_ROOT = 'ext/aio'
|
6
|
+
|
7
|
+
desc 'Default: test'
|
8
|
+
task :default => :test
|
9
|
+
|
10
|
+
desc 'Run AIO tests.'
|
11
|
+
Rake::TestTask.new(:test) do |t|
|
12
|
+
t.libs = [AIO_ROOT]
|
13
|
+
t.pattern = 'test/test_*.rb'
|
14
|
+
t.verbose = true
|
15
|
+
end
|
16
|
+
task :test => :build
|
17
|
+
|
18
|
+
namespace :build do
|
19
|
+
file "#{AIO_ROOT}/aio.c"
|
20
|
+
file "#{AIO_ROOT}/extconf.rb"
|
21
|
+
file "#{AIO_ROOT}/Makefile" => %W(#{AIO_ROOT}/aio.c #{AIO_ROOT}/extconf.rb) do
|
22
|
+
Dir.chdir(AIO_ROOT) do
|
23
|
+
ruby 'extconf.rb'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "generate makefile"
|
28
|
+
task :makefile => %W(#{AIO_ROOT}/Makefile #{AIO_ROOT}/aio.c)
|
29
|
+
|
30
|
+
dlext = Config::CONFIG['DLEXT']
|
31
|
+
file "#{AIO_ROOT}/aio.#{dlext}" => %W(#{AIO_ROOT}/Makefile #{AIO_ROOT}/aio.c) do
|
32
|
+
Dir.chdir(AIO_ROOT) do
|
33
|
+
sh 'make' # TODO - is there a config for which make somewhere?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "compile aio extension"
|
38
|
+
task :compile => "#{AIO_ROOT}/aio.#{dlext}"
|
39
|
+
|
40
|
+
task :clean do
|
41
|
+
Dir.chdir(AIO_ROOT) do
|
42
|
+
sh 'make clean'
|
43
|
+
end if File.exists?("#{AIO_ROOT}/Makefile")
|
44
|
+
end
|
45
|
+
|
46
|
+
CLEAN.include("#{AIO_ROOT}/Makefile")
|
47
|
+
CLEAN.include("#{AIO_ROOT}/aio.#{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(AIO_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
|
+
desc "run benchmarks"
|
65
|
+
task :bench do |t|
|
66
|
+
ruby "bench/read.rb"
|
67
|
+
ruby "bench/write.rb"
|
68
|
+
end
|
69
|
+
task :bench => :build
|
data/aio.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "rb_aio"
|
3
|
+
s.version = "0.1.0"
|
4
|
+
s.date = "2009-09-01"
|
5
|
+
s.summary = "POSIX Realtime IO extension for Ruby"
|
6
|
+
s.email = "lourens@methodmissing.com"
|
7
|
+
s.homepage = "http://github.com/methodmissing/rb_aio"
|
8
|
+
s.description = "POSIX Realtime IO extension for Ruby MRI (1.8.{6,7} and 1.9.2)"
|
9
|
+
s.has_rdoc = true
|
10
|
+
s.authors = ["Lourens Naudé (methodmissing)","James Tucker (raggi)","Aman Gupta (tmm1)"]
|
11
|
+
s.platform = Gem::Platform::RUBY
|
12
|
+
s.files = %w[
|
13
|
+
README
|
14
|
+
Rakefile
|
15
|
+
bench/read.rb
|
16
|
+
bench/write.rb
|
17
|
+
ext/aio/extconf.rb
|
18
|
+
ext/aio/aio.c
|
19
|
+
aio.gemspec
|
20
|
+
] + Dir.glob('test/*')
|
21
|
+
s.rdoc_options = ["--main", "README"]
|
22
|
+
s.extra_rdoc_files = ["README"]
|
23
|
+
s.extensions << "ext/aio/extconf.rb"
|
24
|
+
end
|
data/bench/read.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
$:.unshift "."
|
2
|
+
require File.dirname(__FILE__) + '/../ext/aio/aio'
|
3
|
+
require "benchmark"
|
4
|
+
|
5
|
+
CALLBACKS = (1..8).to_a.map{|f| AIO::CB.new( File.dirname(__FILE__) + "/../test/fixtures/#{f}.txt" ) }
|
6
|
+
NON_BLOCKING = [AIO::NOWAIT].concat( CALLBACKS )
|
7
|
+
PATHS = CALLBACKS.map{|cb| cb.path }
|
8
|
+
|
9
|
+
aio_results, io_results = [], []
|
10
|
+
|
11
|
+
begin
|
12
|
+
puts "* Bench reads ..."
|
13
|
+
Benchmark.bmbm do |results|
|
14
|
+
results.report("AIO.lio_listio(AIO::WAIT)") { aio_results << AIO.lio_listio( *CALLBACKS ) }
|
15
|
+
results.report("IO.read") { io_results << PATHS.map{|p| IO.read(p) } }
|
16
|
+
end
|
17
|
+
|
18
|
+
Benchmark.bmbm do |results|
|
19
|
+
results.report("AIO.lio_listio(AIO::NOWAIT)") { aio_results << AIO.lio_listio( *NON_BLOCKING ) }
|
20
|
+
results.report("IO.read") { io_results << PATHS.map{|p| IO.read(p) } }
|
21
|
+
end
|
22
|
+
ensure
|
23
|
+
CALLBACKS.each{|cb| cb.close }
|
24
|
+
puts "* AIO results ..."
|
25
|
+
aio_results.each{|r| p r }
|
26
|
+
puts "* IO results ..."
|
27
|
+
io_results.each{|r| p r }
|
28
|
+
end
|
data/bench/write.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
$:.unshift "."
|
2
|
+
require File.dirname(__FILE__) + '/../ext/aio/aio'
|
3
|
+
require "benchmark"
|
4
|
+
require "fileutils"
|
5
|
+
|
6
|
+
PAYLOAD = 'a' * 4096
|
7
|
+
CALLBACKS = (1..8).to_a.map{|f| c = AIO::CB.new; c.open(File.dirname(__FILE__) + "/../test/scratch/#{f}.aio.txt", 'w+' ); c.buf = PAYLOAD; c.lio_opcode = AIO::WRITE; c }
|
8
|
+
NON_BLOCKING = [AIO::NOWAIT].concat( CALLBACKS )
|
9
|
+
IOS = CALLBACKS.map{|cb| File.new(cb.path.gsub(/\.aio\.txt/,'.io.txt'), 'w+') }
|
10
|
+
|
11
|
+
aio_results, io_results = [], []
|
12
|
+
|
13
|
+
begin
|
14
|
+
puts "* Bench writes ..."
|
15
|
+
Benchmark.bmbm do |results|
|
16
|
+
results.report("AIO.lio_listio(AIO::WAIT)") { aio_results << AIO.lio_listio( *CALLBACKS ) }
|
17
|
+
results.report("IO.write") { io_results << IOS.map{|io| io.write(PAYLOAD) } }
|
18
|
+
end
|
19
|
+
|
20
|
+
Benchmark.bmbm do |results|
|
21
|
+
results.report("AIO.lio_listio(AIO::NOWAIT)") { aio_results << AIO.lio_listio( *NON_BLOCKING ) }
|
22
|
+
results.report("IO.write") { io_results << IOS.map{|io| io.write(PAYLOAD) } }
|
23
|
+
end
|
24
|
+
ensure
|
25
|
+
CALLBACKS.each{|cb| cb.close }
|
26
|
+
IOS.each{|io| io.close }
|
27
|
+
FileUtils.rm Dir.glob(File.dirname(__FILE__) + "/../test/scratch/*.txt")
|
28
|
+
puts "* AIO results ..."
|
29
|
+
aio_results.each{|r| p r }
|
30
|
+
puts "* IO results ..."
|
31
|
+
io_results.each{|r| p r }
|
32
|
+
end
|
data/ext/aio/aio.c
ADDED
@@ -0,0 +1,851 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include <unistd.h>
|
3
|
+
#include <stdio.h>
|
4
|
+
#include <sys/types.h>
|
5
|
+
#include <sys/stat.h>
|
6
|
+
#include <errno.h>
|
7
|
+
#include <signal.h>
|
8
|
+
#include <fcntl.h>
|
9
|
+
#ifdef _POSIX_ASYNCHRONOUS_IO
|
10
|
+
#include <aio.h>
|
11
|
+
#endif
|
12
|
+
|
13
|
+
#ifndef RSTRING_PTR
|
14
|
+
#define RSTRING_PTR(obj) RSTRING(obj)->ptr
|
15
|
+
#endif
|
16
|
+
|
17
|
+
#ifndef RSTRING_LEN
|
18
|
+
#define RSTRING_LEN(obj) RSTRING(obj)->len
|
19
|
+
#endif
|
20
|
+
|
21
|
+
#ifndef RARRAY_PTR
|
22
|
+
#define RARRAY_PTR(obj) RARRAY(obj)->ptr
|
23
|
+
#endif
|
24
|
+
|
25
|
+
#ifndef RARRAY_LEN
|
26
|
+
#define RARRAY_LEN(obj) RARRAY(obj)->len
|
27
|
+
#endif
|
28
|
+
|
29
|
+
#ifdef RUBY19
|
30
|
+
#include "ruby/io.h"
|
31
|
+
#define TRAP_BEG
|
32
|
+
#define TRAP_END
|
33
|
+
#else
|
34
|
+
#include "rubysig.h"
|
35
|
+
#include "rubyio.h"
|
36
|
+
#endif
|
37
|
+
|
38
|
+
/* Max I/O operations across all supported platforms */
|
39
|
+
#ifdef AIO_LISTIO_MAX
|
40
|
+
#define AIO_MAX_LIST AIO_LISTIO_MAX
|
41
|
+
#else
|
42
|
+
#define AIO_MAX_LIST 16
|
43
|
+
#endif
|
44
|
+
|
45
|
+
static VALUE mAio, eAio;
|
46
|
+
|
47
|
+
VALUE rb_cCB;
|
48
|
+
|
49
|
+
typedef struct aiocb aiocb_t;
|
50
|
+
|
51
|
+
typedef struct{
|
52
|
+
aiocb_t cb;
|
53
|
+
VALUE io;
|
54
|
+
VALUE rcb;
|
55
|
+
} rb_aiocb_t;
|
56
|
+
|
57
|
+
static ID s_to_str, s_to_s, s_buf;
|
58
|
+
|
59
|
+
static VALUE c_aio_sync, c_aio_queue, c_aio_inprogress, c_aio_alldone;
|
60
|
+
static VALUE c_aio_canceled, c_aio_notcanceled, c_aio_wait, c_aio_nowait;
|
61
|
+
static VALUE c_aio_nop, c_aio_read, c_aio_write;
|
62
|
+
|
63
|
+
static void rb_aio_error( const char * msg ){
|
64
|
+
rb_raise( eAio, msg );
|
65
|
+
}
|
66
|
+
|
67
|
+
#define GetCBStruct(obj) (Check_Type(obj, T_DATA), (rb_aiocb_t*)DATA_PTR(obj))
|
68
|
+
|
69
|
+
static void
|
70
|
+
mark_control_block(rb_aiocb_t *cb)
|
71
|
+
{
|
72
|
+
rb_gc_mark(cb->io);
|
73
|
+
rb_gc_mark(cb->rcb);
|
74
|
+
}
|
75
|
+
|
76
|
+
static void
|
77
|
+
free_control_block(rb_aiocb_t* cb)
|
78
|
+
{
|
79
|
+
xfree(cb);
|
80
|
+
}
|
81
|
+
|
82
|
+
static VALUE
|
83
|
+
control_block_nbytes_set(VALUE cb, VALUE bytes)
|
84
|
+
{
|
85
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
86
|
+
Check_Type(bytes, T_FIXNUM);
|
87
|
+
cbs->cb.aio_nbytes = FIX2INT(bytes);
|
88
|
+
if (cbs->cb.aio_buf != NULL) free((char *)cbs->cb.aio_buf);
|
89
|
+
cbs->cb.aio_buf = malloc(cbs->cb.aio_nbytes + 1);
|
90
|
+
if (!cbs->cb.aio_buf) rb_aio_error( "not able to allocate a read buffer" );
|
91
|
+
return bytes;
|
92
|
+
}
|
93
|
+
|
94
|
+
static VALUE
|
95
|
+
control_block_open(int argc, VALUE *argv, VALUE cb)
|
96
|
+
{
|
97
|
+
const char *fmode;
|
98
|
+
#ifdef RUBY19
|
99
|
+
rb_io_t *fptr;
|
100
|
+
#else
|
101
|
+
OpenFile *fptr;
|
102
|
+
#endif
|
103
|
+
VALUE file, mode;
|
104
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
105
|
+
rb_scan_args(argc, argv, "02", &file, &mode);
|
106
|
+
fmode = NIL_P(mode) ? "r" : RSTRING_PTR(mode);
|
107
|
+
struct stat stats;
|
108
|
+
|
109
|
+
Check_Type(file, T_STRING);
|
110
|
+
|
111
|
+
cbs->io = rb_file_open(RSTRING_PTR(file), fmode);
|
112
|
+
GetOpenFile(cbs->io, fptr);
|
113
|
+
rb_io_check_readable(fptr);
|
114
|
+
|
115
|
+
if ( cbs->cb.aio_fildes == 0 && cbs->cb.aio_nbytes == 0){
|
116
|
+
#ifdef RUBY19
|
117
|
+
cbs->cb.aio_fildes = fptr->fd;
|
118
|
+
#else
|
119
|
+
cbs->cb.aio_fildes = fileno(fptr->f);
|
120
|
+
#endif
|
121
|
+
fstat(cbs->cb.aio_fildes, &stats);
|
122
|
+
control_block_nbytes_set(cb, INT2FIX(stats.st_size));
|
123
|
+
}
|
124
|
+
return cb;
|
125
|
+
}
|
126
|
+
|
127
|
+
static void
|
128
|
+
control_block_reset0(rb_aiocb_t *cb)
|
129
|
+
{
|
130
|
+
bzero(cb, sizeof(rb_aiocb_t));
|
131
|
+
bzero(&cb->cb, sizeof(aiocb_t));
|
132
|
+
/* cleanup with rb_io_close(cb->io) */
|
133
|
+
cb->io = Qnil;
|
134
|
+
cb->rcb = Qnil;
|
135
|
+
cb->cb.aio_fildes = 0;
|
136
|
+
cb->cb.aio_buf = NULL;
|
137
|
+
cb->cb.aio_nbytes = 0;
|
138
|
+
cb->cb.aio_offset = 0;
|
139
|
+
cb->cb.aio_reqprio = 0;
|
140
|
+
cb->cb.aio_lio_opcode = LIO_READ;
|
141
|
+
/* Disable signals for the time being */
|
142
|
+
cb->cb.aio_sigevent.sigev_notify = SIGEV_NONE;
|
143
|
+
cb->cb.aio_sigevent.sigev_signo = 0;
|
144
|
+
cb->cb.aio_sigevent.sigev_value.sival_int = 0;
|
145
|
+
}
|
146
|
+
|
147
|
+
static VALUE
|
148
|
+
control_block_reset(VALUE cb)
|
149
|
+
{
|
150
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
151
|
+
control_block_reset0(cbs);
|
152
|
+
return cb;
|
153
|
+
}
|
154
|
+
|
155
|
+
static VALUE control_block_alloc _((VALUE));
|
156
|
+
static VALUE
|
157
|
+
control_block_alloc(VALUE klass)
|
158
|
+
{
|
159
|
+
VALUE obj;
|
160
|
+
rb_aiocb_t *cb;
|
161
|
+
obj = Data_Make_Struct(klass, rb_aiocb_t, mark_control_block, free_control_block, cb);
|
162
|
+
control_block_reset0(cb);
|
163
|
+
return obj;
|
164
|
+
}
|
165
|
+
|
166
|
+
static VALUE
|
167
|
+
control_block_initialize(int argc, VALUE *argv, VALUE cb)
|
168
|
+
{
|
169
|
+
VALUE file, mode;
|
170
|
+
VALUE args[2];
|
171
|
+
rb_scan_args(argc, argv, "02", &file, &mode);
|
172
|
+
if (RTEST(file)){
|
173
|
+
args[0] = file;
|
174
|
+
args[1] = mode;
|
175
|
+
control_block_open(1, (VALUE *)args, cb);
|
176
|
+
}
|
177
|
+
if (rb_block_given_p()) rb_obj_instance_eval( 0, 0, cb );
|
178
|
+
return cb;
|
179
|
+
}
|
180
|
+
|
181
|
+
static VALUE
|
182
|
+
control_block_path(VALUE cb)
|
183
|
+
{
|
184
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
185
|
+
#ifdef RUBY19
|
186
|
+
rb_io_t *fptr;
|
187
|
+
#else
|
188
|
+
OpenFile *fptr;
|
189
|
+
#endif
|
190
|
+
if NIL_P(cbs->io) return rb_str_new2("");
|
191
|
+
GetOpenFile(cbs->io, fptr);
|
192
|
+
rb_io_check_readable(fptr);
|
193
|
+
#ifdef RUBY19
|
194
|
+
return rb_file_s_expand_path( 1, &fptr->pathv );
|
195
|
+
#else
|
196
|
+
VALUE path = rb_str_new2(fptr->path);
|
197
|
+
return rb_file_s_expand_path( 1, &path );
|
198
|
+
#endif
|
199
|
+
}
|
200
|
+
|
201
|
+
static VALUE
|
202
|
+
control_block_callback_get(VALUE cb)
|
203
|
+
{
|
204
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
205
|
+
return cbs->rcb;
|
206
|
+
}
|
207
|
+
|
208
|
+
static VALUE
|
209
|
+
control_block_callback_set(VALUE cb, VALUE rcb)
|
210
|
+
{
|
211
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
212
|
+
if (RBASIC(rcb)->klass != rb_cProc) rb_aio_error("Block required for callback!");
|
213
|
+
cbs->rcb = rcb;
|
214
|
+
return cbs->rcb;
|
215
|
+
}
|
216
|
+
|
217
|
+
static VALUE
|
218
|
+
control_block_fildes_get(VALUE cb)
|
219
|
+
{
|
220
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
221
|
+
return INT2FIX(cbs->cb.aio_fildes);
|
222
|
+
}
|
223
|
+
|
224
|
+
static VALUE
|
225
|
+
control_block_fildes_set(VALUE cb, VALUE fd)
|
226
|
+
{
|
227
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
228
|
+
Check_Type(fd, T_FIXNUM);
|
229
|
+
cbs->cb.aio_fildes = FIX2INT(fd);
|
230
|
+
return fd;
|
231
|
+
}
|
232
|
+
|
233
|
+
static VALUE
|
234
|
+
control_block_buf_get(VALUE cb)
|
235
|
+
{
|
236
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
237
|
+
return cbs->cb.aio_buf == NULL ? rb_str_new2("") : rb_str_new((char *)cbs->cb.aio_buf, cbs->cb.aio_nbytes);
|
238
|
+
}
|
239
|
+
|
240
|
+
static VALUE
|
241
|
+
control_block_buf_set(VALUE cb, VALUE buf)
|
242
|
+
{
|
243
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
244
|
+
Check_Type(buf, T_STRING);
|
245
|
+
if (cbs->cb.aio_buf != NULL){
|
246
|
+
free((char *)cbs->cb.aio_buf);
|
247
|
+
cbs->cb.aio_buf = NULL;
|
248
|
+
}
|
249
|
+
cbs->cb.aio_buf = RSTRING_PTR(buf);
|
250
|
+
cbs->cb.aio_nbytes = RSTRING_LEN(buf);
|
251
|
+
return buf;
|
252
|
+
}
|
253
|
+
|
254
|
+
static VALUE
|
255
|
+
control_block_nbytes_get(VALUE cb)
|
256
|
+
{
|
257
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
258
|
+
return INT2FIX(cbs->cb.aio_nbytes);
|
259
|
+
}
|
260
|
+
|
261
|
+
static VALUE
|
262
|
+
control_block_offset_get(VALUE cb)
|
263
|
+
{
|
264
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
265
|
+
return INT2FIX(cbs->cb.aio_offset);
|
266
|
+
}
|
267
|
+
|
268
|
+
static VALUE
|
269
|
+
control_block_offset_set(VALUE cb, VALUE offset)
|
270
|
+
{
|
271
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
272
|
+
Check_Type(offset, T_FIXNUM);
|
273
|
+
cbs->cb.aio_offset = FIX2INT(offset);
|
274
|
+
return offset;
|
275
|
+
}
|
276
|
+
|
277
|
+
static VALUE
|
278
|
+
control_block_reqprio_get(VALUE cb)
|
279
|
+
{
|
280
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
281
|
+
return INT2FIX(cbs->cb.aio_reqprio);
|
282
|
+
}
|
283
|
+
|
284
|
+
static VALUE
|
285
|
+
control_block_reqprio_set(VALUE cb, VALUE reqprio)
|
286
|
+
{
|
287
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
288
|
+
Check_Type(reqprio, T_FIXNUM);
|
289
|
+
cbs->cb.aio_reqprio = FIX2INT(reqprio);
|
290
|
+
return reqprio;
|
291
|
+
}
|
292
|
+
|
293
|
+
static VALUE
|
294
|
+
control_block_lio_opcode_get(VALUE cb)
|
295
|
+
{
|
296
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
297
|
+
return INT2FIX(cbs->cb.aio_lio_opcode);
|
298
|
+
}
|
299
|
+
|
300
|
+
static VALUE
|
301
|
+
control_block_lio_opcode_set(VALUE cb, VALUE opcode)
|
302
|
+
{
|
303
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
304
|
+
Check_Type(opcode, T_FIXNUM);
|
305
|
+
if (opcode != c_aio_read && opcode != c_aio_write) rb_aio_error( "Only AIO::READ and AIO::WRITE modes supported" );
|
306
|
+
cbs->cb.aio_lio_opcode = NUM2INT(opcode);
|
307
|
+
return opcode;
|
308
|
+
}
|
309
|
+
|
310
|
+
static VALUE
|
311
|
+
control_block_validate(VALUE cb)
|
312
|
+
{
|
313
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
314
|
+
if (cbs->cb.aio_fildes <= 0) rb_aio_error( "Invalid file descriptor" );
|
315
|
+
if (cbs->cb.aio_nbytes <= 0) rb_aio_error( "Invalid buffer length" );
|
316
|
+
if (cbs->cb.aio_offset < 0) rb_aio_error( "Invalid file offset" );
|
317
|
+
if (cbs->cb.aio_reqprio < 0) rb_aio_error( "Invalid request priority" );
|
318
|
+
if (cbs->cb.aio_lio_opcode != LIO_READ && cbs->cb.aio_lio_opcode != LIO_WRITE) rb_aio_error( "Only AIO::READ and AIO::WRITE modes supported" );
|
319
|
+
if (!cbs->cb.aio_buf) rb_aio_error( "No buffer allocated" );
|
320
|
+
return cb;
|
321
|
+
}
|
322
|
+
|
323
|
+
static VALUE
|
324
|
+
control_block_open_p(VALUE cb)
|
325
|
+
{
|
326
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
327
|
+
return NIL_P(cbs->io) ? Qfalse : Qtrue;
|
328
|
+
}
|
329
|
+
|
330
|
+
static VALUE
|
331
|
+
control_block_closed_p(VALUE cb)
|
332
|
+
{
|
333
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
334
|
+
return NIL_P(cbs->io) ? Qtrue : Qfalse;
|
335
|
+
}
|
336
|
+
|
337
|
+
static VALUE
|
338
|
+
control_block_close(VALUE cb)
|
339
|
+
{
|
340
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
341
|
+
if NIL_P(cbs->io) return Qfalse;
|
342
|
+
rb_io_close(cbs->io);
|
343
|
+
cbs->io = Qnil;
|
344
|
+
cbs->rcb = Qnil;
|
345
|
+
return Qtrue;
|
346
|
+
}
|
347
|
+
|
348
|
+
/*
|
349
|
+
* Error handling for aio_write
|
350
|
+
*/
|
351
|
+
static void
|
352
|
+
rb_aio_write_error()
|
353
|
+
{
|
354
|
+
switch(errno){
|
355
|
+
case EAGAIN:
|
356
|
+
rb_aio_error( "[EAGAIN] The request cannot be queued due to exceeding resource (queue) limitations." );
|
357
|
+
case EBADF:
|
358
|
+
rb_aio_error( "[EBADF] File descriptor is not valid for writing." );
|
359
|
+
case ENOSYS:
|
360
|
+
rb_aio_error( "[ENOSYS] aio_read not supported by this implementation." );
|
361
|
+
case EINVAL:
|
362
|
+
rb_aio_error( "[EINVAL] Read offset is invalid" );
|
363
|
+
case EOVERFLOW:
|
364
|
+
rb_aio_error( "[EOVERFLOW] Control block offset exceeded." );
|
365
|
+
case ECANCELED:
|
366
|
+
rb_aio_error( "[ECANCELED] The requested I/O was canceled by an explicit aio_cancel() request." );
|
367
|
+
case EFBIG:
|
368
|
+
rb_aio_error( "[EFBIG] Wrong offset." );
|
369
|
+
}
|
370
|
+
}
|
371
|
+
|
372
|
+
/*
|
373
|
+
* Error handling for aio_read
|
374
|
+
*/
|
375
|
+
static void
|
376
|
+
rb_aio_read_error()
|
377
|
+
{
|
378
|
+
switch(errno){
|
379
|
+
case EAGAIN:
|
380
|
+
rb_aio_error( "[EAGAIN] The request cannot be queued due to exceeding resource (queue) limitations." );
|
381
|
+
case EBADF:
|
382
|
+
rb_aio_error( "[EBADF] File descriptor is not valid for reading." );
|
383
|
+
case ENOSYS:
|
384
|
+
rb_aio_error( "[ENOSYS] aio_read not supported by this implementation." );
|
385
|
+
case EINVAL:
|
386
|
+
rb_aio_error( "[EINVAL] Read offset is invalid" );
|
387
|
+
case EOVERFLOW:
|
388
|
+
rb_aio_error( "[EOVERFLOW] Control block offset exceeded." );
|
389
|
+
}
|
390
|
+
}
|
391
|
+
|
392
|
+
/*
|
393
|
+
* Initiates a *blocking* write
|
394
|
+
*/
|
395
|
+
static VALUE
|
396
|
+
rb_aio_write( aiocb_t *cb )
|
397
|
+
{
|
398
|
+
int ret;
|
399
|
+
|
400
|
+
TRAP_BEG;
|
401
|
+
ret = aio_write( cb );
|
402
|
+
TRAP_END;
|
403
|
+
if (ret != 0) rb_aio_write_error();
|
404
|
+
while ( aio_error( cb ) == EINPROGRESS );
|
405
|
+
if ((ret = aio_return( cb )) > 0) {
|
406
|
+
return INT2NUM(cb->aio_nbytes);
|
407
|
+
}else{
|
408
|
+
return INT2NUM(errno);
|
409
|
+
}
|
410
|
+
}
|
411
|
+
|
412
|
+
/*
|
413
|
+
* Initiates a *blocking* read
|
414
|
+
*/
|
415
|
+
static VALUE
|
416
|
+
rb_aio_read( aiocb_t *cb )
|
417
|
+
{
|
418
|
+
int ret;
|
419
|
+
|
420
|
+
TRAP_BEG;
|
421
|
+
ret = aio_read( cb );
|
422
|
+
TRAP_END;
|
423
|
+
if (ret != 0) rb_aio_read_error();
|
424
|
+
while ( aio_error( cb ) == EINPROGRESS );
|
425
|
+
if ((ret = aio_return( cb )) > 0) {
|
426
|
+
return rb_str_new( (char *)cb->aio_buf, cb->aio_nbytes );
|
427
|
+
}else{
|
428
|
+
return INT2NUM(errno);
|
429
|
+
}
|
430
|
+
}
|
431
|
+
|
432
|
+
/*
|
433
|
+
* Error handling for lio_listio
|
434
|
+
*/
|
435
|
+
static void
|
436
|
+
rb_aio_listio_error()
|
437
|
+
{
|
438
|
+
switch(errno){
|
439
|
+
case EAGAIN:
|
440
|
+
rb_aio_error( "[EAGAIN] Resources necessary to queue all the requests are not available at the moment." );
|
441
|
+
case EIO:
|
442
|
+
rb_aio_error( "[EIO] One or more requests failed" );
|
443
|
+
case ENOSYS:
|
444
|
+
rb_aio_error( "[ENOSYS] lio_listio not supported by this implementation." );
|
445
|
+
case EINVAL:
|
446
|
+
rb_aio_error( "[EINVAL] Maximum number of allowed simultaneous requests exceeded." );
|
447
|
+
case EINTR:
|
448
|
+
rb_aio_error( "[EINTR] A signal was delivered while waiting for all I/O requests to complete during a LIO_WAIT operation." );
|
449
|
+
}
|
450
|
+
}
|
451
|
+
|
452
|
+
static void
|
453
|
+
rb_aio_lio_listio0( int mode, VALUE *cbs, aiocb_t **list, int ops )
|
454
|
+
{
|
455
|
+
int op;
|
456
|
+
bzero( (char *)list, sizeof(list) );
|
457
|
+
for (op=0; op < ops; op++) {
|
458
|
+
rb_aiocb_t *cb = GetCBStruct(RARRAY_PTR(cbs)[op]);
|
459
|
+
if (rb_block_given_p()){
|
460
|
+
cb->rcb = rb_block_proc();
|
461
|
+
}
|
462
|
+
list[op] = &cb->cb;
|
463
|
+
}
|
464
|
+
}
|
465
|
+
|
466
|
+
/*
|
467
|
+
* Initiates lio_listio
|
468
|
+
*/
|
469
|
+
static int
|
470
|
+
rb_aio_lio_listio( int mode, VALUE *cbs, aiocb_t **list )
|
471
|
+
{
|
472
|
+
int ret;
|
473
|
+
int ops = RARRAY_LEN(cbs);
|
474
|
+
rb_aio_lio_listio0(mode, cbs, list, ops);
|
475
|
+
TRAP_BEG;
|
476
|
+
ret = lio_listio( mode, list, ops, NULL );
|
477
|
+
TRAP_END;
|
478
|
+
if (ret != 0) rb_aio_listio_error();
|
479
|
+
return ops;
|
480
|
+
}
|
481
|
+
|
482
|
+
/*
|
483
|
+
* Blocking lio_listio
|
484
|
+
*/
|
485
|
+
static VALUE
|
486
|
+
rb_aio_lio_listio_blocking( VALUE *cbs )
|
487
|
+
{
|
488
|
+
aiocb_t *list[AIO_MAX_LIST];
|
489
|
+
int op;
|
490
|
+
int ops = rb_aio_lio_listio( LIO_WAIT, cbs, list );
|
491
|
+
VALUE results = rb_ary_new2( ops );
|
492
|
+
for (op=0; op < ops; op++) {
|
493
|
+
if (list[op]->aio_lio_opcode == LIO_READ){
|
494
|
+
rb_ary_push( results, rb_str_new( (char *)list[op]->aio_buf, list[op]->aio_nbytes ) );
|
495
|
+
}else{
|
496
|
+
rb_ary_push( results, INT2FIX(list[op]->aio_nbytes) );
|
497
|
+
}
|
498
|
+
}
|
499
|
+
return results;
|
500
|
+
}
|
501
|
+
|
502
|
+
/*
|
503
|
+
* No-op lio_listio
|
504
|
+
*/
|
505
|
+
static VALUE
|
506
|
+
rb_aio_lio_listio_noop( VALUE *cbs )
|
507
|
+
{
|
508
|
+
aiocb_t *list[AIO_MAX_LIST];
|
509
|
+
rb_aio_lio_listio( LIO_NOP, cbs, list );
|
510
|
+
return Qnil;
|
511
|
+
}
|
512
|
+
|
513
|
+
/*
|
514
|
+
* Non-blocking lio_listio
|
515
|
+
*/
|
516
|
+
static VALUE
|
517
|
+
rb_aio_lio_listio_non_blocking( VALUE *cbs )
|
518
|
+
{
|
519
|
+
aiocb_t *list[AIO_MAX_LIST];
|
520
|
+
rb_aio_lio_listio( LIO_NOWAIT, cbs, list );
|
521
|
+
return Qnil;
|
522
|
+
}
|
523
|
+
|
524
|
+
/*
|
525
|
+
* Helper to ensure files opened via AIO.lio_listio is closed.
|
526
|
+
*/
|
527
|
+
static void
|
528
|
+
rb_io_closes( VALUE cbs ){
|
529
|
+
int io;
|
530
|
+
for (io=0; io < RARRAY_LEN(cbs); io++) {
|
531
|
+
control_block_close( RARRAY_PTR(cbs)[io] );
|
532
|
+
}
|
533
|
+
}
|
534
|
+
|
535
|
+
/*
|
536
|
+
* call-seq:
|
537
|
+
* AIO.write(cb) -> fixnum
|
538
|
+
*
|
539
|
+
* Asynchronously writes to a file.This is an initial *blocking* implementation until
|
540
|
+
* cross platform notification is supported.
|
541
|
+
*/
|
542
|
+
static VALUE
|
543
|
+
rb_aio_s_write( VALUE aio, VALUE cb )
|
544
|
+
{
|
545
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
546
|
+
#ifdef RUBY19
|
547
|
+
rb_io_t *fptr;
|
548
|
+
#else
|
549
|
+
OpenFile *fptr;
|
550
|
+
#endif
|
551
|
+
GetOpenFile(cbs->io, fptr);
|
552
|
+
rb_io_check_writable(fptr);
|
553
|
+
if (rb_block_given_p()){
|
554
|
+
cbs->rcb = rb_block_proc();
|
555
|
+
}
|
556
|
+
|
557
|
+
return rb_ensure( rb_aio_write, (VALUE)&cbs->cb, control_block_close, cb );
|
558
|
+
}
|
559
|
+
|
560
|
+
/*
|
561
|
+
* call-seq:
|
562
|
+
* AIO.read(cb) -> string
|
563
|
+
*
|
564
|
+
* Asynchronously reads a file.This is an initial *blocking* implementation until
|
565
|
+
* cross platform notification is supported.
|
566
|
+
*/
|
567
|
+
static VALUE
|
568
|
+
rb_aio_s_read( VALUE aio, VALUE cb )
|
569
|
+
{
|
570
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
571
|
+
if (rb_block_given_p()){
|
572
|
+
cbs->rcb = rb_block_proc();
|
573
|
+
}
|
574
|
+
return rb_ensure( rb_aio_read, (VALUE)&cbs->cb, control_block_close, cb );
|
575
|
+
}
|
576
|
+
|
577
|
+
/*
|
578
|
+
* call-seq:
|
579
|
+
* AIO.lio_listio(cb1, cb2, ...) -> array
|
580
|
+
*
|
581
|
+
* Schedules a batch of read requests for execution by the kernel in order
|
582
|
+
* to reduce system calls.Blocks until all the requests complete and returns
|
583
|
+
* an array equal in length to the given files, with the read buffers as string
|
584
|
+
* elements.The number of operations is currently limited to 16 due to cross
|
585
|
+
* platform limitations.
|
586
|
+
*
|
587
|
+
* open_nocancel("first.txt\0", 0x0, 0x1B6) = 3 0
|
588
|
+
* fstat(0x3, 0xBFFFEE04, 0x1B6) = 0 0
|
589
|
+
* open_nocancel("second.txt\0", 0x0, 0x1B6) = 4 0
|
590
|
+
* fstat(0x4, 0xBFFFEE04, 0x1B6) = 0 0
|
591
|
+
* open_nocancel("third.txt\0", 0x0, 0x1B6) = 5 0
|
592
|
+
* fstat(0x5, 0xBFFFEE04, 0x1B6) = 0 0
|
593
|
+
* fstat64(0x1, 0xBFFFE234, 0x1B6) = 0 0
|
594
|
+
* ioctl(0x1, 0x4004667A, 0xBFFFE29C) = 0 0
|
595
|
+
* lio_listio(0x2, 0xBFFFEE64, 0x3) = 0 0
|
596
|
+
* close_nocancel(0x4) = 0 0
|
597
|
+
* close_nocancel(0x3) = 0 0
|
598
|
+
*/
|
599
|
+
static VALUE
|
600
|
+
rb_aio_s_lio_listio( VALUE aio, VALUE cbs )
|
601
|
+
{
|
602
|
+
VALUE mode_arg, mode;
|
603
|
+
mode_arg = RARRAY_PTR(cbs)[0];
|
604
|
+
mode = (mode_arg == c_aio_wait || mode_arg == c_aio_nowait || mode_arg == c_aio_nop) ? rb_ary_shift(cbs) : c_aio_wait;
|
605
|
+
int ops = RARRAY_LEN(cbs);
|
606
|
+
if (ops > AIO_MAX_LIST) return c_aio_queue;
|
607
|
+
switch(NUM2INT(mode)){
|
608
|
+
case LIO_WAIT:
|
609
|
+
return rb_ensure( rb_aio_lio_listio_blocking, (VALUE)cbs, rb_io_closes, (VALUE)cbs );
|
610
|
+
case LIO_NOWAIT:
|
611
|
+
return rb_ensure( rb_aio_lio_listio_non_blocking, (VALUE)cbs, rb_io_closes, (VALUE)cbs );
|
612
|
+
case LIO_NOP:
|
613
|
+
return rb_ensure( rb_aio_lio_listio_noop, (VALUE)cbs, rb_io_closes, (VALUE)cbs );
|
614
|
+
}
|
615
|
+
rb_aio_error("Only modes AIO::WAIT, AIO::NOWAIT and AIO::NOP supported");
|
616
|
+
}
|
617
|
+
|
618
|
+
/*
|
619
|
+
* Error handling for aio_cancel
|
620
|
+
*/
|
621
|
+
static void
|
622
|
+
rb_aio_cancel_error()
|
623
|
+
{
|
624
|
+
switch(errno){
|
625
|
+
case EBADF:
|
626
|
+
rb_aio_error( "[EBADF] Invalid file descriptor." );
|
627
|
+
case ENOSYS:
|
628
|
+
rb_aio_error( "[ENOSYS] aio_cancel is not supported by this implementation." );
|
629
|
+
}
|
630
|
+
}
|
631
|
+
|
632
|
+
static VALUE
|
633
|
+
rb_aio_cancel( int fd, void *cb )
|
634
|
+
{
|
635
|
+
int ret;
|
636
|
+
TRAP_BEG;
|
637
|
+
ret = aio_cancel( fd, cb );
|
638
|
+
TRAP_END;
|
639
|
+
if (ret != 0) rb_aio_cancel_error();
|
640
|
+
switch(ret){
|
641
|
+
case AIO_CANCELED:
|
642
|
+
return c_aio_canceled;
|
643
|
+
case AIO_NOTCANCELED:
|
644
|
+
return c_aio_notcanceled;
|
645
|
+
case AIO_ALLDONE:
|
646
|
+
return c_aio_alldone;
|
647
|
+
}
|
648
|
+
return Qnil;
|
649
|
+
}
|
650
|
+
|
651
|
+
static VALUE
|
652
|
+
rb_aio_s_cancel(int argc, VALUE *argv, VALUE aio)
|
653
|
+
{
|
654
|
+
VALUE fd, cb;
|
655
|
+
rb_scan_args(argc, argv, "02", &fd, &cb);
|
656
|
+
if (NIL_P(fd) || !FIXNUM_P(fd)) rb_aio_error("No file descriptor given");
|
657
|
+
if (NIL_P(cb)) return rb_aio_cancel( NUM2INT(fd), NULL );
|
658
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
659
|
+
if (rb_block_given_p()){
|
660
|
+
cbs->rcb = rb_block_proc();
|
661
|
+
}
|
662
|
+
return rb_aio_cancel( NUM2INT(fd), &cbs->cb );
|
663
|
+
}
|
664
|
+
|
665
|
+
/*
|
666
|
+
* Error handling for aio_return
|
667
|
+
*/
|
668
|
+
static void
|
669
|
+
rb_aio_return_error()
|
670
|
+
{
|
671
|
+
switch(errno){
|
672
|
+
case ENOMEM:
|
673
|
+
rb_aio_error( "[ENOMEM] There were no Kernel control blocks available to service this request." );
|
674
|
+
case EINVAL:
|
675
|
+
rb_aio_error( "[EINVAL] The control block does not refer to an asynchronous operation whose return status has not yet been retrieved." );
|
676
|
+
case ENOSYS:
|
677
|
+
rb_aio_error( "[ENOSYS] aio_return not supported by this implementation." );
|
678
|
+
}
|
679
|
+
}
|
680
|
+
|
681
|
+
static VALUE
|
682
|
+
rb_aio_return( aiocb_t *cb )
|
683
|
+
{
|
684
|
+
int ret;
|
685
|
+
TRAP_BEG;
|
686
|
+
ret = aio_return( cb );
|
687
|
+
TRAP_END;
|
688
|
+
if (ret != 0) rb_aio_return_error();
|
689
|
+
return INT2FIX(ret);
|
690
|
+
}
|
691
|
+
|
692
|
+
static VALUE
|
693
|
+
rb_aio_s_return( VALUE aio, VALUE cb )
|
694
|
+
{
|
695
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
696
|
+
if (rb_block_given_p()){
|
697
|
+
cbs->rcb = rb_block_proc();
|
698
|
+
}
|
699
|
+
return rb_aio_return( &cbs->cb );
|
700
|
+
}
|
701
|
+
|
702
|
+
/*
|
703
|
+
* Error handling for aio_error
|
704
|
+
*/
|
705
|
+
static void
|
706
|
+
rb_aio_err_error()
|
707
|
+
{
|
708
|
+
switch(errno){
|
709
|
+
case EINVAL:
|
710
|
+
rb_aio_error( "[EINVAL] The control block does not refer to an asynchronous operation whose return status has not yet been retrieved." );
|
711
|
+
case ENOSYS:
|
712
|
+
rb_aio_error( "[ENOSYS] aio_error not supported by this implementation." );
|
713
|
+
}
|
714
|
+
}
|
715
|
+
|
716
|
+
static VALUE
|
717
|
+
rb_aio_err( aiocb_t *cb )
|
718
|
+
{
|
719
|
+
int ret;
|
720
|
+
TRAP_BEG;
|
721
|
+
ret = aio_error( cb );
|
722
|
+
TRAP_END;
|
723
|
+
if (ret != 0) rb_aio_err_error();
|
724
|
+
return INT2FIX(ret);
|
725
|
+
}
|
726
|
+
|
727
|
+
static VALUE
|
728
|
+
rb_aio_s_error( VALUE aio, VALUE cb )
|
729
|
+
{
|
730
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
731
|
+
if (rb_block_given_p()){
|
732
|
+
cbs->rcb = rb_block_proc();
|
733
|
+
}
|
734
|
+
return rb_aio_err( &cbs->cb );
|
735
|
+
}
|
736
|
+
|
737
|
+
/*
|
738
|
+
* Error handling for aio_error
|
739
|
+
*/
|
740
|
+
static void
|
741
|
+
rb_aio_sync_error()
|
742
|
+
{
|
743
|
+
switch(errno){
|
744
|
+
case EINVAL:
|
745
|
+
rb_aio_error( "[EINVAL] A value of op other than AIO::DSYNC or AIO::SYNC was specified." );
|
746
|
+
case EAGAIN:
|
747
|
+
rb_aio_error( "[EAGAIN] The requested asynchronous operation was not queued due to temporary resource limitations." );
|
748
|
+
case ENOSYS:
|
749
|
+
rb_aio_error( "[ENOSYS] aio_error not supported by this implementation." );
|
750
|
+
case EBADF:
|
751
|
+
rb_aio_error( "[EBADF] Invalid file descriptor." );
|
752
|
+
}
|
753
|
+
}
|
754
|
+
|
755
|
+
static VALUE
|
756
|
+
rb_aio_sync( int op, aiocb_t *cb )
|
757
|
+
{
|
758
|
+
int ret;
|
759
|
+
TRAP_BEG;
|
760
|
+
ret = aio_fsync( op, cb );
|
761
|
+
TRAP_END;
|
762
|
+
if (ret != 0) rb_aio_sync_error();
|
763
|
+
return INT2FIX(ret);
|
764
|
+
}
|
765
|
+
|
766
|
+
static VALUE
|
767
|
+
rb_aio_s_sync( VALUE aio, VALUE op, VALUE cb )
|
768
|
+
{
|
769
|
+
rb_aiocb_t *cbs = GetCBStruct(cb);
|
770
|
+
if (rb_block_given_p()){
|
771
|
+
cbs->rcb = rb_block_proc();
|
772
|
+
}
|
773
|
+
Check_Type( op, T_FIXNUM );
|
774
|
+
/* XXX handle AIO::DSYNC gracefully as well */
|
775
|
+
if (op != c_aio_sync) rb_aio_error("Operation AIO::SYNC expected");
|
776
|
+
return rb_aio_sync( NUM2INT(op), &cbs->cb );
|
777
|
+
}
|
778
|
+
|
779
|
+
void Init_aio()
|
780
|
+
{
|
781
|
+
s_buf = rb_intern("buf");
|
782
|
+
s_to_str = rb_intern("to_str");
|
783
|
+
s_to_s = rb_intern("to_s");
|
784
|
+
|
785
|
+
mAio = rb_define_module("AIO");
|
786
|
+
|
787
|
+
rb_cCB = rb_define_class_under( mAio, "CB", rb_cObject);
|
788
|
+
rb_define_alloc_func(rb_cCB, control_block_alloc);
|
789
|
+
rb_define_method(rb_cCB, "initialize", control_block_initialize, -1);
|
790
|
+
rb_define_method(rb_cCB, "fildes", control_block_fildes_get, 0);
|
791
|
+
rb_define_method(rb_cCB, "fildes=", control_block_fildes_set, 1);
|
792
|
+
rb_define_method(rb_cCB, "buf", control_block_buf_get, 0);
|
793
|
+
rb_define_method(rb_cCB, "buf=", control_block_buf_set, 1);
|
794
|
+
rb_define_method(rb_cCB, "nbytes", control_block_nbytes_get, 0);
|
795
|
+
rb_define_method(rb_cCB, "nbytes=", control_block_nbytes_set, 1);
|
796
|
+
rb_define_method(rb_cCB, "offset", control_block_offset_get, 0);
|
797
|
+
rb_define_method(rb_cCB, "offset=", control_block_offset_set, 1);
|
798
|
+
rb_define_method(rb_cCB, "reqprio", control_block_reqprio_get, 0);
|
799
|
+
rb_define_method(rb_cCB, "reqprio=", control_block_reqprio_set, 1);
|
800
|
+
rb_define_method(rb_cCB, "lio_opcode", control_block_lio_opcode_get, 0);
|
801
|
+
rb_define_method(rb_cCB, "lio_opcode=", control_block_lio_opcode_set, 1);
|
802
|
+
rb_define_method(rb_cCB, "callback", control_block_callback_get, 0);
|
803
|
+
rb_define_method(rb_cCB, "callback=", control_block_callback_set, 1);
|
804
|
+
rb_define_method(rb_cCB, "validate", control_block_validate, 0);
|
805
|
+
rb_define_method(rb_cCB, "reset", control_block_reset, 0);
|
806
|
+
rb_define_method(rb_cCB, "open", control_block_open, -1);
|
807
|
+
rb_define_method(rb_cCB, "open?", control_block_open_p, 0);
|
808
|
+
rb_define_method(rb_cCB, "close", control_block_close, 0);
|
809
|
+
rb_define_method(rb_cCB, "closed?", control_block_closed_p, 0);
|
810
|
+
rb_define_method(rb_cCB, "path", control_block_path, 0);
|
811
|
+
|
812
|
+
rb_alias( rb_cCB, s_to_str, s_buf );
|
813
|
+
rb_alias( rb_cCB, s_to_s, s_buf );
|
814
|
+
|
815
|
+
rb_define_const(mAio, "SYNC", INT2NUM(O_SYNC));
|
816
|
+
/*
|
817
|
+
XXX O_DSYNC not supported by Darwin
|
818
|
+
rb_define_const(mAio, "DSYNC", INT2NUM(O_DSYNC));*/
|
819
|
+
rb_define_const(mAio, "QUEUE", INT2NUM(100));
|
820
|
+
rb_define_const(mAio, "INPROGRESS", INT2NUM(EINPROGRESS));
|
821
|
+
rb_define_const(mAio, "ALLDONE", INT2NUM(AIO_ALLDONE));
|
822
|
+
rb_define_const(mAio, "CANCELED", INT2NUM(AIO_CANCELED));
|
823
|
+
rb_define_const(mAio, "NOTCANCELED", INT2NUM(AIO_NOTCANCELED));
|
824
|
+
rb_define_const(mAio, "WAIT", INT2NUM(LIO_WAIT));
|
825
|
+
rb_define_const(mAio, "NOWAIT", INT2NUM(LIO_NOWAIT));
|
826
|
+
rb_define_const(mAio, "NOP", INT2NUM(LIO_NOP));
|
827
|
+
rb_define_const(mAio, "READ", INT2NUM(LIO_READ));
|
828
|
+
rb_define_const(mAio, "WRITE", INT2NUM(LIO_WRITE));
|
829
|
+
|
830
|
+
c_aio_sync = INT2NUM(O_SYNC);
|
831
|
+
c_aio_queue = INT2NUM(100);
|
832
|
+
c_aio_inprogress = INT2NUM(EINPROGRESS);
|
833
|
+
c_aio_alldone = INT2NUM(AIO_ALLDONE);
|
834
|
+
c_aio_canceled = INT2NUM(AIO_CANCELED);
|
835
|
+
c_aio_notcanceled = INT2NUM(AIO_NOTCANCELED);
|
836
|
+
c_aio_wait = INT2NUM(LIO_WAIT);
|
837
|
+
c_aio_nowait = INT2NUM(LIO_NOWAIT);
|
838
|
+
c_aio_nop = INT2NUM(LIO_NOP);
|
839
|
+
c_aio_read = INT2NUM(LIO_READ);
|
840
|
+
c_aio_write = INT2NUM(LIO_WRITE);
|
841
|
+
|
842
|
+
eAio = rb_define_class_under(mAio, "Error", rb_eStandardError);
|
843
|
+
|
844
|
+
rb_define_module_function( mAio, "lio_listio", rb_aio_s_lio_listio, -2 );
|
845
|
+
rb_define_module_function( mAio, "read", rb_aio_s_read, 1 );
|
846
|
+
rb_define_module_function( mAio, "write", rb_aio_s_write, 1 );
|
847
|
+
rb_define_module_function( mAio, "cancel", rb_aio_s_cancel, -1 );
|
848
|
+
rb_define_module_function( mAio, "return", rb_aio_s_return, 1 );
|
849
|
+
rb_define_module_function( mAio, "error", rb_aio_s_error, 1 );
|
850
|
+
rb_define_module_function( mAio, "sync", rb_aio_s_sync, 2 );
|
851
|
+
}
|
data/ext/aio/extconf.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
def add_define(name)
|
4
|
+
$defs.push("-D#{name}")
|
5
|
+
end
|
6
|
+
|
7
|
+
dir_config('aio')
|
8
|
+
|
9
|
+
if RUBY_PLATFORM =~ /linux/i
|
10
|
+
raise 'cannot find AIO' unless have_library('rt', 'aio_read', 'aio.h')
|
11
|
+
end
|
12
|
+
add_define 'RUBY19' if have_func('rb_thread_blocking_region') and have_macro('RUBY_UBF_IO', 'ruby.h')
|
13
|
+
add_define 'RUBY18' if have_var('rb_trap_immediate', ['ruby.h', 'rubysig.h'])
|
14
|
+
|
15
|
+
create_makefile('aio')
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: methodmissing-rb_aio
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Lourens Naud\xC3\xA9 (methodmissing)"
|
8
|
+
- James Tucker (raggi)
|
9
|
+
- Aman Gupta (tmm1)
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
|
14
|
+
date: 2009-09-01 00:00:00 -07:00
|
15
|
+
default_executable:
|
16
|
+
dependencies: []
|
17
|
+
|
18
|
+
description: POSIX Realtime IO extension for Ruby MRI (1.8.{6,7} and 1.9.2)
|
19
|
+
email: lourens@methodmissing.com
|
20
|
+
executables: []
|
21
|
+
|
22
|
+
extensions:
|
23
|
+
- ext/aio/extconf.rb
|
24
|
+
extra_rdoc_files:
|
25
|
+
- README
|
26
|
+
files:
|
27
|
+
- README
|
28
|
+
- Rakefile
|
29
|
+
- bench/read.rb
|
30
|
+
- bench/write.rb
|
31
|
+
- ext/aio/extconf.rb
|
32
|
+
- ext/aio/aio.c
|
33
|
+
- aio.gemspec
|
34
|
+
has_rdoc: true
|
35
|
+
homepage: http://github.com/methodmissing/rb_aio
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options:
|
38
|
+
- --main
|
39
|
+
- README
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
version:
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
requirements: []
|
55
|
+
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 1.2.0
|
58
|
+
signing_key:
|
59
|
+
specification_version: 2
|
60
|
+
summary: POSIX Realtime IO extension for Ruby
|
61
|
+
test_files: []
|
62
|
+
|