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

ruby-changes:48653

From: normal <ko1@a...>
Date: Wed, 15 Nov 2017 08:20:36 +0900 (JST)
Subject: [ruby-changes:48653] normal:r60769 (trunk): dir.c: release GVL around remaining readdir calls

normal	2017-11-15 08:20:31 +0900 (Wed, 15 Nov 2017)

  New Revision: 60769

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

  Log:
    dir.c: release GVL around remaining readdir calls
    
    Release GVL around all remaining readdir calls from the Dir
    class to prevent pathological stalls on slow filesystems in
    multi-threaded applications.
    
    opendir, rewinddir, closedir calls are not affected yet, but
    will be changed in future commits.
    
    In the future, further work may be done consolidate multiple GVL
    releasing calls to reduce overhead, similar to how changes to
    Dir.empty? were made in r60111
    
    * dir.c (nogvl_readdir): new function
      (readdir_without_gvl): ditto
      (dir_read): s/READDIR/readdir_without_gvl/
      (dir_each_entry): ditto
      (glob_helper): ditto

  Modified files:
    trunk/dir.c
Index: dir.c
===================================================================
--- dir.c	(revision 60768)
+++ dir.c	(revision 60769)
@@ -743,6 +743,20 @@ to_be_skipped(const struct dirent *dp) https://github.com/ruby/ruby/blob/trunk/dir.c#L743
     return FALSE;
 }
 
+static void *
+nogvl_readdir(void *ptr)
+{
+    struct dir_data *dirp = ptr;
+
+    return READDIR(dirp->dir, dirp->enc);
+}
+
+static struct dirent *
+readdir_without_gvl(struct dir_data *dirp)
+{
+    return rb_thread_call_without_gvl(nogvl_readdir, dirp, RUBY_UBF_IO, 0);
+}
+
 /*
  *  call-seq:
  *     dir.read -> string or nil
@@ -763,7 +777,7 @@ dir_read(VALUE dir) https://github.com/ruby/ruby/blob/trunk/dir.c#L777
 
     GetDIR(dir, dirp);
     errno = 0;
-    if ((dp = READDIR(dirp->dir, dirp->enc)) != NULL) {
+    if ((dp = readdir_without_gvl(dirp))) {
 	return rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc);
     }
     else {
@@ -818,7 +832,7 @@ dir_each_entry(VALUE dir, VALUE (*each)( https://github.com/ruby/ruby/blob/trunk/dir.c#L832
     GetDIR(dir, dirp);
     rewinddir(dirp->dir);
     IF_NORMALIZE_UTF8PATH(norm_p = need_normalization(dirp->dir, RSTRING_PTR(dirp->path)));
-    while ((dp = READDIR(dirp->dir, dirp->enc)) != NULL) {
+    while ((dp = readdir_without_gvl(dirp)) != NULL) {
 	const char *name = dp->d_name;
 	size_t namlen = NAMLEN(dp);
 	VALUE path;
@@ -2006,25 +2020,27 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/dir.c#L2020
     if (pathtype == path_noent) return 0;
 
     if (magical || recursive) {
+	struct dir_data dd;
 	struct dirent *dp;
-	DIR *dirp;
 # if USE_NAME_ON_FS == USE_NAME_ON_FS_BY_FNMATCH
 	char *plainname = 0;
 # endif
 	IF_NORMALIZE_UTF8PATH(int norm_p);
+
+	dd.enc = enc;
 # if USE_NAME_ON_FS == USE_NAME_ON_FS_BY_FNMATCH
 	if (cur + 1 == end && (*cur)->type <= ALPHA) {
 	    plainname = join_path(path, pathlen, dirsep, (*cur)->str, strlen((*cur)->str));
 	    if (!plainname) return -1;
-	    dirp = do_opendir(fd, plainname, flags, enc, funcs->error, arg, &status);
+	    dd.dir = do_opendir(fd, plainname, flags, enc, funcs->error, arg, &status);
 	    GLOB_FREE(plainname);
 	}
 	else
 # else
 	    ;
 # endif
-	dirp = do_opendir(fd, *base ? base : ".", flags, enc, funcs->error, arg, &status);
-	if (dirp == NULL) {
+	dd.dir = do_opendir(fd, *base ? base : ".", flags, enc, funcs->error, arg, &status);
+	if (dd.dir == NULL) {
 # if FNM_SYSCASE || NORMALIZE_UTF8PATH
 	    if ((magical < 2) && !recursive && (errno == EACCES)) {
 		/* no read permission, fallback */
@@ -2033,19 +2049,19 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/dir.c#L2049
 # endif
 	    return status;
 	}
-	IF_NORMALIZE_UTF8PATH(norm_p = need_normalization(dirp, *base ? base : "."));
+	IF_NORMALIZE_UTF8PATH(norm_p = need_normalization(dd.dir, *base ? base : "."));
 
 # if NORMALIZE_UTF8PATH
 	if (!(norm_p || magical || recursive)) {
-	    closedir(dirp);
+	    closedir(dd.dir);
 	    goto literally;
 	}
 # endif
 # ifdef HAVE_GETATTRLIST
-	if (is_case_sensitive(dirp, path) == 0)
+	if (is_case_sensitive(dd.dir, path) == 0)
 	    flags |= FNM_CASEFOLD;
 # endif
-	while ((dp = READDIR(dirp, enc)) != NULL) {
+	while ((dp = readdir_without_gvl(&dd)) != NULL) {
 	    char *buf;
 	    rb_pathtype_t new_pathtype = path_unknown;
 	    const char *name;
@@ -2140,7 +2156,7 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/dir.c#L2156
 	    if (status) break;
 	}
 
-	closedir(dirp);
+	closedir(dd.dir);
     }
     else if (plain) {
 	struct glob_pattern **copy_beg, **copy_end, **cur2;

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

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