File.readlink and rb_readlink releases GVL

The `readlink' can stall on slow filesystems like `open' and
`read' syscalls.  Release the GVL and let the rest of the VM
function while `readlink' runs.

* file.c (nogvl_readlink): new function
  (readlink_without_gvl): ditto
  (rb_readlink): use readlink_without_gvl

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60845 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
normal 2017-11-19 05:03:17 +00:00
parent 935d29f73c
commit 6b58fd54d8

29
file.c
View File

@ -2873,6 +2873,33 @@ rb_file_s_readlink(VALUE klass, VALUE path)
}
#ifndef _WIN32
struct readlink_arg {
const char *path;
char *buf;
size_t size;
};
static void *
nogvl_readlink(void *ptr)
{
struct readlink_arg *ra = ptr;
return (void *)(VALUE)readlink(ra->path, ra->buf, ra->size);
}
static ssize_t
readlink_without_gvl(VALUE path, VALUE buf, size_t size)
{
struct readlink_arg ra;
ra.path = RSTRING_PTR(path);
ra.buf = RSTRING_PTR(buf);
ra.size = size;
return (ssize_t)rb_thread_call_without_gvl(nogvl_readlink, &ra,
RUBY_UBF_IO, 0);
}
VALUE
rb_readlink(VALUE path, rb_encoding *enc)
{
@ -2883,7 +2910,7 @@ rb_readlink(VALUE path, rb_encoding *enc)
FilePathValue(path);
path = rb_str_encode_ospath(path);
v = rb_enc_str_new(0, size, enc);
while ((rv = readlink(RSTRING_PTR(path), RSTRING_PTR(v), size)) == size
while ((rv = readlink_without_gvl(path, v, size)) == size
#ifdef _AIX
|| (rv < 0 && errno == ERANGE) /* quirky behavior of GPFS */
#endif