Class: IO

Inherits:
Object
  • Object
show all
Defined in:
(unknown)

Constant Summary collapse

DIRECTIO_OFF =

Applications get the default system behavior when accessing file data.

0
DIRECTIO_ON =

File data is not cached in the system’s memory pages.

1
DIRECT =

direct disk access (in Linux)

040000
IOV_MAX =
LONG2NUM(IOV_MAX)
EXTRA_VERSION =

The version of this library. This a string.

1.2.8

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.closefrom(lowfd) ⇒ Object

Close all open file descriptors (associated with the current process) that are greater than or equal to lowfd.

This method uses your system’s builtin closefrom() function, if supported. Otherwise, it uses a manual, and (probably) less efficient approach.



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'ext/io/extra.c', line 149

static VALUE io_closefrom(VALUE klass, VALUE v_low_fd){
#if defined(HAVE_CLOSEFROM) && !defined(HAVE_RB_RESERVED_FD_P)
   /* we can't safely use closefrom() if the RubyVM reserves FDs */
   closefrom(NUM2INT(v_low_fd));
#else
   int i, lowfd;
   int maxfd = open_max();
   lowfd = NUM2INT(v_low_fd);

   for(i = lowfd; i < maxfd; i++) {
      if(!RB_RESERVED_FD_P(i))
         close(i);
   }
#endif
   return klass;
}

.fdwalk(lowfd) {|fh| ... } ⇒ Object

Iterates over each open file descriptor and yields back a File object.

Not supported on all platforms.

Yields:

  • (fh)


244
245
246
247
248
249
250
251
252
253
254
# File 'ext/io/extra.c', line 244

static VALUE io_fdwalk(int argc, VALUE* argv, VALUE klass){
   VALUE v_low_fd, v_block;
   int lowfd;

   rb_scan_args(argc, argv, "1&", &v_low_fd, &v_block);
   lowfd = NUM2INT(v_low_fd);

   fdwalk(close_func, &lowfd);

   return klass;
}

.pread(fd, nbyte, offset) ⇒ Object

IO.pread(fd, length, offset)

This is similar to the IO.read method, except that it reads from a given position in the file without changing the file pointer. And unlike IO.read, the fd, length and offset arguments are all mandatory.



373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'ext/io/extra.c', line 373

static VALUE s_io_pread(VALUE klass, VALUE fd, VALUE nbyte, VALUE offset){
   struct pread_args args;
   VALUE str;
   ssize_t nread;

   args.fd = NUM2INT(fd);
   args.nbyte = NUM2ULONG(nbyte);
   args.offset = NUM2OFFT(offset);
   str = rb_str_new(NULL, args.nbyte);
   args.buf = RSTRING_PTR(str);

#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
   nread = (ssize_t)rb_thread_call_without_gvl((void*)nogvl_pread, &args, RUBY_UBF_IO, 0);
#else
   nread = (ssize_t)rb_thread_blocking_region(nogvl_pread, &args, RUBY_UBF_IO, 0);
#endif

   if (nread == -1)
      rb_sys_fail("pread");
   if ((size_t)nread != args.nbyte)
      rb_str_set_len(str, nread);

   return str;
}

.pread_ptr(v_fd, v_nbyte, v_offset) ⇒ Object

IO.pread_ptr(fd, length, offset)

This is identical to IO.pread, except that it returns the pointer address of the string, instead of the actual buffer.



408
409
410
411
412
413
414
415
416
417
418
419
420
# File 'ext/io/extra.c', line 408

static VALUE s_io_pread_ptr(VALUE klass, VALUE v_fd, VALUE v_nbyte, VALUE v_offset){
  int fd = NUM2INT(v_fd);
  size_t nbyte = NUM2ULONG(v_nbyte);
  off_t offset = NUM2OFFT(v_offset);
  uintptr_t* vector = malloc(nbyte + 1);

  if(pread(fd, vector, nbyte, offset) == -1){
    free(vector);
    rb_sys_fail("pread");
  }

  return ULL2NUM(vector[0]);
}

.pwrite(fd, buf, offset) ⇒ Object

IO.pwrite(fd, buf, offset)

This method writes the buf, starting at offset, to the given fd, which must be opened with write permissions.

This is similar to a seek & write in standard Ruby but the difference, beyond being a singleton method, is that the file pointer is never moved.

Returns the number of bytes written.



449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
# File 'ext/io/extra.c', line 449

static VALUE s_io_pwrite(VALUE klass, VALUE fd, VALUE buf, VALUE offset){
   ssize_t result;
   struct pwrite_args args;

   args.fd = NUM2INT(fd);
   args.buf = RSTRING_PTR(buf);
   args.nbyte = RSTRING_LEN(buf);
   args.offset = NUM2OFFT(offset);

#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
   result = (ssize_t)rb_thread_call_without_gvl((void*)nogvl_pwrite, &args, RUBY_UBF_IO, 0);
#else
   result = (ssize_t)rb_thread_blocking_region(nogvl_pwrite, &args, RUBY_UBF_IO, 0);
#endif

   if(result == -1)
      rb_sys_fail("pwrite");

   return ULL2NUM(result);
}

.writev(fd, ary) ⇒ Object

IO.writev(fd, %w(hello world))

This method writes the contents of an array of strings to the given fd. It can be useful to avoid generating a temporary string via Array#join when writing out large arrays of strings.

The given array should have fewer elements than the IO::IOV_MAX constant.

Returns the number of bytes written.



520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
# File 'ext/io/extra.c', line 520

static VALUE s_io_writev(VALUE klass, VALUE fd, VALUE ary) {
   ssize_t result = 0;
   ssize_t left;
   struct writev_args args;

   args.fd = NUM2INT(fd);
   ARY2IOVEC(args.iov, args.iovcnt, left, ary);

   for(;;) {
#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
      ssize_t w = (ssize_t)rb_thread_call_without_gvl(
        (void*)nogvl_writev, &args, RUBY_UBF_IO, 0
      );
#else
      ssize_t w = (ssize_t)rb_thread_blocking_region(
        nogvl_writev, &args, RUBY_UBF_IO, 0
      );
#endif

      if(w == -1) {
         if (rb_io_wait_writable(args.fd)) {
            continue;
         } else {
            if (result > 0) {
               /*
                * unlikely to hit this case, return the already written bytes,
                * we'll let the next write (or close) fail instead
                */
               break;
            }
            rb_sys_fail("writev");
         }
      }

      result += w;
      if(w == left) {
         break;
      } else { /* partial write, this can get tricky */
         int i;
         struct iovec *new_iov = args.iov;

         left -= w;

         /* skip over iovecs we've already written completely */
         for (i = 0; i < args.iovcnt; i++, new_iov++) {
            if (w == 0)
               break;

            /*
             * partially written iov,
             * modify and retry with current iovec in front
             */
            if (new_iov->iov_len > (size_t)w) {
               VALUE base = (VALUE)new_iov->iov_base;

               new_iov->iov_len -= w;
               new_iov->iov_base = (void *)(base + w);
               break;
            }

            w -= new_iov->iov_len;
         }

         /* retry without the already-written iovecs */
         args.iovcnt -= i;
         args.iov = new_iov;
      }
   }

   return LONG2NUM(result);
}

Instance Method Details

#directio=(advice) ⇒ Object

Sets the advice for the current file descriptor using directio(). Valid values are IO::DIRECTIO_ON and IO::DIRECTIO_OFF. See the directio(3c) man page for more information.

All file descriptors start at DIRECTIO_OFF, unless your filesystem has been mounted using ‘forcedirectio’ (and supports that option).



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
# File 'ext/io/extra.c', line 295

static VALUE io_set_directio(VALUE self, VALUE v_advice){
   int fd;
   int advice = NUM2INT(v_advice);

   /* Only two possible valid values */
   if( (advice != DIRECTIO_OFF) && (advice != DIRECTIO_ON) )
      rb_raise(rb_eStandardError, "Invalid value passed to IO#directio=");

   /* Retrieve the current file descriptor in order to pass it to directio() */
   fd = NUM2INT(rb_funcall(self, rb_intern("fileno"), 0, 0));

#if defined(HAVE_DIRECTIO)
   if(directio(fd, advice) < 0)
      rb_raise(rb_eStandardError, "The directio() call failed");

   if(advice == DIRECTIO_ON)
      rb_iv_set(self, "@directio", Qtrue);
   else
      rb_iv_set(self, "@directio", Qfalse);
#else
   {
#if defined(O_DIRECT)
      int flags = fcntl(fd, F_GETFL);

      if(flags < 0)
         rb_sys_fail("fcntl");

      if(advice == DIRECTIO_OFF){
         if(flags & O_DIRECT){
            if(fcntl(fd, F_SETFL, flags & ~O_DIRECT) < 0)
               rb_sys_fail("fcntl");
         }
      } else { /* DIRECTIO_ON */
         if(!(flags & O_DIRECT)){
            if(fcntl(fd, F_SETFL, flags | O_DIRECT) < 0)
               rb_sys_fail("fcntl");
         }
      }
#elif defined(F_NOCACHE)
      if(advice == DIRECTIO_OFF){
         if(fcntl(fd, F_NOCACHE, 0) < 0)
            rb_sys_fail("fcntl");
         rb_iv_set(self, "@directio", Qfalse);
      } else { /* DIRECTIO_ON*/
         if(fcntl(fd, F_NOCACHE, 1) < 0)
            rb_sys_fail("fcntl");
         rb_iv_set(self, "@directio", Qtrue);
      }
#endif
   }
#endif

   return self;
}

#directio?Boolean

Returns true or false, based on whether directio has been set for the current handle. The default is false.

Returns:

  • (Boolean)


265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'ext/io/extra.c', line 265

static VALUE io_get_directio(VALUE self){
#if defined(HAVE_DIRECTIO) || defined(F_NOCACHE)
   VALUE v_advice = rb_iv_get(self, "@directio");

   if(NIL_P(v_advice))
      v_advice = Qfalse;

   return v_advice;
#elif defined(O_DIRECT)
   int fd = NUM2INT(rb_funcall(self, rb_intern("fileno"), 0, 0));
   int flags = fcntl(fd, F_GETFL);

   if(flags < 0)
      rb_sys_fail("fcntl");

   return (flags & O_DIRECT) ? Qtrue : Qfalse;
#endif /* O_DIRECT */
}

#ttynameObject

io.ttyname

Returns the ttyname associated with the IO object, or nil if the IO object isn’t associated with a tty.

Example:

STDOUT.ttyname # => '/dev/ttyp1'


604
605
606
607
608
609
610
611
612
613
# File 'ext/io/extra.c', line 604

static VALUE io_get_ttyname(VALUE self){
  VALUE v_return = Qnil;

  int fd = NUM2INT(rb_funcall(self, rb_intern("fileno"), 0, 0));

  if(isatty(fd))
    v_return = rb_str_new2(ttyname(fd));

  return v_return;
}