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.
@@ -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
@@ -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
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
- * test/test_io_extra.rb
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 the documentation for details.
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
- ObjectSpace.each_object(File){ |f|
49
- yield f if f.fileno >= n
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(), fdwalk() or directio(). The
59
- hand-crafted IO.closefrom function will not work because the getrlimit()
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. We are not sure why yet.
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
- Please file any bug reports on the project page at
70
- http://www.rubyforge.org/projects/shards.
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
- = Future Plans
73
- * I may add the File::O_DIRECT open constant on platforms that support it.
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
- Artistic 2.0
85
+ Apache-2.0
82
86
 
83
87
  = Copyright
84
- (C) 2003-2010 Daniel J. Berger
88
+ (C) 2003-2020 Daniel J. Berger
85
89
  All Rights Reserved
86
90
 
87
91
  = Warranty
@@ -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('rb_str_set_len', 'ruby.h')
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')
@@ -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
- #else
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
- /* assume infinity, or let the syscall return with error ... */
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
- #ifdef HAVE_CLOSEFROM
135
- closefrom(NUM2INT(v_low_fd));
136
- #else
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
- for(i = lowfd; i < maxfd; i++)
93
+ for(i = lowfd; i < maxfd; i++) {
94
+ if(!RB_RESERVED_FD_P(i))
142
95
  close(i);
143
- #endif
144
- return klass;
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
- VALUE v_args[1];
159
+ VALUE v_args[1];
206
160
 
207
- v_args[0] = UINT2NUM(fd);
208
- rb_yield(rb_class_new_instance(1, v_args, rb_cFile));
209
- return 0;
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
- VALUE v_low_fd, v_block;
222
- int lowfd;
181
+ VALUE v_low_fd, v_block;
182
+ int lowfd;
223
183
 
224
- rb_scan_args(argc, argv, "1&", &v_low_fd, &v_block);
225
- lowfd = NUM2INT(v_low_fd);
184
+ rb_scan_args(argc, argv, "1&", &v_low_fd, &v_block);
185
+ lowfd = NUM2INT(v_low_fd);
226
186
 
227
- fdwalk(close_func, &lowfd);
187
+ fdwalk(close_func, &lowfd);
228
188
 
229
- return klass;
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
- VALUE v_advice = Qnil;
202
+ #if defined(HAVE_DIRECTIO) || defined(F_NOCACHE)
203
+ VALUE v_advice = rb_iv_get(self, "@directio");
244
204
 
245
- if(rb_ivar_defined(rb_cIO, rb_intern("@directio")))
246
- v_advice = rb_iv_get(self, "directio");
205
+ if(NIL_P(v_advice))
206
+ v_advice = Qfalse;
247
207
 
248
- if(NIL_P(v_advice))
249
- v_advice = Qfalse;
250
-
251
- return v_advice;
208
+ return v_advice;
252
209
  #elif defined(O_DIRECT)
253
- int fd = NUM2INT(rb_funcall(self, rb_intern("fileno"), 0, 0));
254
- int flags = fcntl(fd, F_GETFL);
210
+ int fd = NUM2INT(rb_funcall(self, rb_intern("fileno"), 0, 0));
211
+ int flags = fcntl(fd, F_GETFL);
255
212
 
256
- if(flags < 0)
257
- rb_sys_fail("fcntl");
213
+ if(flags < 0)
214
+ rb_sys_fail("fcntl");
258
215
 
259
- return (flags & O_DIRECT) ? Qtrue : Qfalse;
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
- int fd;
453
- struct iovec *iov;
454
- int iovcnt;
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
- struct writev_args *args = ptr;
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
- ssize_t result = 0;
477
- ssize_t left;
478
- struct writev_args args;
336
+ ssize_t result = 0;
337
+ ssize_t left;
338
+ struct writev_args args;
479
339
 
480
- args.fd = NUM2INT(fd);
481
- ARY2IOVEC(args.iov, args.iovcnt, left, ary);
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
- for(;;) {
484
- ssize_t w = (ssize_t)rb_thread_blocking_region(nogvl_writev, &args,
485
- RUBY_UBF_IO, 0);
344
+ args.fd = NUM2INT(fd);
345
+ ARY2IOVEC(args.iov, args.iovcnt, left, ary);
486
346
 
487
- if(w == -1) {
488
- if (rb_io_wait_writable(args.fd)) {
489
- continue;
490
- } else {
491
- if (result > 0) {
492
- /*
493
- * unlikely to hit this case, return the already written bytes,
494
- * we'll let the next write (or close) fail instead
495
- */
496
- break;
497
- }
498
- rb_sys_fail("writev");
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
- result += w;
503
- if(w == left) {
504
- break;
505
- } else { /* partial write, this can get tricky */
506
- int i;
507
- struct iovec *new_iov = args.iov;
508
-
509
- left -= w;
510
-
511
- /* skip over iovecs we've already written completely */
512
- for (i = 0; i < args.iovcnt; i++, new_iov++) {
513
- if (w == 0)
514
- break;
515
-
516
- /*
517
- * partially written iov,
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
- /* retry without the already-written iovecs */
532
- args.iovcnt -= i;
533
- args.iov = new_iov;
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
- return LONG2NUM(result);
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
- rb_define_singleton_method(rb_cIO, "closefrom", io_closefrom, 1);
432
+ rb_define_singleton_method(rb_cIO, "closefrom", io_closefrom, 1);
546
433
 
547
434
  #ifdef HAVE_FDWALK
548
- rb_define_singleton_method(rb_cIO, "fdwalk", io_fdwalk, -1);
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
- rb_define_method(rb_cIO, "directio?", io_get_directio, 0);
553
- rb_define_method(rb_cIO, "directio=", io_set_directio, 1);
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
- /* 0: Applications get the default system behavior when accessing file data. */
556
- rb_define_const(rb_cIO, "DIRECTIO_OFF", UINT2NUM(DIRECTIO_OFF));
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
- /* 1: File data is not cached in the system's memory pages. */
559
- rb_define_const(rb_cIO, "DIRECTIO_ON", UINT2NUM(DIRECTIO_ON));
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
- #ifdef O_DIRECT
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
- rb_define_singleton_method(rb_cIO, "writev", s_io_writev, 2);
452
+ rb_define_singleton_method(rb_cIO, "writev", s_io_writev, 2);
580
453
  #endif
581
454
 
582
- /* 1.2.5: The version of this library. This a string. */
583
- rb_define_const(rb_cIO, "EXTRA_VERSION", rb_str_new2("1.2.5"));
455
+ #ifdef HAVE_TTYNAME
456
+ rb_define_method(rb_cIO, "ttyname", io_get_ttyname, 0);
457
+ #endif
584
458
  }