io-extra 1.2.5 → 1.4.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.
- 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
|
}
|