io-extra 1.2.5 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +2 -0
- data.tar.gz.sig +0 -0
- data/CHANGES +45 -0
- data/MANIFEST +5 -2
- data/README +20 -16
- data/ext/extconf.rb +5 -4
- data/ext/io/extra.c +152 -278
- data/lib/io-extra.rb +17 -0
- data/test/test_io_extra.rb +21 -28
- metadata +77 -75
- metadata.gz.sig +0 -0
- data/Rakefile +0 -93
- data/doc/io_extra.txt +0 -85
- data/examples/example_io_extra.rb +0 -42
- data/examples/example_pread.rb +0 -24
- data/io-extra.gemspec +0 -38
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 413914a045cda689f991f043d5b314d6734777094d0f90359e5c10c1062d7648
|
4
|
+
data.tar.gz: beeb120887bf9e7c3af06f0f2a9cc733cce21f21ddf9738ef2830bab0be1931f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2ad2db30be150d3837b182e6063f2db69faf0895fde33b5ba552029c1ba988093efdfd96421a155129543ae43b545eca656b2e9243bc6c0c13fd3a4dec37a842
|
7
|
+
data.tar.gz: 3611120e98da21cd73fd3960a6a1df6a05514a5436fbf29de3e9d0f27971ad5c94e2309fcc3399581439dc95735c78bb75303ca772cca8dcd0225631a266a1b3
|
checksums.yaml.gz.sig
ADDED
@@ -0,0 +1,2 @@
|
|
1
|
+
\����}WyN�P:���n���?`>����+�w�t�&�O�ϴb�ľ�W �QX�'���%�Ȏ�w���������,h4�h�"�\�"N@�i՞�x�?���bC7R}����h ��^��%�U��Z�u+��m,|� ���>X]�M�9�L�ZI�X����,Ω=�V=p�&�����M����|r��BpӃâC��������OLdzb`Y�ݽ��N�Q ,�]y���k��'�z��3�d����.�R4�7������ש8���K@U�`���ϩ_�0Z�ii��9��+��3��_iҽ�c�"ÐrQ���i��~��t�f����ql
|
2
|
+
�u�@��l��|2��v�5X>��!)k�=@`n�҉��͕�ڐJK
|
data.tar.gz.sig
ADDED
Binary file
|
data/CHANGES
CHANGED
@@ -1,3 +1,48 @@
|
|
1
|
+
== 1.4.0 - 8-Jul-2020
|
2
|
+
* Replaced the C versions of IO.pread and IO.pwrite singleton methods with
|
3
|
+
pure Ruby wrappers since core Ruby has implemented instance method versions
|
4
|
+
since Ruby 2.5. These now require filehandles (rather than fileno) as an
|
5
|
+
argument.
|
6
|
+
* Removed the pread_ptr method, I don't think anyone was using it. Might get
|
7
|
+
added back if there are complaints.
|
8
|
+
* Removed the DIRECT constant since that is now defined by core Ruby.
|
9
|
+
* Moved the VERSION constant into the pure Ruby file.
|
10
|
+
* Now requires Ruby 2.5 or later.
|
11
|
+
* Added a LICENSE file as required by the Apache-2.0 license.
|
12
|
+
* The 'io-extra' file is now the preferred way to require this library.
|
13
|
+
|
14
|
+
== 1.3.0 - 19-Oct-2018
|
15
|
+
* Now assumes Ruby 2.1 or later. This has no effect on the external API, but
|
16
|
+
it does allow for lots of internal cleanup.
|
17
|
+
* License changed to Apache-2.0.
|
18
|
+
* The EXTRA_VERSION constant is now frozen.
|
19
|
+
* Added the io-extra.rb file for convenience.
|
20
|
+
* Updates to the gemspec, including the addition of metadata.
|
21
|
+
* The Rakefile now assumes Rubygems 2.0 or later.
|
22
|
+
* Added a cert.
|
23
|
+
* Removed the .gemtest file.
|
24
|
+
|
25
|
+
== 1.2.8 - 29-Dec-2014
|
26
|
+
* Updated for compatibility with Ruby 2.2.x.
|
27
|
+
|
28
|
+
== 1.2.7 - 10-Aug-2013
|
29
|
+
* Direct IO is now supported on Darwin, and some bugs in the directio
|
30
|
+
methods have been fixed. Thanks go to Genki Takiuchi for the patches.
|
31
|
+
* Fixed a bug in fdwalk and closefrom when using Ruby 1.9.3 where
|
32
|
+
closing reserved file descriptors would segfault the interpreter.
|
33
|
+
Thanks go to Eric Wong for the patch.
|
34
|
+
* Fixed a bug in the fdwalk method where it was not honoring the
|
35
|
+
lowfd argument, and added a test for it.
|
36
|
+
* The rb_thread_call_without_gvl function is now used internally in
|
37
|
+
place of rb_thread_blocking_region for Ruby 2.x.
|
38
|
+
|
39
|
+
== 1.2.6 - 22-May-2011
|
40
|
+
* Fixed a potential memory leak in the pread_ptr method where malloc'ed
|
41
|
+
memory was not freed if the pread function call failed. Thanks go to
|
42
|
+
Eric Wong for the spot.
|
43
|
+
* Added the IO#ttyname method.
|
44
|
+
* Added the (empty) .gemtest file for test.rubygems.org.
|
45
|
+
|
1
46
|
== 1.2.5 - 23-Mar-2011
|
2
47
|
* Use rb_thread_blocking_region internally for IO.pread and IO.pwrite. Thanks
|
3
48
|
go to Eric Wong for the patch.
|
data/MANIFEST
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
+
* CHANGES
|
2
|
+
* LICENSE
|
1
3
|
* MANIFEST
|
2
4
|
* README
|
3
|
-
* CHANGES
|
4
5
|
* Rakefile
|
5
6
|
* io-extra.gemspec
|
7
|
+
* certs/djberg96_pub.pem
|
6
8
|
* doc/io_extra.txt
|
7
9
|
* examples/example_io_extra.rb
|
8
10
|
* ext/extconf.rb
|
9
11
|
* ext/io/extra.c
|
10
|
-
*
|
12
|
+
* lib/io-extra.rb
|
13
|
+
* test/test_io_extra.rb
|
data/README
CHANGED
@@ -5,13 +5,13 @@
|
|
5
5
|
|
6
6
|
This library is not supported on MS Windows.
|
7
7
|
|
8
|
-
Support for OS X is limited. See
|
8
|
+
Support for OS X is limited. See below for details.
|
9
9
|
|
10
10
|
= Installation
|
11
11
|
gem install io-extra
|
12
12
|
|
13
13
|
= Synopsis
|
14
|
-
require 'io/extra'
|
14
|
+
require 'io-extra' # Do not use 'io/extra'
|
15
15
|
|
16
16
|
# Close all file descriptors from 3 up.
|
17
17
|
IO.closefrom(3)
|
@@ -27,6 +27,10 @@
|
|
27
27
|
IO.writev(fh.fileno, %w[a b c])
|
28
28
|
|
29
29
|
= Developer's Notes
|
30
|
+
The "require 'io-extra'" is preferred over 'io/extra' because this is a mix
|
31
|
+
of pure Ruby and C extension. The former require's the latter, so that way
|
32
|
+
you get all the methods and constants that you expect.
|
33
|
+
|
30
34
|
You might be wondering what the difference is between my implementation of
|
31
35
|
IO.closefrom and a pure Ruby version that looks something like this:
|
32
36
|
|
@@ -45,9 +49,9 @@
|
|
45
49
|
of IO.fdwalk and a pure Ruby version that looks something like this:
|
46
50
|
|
47
51
|
def IO.fdwalk(n)
|
48
|
-
|
49
|
-
|
50
|
-
|
52
|
+
ObjectSpace.each_object(File){ |f|
|
53
|
+
yield f if f.fileno >= n
|
54
|
+
}
|
51
55
|
end
|
52
56
|
|
53
57
|
The primary difference is that this only closes Ruby file objects, not
|
@@ -55,8 +59,8 @@
|
|
55
59
|
opened via system() calls.
|
56
60
|
|
57
61
|
= Note to OS X Users
|
58
|
-
The OS X platform does not support closefrom()
|
59
|
-
|
62
|
+
The OS X platform does not support closefrom() or fdwalk(). The hand-
|
63
|
+
crafted IO.closefrom function will not work because the getrlimit()
|
60
64
|
function on OS X does not work. Patches welcome.
|
61
65
|
|
62
66
|
= Documentation
|
@@ -64,24 +68,24 @@
|
|
64
68
|
documentation that was generated by RDoc (if you did a gem install).
|
65
69
|
|
66
70
|
= Known Issues
|
67
|
-
The IO.writev tests fail on Solaris.
|
71
|
+
The IO.writev tests fail on Solaris. Short test scripts seem to work,
|
72
|
+
however. We're not sure what the issue is yet. Help wanted.
|
68
73
|
|
69
|
-
|
70
|
-
|
74
|
+
Update: As of 2018 Solaris is basically dead, so I'm not going to worry
|
75
|
+
about supporting Solaris unless there's an outcry.
|
71
76
|
|
72
|
-
|
73
|
-
|
74
|
-
* Switch from C extension to FFI.
|
77
|
+
Please file any bug reports on the project page at
|
78
|
+
https://github.com/djberg96/io-extra
|
75
79
|
|
76
80
|
= Acknowledgements
|
77
81
|
Eric Wong for some great work on Linux compatibility and other fixes, as
|
78
82
|
well as the code for the IO.writev method.
|
79
|
-
|
83
|
+
|
80
84
|
= License
|
81
|
-
|
85
|
+
Apache-2.0
|
82
86
|
|
83
87
|
= Copyright
|
84
|
-
(C) 2003-
|
88
|
+
(C) 2003-2020 Daniel J. Berger
|
85
89
|
All Rights Reserved
|
86
90
|
|
87
91
|
= Warranty
|
data/ext/extconf.rb
CHANGED
@@ -10,11 +10,8 @@ have_header('sys/uio.h')
|
|
10
10
|
have_func('closefrom')
|
11
11
|
have_func('fdwalk')
|
12
12
|
have_func('directio')
|
13
|
-
have_func('pread')
|
14
|
-
have_func('pwrite')
|
15
13
|
have_func('writev')
|
16
|
-
have_func('
|
17
|
-
have_func('rb_thread_blocking_region')
|
14
|
+
have_func('ttyname')
|
18
15
|
|
19
16
|
case RbConfig::CONFIG['host_os']
|
20
17
|
when /darwin/i
|
@@ -35,4 +32,8 @@ if have_macro("O_DIRECT", %w(sys/types.h fcntl.h))
|
|
35
32
|
$CPPFLAGS += " -DHAVE_O_DIRECT_MACRO"
|
36
33
|
end
|
37
34
|
|
35
|
+
if have_macro("F_NOCACHE", %w(fcntl.h))
|
36
|
+
$CPPFLAGS += " -DHAVE_F_NOCACHE_MACRO"
|
37
|
+
end
|
38
|
+
|
38
39
|
create_makefile('io/extra', 'io')
|
data/ext/io/extra.c
CHANGED
@@ -1,10 +1,7 @@
|
|
1
1
|
/* Extra methods for the IO class */
|
2
2
|
#include "ruby.h"
|
3
|
-
#ifdef HAVE_RUBY_IO_H
|
4
3
|
#include "ruby/io.h"
|
5
|
-
#
|
6
|
-
#include "rubyio.h"
|
7
|
-
#endif
|
4
|
+
#include "ruby/thread.h"
|
8
5
|
|
9
6
|
#include <unistd.h>
|
10
7
|
#include <stdlib.h>
|
@@ -26,53 +23,11 @@
|
|
26
23
|
#if defined(_SC_IOV_MAX)
|
27
24
|
#define IOV_MAX (sysconf(_SC_IOV_MAX))
|
28
25
|
#else
|
29
|
-
|
26
|
+
// Assume infinity, or let the syscall return with error
|
30
27
|
#define IOV_MAX INT_MAX
|
31
28
|
#endif
|
32
29
|
#endif
|
33
30
|
|
34
|
-
#ifndef HAVE_RB_THREAD_BLOCKING_REGION
|
35
|
-
/*
|
36
|
-
* partial emulation of the 1.9 rb_thread_blocking_region under 1.8,
|
37
|
-
* this is enough to ensure signals are processed safely when doing I/O
|
38
|
-
* to a slow device, but doesn't actually ensure threads can be
|
39
|
-
* scheduled fairly in 1.8
|
40
|
-
*/
|
41
|
-
#include <rubysig.h>
|
42
|
-
#define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
|
43
|
-
typedef void rb_unblock_function_t(void *);
|
44
|
-
typedef VALUE rb_blocking_function_t(void *);
|
45
|
-
static VALUE
|
46
|
-
rb_thread_blocking_region(
|
47
|
-
rb_blocking_function_t *fn, void *data1,
|
48
|
-
rb_unblock_function_t *ubf, void *data2)
|
49
|
-
{
|
50
|
-
VALUE rv;
|
51
|
-
|
52
|
-
TRAP_BEG;
|
53
|
-
rv = fn(data1);
|
54
|
-
TRAP_END;
|
55
|
-
|
56
|
-
return rv;
|
57
|
-
}
|
58
|
-
#endif
|
59
|
-
|
60
|
-
#ifndef RSTRING_PTR
|
61
|
-
#define RSTRING_PTR(v) (RSTRING(v)->ptr)
|
62
|
-
#define RSTRING_LEN(v) (RSTRING(v)->len)
|
63
|
-
#endif
|
64
|
-
|
65
|
-
#ifndef HAVE_RB_STR_SET_LEN
|
66
|
-
/* this is taken from Ruby 1.8.7, 1.8.6 may not have it */
|
67
|
-
static void rb_18_str_set_len(VALUE str, long len)
|
68
|
-
{
|
69
|
-
RSTRING(str)->len = len;
|
70
|
-
RSTRING(str)->ptr[len] = '\0';
|
71
|
-
}
|
72
|
-
#define rb_str_set_len(str,len) rb_18_str_set_len(str,len)
|
73
|
-
#endif
|
74
|
-
|
75
|
-
|
76
31
|
#ifdef PROC_SELF_FD_DIR
|
77
32
|
#include <dirent.h>
|
78
33
|
#endif
|
@@ -131,17 +86,16 @@ static int open_max(void){
|
|
131
86
|
* The manual approach was copied from the closefrom() man page on Solaris 9.
|
132
87
|
*/
|
133
88
|
static VALUE io_closefrom(VALUE klass, VALUE v_low_fd){
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
int i, lowfd;
|
138
|
-
int maxfd = open_max();
|
139
|
-
lowfd = NUM2INT(v_low_fd);
|
89
|
+
int i, lowfd;
|
90
|
+
int maxfd = open_max();
|
91
|
+
lowfd = NUM2INT(v_low_fd);
|
140
92
|
|
141
|
-
|
93
|
+
for(i = lowfd; i < maxfd; i++) {
|
94
|
+
if(!RB_RESERVED_FD_P(i))
|
142
95
|
close(i);
|
143
|
-
|
144
|
-
|
96
|
+
}
|
97
|
+
|
98
|
+
return klass;
|
145
99
|
}
|
146
100
|
|
147
101
|
#ifndef HAVE_FDWALK
|
@@ -202,11 +156,17 @@ static int fdwalk(int (*func)(void *data, int fd), void *data){
|
|
202
156
|
* It's up to the user to close it.
|
203
157
|
*/
|
204
158
|
static int close_func(void* lowfd, int fd){
|
205
|
-
|
159
|
+
VALUE v_args[1];
|
206
160
|
|
207
|
-
|
208
|
-
|
209
|
-
|
161
|
+
if(fd >= *(int*)lowfd){
|
162
|
+
if (RB_RESERVED_FD_P(fd))
|
163
|
+
return 0;
|
164
|
+
|
165
|
+
v_args[0] = UINT2NUM(fd);
|
166
|
+
rb_yield(rb_class_new_instance(1, v_args, rb_cFile));
|
167
|
+
}
|
168
|
+
|
169
|
+
return 0;
|
210
170
|
}
|
211
171
|
|
212
172
|
/*
|
@@ -218,19 +178,19 @@ static int close_func(void* lowfd, int fd){
|
|
218
178
|
* Not supported on all platforms.
|
219
179
|
*/
|
220
180
|
static VALUE io_fdwalk(int argc, VALUE* argv, VALUE klass){
|
221
|
-
|
222
|
-
|
181
|
+
VALUE v_low_fd, v_block;
|
182
|
+
int lowfd;
|
223
183
|
|
224
|
-
|
225
|
-
|
184
|
+
rb_scan_args(argc, argv, "1&", &v_low_fd, &v_block);
|
185
|
+
lowfd = NUM2INT(v_low_fd);
|
226
186
|
|
227
|
-
|
187
|
+
fdwalk(close_func, &lowfd);
|
228
188
|
|
229
|
-
|
189
|
+
return klass;
|
230
190
|
}
|
231
191
|
#endif
|
232
192
|
|
233
|
-
#if defined(HAVE_DIRECTIO) || defined(O_DIRECT)
|
193
|
+
#if defined(HAVE_DIRECTIO) || defined(O_DIRECT) || defined(F_NOCACHE)
|
234
194
|
/*
|
235
195
|
* call-seq:
|
236
196
|
* IO#directio?
|
@@ -239,24 +199,21 @@ static VALUE io_fdwalk(int argc, VALUE* argv, VALUE klass){
|
|
239
199
|
* current handle. The default is false.
|
240
200
|
*/
|
241
201
|
static VALUE io_get_directio(VALUE self){
|
242
|
-
#if defined(HAVE_DIRECTIO)
|
243
|
-
|
202
|
+
#if defined(HAVE_DIRECTIO) || defined(F_NOCACHE)
|
203
|
+
VALUE v_advice = rb_iv_get(self, "@directio");
|
244
204
|
|
245
|
-
|
246
|
-
|
205
|
+
if(NIL_P(v_advice))
|
206
|
+
v_advice = Qfalse;
|
247
207
|
|
248
|
-
|
249
|
-
v_advice = Qfalse;
|
250
|
-
|
251
|
-
return v_advice;
|
208
|
+
return v_advice;
|
252
209
|
#elif defined(O_DIRECT)
|
253
|
-
|
254
|
-
|
210
|
+
int fd = NUM2INT(rb_funcall(self, rb_intern("fileno"), 0, 0));
|
211
|
+
int flags = fcntl(fd, F_GETFL);
|
255
212
|
|
256
|
-
|
257
|
-
|
213
|
+
if(flags < 0)
|
214
|
+
rb_sys_fail("fcntl");
|
258
215
|
|
259
|
-
|
216
|
+
return (flags & O_DIRECT) ? Qtrue : Qfalse;
|
260
217
|
#endif /* O_DIRECT */
|
261
218
|
}
|
262
219
|
|
@@ -287,9 +244,12 @@ static VALUE io_set_directio(VALUE self, VALUE v_advice){
|
|
287
244
|
rb_raise(rb_eStandardError, "The directio() call failed");
|
288
245
|
|
289
246
|
if(advice == DIRECTIO_ON)
|
290
|
-
rb_iv_set(self, "directio", Qtrue);
|
247
|
+
rb_iv_set(self, "@directio", Qtrue);
|
248
|
+
else
|
249
|
+
rb_iv_set(self, "@directio", Qfalse);
|
291
250
|
#else
|
292
251
|
{
|
252
|
+
#if defined(O_DIRECT)
|
293
253
|
int flags = fcntl(fd, F_GETFL);
|
294
254
|
|
295
255
|
if(flags < 0)
|
@@ -306,6 +266,17 @@ static VALUE io_set_directio(VALUE self, VALUE v_advice){
|
|
306
266
|
rb_sys_fail("fcntl");
|
307
267
|
}
|
308
268
|
}
|
269
|
+
#elif defined(F_NOCACHE)
|
270
|
+
if(advice == DIRECTIO_OFF){
|
271
|
+
if(fcntl(fd, F_NOCACHE, 0) < 0)
|
272
|
+
rb_sys_fail("fcntl");
|
273
|
+
rb_iv_set(self, "@directio", Qfalse);
|
274
|
+
} else { /* DIRECTIO_ON*/
|
275
|
+
if(fcntl(fd, F_NOCACHE, 1) < 0)
|
276
|
+
rb_sys_fail("fcntl");
|
277
|
+
rb_iv_set(self, "@directio", Qtrue);
|
278
|
+
}
|
279
|
+
#endif
|
309
280
|
}
|
310
281
|
#endif
|
311
282
|
|
@@ -313,116 +284,6 @@ static VALUE io_set_directio(VALUE self, VALUE v_advice){
|
|
313
284
|
}
|
314
285
|
#endif
|
315
286
|
|
316
|
-
#ifdef HAVE_PREAD
|
317
|
-
struct pread_args {
|
318
|
-
int fd;
|
319
|
-
void *buf;
|
320
|
-
size_t nbyte;
|
321
|
-
off_t offset;
|
322
|
-
};
|
323
|
-
|
324
|
-
static VALUE nogvl_pread(void *ptr)
|
325
|
-
{
|
326
|
-
struct pread_args *args = ptr;
|
327
|
-
|
328
|
-
return (VALUE)pread(args->fd, args->buf, args->nbyte, args->offset);
|
329
|
-
}
|
330
|
-
|
331
|
-
/*
|
332
|
-
* IO.pread(fd, length, offset)
|
333
|
-
*
|
334
|
-
* This is similar to the IO.read method, except that it reads from a given
|
335
|
-
* position in the file without changing the file pointer. And unlike IO.read,
|
336
|
-
* the +fd+, +length+ and +offset+ arguments are all mandatory.
|
337
|
-
*/
|
338
|
-
static VALUE s_io_pread(VALUE klass, VALUE fd, VALUE nbyte, VALUE offset){
|
339
|
-
struct pread_args args;
|
340
|
-
VALUE str;
|
341
|
-
ssize_t nread;
|
342
|
-
|
343
|
-
args.fd = NUM2INT(fd);
|
344
|
-
args.nbyte = NUM2ULONG(nbyte);
|
345
|
-
args.offset = NUM2OFFT(offset);
|
346
|
-
str = rb_str_new(NULL, args.nbyte);
|
347
|
-
args.buf = RSTRING_PTR(str);
|
348
|
-
|
349
|
-
nread = (ssize_t)rb_thread_blocking_region(nogvl_pread, &args, RUBY_UBF_IO, 0);
|
350
|
-
|
351
|
-
if (nread == -1)
|
352
|
-
rb_sys_fail("pread");
|
353
|
-
if ((size_t)nread != args.nbyte)
|
354
|
-
rb_str_set_len(str, nread);
|
355
|
-
|
356
|
-
return str;
|
357
|
-
}
|
358
|
-
|
359
|
-
/*
|
360
|
-
* IO.pread_ptr(fd, length, offset)
|
361
|
-
*
|
362
|
-
* This is identical to IO.pread, except that it returns the pointer address
|
363
|
-
* of the string, instead of the actual buffer.
|
364
|
-
*--
|
365
|
-
* This was added because, in some cases, the IO.pread buffer might return
|
366
|
-
* an empty string. In such situations we are unable to get the actual pointer
|
367
|
-
* address with pure Ruby.
|
368
|
-
*/
|
369
|
-
static VALUE s_io_pread_ptr(VALUE klass, VALUE v_fd, VALUE v_nbyte, VALUE v_offset){
|
370
|
-
int fd = NUM2INT(v_fd);
|
371
|
-
size_t nbyte = NUM2ULONG(v_nbyte);
|
372
|
-
off_t offset = NUM2OFFT(v_offset);
|
373
|
-
uintptr_t* vector = malloc(nbyte + 1);
|
374
|
-
|
375
|
-
if(pread(fd, vector, nbyte, offset) == -1)
|
376
|
-
rb_sys_fail("pread");
|
377
|
-
|
378
|
-
return ULL2NUM(vector[0]);
|
379
|
-
}
|
380
|
-
#endif
|
381
|
-
|
382
|
-
#ifdef HAVE_PWRITE
|
383
|
-
struct pwrite_args {
|
384
|
-
int fd;
|
385
|
-
const void *buf;
|
386
|
-
size_t nbyte;
|
387
|
-
off_t offset;
|
388
|
-
};
|
389
|
-
|
390
|
-
static VALUE nogvl_pwrite(void *ptr)
|
391
|
-
{
|
392
|
-
struct pwrite_args *args = ptr;
|
393
|
-
|
394
|
-
return (VALUE)pwrite(args->fd, args->buf, args->nbyte, args->offset);
|
395
|
-
}
|
396
|
-
|
397
|
-
/*
|
398
|
-
* IO.pwrite(fd, buf, offset)
|
399
|
-
*
|
400
|
-
* This method writes the +buf+, starting at +offset+, to the given +fd+,
|
401
|
-
* which must be opened with write permissions.
|
402
|
-
*
|
403
|
-
* This is similar to a seek & write in standard Ruby but the difference,
|
404
|
-
* beyond being a singleton method, is that the file pointer is never moved.
|
405
|
-
*
|
406
|
-
* Returns the number of bytes written.
|
407
|
-
*/
|
408
|
-
static VALUE s_io_pwrite(VALUE klass, VALUE fd, VALUE buf, VALUE offset){
|
409
|
-
ssize_t result;
|
410
|
-
struct pwrite_args args;
|
411
|
-
|
412
|
-
args.fd = NUM2INT(fd);
|
413
|
-
args.buf = RSTRING_PTR(buf);
|
414
|
-
args.nbyte = RSTRING_LEN(buf);
|
415
|
-
args.offset = NUM2OFFT(offset);
|
416
|
-
|
417
|
-
result = (ssize_t)rb_thread_blocking_region(nogvl_pwrite, &args, RUBY_UBF_IO, 0);
|
418
|
-
|
419
|
-
if(result == -1)
|
420
|
-
rb_sys_fail("pwrite");
|
421
|
-
|
422
|
-
return ULL2NUM(result);
|
423
|
-
}
|
424
|
-
#endif
|
425
|
-
|
426
287
|
/* this can't be a function since we use alloca() */
|
427
288
|
#define ARY2IOVEC(iov,iovcnt,expect,ary) \
|
428
289
|
do { \
|
@@ -449,16 +310,15 @@ static VALUE s_io_pwrite(VALUE klass, VALUE fd, VALUE buf, VALUE offset){
|
|
449
310
|
|
450
311
|
#if defined(HAVE_WRITEV)
|
451
312
|
struct writev_args {
|
452
|
-
|
453
|
-
|
454
|
-
|
313
|
+
int fd;
|
314
|
+
struct iovec *iov;
|
315
|
+
int iovcnt;
|
455
316
|
};
|
456
317
|
|
457
318
|
static VALUE nogvl_writev(void *ptr)
|
458
319
|
{
|
459
|
-
|
460
|
-
|
461
|
-
return (VALUE)writev(args->fd, args->iov, args->iovcnt);
|
320
|
+
struct writev_args *args = ptr;
|
321
|
+
return (VALUE)writev(args->fd, args->iov, args->iovcnt);
|
462
322
|
}
|
463
323
|
|
464
324
|
/*
|
@@ -473,68 +333,95 @@ static VALUE nogvl_writev(void *ptr)
|
|
473
333
|
* Returns the number of bytes written.
|
474
334
|
*/
|
475
335
|
static VALUE s_io_writev(VALUE klass, VALUE fd, VALUE ary) {
|
476
|
-
|
477
|
-
|
478
|
-
|
336
|
+
ssize_t result = 0;
|
337
|
+
ssize_t left;
|
338
|
+
struct writev_args args;
|
479
339
|
|
480
|
-
|
481
|
-
|
340
|
+
// Allow a fileno or filehandle
|
341
|
+
if(rb_respond_to(fd, rb_intern("fileno")))
|
342
|
+
fd = rb_funcall(fd, rb_intern("fileno"), 0, 0);
|
482
343
|
|
483
|
-
|
484
|
-
|
485
|
-
RUBY_UBF_IO, 0);
|
344
|
+
args.fd = NUM2INT(fd);
|
345
|
+
ARY2IOVEC(args.iov, args.iovcnt, left, ary);
|
486
346
|
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
347
|
+
for(;;) {
|
348
|
+
ssize_t w = (ssize_t)rb_thread_call_without_gvl(
|
349
|
+
(void*)nogvl_writev, &args, RUBY_UBF_IO, 0
|
350
|
+
);
|
351
|
+
|
352
|
+
if(w == -1){
|
353
|
+
if(rb_io_wait_writable(args.fd)){
|
354
|
+
continue;
|
355
|
+
}
|
356
|
+
else{
|
357
|
+
if(result > 0){
|
358
|
+
/* unlikely to hit this case, return the already written bytes,
|
359
|
+
* we'll let the next write (or close) fail instead */
|
360
|
+
break;
|
361
|
+
}
|
362
|
+
rb_sys_fail("writev");
|
500
363
|
}
|
364
|
+
}
|
501
365
|
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
* modify and retry with current iovec in front
|
519
|
-
*/
|
520
|
-
if (new_iov->iov_len > (size_t)w) {
|
521
|
-
VALUE base = (VALUE)new_iov->iov_base;
|
522
|
-
|
523
|
-
new_iov->iov_len -= w;
|
524
|
-
new_iov->iov_base = (void *)(base + w);
|
525
|
-
break;
|
526
|
-
}
|
527
|
-
|
528
|
-
w -= new_iov->iov_len;
|
529
|
-
}
|
366
|
+
result += w;
|
367
|
+
|
368
|
+
if(w == left){
|
369
|
+
break;
|
370
|
+
}
|
371
|
+
else{
|
372
|
+
// Partial write, this can get tricky
|
373
|
+
int i;
|
374
|
+
struct iovec *new_iov = args.iov;
|
375
|
+
|
376
|
+
left -= w;
|
377
|
+
|
378
|
+
// Skip over iovecs we've already written completely
|
379
|
+
for(i = 0; i < args.iovcnt; i++, new_iov++){
|
380
|
+
if (w == 0)
|
381
|
+
break;
|
530
382
|
|
531
|
-
|
532
|
-
|
533
|
-
|
383
|
+
// Partially written iov, modify and retry with current iovec in front
|
384
|
+
if(new_iov->iov_len > (size_t)w){
|
385
|
+
VALUE base = (VALUE)new_iov->iov_base;
|
386
|
+
|
387
|
+
new_iov->iov_len -= w;
|
388
|
+
new_iov->iov_base = (void *)(base + w);
|
389
|
+
break;
|
390
|
+
}
|
391
|
+
|
392
|
+
w -= new_iov->iov_len;
|
534
393
|
}
|
535
|
-
}
|
536
394
|
|
537
|
-
|
395
|
+
// Retry without the already-written iovecs
|
396
|
+
args.iovcnt -= i;
|
397
|
+
args.iov = new_iov;
|
398
|
+
}
|
399
|
+
}
|
400
|
+
|
401
|
+
return LONG2NUM(result);
|
402
|
+
}
|
403
|
+
#endif
|
404
|
+
|
405
|
+
#ifdef HAVE_TTYNAME
|
406
|
+
/*
|
407
|
+
* io.ttyname
|
408
|
+
*
|
409
|
+
* Returns the ttyname associated with the IO object, or nil if the IO
|
410
|
+
* object isn't associated with a tty.
|
411
|
+
*
|
412
|
+
* Example:
|
413
|
+
*
|
414
|
+
* STDOUT.ttyname # => '/dev/ttyp1'
|
415
|
+
*/
|
416
|
+
static VALUE io_get_ttyname(VALUE self){
|
417
|
+
VALUE v_return = Qnil;
|
418
|
+
|
419
|
+
int fd = NUM2INT(rb_funcall(self, rb_intern("fileno"), 0, 0));
|
420
|
+
|
421
|
+
if(isatty(fd))
|
422
|
+
v_return = rb_str_new2(ttyname(fd));
|
423
|
+
|
424
|
+
return v_return;
|
538
425
|
}
|
539
426
|
#endif
|
540
427
|
|
@@ -542,43 +429,30 @@ static VALUE s_io_writev(VALUE klass, VALUE fd, VALUE ary) {
|
|
542
429
|
* and IO#directio? instance methods (if supported on your platform).
|
543
430
|
*/
|
544
431
|
void Init_extra(){
|
545
|
-
|
432
|
+
rb_define_singleton_method(rb_cIO, "closefrom", io_closefrom, 1);
|
546
433
|
|
547
434
|
#ifdef HAVE_FDWALK
|
548
|
-
|
435
|
+
rb_define_singleton_method(rb_cIO, "fdwalk", io_fdwalk, -1);
|
549
436
|
#endif
|
550
437
|
|
551
|
-
#if defined(HAVE_DIRECTIO) || defined(O_DIRECT)
|
552
|
-
|
553
|
-
|
438
|
+
#if defined(HAVE_DIRECTIO) || defined(O_DIRECT) || defined(F_NOCACHE)
|
439
|
+
rb_define_method(rb_cIO, "directio?", io_get_directio, 0);
|
440
|
+
rb_define_method(rb_cIO, "directio=", io_set_directio, 1);
|
554
441
|
|
555
|
-
|
556
|
-
|
442
|
+
/* 0: Applications get the default system behavior when accessing file data. */
|
443
|
+
rb_define_const(rb_cIO, "DIRECTIO_OFF", UINT2NUM(DIRECTIO_OFF));
|
557
444
|
|
558
|
-
|
559
|
-
|
445
|
+
/* 1: File data is not cached in the system's memory pages. */
|
446
|
+
rb_define_const(rb_cIO, "DIRECTIO_ON", UINT2NUM(DIRECTIO_ON));
|
560
447
|
#endif
|
561
448
|
|
562
|
-
|
563
|
-
/* 040000: direct disk access (in Linux) */
|
564
|
-
rb_define_const(rb_cIO, "DIRECT", UINT2NUM(O_DIRECT));
|
565
|
-
#endif
|
566
|
-
|
567
|
-
rb_define_const(rb_cIO, "IOV_MAX", LONG2NUM(IOV_MAX));
|
568
|
-
|
569
|
-
#ifdef HAVE_PREAD
|
570
|
-
rb_define_singleton_method(rb_cIO, "pread", s_io_pread, 3);
|
571
|
-
rb_define_singleton_method(rb_cIO, "pread_ptr", s_io_pread_ptr, 3);
|
572
|
-
#endif
|
573
|
-
|
574
|
-
#ifdef HAVE_PWRITE
|
575
|
-
rb_define_singleton_method(rb_cIO, "pwrite", s_io_pwrite, 3);
|
576
|
-
#endif
|
449
|
+
rb_define_const(rb_cIO, "IOV_MAX", LONG2NUM(IOV_MAX));
|
577
450
|
|
578
451
|
#ifdef HAVE_WRITEV
|
579
|
-
|
452
|
+
rb_define_singleton_method(rb_cIO, "writev", s_io_writev, 2);
|
580
453
|
#endif
|
581
454
|
|
582
|
-
|
583
|
-
|
455
|
+
#ifdef HAVE_TTYNAME
|
456
|
+
rb_define_method(rb_cIO, "ttyname", io_get_ttyname, 0);
|
457
|
+
#endif
|
584
458
|
}
|