diff options
author | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-11-19 05:03:17 +0000 |
---|---|---|
committer | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-11-19 05:03:17 +0000 |
commit | 6b58fd54d819d6356bc51bba82baf9565fd11854 (patch) | |
tree | 3b4a4be25aef0a0dadcd628012c1e985fa050a5c | |
parent | 935d29f73cc9abed70ef2dbc2ca423e032c2199f (diff) | |
download | ruby-6b58fd54d819d6356bc51bba82baf9565fd11854.tar.gz |
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
-rw-r--r-- | file.c | 29 |
1 files changed, 28 insertions, 1 deletions
@@ -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 |