Feature #13958 ยป 0001-Dir.empty-releases-GVL.patch
dir.c | ||
---|---|---|
#include "internal.h"
|
||
#include "encindex.h"
|
||
#include "ruby/thread.h"
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
... | ... | |
#else
|
||
# define READDIR(dir, enc) readdir((dir))
|
||
#endif
|
||
/* safe to use without GVL */
|
||
static int
|
||
to_be_skipped(const struct dirent *dp)
|
||
{
|
||
... | ... | |
return rb_file_directory_p(obj, fname);
|
||
}
|
||
static void *
|
||
rb_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;
|
||
DIR *dir = opendir(path);
|
||
struct dirent *dp;
|
||
VALUE result = Qtrue;
|
||
if (!dir) {
|
||
int e = errno;
|
||
switch ((VALUE)rb_thread_call_with_gvl(rb_gc_for_fd_with_gvl, &e)) {
|
||
default:
|
||
dir = opendir(path);
|
||
if (dir) break;
|
||
e = errno;
|
||
/* fall through */
|
||
case 0:
|
||
if (e == ENOTDIR) return (void *)Qfalse;
|
||
errno = e; /* for rb_sys_fail_path */
|
||
return (void *)Qundef;
|
||
}
|
||
}
|
||
while ((dp = READDIR(dir, NULL)) != NULL) {
|
||
if (!to_be_skipped(dp)) {
|
||
result = Qfalse;
|
||
break;
|
||
}
|
||
}
|
||
closedir(dir);
|
||
return (void *)result;
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* Dir.empty?(path_name) -> true or false
|
||
... | ... | |
static VALUE
|
||
rb_dir_s_empty_p(VALUE obj, VALUE dirname)
|
||
{
|
||
DIR *dir;
|
||
struct dirent *dp;
|
||
VALUE result = Qtrue, orig;
|
||
VALUE result, orig;
|
||
const char *path;
|
||
enum {false_on_notdir = 1};
|
||
... | ... | |
}
|
||
#endif
|
||
dir = opendir(path);
|
||
if (!dir) {
|
||
int e = errno;
|
||
switch (rb_gc_for_fd(e)) {
|
||
default:
|
||
dir = opendir(path);
|
||
if (dir) break;
|
||
e = errno;
|
||
/* fall through */
|
||
case 0:
|
||
if (false_on_notdir && e == ENOTDIR) return Qfalse;
|
||
rb_syserr_fail_path(e, orig);
|
||
}
|
||
}
|
||
errno = 0;
|
||
while ((dp = READDIR(dir, NULL)) != NULL) {
|
||
if (!to_be_skipped(dp)) {
|
||
result = Qfalse;
|
||
break;
|
||
}
|
||
result = (VALUE)rb_thread_call_without_gvl(nogvl_dir_empty_p, (void *)path,
|
||
RUBY_UBF_IO, 0);
|
||
if (result == Qundef) {
|
||
rb_sys_fail_path(orig);
|
||
}
|
||
closedir(dir);
|
||
return result;
|
||
}
|
||
-
|