Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 18e55fc

Browse files
ioquatixKJ Tsanaktsidis
and
KJ Tsanaktsidis
authored
Hide most of the implementation of struct rb_io. (#6511)
* Add rb_io_path and rb_io_open_descriptor. * Use rb_io_open_descriptor to create PTY objects * Rename FMODE_PREP -> FMODE_EXTERNAL and expose it FMODE_PREP I believe refers to the concept of a "pre-prepared" file, but FMODE_EXTERNAL is clearer about what the file descriptor represents and aligns with language in the IO::Buffer module. * Ensure that rb_io_open_descriptor closes the FD if it fails If FMODE_EXTERNAL is not set, then it's guaranteed that Ruby will be responsible for closing your file, eventually, if you pass it to rb_io_open_descriptor, even if it raises an exception. * Rename IS_EXTERNAL_FD -> RUBY_IO_EXTERNAL_P * Expose `rb_io_closed_p`. * Add `rb_io_mode` to get IO mode. --------- Co-authored-by: KJ Tsanaktsidis <[email protected]>
1 parent 7ddcd06 commit 18e55fc

File tree

14 files changed

+298
-211
lines changed

14 files changed

+298
-211
lines changed

common.mk

+1
Original file line numberDiff line numberDiff line change
@@ -10997,6 +10997,7 @@ process.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
1099710997
process.$(OBJEXT): $(top_srcdir)/internal/gc.h
1099810998
process.$(OBJEXT): $(top_srcdir)/internal/hash.h
1099910999
process.$(OBJEXT): $(top_srcdir)/internal/imemo.h
11000+
process.$(OBJEXT): $(top_srcdir)/internal/io.h
1100011001
process.$(OBJEXT): $(top_srcdir)/internal/numeric.h
1100111002
process.$(OBJEXT): $(top_srcdir)/internal/object.h
1100211003
process.$(OBJEXT): $(top_srcdir)/internal/process.h

debug.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ const union {
7070
RUBY_FMODE_NOREVLOOKUP = 0x00000100,
7171
RUBY_FMODE_TRUNC = FMODE_TRUNC,
7272
RUBY_FMODE_TEXTMODE = FMODE_TEXTMODE,
73-
RUBY_FMODE_PREP = 0x00010000,
73+
RUBY_FMODE_EXTERNAL = 0x00010000,
7474
RUBY_FMODE_SETENC_BY_BOM = FMODE_SETENC_BY_BOM,
7575
RUBY_FMODE_UNIX = 0x00200000,
7676
RUBY_FMODE_INET = 0x00400000,

ext/objspace/depend

+1
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ objspace_dump.o: $(top_srcdir)/internal/compilers.h
580580
objspace_dump.o: $(top_srcdir)/internal/gc.h
581581
objspace_dump.o: $(top_srcdir)/internal/hash.h
582582
objspace_dump.o: $(top_srcdir)/internal/imemo.h
583+
objspace_dump.o: $(top_srcdir)/internal/io.h
583584
objspace_dump.o: $(top_srcdir)/internal/sanitizers.h
584585
objspace_dump.o: $(top_srcdir)/internal/serial.h
585586
objspace_dump.o: $(top_srcdir)/internal/static_assert.h

ext/objspace/objspace_dump.c

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "internal/class.h"
1919
#include "internal/gc.h"
2020
#include "internal/hash.h"
21+
#include "internal/io.h"
2122
#include "internal/string.h"
2223
#include "internal/sanitizers.h"
2324
#include "symbol.h"

ext/pty/pty.c

+23-31
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,10 @@ pty_close_pty(VALUE assoc)
448448

449449
for (i = 0; i < 2; i++) {
450450
io = rb_ary_entry(assoc, i);
451-
if (RB_TYPE_P(io, T_FILE) && 0 <= RFILE(io)->fptr->fd)
451+
if (RB_TYPE_P(io, T_FILE)) {
452+
/* it's OK to call rb_io_close again even if it's already closed */
452453
rb_io_close(io);
454+
}
453455
}
454456
return Qnil;
455457
}
@@ -499,28 +501,21 @@ pty_open(VALUE klass)
499501
{
500502
int master_fd, slave_fd;
501503
char slavename[DEVICELEN];
502-
VALUE master_io, slave_file;
503-
rb_io_t *master_fptr, *slave_fptr;
504-
VALUE assoc;
505504

506505
getDevice(&master_fd, &slave_fd, slavename, 1);
507506

508-
master_io = rb_obj_alloc(rb_cIO);
509-
MakeOpenFile(master_io, master_fptr);
510-
master_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX;
511-
master_fptr->fd = master_fd;
512-
master_fptr->pathv = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
507+
VALUE master_path = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
508+
VALUE master_io = rb_io_open_descriptor(rb_cIO, master_fd, FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX, master_path, RUBY_IO_TIMEOUT_DEFAULT, NULL);
509+
510+
VALUE slave_path = rb_obj_freeze(rb_str_new_cstr(slavename));
511+
VALUE slave_file = rb_io_open_descriptor(rb_cFile, slave_fd, FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY, slave_path, RUBY_IO_TIMEOUT_DEFAULT, NULL);
513512

514-
slave_file = rb_obj_alloc(rb_cFile);
515-
MakeOpenFile(slave_file, slave_fptr);
516-
slave_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY;
517-
slave_fptr->fd = slave_fd;
518-
slave_fptr->pathv = rb_obj_freeze(rb_str_new_cstr(slavename));
513+
VALUE assoc = rb_assoc_new(master_io, slave_file);
519514

520-
assoc = rb_assoc_new(master_io, slave_file);
521515
if (rb_block_given_p()) {
522516
return rb_ensure(rb_yield, assoc, pty_close_pty, assoc);
523517
}
518+
524519
return assoc;
525520
}
526521

@@ -577,30 +572,27 @@ pty_getpty(int argc, VALUE *argv, VALUE self)
577572
{
578573
VALUE res;
579574
struct pty_info info;
580-
rb_io_t *wfptr,*rfptr;
581-
VALUE rport = rb_obj_alloc(rb_cFile);
582-
VALUE wport = rb_obj_alloc(rb_cFile);
583575
char SlaveName[DEVICELEN];
584576

585-
MakeOpenFile(rport, rfptr);
586-
MakeOpenFile(wport, wfptr);
587-
588577
establishShell(argc, argv, &info, SlaveName);
589578

590-
rfptr->mode = rb_io_modestr_fmode("r");
591-
rfptr->fd = info.fd;
592-
rfptr->pathv = rb_obj_freeze(rb_str_new_cstr(SlaveName));
579+
VALUE pty_path = rb_obj_freeze(rb_str_new_cstr(SlaveName));
580+
VALUE rport = rb_io_open_descriptor(
581+
rb_cFile, info.fd, FMODE_READABLE, pty_path, RUBY_IO_TIMEOUT_DEFAULT, NULL
582+
);
593583

594-
wfptr->mode = rb_io_modestr_fmode("w") | FMODE_SYNC;
595-
wfptr->fd = rb_cloexec_dup(info.fd);
596-
if (wfptr->fd == -1)
584+
int wpty_fd = rb_cloexec_dup(info.fd);
585+
if (wpty_fd == -1) {
597586
rb_sys_fail("dup()");
598-
rb_update_max_fd(wfptr->fd);
599-
wfptr->pathv = rfptr->pathv;
587+
}
588+
VALUE wport = rb_io_open_descriptor(
589+
rb_cFile, wpty_fd, FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE | FMODE_SYNC,
590+
pty_path, RUBY_IO_TIMEOUT_DEFAULT, NULL
591+
);
600592

601593
res = rb_ary_new2(3);
602-
rb_ary_store(res,0,(VALUE)rport);
603-
rb_ary_store(res,1,(VALUE)wport);
594+
rb_ary_store(res, 0, rport);
595+
rb_ary_store(res, 1, wport);
604596
rb_ary_store(res,2,PIDT2NUM(info.child_pid));
605597

606598
if (rb_block_given_p()) {

ext/stringio/stringio.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
276276
{
277277
VALUE string, vmode, opt;
278278
int oflags;
279-
struct rb_io_enc_t convconfig;
279+
struct rb_io_encoding convconfig;
280280

281281
argc = rb_scan_args(argc, argv, "02:", &string, &vmode, &opt);
282282
rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &ptr->flags, &convconfig);
@@ -1743,7 +1743,7 @@ strio_set_encoding(int argc, VALUE *argv, VALUE self)
17431743
else {
17441744
enc = rb_find_encoding(ext_enc);
17451745
if (!enc) {
1746-
struct rb_io_enc_t convconfig;
1746+
struct rb_io_encoding convconfig;
17471747
int oflags, fmode;
17481748
VALUE vmode = rb_str_append(rb_str_new_cstr("r:"), ext_enc);
17491749
rb_io_extract_modeenc(&vmode, 0, Qnil, &oflags, &fmode, &convconfig);

file.c

-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@ int flock(int, int);
169169
#include "internal/thread.h"
170170
#include "internal/vm.h"
171171
#include "ruby/encoding.h"
172-
#include "ruby/io.h"
173172
#include "ruby/thread.h"
174173
#include "ruby/util.h"
175174

include/ruby/internal/core/rfile.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323
#include "ruby/internal/core/rbasic.h"
2424
#include "ruby/internal/cast.h"
2525

26-
/* rb_io_t is in ruby/io.h. The header file has historically not been included
27-
* into ruby/ruby.h. We follow that tradition. */
28-
struct rb_io_t;
26+
/* rb_io is in ruby/io.h and internal/io.h. The header file has historically
27+
* not been included into ruby/ruby.h. We follow that tradition.
28+
*/
29+
struct rb_io;
2930

3031
/**
3132
* Ruby's File and IO. Ruby's IO are not just file descriptors. They have
@@ -38,7 +39,7 @@ struct RFile {
3839
struct RBasic basic;
3940

4041
/** IO's specific fields. */
41-
struct rb_io_t *fptr;
42+
struct rb_io *fptr;
4243
};
4344

4445
/**

include/ruby/io.h

+38-121
Original file line numberDiff line numberDiff line change
@@ -84,37 +84,14 @@ typedef enum {
8484
RUBY_IO_PRIORITY = RB_WAITFD_PRI, /**< `IO::PRIORITY` */
8585
} rb_io_event_t;
8686

87-
/**
88-
* IO buffers. This is an implementation detail of ::rb_io_t::wbuf and
89-
* ::rb_io_t::rbuf. People don't manipulate it directly.
90-
*/
91-
RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN()
92-
struct rb_io_buffer_t {
93-
94-
/** Pointer to the underlying memory region, of at least `capa` bytes. */
95-
char *ptr; /* off + len <= capa */
96-
97-
/** Offset inside of `ptr`. */
98-
int off;
99-
100-
/** Length of the buffer. */
101-
int len;
102-
103-
/** Designed capacity of the buffer. */
104-
int capa;
105-
} RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END();
106-
107-
/** @alias{rb_io_buffer_t} */
108-
typedef struct rb_io_buffer_t rb_io_buffer_t;
109-
11087
/** Decomposed encoding flags (e.g. `"enc:enc2""`). */
11188
/*
11289
* enc enc2 read action write action
11390
* NULL NULL force_encoding(default_external) write the byte sequence of str
11491
* e1 NULL force_encoding(e1) convert str.encoding to e1
11592
* e1 e2 convert from e2 to e1 convert str.encoding to e2
11693
*/
117-
struct rb_io_enc_t {
94+
struct rb_io_encoding {
11895
/** Internal encoding. */
11996
rb_encoding *enc;
12097
/** External encoding. */
@@ -135,103 +112,10 @@ struct rb_io_enc_t {
135112
VALUE ecopts;
136113
};
137114

138-
/** Ruby's IO, metadata and buffers. */
139-
typedef struct rb_io_t {
140-
141-
/** The IO's Ruby level counterpart. */
142-
VALUE self;
143-
144-
/** stdio ptr for read/write, if available. */
145-
FILE *stdio_file;
146-
147-
/** file descriptor. */
148-
int fd;
149-
150-
/** mode flags: FMODE_XXXs */
151-
int mode;
152-
153-
/** child's pid (for pipes) */
154-
rb_pid_t pid;
155-
156-
/** number of lines read */
157-
int lineno;
158-
159-
/** pathname for file */
160-
VALUE pathv;
161-
162-
/** finalize proc */
163-
void (*finalize)(struct rb_io_t*,int);
164-
165-
/** Write buffer. */
166-
rb_io_buffer_t wbuf;
167-
168-
/**
169-
* (Byte) read buffer. Note also that there is a field called
170-
* ::rb_io_t::cbuf, which also concerns read IO.
171-
*/
172-
rb_io_buffer_t rbuf;
173-
174-
/**
175-
* Duplex IO object, if set.
176-
*
177-
* @see rb_io_set_write_io()
178-
*/
179-
VALUE tied_io_for_writing;
180-
181-
struct rb_io_enc_t encs; /**< Decomposed encoding flags. */
182-
183-
/** Encoding converter used when reading from this IO. */
184-
rb_econv_t *readconv;
185-
186-
/**
187-
* rb_io_ungetc() destination. This buffer is read before checking
188-
* ::rb_io_t::rbuf
189-
*/
190-
rb_io_buffer_t cbuf;
191-
192-
/** Encoding converter used when writing to this IO. */
193-
rb_econv_t *writeconv;
194-
195-
/**
196-
* This is, when set, an instance of ::rb_cString which holds the "common"
197-
* encoding. Write conversion can convert strings twice... In case
198-
* conversion from encoding X to encoding Y does not exist, Ruby finds an
199-
* encoding Z that bridges the two, so that X to Z to Y conversion happens.
200-
*/
201-
VALUE writeconv_asciicompat;
202-
203-
/** Whether ::rb_io_t::writeconv is already set up. */
204-
int writeconv_initialized;
115+
struct rb_io;
116+
typedef struct rb_io rb_io_t;
205117

206-
/**
207-
* Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before
208-
* initialising ::rb_io_t::writeconv.
209-
*/
210-
int writeconv_pre_ecflags;
211-
212-
/**
213-
* Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising
214-
* ::rb_io_t::writeconv.
215-
*/
216-
VALUE writeconv_pre_ecopts;
217-
218-
/**
219-
* This is a Ruby level mutex. It avoids multiple threads to write to an
220-
* IO at once; helps for instance rb_io_puts() to ensure newlines right
221-
* next to its arguments.
222-
*
223-
* This of course doesn't help inter-process IO interleaves, though.
224-
*/
225-
VALUE write_lock;
226-
227-
/**
228-
* The timeout associated with this IO when performing blocking operations.
229-
*/
230-
VALUE timeout;
231-
} rb_io_t;
232-
233-
/** @alias{rb_io_enc_t} */
234-
typedef struct rb_io_enc_t rb_io_enc_t;
118+
typedef struct rb_io_encoding rb_io_enc_t;
235119

236120
/**
237121
* @private
@@ -331,7 +215,16 @@ typedef struct rb_io_enc_t rb_io_enc_t;
331215
* Setting this one and #FMODE_BINMODE at the same time is a contradiction.
332216
*/
333217
#define FMODE_TEXTMODE 0x00001000
334-
/* #define FMODE_PREP 0x00010000 */
218+
/**
219+
* This flag means that an IO object is wrapping an "external" file descriptor,
220+
* which is owned by something outside the Ruby interpreter (usually a C extension).
221+
* Ruby will not close this file when the IO object is garbage collected.
222+
* If this flag is set, then IO#autoclose? is false, and vice-versa.
223+
*
224+
* This flag was previously called FMODE_PREP internally.
225+
*/
226+
#define FMODE_EXTERNAL 0x00010000
227+
335228
/* #define FMODE_SIGNAL_ON_EPIPE 0x00020000 */
336229

337230
/**
@@ -345,6 +238,18 @@ typedef struct rb_io_enc_t rb_io_enc_t;
345238

346239
/** @} */
347240

241+
/**
242+
* Allocate a new IO object, with the given file descriptor.
243+
*/
244+
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding);
245+
246+
/**
247+
* Returns whether or not the underlying IO is closed.
248+
*
249+
* @return Whether the underlying IO is closed.
250+
*/
251+
VALUE rb_io_closed_p(VALUE io);
252+
348253
/**
349254
* Queries the underlying IO pointer.
350255
*
@@ -703,6 +608,12 @@ VALUE rb_io_set_write_io(VALUE io, VALUE w);
703608
*/
704609
void rb_io_set_nonblock(rb_io_t *fptr);
705610

611+
/**
612+
* Returns the path for the given IO.
613+
*
614+
*/
615+
VALUE rb_io_path(VALUE io);
616+
706617
/**
707618
* Returns an integer representing the numeric file descriptor for
708619
* <em>io</em>.
@@ -712,6 +623,12 @@ void rb_io_set_nonblock(rb_io_t *fptr);
712623
*/
713624
int rb_io_descriptor(VALUE io);
714625

626+
/**
627+
* Get the mode of the IO.
628+
*
629+
*/
630+
int rb_io_mode(VALUE io);
631+
715632
/**
716633
* This function breaks down the option hash that `IO#initialize` takes into
717634
* components. This is an implementation detail of rb_io_extract_modeenc()

0 commit comments

Comments
 (0)