Skip to content

Commit 4a3c853

Browse files
committed
[WIP] Do only one open syscall per Kernel#require
1 parent 6eb9dfc commit 4a3c853

File tree

7 files changed

+59
-33
lines changed

7 files changed

+59
-33
lines changed

file.c

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6612,7 +6612,7 @@ ruby_is_fd_loadable(int fd)
66126612

66136613
#ifndef _WIN32
66146614
int
6615-
rb_file_load_ok(const char *path)
6615+
rb_file_load_ok(const char *path, int *fd_ptr)
66166616
{
66176617
int ret = 1;
66186618
/*
@@ -6634,7 +6634,12 @@ rb_file_load_ok(const char *path)
66346634
}
66356635
rb_update_max_fd(fd);
66366636
ret = ruby_is_fd_loadable(fd);
6637-
(void)close(fd);
6637+
if (ret && fd_ptr) {
6638+
*fd_ptr = fd;
6639+
}
6640+
else {
6641+
(void)close(fd);
6642+
}
66386643
return ret;
66396644
}
66406645
#endif
@@ -6661,7 +6666,7 @@ copy_path_class(VALUE path, VALUE orig)
66616666
}
66626667

66636668
int
6664-
rb_find_file_ext(VALUE *filep, const char *const *ext)
6669+
rb_find_file_ext_internal(VALUE *filep, const char *const *ext, int *fd)
66656670
{
66666671
const char *f = StringValueCStr(*filep);
66676672
VALUE fname = *filep, load_path, tmp;
@@ -6682,7 +6687,7 @@ rb_find_file_ext(VALUE *filep, const char *const *ext)
66826687
fnlen = RSTRING_LEN(fname);
66836688
for (i=0; ext[i]; i++) {
66846689
rb_str_cat2(fname, ext[i]);
6685-
if (rb_file_load_ok(RSTRING_PTR(fname))) {
6690+
if (rb_file_load_ok(RSTRING_PTR(fname), fd)) {
66866691
*filep = copy_path_class(fname, *filep);
66876692
return (int)(i+1);
66886693
}
@@ -6707,7 +6712,7 @@ rb_find_file_ext(VALUE *filep, const char *const *ext)
67076712
RB_GC_GUARD(str) = rb_get_path(str);
67086713
if (RSTRING_LEN(str) == 0) continue;
67096714
rb_file_expand_path_internal(fname, str, 0, 0, tmp);
6710-
if (rb_file_load_ok(RSTRING_PTR(tmp))) {
6715+
if (rb_file_load_ok(RSTRING_PTR(tmp), fd)) {
67116716
*filep = copy_path_class(tmp, *filep);
67126717
return (int)(j+1);
67136718
}
@@ -6719,8 +6724,14 @@ rb_find_file_ext(VALUE *filep, const char *const *ext)
67196724
return 0;
67206725
}
67216726

6727+
int
6728+
rb_find_file_ext(VALUE *filep, const char *const *ext)
6729+
{
6730+
return rb_find_file_ext_internal(filep, ext, NULL);
6731+
}
6732+
67226733
VALUE
6723-
rb_find_file(VALUE path)
6734+
rb_find_file_internal(VALUE path, int *fd)
67246735
{
67256736
VALUE tmp, load_path;
67266737
const char *f = StringValueCStr(path);
@@ -6734,7 +6745,7 @@ rb_find_file(VALUE path)
67346745
}
67356746

67366747
if (expanded || rb_is_absolute_path(f) || is_explicit_relative(f)) {
6737-
if (!rb_file_load_ok(f)) return 0;
6748+
if (!rb_file_load_ok(f, fd)) return 0;
67386749
if (!expanded)
67396750
path = copy_path_class(file_expand_path_1(path), path);
67406751
return path;
@@ -6752,7 +6763,7 @@ rb_find_file(VALUE path)
67526763
if (RSTRING_LEN(str) > 0) {
67536764
rb_file_expand_path_internal(path, str, 0, 0, tmp);
67546765
f = RSTRING_PTR(tmp);
6755-
if (rb_file_load_ok(f)) goto found;
6766+
if (rb_file_load_ok(f, fd)) goto found;
67566767
}
67576768
}
67586769
rb_str_resize(tmp, 0);
@@ -6766,6 +6777,12 @@ rb_find_file(VALUE path)
67666777
return copy_path_class(tmp, path);
67676778
}
67686779

6780+
VALUE
6781+
rb_find_file(VALUE path)
6782+
{
6783+
return rb_find_file_internal(path, NULL);
6784+
}
6785+
67696786
#define define_filetest_function(name, func, argc) do { \
67706787
rb_define_module_function(rb_mFileTest, name, func, argc); \
67716788
rb_define_singleton_method(rb_cFile, name, func, argc); \

internal/file.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ VALUE rb_default_home_dir(VALUE result);
1818
VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict);
1919
VALUE rb_check_realpath(VALUE basedir, VALUE path, rb_encoding *origenc);
2020
void rb_file_const(const char*, VALUE);
21-
int rb_file_load_ok(const char *);
21+
int rb_file_load_ok(const char *, int *);
22+
int rb_find_file_ext_internal(VALUE *filep, const char *const *ext, int *fd);
23+
VALUE rb_find_file_internal(VALUE path, int *fd);
2224
VALUE rb_file_expand_path_fast(VALUE, VALUE);
2325
VALUE rb_file_expand_path_internal(VALUE, VALUE, int, int, VALUE);
2426
VALUE rb_get_path_check_to_string(VALUE);

iseq.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,7 +1376,7 @@ pm_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
13761376
VALUE error;
13771377

13781378
if (parse_file) {
1379-
error = pm_load_parse_file(&result, src, ruby_vm_keep_script_lines ? &script_lines : NULL);
1379+
error = pm_load_parse_file(&result, src, NULL, ruby_vm_keep_script_lines ? &script_lines : NULL);
13801380
}
13811381
else {
13821382
error = pm_parse_string(&result, src, file, ruby_vm_keep_script_lines ? &script_lines : NULL);
@@ -1838,7 +1838,7 @@ iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self)
18381838
result.node.coverage_enabled = 1;
18391839

18401840
VALUE script_lines;
1841-
VALUE error = pm_load_parse_file(&result, file, ruby_vm_keep_script_lines ? &script_lines : NULL);
1841+
VALUE error = pm_load_parse_file(&result, file, NULL, ruby_vm_keep_script_lines ? &script_lines : NULL);
18421842

18431843
if (error == Qnil) {
18441844
make_compile_option(&option, opt);

load.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,7 @@ iseq_eval_in_namespace(VALUE arg)
817817
}
818818

819819
static inline void
820-
load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
820+
load_iseq_eval(rb_execution_context_t *ec, VALUE fname, int *fd)
821821
{
822822
GET_loading_vm_ns();
823823
const rb_namespace_t *loading_ns = rb_loading_namespace();
@@ -834,7 +834,7 @@ load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
834834
result.options.line = 1;
835835
result.node.coverage_enabled = 1;
836836

837-
VALUE error = pm_load_parse_file(&result, fname, NULL);
837+
VALUE error = pm_load_parse_file(&result, fname, fd, NULL);
838838

839839
if (error == Qnil) {
840840
int error_state;
@@ -915,7 +915,7 @@ load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
915915
EC_PUSH_TAG(ec);
916916
state = EC_EXEC_TAG();
917917
if (state == TAG_NONE) {
918-
load_iseq_eval(ec, fname);
918+
load_iseq_eval(ec, fname, NULL);
919919
}
920920
EC_POP_TAG();
921921

@@ -958,7 +958,7 @@ rb_load_internal(VALUE fname, VALUE wrap)
958958
state = load_wrapping(ec, fname, namespace);
959959
}
960960
else {
961-
load_iseq_eval(ec, fname);
961+
load_iseq_eval(ec, fname, NULL);
962962
}
963963
raise_load_if_failed(ec, state);
964964
}
@@ -996,7 +996,7 @@ load_entrypoint_internal(VALUE fname, VALUE wrap)
996996

997997
path = rb_find_file(fname);
998998
if (!path) {
999-
if (!rb_file_load_ok(RSTRING_PTR(fname)))
999+
if (!rb_file_load_ok(RSTRING_PTR(fname), NULL))
10001000
load_failed(orig_fname);
10011001
path = fname;
10021002
}
@@ -1189,7 +1189,7 @@ rb_f_require_relative(VALUE obj, VALUE fname)
11891189
typedef int (*feature_func)(vm_ns_t *vm_ns, const char *feature, const char *ext, int rb, int expanded, const char **fn);
11901190

11911191
static int
1192-
search_required(vm_ns_t *vm_ns, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
1192+
search_required(vm_ns_t *vm_ns, VALUE fname, volatile VALUE *path, feature_func rb_feature_p, int *fd)
11931193
{
11941194
VALUE tmp;
11951195
char *ext, *ftptr;
@@ -1204,7 +1204,7 @@ search_required(vm_ns_t *vm_ns, VALUE fname, volatile VALUE *path, feature_func
12041204
if (loading) *path = rb_filesystem_str_new_cstr(loading);
12051205
return 'r';
12061206
}
1207-
if ((tmp = rb_find_file(fname)) != 0) {
1207+
if ((tmp = rb_find_file_internal(fname, fd)) != 0) {
12081208
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
12091209
if (!rb_feature_p(vm_ns, ftptr, ext, TRUE, TRUE, &loading) || loading)
12101210
*path = tmp;
@@ -1245,7 +1245,7 @@ search_required(vm_ns_t *vm_ns, VALUE fname, volatile VALUE *path, feature_func
12451245
return 'r';
12461246
}
12471247
tmp = fname;
1248-
const unsigned int type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
1248+
const unsigned int type = rb_find_file_ext_internal(&tmp, ft == 's' ? ruby_ext : loadable_ext, ft == 's' ? NULL : fd);
12491249

12501250
// Check if it's a statically linked extension when
12511251
// not already a feature and not found as a dynamic library.
@@ -1339,7 +1339,7 @@ rb_resolve_feature_path(VALUE klass, VALUE fname)
13391339

13401340
fname = rb_get_path(fname);
13411341
path = rb_str_encode_ospath(fname);
1342-
found = search_required(vm_ns, path, &path, no_feature_p);
1342+
found = search_required(vm_ns, path, &path, no_feature_p, NULL);
13431343

13441344
switch (found) {
13451345
case 'r':
@@ -1429,9 +1429,10 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
14291429
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
14301430
VALUE handle;
14311431
int found;
1432+
int fd = -1;
14321433

14331434
RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
1434-
found = search_required(vm_ns, path, &saved_path, rb_feature_p);
1435+
found = search_required(vm_ns, path, &saved_path, rb_feature_p, &fd);
14351436
RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
14361437
path = saved_path;
14371438

@@ -1459,7 +1460,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
14591460
load_wrapping(saved.ec, path, vm_ns->ns->ns_object);
14601461
}
14611462
else {
1462-
load_iseq_eval(saved.ec, path);
1463+
load_iseq_eval(saved.ec, path, &fd);
14631464
}
14641465
break;
14651466

prism_compile.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11187,7 +11187,7 @@ pm_parse_file_script_lines(const pm_scope_node_t *scope_node, const pm_parser_t
1118711187
// file, with additional handling for files that require blocking to properly
1118811188
// read (e.g. pipes).
1118911189
static pm_string_init_result_t
11190-
pm_read_file(pm_string_t *string, const char *filepath)
11190+
pm_read_file(pm_string_t *string, const char *filepath, int *passed_fd)
1119111191
{
1119211192
#ifdef _WIN32
1119311193
// Open the file for reading.
@@ -11256,9 +11256,15 @@ pm_read_file(pm_string_t *string, const char *filepath)
1125611256
#elif defined(_POSIX_MAPPED_FILES)
1125711257
// Open the file for reading
1125811258
const int open_mode = O_RDONLY | O_NONBLOCK;
11259-
int fd = open(filepath, open_mode);
11260-
if (fd == -1) {
11261-
return PM_STRING_INIT_ERROR_GENERIC;
11259+
int fd;
11260+
if (passed_fd && *passed_fd != -1) {
11261+
fd = *passed_fd;
11262+
*passed_fd = -1;
11263+
} else {
11264+
fd = open(filepath, open_mode);
11265+
if (fd == -1) {
11266+
return PM_STRING_INIT_ERROR_GENERIC;
11267+
}
1126211268
}
1126311269

1126411270
// Stat the file to get the file size
@@ -11329,9 +11335,9 @@ pm_read_file(pm_string_t *string, const char *filepath)
1132911335
* be read.
1133011336
*/
1133111337
VALUE
11332-
pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error)
11338+
pm_load_file(pm_parse_result_t *result, VALUE filepath, int *fd, bool load_error)
1133311339
{
11334-
pm_string_init_result_t init_result = pm_read_file(&result->input, RSTRING_PTR(filepath));
11340+
pm_string_init_result_t init_result = pm_read_file(&result->input, RSTRING_PTR(filepath), fd);
1133511341

1133611342
if (init_result == PM_STRING_INIT_SUCCESS) {
1133711343
pm_options_frozen_string_literal_init(&result->options);
@@ -11406,9 +11412,9 @@ pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines)
1140611412
* cannot be read or if it cannot be parsed properly.
1140711413
*/
1140811414
VALUE
11409-
pm_load_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines)
11415+
pm_load_parse_file(pm_parse_result_t *result, VALUE filepath, int *fd, VALUE *script_lines)
1141011416
{
11411-
VALUE error = pm_load_file(result, filepath, false);
11417+
VALUE error = pm_load_file(result, filepath, fd, false);
1141211418
if (NIL_P(error)) {
1141311419
error = pm_parse_file(result, filepath, script_lines);
1141411420
}

prism_compile.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ typedef struct {
8989
#define PM_CONSTANT_MULT ((pm_constant_id_t)(idMULT | PM_SPECIAL_CONSTANT_FLAG))
9090
#define PM_CONSTANT_POW ((pm_constant_id_t)(idPow | PM_SPECIAL_CONSTANT_FLAG))
9191

92-
VALUE pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error);
92+
VALUE pm_load_file(pm_parse_result_t *result, VALUE filepath, int *fd, bool load_error);
9393
VALUE pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines);
94-
VALUE pm_load_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines);
94+
VALUE pm_load_parse_file(pm_parse_result_t *result, VALUE filepath, int *fd, VALUE *script_lines);
9595
VALUE pm_parse_string(pm_parse_result_t *result, VALUE source, VALUE filepath, VALUE *script_lines);
9696
VALUE pm_parse_stdin(pm_parse_result_t *result);
9797
void pm_options_version_for_current_ruby_set(pm_options_t *options);

ruby.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2224,7 +2224,7 @@ prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *result)
22242224
pm_options_command_line_set(options, command_line);
22252225
pm_options_shebang_callback_set(options, prism_script_shebang_callback, (void *) opt);
22262226

2227-
error = pm_load_file(result, script_name, true);
2227+
error = pm_load_file(result, script_name, NULL, true);
22282228

22292229
// If reading the file did not error, at that point we load the command
22302230
// line options. We do it in this order so that if the main script fails

0 commit comments

Comments
 (0)