dir: Dir.mkdir and Dir.rmdir release GVL

This avoids blocking the entire VM when operating on slow or
unreliable filesystems.  Instead, only the thread performing
the mkdir or rmdir operation is blocked and other threads
are free to proceed.

* dir.c (nogvl_mkdir): new function
  (nogvl_rmdir): ditto
  (dir_s_mkdir): release GVL
  (dir_s_rmdir): ditto

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60595 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
normal 2017-11-01 00:17:11 +00:00
Родитель e63dd598a7
Коммит f5f6232399
1 изменённых файлов: 34 добавлений и 5 удалений

39
dir.c
Просмотреть файл

@ -1199,6 +1199,19 @@ dir_s_chroot(VALUE dir, VALUE path)
#define dir_s_chroot rb_f_notimplement
#endif
struct mkdir_arg {
const char *path;
mode_t mode;
};
static void *
nogvl_mkdir(void *ptr)
{
struct mkdir_arg *m = ptr;
return (void *)(VALUE)mkdir(m->path, m->mode);
}
/*
* call-seq:
* Dir.mkdir( string [, integer] ) -> 0
@ -1217,23 +1230,34 @@ dir_s_chroot(VALUE dir, VALUE path)
static VALUE
dir_s_mkdir(int argc, VALUE *argv, VALUE obj)
{
struct mkdir_arg m;
VALUE path, vmode;
mode_t mode;
int r;
if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
mode = NUM2MODET(vmode);
m.mode = NUM2MODET(vmode);
}
else {
mode = 0777;
m.mode = 0777;
}
path = check_dirname(path);
if (mkdir(RSTRING_PTR(path), mode) == -1)
m.path = RSTRING_PTR(path);
r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_mkdir, &m, RUBY_UBF_IO, 0);
if (r < 0)
rb_sys_fail_path(path);
return INT2FIX(0);
}
static void *
nogvl_rmdir(void *ptr)
{
const char *path = ptr;
return (void *)(VALUE)rmdir(path);
}
/*
* call-seq:
* Dir.delete( string ) -> 0
@ -1246,8 +1270,13 @@ dir_s_mkdir(int argc, VALUE *argv, VALUE obj)
static VALUE
dir_s_rmdir(VALUE obj, VALUE dir)
{
const char *p;
int r;
dir = check_dirname(dir);
if (rmdir(RSTRING_PTR(dir)) < 0)
p = RSTRING_PTR(dir);
r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_rmdir, p, RUBY_UBF_IO, 0);
if (r < 0)
rb_sys_fail_path(dir);
return INT2FIX(0);