summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2023-02-24 18:05:36 +0000
committerEric Wong <normal@ruby-lang.org>2023-02-26 20:39:41 +0000
commit35136e1e9c232ad7a03407b992b2e86b6df43f63 (patch)
tree2c60e2d5c9a10089badd41d0f696fe41e70f4a1a /internal
parent6e6992e5db49a238baf290d9b9b521f6b6be5a19 (diff)
downloadruby-35136e1e9c232ad7a03407b992b2e86b6df43f63.tar.gz
reuse open(2) from rb_file_load_ok on POSIX-like system
When loading Ruby source files, we can save the result of successful opens as open(2)/openat(2) are a fairly expensive syscalls. This also avoids a time-of-check-to-time-of-use (TOCTTOU) problem. This reduces open(2) syscalls during `require'; but should be most apparent when users have a small $LOAD_PATH. Users with large $LOAD_PATH will benefit less since there'll be more open(2) failures due to ENOENT. With `strace -c -e openat ruby -e exit' under Linux, this results in a ~14% reduction of openat(2) syscalls (glibc uses openat(2) to implement open(2)). % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 0.00 0.000000 0 296 110 openat 0.00 0.000000 0 254 110 openat Additionally, the introduction of `struct ruby_file_load_state' may make future optimizations more apparent. This change cannot benefit binary (.so) loading since the dlopen(3) API requires a filename and I'm not aware of an alternative that takes a pre-existing FD. In typical situations, Ruby source files outnumber the mount of .so files.
Diffstat (limited to 'internal')
-rw-r--r--internal/file.h14
-rw-r--r--internal/parse.h3
2 files changed, 16 insertions, 1 deletions
diff --git a/internal/file.h b/internal/file.h
index 9c192ff4d1..2768418ac5 100644
--- a/internal/file.h
+++ b/internal/file.h
@@ -11,6 +11,14 @@
#include "ruby/ruby.h" /* for VALUE */
#include "ruby/encoding.h" /* for rb_encodinng */
+struct ruby_file_load_state {
+ /* TODO: consider stuffing `VALUE fname' here */
+ VALUE filev;
+ unsigned int is_fifo:1;
+ unsigned int is_nonblock:1;
+ /* TODO: DOSISH / __CYGWIN__ maintainer may add xflag here */
+};
+
/* file.c */
extern const char ruby_null_device[];
VALUE rb_home_dir_of(VALUE user, VALUE result);
@@ -18,12 +26,16 @@ VALUE rb_default_home_dir(VALUE result);
VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict);
VALUE rb_check_realpath(VALUE basedir, VALUE path, rb_encoding *origenc);
void rb_file_const(const char*, VALUE);
-int rb_file_load_ok(const char *);
+int rb_file_load_ok(const char *, struct ruby_file_load_state *);
VALUE rb_file_expand_path_fast(VALUE, VALUE);
VALUE rb_file_expand_path_internal(VALUE, VALUE, int, int, VALUE);
VALUE rb_get_path_check_to_string(VALUE);
VALUE rb_get_path_check_convert(VALUE);
int ruby_is_fd_loadable(int fd);
+int ruby_disable_nonblock(int fd);
+int ruby_find_file_ext(VALUE *filep, const char *const *ext,
+ struct ruby_file_load_state *);
+VALUE ruby_find_file(VALUE path, struct ruby_file_load_state *);
RUBY_SYMBOL_EXPORT_BEGIN
/* file.c (export) */
diff --git a/internal/parse.h b/internal/parse.h
index f242c384ad..7cadd0cd5b 100644
--- a/internal/parse.h
+++ b/internal/parse.h
@@ -10,10 +10,13 @@
*/
#include "ruby/ruby.h" /* for VALUE */
struct rb_iseq_struct; /* in vm_core.h */
+struct ruby_file_load_state; /* internal/file.h */
/* parse.y */
VALUE rb_parser_set_yydebug(VALUE, VALUE);
void *rb_parser_load_file(VALUE parser, VALUE name);
+void *rb_parser_load_state(VALUE parser, VALUE name,
+ struct ruby_file_load_state *);
void rb_parser_keep_script_lines(VALUE vparser);
void rb_parser_error_tolerant(VALUE vparser);
void rb_parser_keep_tokens(VALUE vparser);