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.
@@ -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
  }