kgio 2.8.0 - TCP Fast Open, writev/trywritev
[kgio.git] / ext / kgio / tryopen.c
blob0ee6a54c98719911dbccbc656b00e133d45a13d5
1 #include <ruby.h>
2 #ifdef HAVE_RUBY_IO_H
3 # include <ruby/io.h>
4 #else
5 # include <rubyio.h>
6 #endif
8 #ifdef HAVE_RUBY_ST_H
9 # include <ruby/st.h>
10 #else
11 # include <st.h>
12 #endif
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <errno.h>
18 #include "set_file_path.h"
19 #include "ancient_ruby.h"
21 static ID id_for_fd, id_to_path, id_path;
22 static st_table *errno2sym;
24 struct open_args {
25 const char *pathname;
26 int flags;
27 mode_t mode;
30 #ifndef HAVE_RB_CLOEXEC_OPEN
31 # define rb_cloexec_open(p,f,m) open((p),(f),(m))
32 #endif
34 static VALUE nogvl_open(void *ptr)
36 struct open_args *o = ptr;
38 return (VALUE)rb_cloexec_open(o->pathname, o->flags, o->mode);
41 #ifndef HAVE_RB_THREAD_BLOCKING_REGION
42 # define RUBY_UBF_IO ((void *)(-1))
43 # include "rubysig.h"
44 typedef void rb_unblock_function_t(void *);
45 typedef VALUE rb_blocking_function_t(void *);
46 static VALUE my_thread_blocking_region(
47 rb_blocking_function_t *fn, void *data1,
48 rb_unblock_function_t *ubf, void *data2)
50 VALUE rv;
52 TRAP_BEG; /* for FIFO */
53 rv = fn(data1);
54 TRAP_END;
56 return rv;
58 #define rb_thread_blocking_region(fn,data1,ubf,data2) \
59 my_thread_blocking_region((fn),(data1),(ubf),(data2))
60 #endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
63 * call-seq:
65 * Kgio::File.tryopen(filename, [, mode [, perm]]) -> Kgio::File or Symbol
67 * Returns a Kgio::File object on a successful open. +filename+ is a
68 * path to any file on the filesystem. If specified, +mode+ is a bitmask
69 * of flags (see IO.sysopen) and +perm+ should be an octal number.
71 * This does not raise errors for most failures, but installs returns a
72 * Ruby symbol for the constant in the Errno::* namespace.
74 * Common error symbols are:
76 * - :ENOENT
77 * - :EACCES
79 * See your open(2) manpage for more information on open(2) errors.
81 static VALUE s_tryopen(int argc, VALUE *argv, VALUE klass)
83 int fd;
84 VALUE pathname, flags, mode;
85 struct open_args o;
86 int retried = 0;
87 VALUE rv;
89 rb_scan_args(argc, argv, "12", &pathname, &flags, &mode);
90 if (rb_respond_to(pathname, id_to_path))
91 pathname = rb_funcall(pathname, id_to_path, 0);
92 o.pathname = StringValueCStr(pathname);
94 switch (TYPE(flags)) {
95 case T_NIL: o.flags = O_RDONLY; break;
96 case T_FIXNUM: o.flags = FIX2INT(flags); break;
97 case T_BIGNUM: o.flags = NUM2INT(flags); break;
98 default: rb_raise(rb_eArgError, "flags must be an Integer");
100 switch (TYPE(mode)) {
101 case T_NIL: o.mode = 0666; break;
102 case T_FIXNUM: o.mode = FIX2INT(mode); break;
103 case T_BIGNUM: o.mode = NUM2INT(mode); break;
104 default: rb_raise(rb_eArgError, "mode must be an Integer");
107 retry:
108 fd = (int)rb_thread_blocking_region(nogvl_open, &o, RUBY_UBF_IO, 0);
109 if (fd == -1) {
110 if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
111 rb_gc();
112 if (retried)
113 rb_sys_fail(o.pathname);
114 retried = 1;
115 goto retry;
117 if (fd == -1) {
118 int saved_errno = errno;
120 if (!st_lookup(errno2sym, (st_data_t)errno, &rv)) {
121 errno = saved_errno;
122 rb_sys_fail(o.pathname);
124 return rv;
127 rv = rb_funcall(klass, id_for_fd, 1, INT2FIX(fd));
128 set_file_path(rv, pathname);
129 return rv;
132 void init_kgio_tryopen(void)
134 VALUE mKgio = rb_define_module("Kgio");
135 VALUE mPipeMethods = rb_const_get(mKgio, rb_intern("PipeMethods"));
136 VALUE cFile;
137 VALUE tmp;
138 VALUE *ptr;
139 long len;
141 id_path = rb_intern("path");
142 id_for_fd = rb_intern("for_fd");
143 id_to_path = rb_intern("to_path");
146 * Document-class: Kgio::File
148 * This subclass of the core File class adds the "tryopen" singleton
149 * method for opening files. A single "tryopen" and check for the
150 * return value may be used to avoid unnecessary stat(2) syscalls
151 * or File.open exceptions when checking for the existence of a file
152 * and opening it.
154 cFile = rb_define_class_under(mKgio, "File", rb_cFile);
155 rb_define_singleton_method(cFile, "tryopen", s_tryopen, -1);
156 rb_include_module(cFile, mPipeMethods);
158 if (!rb_funcall(cFile, rb_intern("method_defined?"), 1,
159 ID2SYM(id_to_path)))
160 rb_define_alias(cFile, "to_path", "path");
162 errno2sym = st_init_numtable();
163 tmp = rb_funcall(rb_mErrno, rb_intern("constants"), 0);
164 ptr = RARRAY_PTR(tmp);
165 len = RARRAY_LEN(tmp);
166 for (; --len >= 0; ptr++) {
167 VALUE error;
168 ID const_id;
170 switch (TYPE(*ptr)) {
171 case T_SYMBOL: const_id = SYM2ID(*ptr); break;
172 case T_STRING: const_id = rb_intern(RSTRING_PTR(*ptr)); break;
173 default: rb_bug("constant not a symbol or string");
176 error = rb_const_get(rb_mErrno, const_id);
177 if ((TYPE(error) != T_CLASS) ||
178 !rb_const_defined(error, rb_intern("Errno")))
179 continue;
181 error = rb_const_get(error, rb_intern("Errno"));
182 switch (TYPE(error)) {
183 case T_FIXNUM:
184 case T_BIGNUM:
185 st_insert(errno2sym, (st_data_t)NUM2INT(error),
186 ID2SYM(const_id));