aboutsummaryrefslogtreecommitdiffstats
path: root/file.c
diff options
context:
space:
mode:
authornormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-11-18 22:45:11 +0000
committernormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-11-18 22:45:11 +0000
commitbd4712d60f84f95dd9bddd0fed0cf5140ff3386f (patch)
treefccd5f998e6e3120f21d52ebef6c43d08e6abdbe /file.c
parent5881e9afac4b7ed74febd2d55259cc86d6104c92 (diff)
downloadruby-bd4712d60f84f95dd9bddd0fed0cf5140ff3386f.tar.gz
file: File#truncate and File.truncate release GVL
Like IO#write and IO.open, these file operations have unpredictable performance on slow file systems. Allow other threads of the VM to proceed while they are taking place. * file.c (nogvl_truncate): extract from rb_file_s_truncate (rb_file_s_truncate): release GVL (nogvl_ftruncate): extract from rb_file_truncate (rb_file_truncate): release GVL git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60844 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'file.c')
-rw-r--r--file.c111
1 files changed, 71 insertions, 40 deletions
diff --git a/file.c b/file.c
index 295192bb79..1e4d5459c0 100644
--- a/file.c
+++ b/file.c
@@ -4609,6 +4609,42 @@ rb_file_s_join(VALUE klass, VALUE args)
}
#if defined(HAVE_TRUNCATE) || defined(HAVE_CHSIZE)
+struct truncate_arg {
+ const char *path;
+#if defined(HAVE_FTRUNCATE)
+#define NUM2POS(n) NUM2OFFT(n)
+ off_t pos;
+#else
+#define NUM2POS(n) NUM2LONG(n)
+ long pos;
+#endif
+};
+
+static void *
+nogvl_truncate(void *ptr)
+{
+ struct truncate_arg *ta = ptr;
+#ifdef HAVE_TRUNCATE
+ return (void *)truncate(ta->path, ta->pos);
+#else /* defined(HAVE_CHSIZE) */
+ {
+ int tmpfd = rb_cloexec_open(ta->path, 0, 0);
+
+ if (tmpfd < 0)
+ return (void *)-1;
+ rb_update_max_fd(tmpfd);
+ if (chsize(tmpfd, ta->pos) < 0) {
+ int e = errno;
+ close(tmpfd);
+ errno = e;
+ return (void *)-1;
+ }
+ close(tmpfd);
+ return 0;
+ }
+#endif
+}
+
/*
* call-seq:
* File.truncate(file_name, integer) -> 0
@@ -4627,36 +4663,17 @@ rb_file_s_join(VALUE klass, VALUE args)
static VALUE
rb_file_s_truncate(VALUE klass, VALUE path, VALUE len)
{
-#ifdef HAVE_TRUNCATE
-#define NUM2POS(n) NUM2OFFT(n)
- off_t pos;
-#else
-#define NUM2POS(n) NUM2LONG(n)
- long pos;
-#endif
+ struct truncate_arg ta;
+ int r;
- pos = NUM2POS(len);
+ ta.pos = NUM2POS(len);
FilePathValue(path);
path = rb_str_encode_ospath(path);
-#ifdef HAVE_TRUNCATE
- if (truncate(StringValueCStr(path), pos) < 0)
- rb_sys_fail_path(path);
-#else /* defined(HAVE_CHSIZE) */
- {
- int tmpfd;
+ ta.path = StringValueCStr(path);
- if ((tmpfd = rb_cloexec_open(StringValueCStr(path), 0, 0)) < 0) {
- rb_sys_fail_path(path);
- }
- rb_update_max_fd(tmpfd);
- if (chsize(tmpfd, pos) < 0) {
- int e = errno;
- close(tmpfd);
- rb_syserr_fail_path(e, path);
- }
- close(tmpfd);
- }
-#endif
+ r = (int)rb_thread_call_without_gvl(nogvl_truncate, &ta, RUBY_UBF_IO, NULL);
+ if (r < 0)
+ rb_sys_fail_path(path);
return INT2FIX(0);
#undef NUM2POS
}
@@ -4665,6 +4682,29 @@ rb_file_s_truncate(VALUE klass, VALUE path, VALUE len)
#endif
#if defined(HAVE_FTRUNCATE) || defined(HAVE_CHSIZE)
+struct ftruncate_arg {
+ int fd;
+#if defined(HAVE_FTRUNCATE)
+#define NUM2POS(n) NUM2OFFT(n)
+ off_t pos;
+#else
+#define NUM2POS(n) NUM2LONG(n)
+ long pos;
+#endif
+};
+
+static VALUE
+nogvl_ftruncate(void *ptr)
+{
+ struct ftruncate_arg *fa = ptr;
+
+#ifdef HAVE_FTRUNCATE
+ return (VALUE)ftruncate(fa->fd, fa->pos);
+#else /* defined(HAVE_CHSIZE) */
+ return (VALUE)chsize(fa->fd, fa->pos);
+#endif
+}
+
/*
* call-seq:
* file.truncate(integer) -> 0
@@ -4683,27 +4723,18 @@ static VALUE
rb_file_truncate(VALUE obj, VALUE len)
{
rb_io_t *fptr;
-#if defined(HAVE_FTRUNCATE)
-#define NUM2POS(n) NUM2OFFT(n)
- off_t pos;
-#else
-#define NUM2POS(n) NUM2LONG(n)
- long pos;
-#endif
+ struct ftruncate_arg fa;
- pos = NUM2POS(len);
+ fa.pos = NUM2POS(len);
GetOpenFile(obj, fptr);
if (!(fptr->mode & FMODE_WRITABLE)) {
rb_raise(rb_eIOError, "not opened for writing");
}
rb_io_flush_raw(obj, 0);
-#ifdef HAVE_FTRUNCATE
- if (ftruncate(fptr->fd, pos) < 0)
+ fa.fd = fptr->fd;
+ if ((int)rb_thread_io_blocking_region(nogvl_ftruncate, &fa, fa.fd) < 0) {
rb_sys_fail_path(fptr->pathv);
-#else /* defined(HAVE_CHSIZE) */
- if (chsize(fptr->fd, pos) < 0)
- rb_sys_fail_path(fptr->pathv);
-#endif
+ }
return INT2FIX(0);
#undef NUM2POS
}