summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--benchmark/bm_file_rename.rb11
-rw-r--r--file.c22
2 files changed, 29 insertions, 4 deletions
diff --git a/benchmark/bm_file_rename.rb b/benchmark/bm_file_rename.rb
new file mode 100644
index 0000000000..3bf6a5ef35
--- /dev/null
+++ b/benchmark/bm_file_rename.rb
@@ -0,0 +1,11 @@
+# rename file
+require 'tempfile'
+
+max = 100_000
+tmp = [ Tempfile.new('rename-a'), Tempfile.new('rename-b') ]
+a, b = tmp.map { |x| x.path }
+max.times do
+ File.rename(a, b)
+ File.rename(b, a)
+end
+tmp.each { |t| t.close! }
diff --git a/file.c b/file.c
index a73ed57360..b24b671bb2 100644
--- a/file.c
+++ b/file.c
@@ -2873,6 +2873,19 @@ rb_file_s_unlink(int argc, VALUE *argv, VALUE klass)
return apply2files(unlink_internal, argc, argv, 0);
}
+struct rename_args {
+ const char *src;
+ const char *dst;
+};
+
+static void *
+no_gvl_rename(void *ptr)
+{
+ struct rename_args *ra = ptr;
+
+ return (void *)(VALUE)rename(ra->src, ra->dst);
+}
+
/*
* call-seq:
* File.rename(old_name, new_name) -> 0
@@ -2886,19 +2899,20 @@ rb_file_s_unlink(int argc, VALUE *argv, VALUE klass)
static VALUE
rb_file_s_rename(VALUE klass, VALUE from, VALUE to)
{
- const char *src, *dst;
+ struct rename_args ra;
VALUE f, t;
FilePathValue(from);
FilePathValue(to);
f = rb_str_encode_ospath(from);
t = rb_str_encode_ospath(to);
- src = StringValueCStr(f);
- dst = StringValueCStr(t);
+ ra.src = StringValueCStr(f);
+ ra.dst = StringValueCStr(t);
#if defined __CYGWIN__
errno = 0;
#endif
- if (rename(src, dst) < 0) {
+ if ((int)(VALUE)rb_thread_call_without_gvl(no_gvl_rename, &ra,
+ RUBY_UBF_IO, 0) < 0) {
int e = errno;
#if defined DOSISH
switch (e) {