mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60831 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
089eb0c5ce
commit
8840b033fb
1 changed files with 78 additions and 43 deletions
121
dir.c
121
dir.c
|
@ -1404,18 +1404,80 @@ do_lstat(int fd, const char *path, struct stat *pst, int flags, rb_encoding *enc
|
|||
#define do_lstat do_stat
|
||||
#endif
|
||||
|
||||
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
|
||||
O_DIRECTORY|
|
||||
# endif /* O_DIRECTORY */
|
||||
0);
|
||||
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)
|
||||
{
|
||||
#if USE_OPENDIR_AT
|
||||
const int opendir_flags = (O_RDONLY|O_CLOEXEC|
|
||||
#ifdef O_DIRECTORY
|
||||
O_DIRECTORY|
|
||||
#endif
|
||||
0);
|
||||
int fd;
|
||||
#endif
|
||||
DIR *dirp;
|
||||
#ifdef _WIN32
|
||||
VALUE tmp = 0;
|
||||
|
@ -1425,37 +1487,18 @@ do_opendir(const int basefd, const char *path, int flags, rb_encoding *enc,
|
|||
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
|
||||
|
@ -3040,14 +3083,6 @@ rb_dir_exists_p(VALUE obj, VALUE fname)
|
|||
return rb_file_directory_p(obj, fname);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -3058,7 +3093,7 @@ nogvl_dir_empty_p(void *ptr)
|
|||
|
||||
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;
|
||||
|
|
Loading…
Reference in a new issue