[前][次][番号順一覧][スレッド一覧]

ruby-changes:48715

From: normal <ko1@a...>
Date: Sat, 18 Nov 2017 11:01:54 +0900 (JST)
Subject: [ruby-changes:48715] normal:r60831 (trunk): dir.c: openat calls release GVL, too

normal	2017-11-18 11:01:49 +0900 (Sat, 18 Nov 2017)

  New Revision: 60831

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=60831

  Log:
    dir.c: openat calls release GVL, too
    
    openat(2) also performs a path lookup, so it is also subject
    to pathological slowdowns like opendir(3) and open(2) syscalls.
    
    * dir.c (struct opendir_at_arg): new struct for callback
      (with_gvl_gc_for_fd): new callback for rb_thread_call_with_gvl
      (gc_for_fd_with_gvl): moved up
      (nogvl_opendir_at): extracted from do_opendir
      (opendir_at): new wrapper to release GVL for opendir_at
      (do_opendir): use new wrappers to release GVL
      (nogvl_dir_empty_p): adjust for gc_for_fd_with_gvl

  Modified files:
    trunk/dir.c
Index: dir.c
===================================================================
--- dir.c	(revision 60830)
+++ dir.c	(revision 60831)
@@ -1404,18 +1404,80 @@ do_lstat(int fd, const char *path, struc https://github.com/ruby/ruby/blob/trunk/dir.c#L1404
 #define do_lstat do_stat
 #endif
 
-static DIR *
-do_opendir(const int basefd, const char *path, int flags, rb_encoding *enc,
-	   ruby_glob_errfunc *errfunc, VALUE arg, int *status)
+struct opendir_at_arg {
+    int basefd;
+    const char *path;
+};
+
+static void *
+with_gvl_gc_for_fd(void *ptr)
 {
+    int *e = ptr;
+
+    return (void *)(rb_gc_for_fd(*e) ? Qtrue : Qfalse);
+}
+
+static int
+gc_for_fd_with_gvl(int e)
+{
+    return (int)(VALUE)rb_thread_call_with_gvl(with_gvl_gc_for_fd, &e);
+}
+
+static void *
+nogvl_opendir_at(void *ptr)
+{
+    const struct opendir_at_arg *oaa = ptr;
+    DIR *dirp;
+
 #if USE_OPENDIR_AT
     const int opendir_flags = (O_RDONLY|O_CLOEXEC|
-#ifdef O_DIRECTORY
+#  ifdef O_DIRECTORY
 			       O_DIRECTORY|
-#endif
+#  endif /* O_DIRECTORY */
 			       0);
-    int fd;
-#endif
+    int fd = openat(oaa->basefd, oaa->path, 0, opendir_flags);
+
+    dirp = fd >= 0 ? fdopendir(fd) : 0;
+    if (!dirp) {
+	int e = errno;
+
+	switch (gc_for_fd_with_gvl(e)) {
+	  default:
+	    if (fd < 0) fd = openat(oaa->basefd, oaa->path, 0, opendir_flags);
+	    if (fd >= 0) dirp = fdopendir(fd);
+	    if (dirp) return dirp;
+
+	    e = errno;
+	    /* fallthrough*/
+	  case 0:
+	    if (fd >= 0) close(fd);
+	    errno = e;
+	}
+    }
+#else  /* !USE_OPENDIR_AT */
+    dirp = opendir(oaa->path);
+    if (!dirp && gc_for_fd_with_gvl(errno))
+	dirp = opendir(oaa->path);
+#endif /* !USE_OPENDIR_AT */
+
+    return dirp;
+}
+
+static DIR *
+opendir_at(int basefd, const char *path)
+{
+    struct opendir_at_arg oaa;
+
+    oaa.basefd = basefd;
+    oaa.path = path;
+
+    return rb_thread_call_without_gvl(nogvl_opendir_at, &oaa, RUBY_UBF_IO, 0);
+}
+
+static DIR *
+do_opendir(const int basefd, const char *path, int flags, rb_encoding *enc,
+	   ruby_glob_errfunc *errfunc, VALUE arg, int *status)
+{
     DIR *dirp;
 #ifdef _WIN32
     VALUE tmp = 0;
@@ -1425,37 +1487,18 @@ do_opendir(const int basefd, const char https://github.com/ruby/ruby/blob/trunk/dir.c#L1487
 	path = RSTRING_PTR(tmp);
     }
 #endif
-#if USE_OPENDIR_AT
-    fd = openat(basefd, path, 0, opendir_flags);
-    dirp = (fd < 0) ? NULL : fdopendir(fd);
-#else
-    dirp = opendir_without_gvl(path);
-#endif
+    dirp = opendir_at(basefd, path);
     if (!dirp) {
 	int e = errno;
-	switch (rb_gc_for_fd(e)) {
-	  default:
-#if USE_OPENDIR_AT
-	    if ((fd >= 0) || (fd = openat(basefd, path, 0, opendir_flags)) >= 0) {
-		dirp = fdopendir(fd);
-	    }
-#else
-	    dirp = opendir_without_gvl(path);
-#endif
-	    if (dirp) break;
-	    e = errno;
-	    /* fallback */
-	  case 0:
-#if USE_OPENDIR_AT
-	    if (fd >= 0) close(fd);
-#endif
-	    *status = 0;
-	    if (to_be_ignored(e)) break;
+
+	*status = 0;
+	if (!to_be_ignored(e)) {
 	    if (errfunc) {
 		*status = (*errfunc)(path, arg, enc, e);
-		break;
 	    }
-	    sys_warning(path, enc);
+	    else {
+		sys_warning(path, enc);
+	    }
 	}
     }
 #ifdef _WIN32
@@ -3041,14 +3084,6 @@ rb_dir_exists_p(VALUE obj, VALUE fname) https://github.com/ruby/ruby/blob/trunk/dir.c#L3084
 }
 
 static void *
-gc_for_fd_with_gvl(void *ptr)
-{
-    int *e = ptr;
-
-    return (void *)(rb_gc_for_fd(*e) ? Qtrue : Qfalse);
-}
-
-static void *
 nogvl_dir_empty_p(void *ptr)
 {
     const char *path = ptr;
@@ -3058,7 +3093,7 @@ nogvl_dir_empty_p(void *ptr) https://github.com/ruby/ruby/blob/trunk/dir.c#L3093
 
     if (!dir) {
 	int e = errno;
-	switch ((int)(VALUE)rb_thread_call_with_gvl(gc_for_fd_with_gvl, &e)) {
+	switch (gc_for_fd_with_gvl(e)) {
 	  default:
 	    dir = opendir(path);
 	    if (dir) break;

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]