summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dir.c28
1 files changed, 23 insertions, 5 deletions
diff --git a/dir.c b/dir.c
index baeaa4db7e..e044228a5b 100644
--- a/dir.c
+++ b/dir.c
@@ -490,6 +490,24 @@ dir_s_alloc(VALUE klass)
return obj;
}
+static void *
+nogvl_opendir(void *ptr)
+{
+ const char *path = ptr;
+
+ return (void *)opendir(path);
+}
+
+static DIR *
+opendir_without_gvl(const char *path)
+{
+ union { const char *in; void *out; } u;
+
+ u.in = path;
+
+ return rb_thread_call_without_gvl(nogvl_opendir, u.out, RUBY_UBF_IO, 0);
+}
+
/*
* call-seq:
* Dir.new( string ) -> aDir
@@ -536,18 +554,18 @@ dir_initialize(int argc, VALUE *argv, VALUE dir)
RB_OBJ_WRITE(dir, &dp->path, Qnil);
dp->enc = fsenc;
path = RSTRING_PTR(dirname);
- dp->dir = opendir(path);
+ dp->dir = opendir_without_gvl(path);
if (dp->dir == NULL) {
int e = errno;
if (rb_gc_for_fd(e)) {
- dp->dir = opendir(path);
+ dp->dir = opendir_without_gvl(path);
}
#ifdef HAVE_GETATTRLIST
else if (e == EIO) {
u_int32_t attrbuf[1];
struct attrlist al = {ATTR_BIT_MAP_COUNT, 0};
if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW) == 0) {
- dp->dir = opendir(path);
+ dp->dir = opendir_without_gvl(path);
}
}
#endif
@@ -1411,7 +1429,7 @@ do_opendir(const int basefd, const char *path, int flags, rb_encoding *enc,
fd = openat(basefd, path, 0, opendir_flags);
dirp = (fd < 0) ? NULL : fdopendir(fd);
#else
- dirp = opendir(path);
+ dirp = opendir_without_gvl(path);
#endif
if (!dirp) {
int e = errno;
@@ -1422,7 +1440,7 @@ do_opendir(const int basefd, const char *path, int flags, rb_encoding *enc,
dirp = fdopendir(fd);
}
#else
- dirp = opendir(path);
+ dirp = opendir_without_gvl(path);
#endif
if (dirp) break;
e = errno;