[Feature #20244] Extract chdir_lock
and its stuffs
This commit is contained in:
parent
1ad366134d
commit
8fe86feecd
74
dir.c
74
dir.c
@ -1041,8 +1041,44 @@ dir_chdir0(VALUE path)
|
|||||||
rb_sys_fail_path(path);
|
rb_sys_fail_path(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int chdir_blocking = 0;
|
static struct {
|
||||||
static VALUE chdir_thread = Qnil;
|
VALUE thread;
|
||||||
|
int blocking;
|
||||||
|
} chdir_lock = {
|
||||||
|
.blocking = 0, .thread = Qnil,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
chdir_enter(void)
|
||||||
|
{
|
||||||
|
chdir_lock.blocking++;
|
||||||
|
if (NIL_P(chdir_lock.thread)) {
|
||||||
|
chdir_lock.thread = rb_thread_current();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
chdir_leave(void)
|
||||||
|
{
|
||||||
|
chdir_lock.blocking--;
|
||||||
|
if (chdir_lock.blocking == 0) {
|
||||||
|
chdir_lock.thread = Qnil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
chdir_alone_block_p(void)
|
||||||
|
{
|
||||||
|
int block_given = rb_block_given_p();
|
||||||
|
if (chdir_lock.blocking > 0) {
|
||||||
|
if (rb_thread_current() != chdir_lock.thread)
|
||||||
|
rb_raise(rb_eRuntimeError, "conflicting chdir during another chdir block");
|
||||||
|
if (!block_given) {
|
||||||
|
rb_warn("conflicting chdir during another chdir block");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return block_given;
|
||||||
|
}
|
||||||
|
|
||||||
struct chdir_data {
|
struct chdir_data {
|
||||||
VALUE old_path, new_path;
|
VALUE old_path, new_path;
|
||||||
@ -1056,9 +1092,7 @@ chdir_yield(VALUE v)
|
|||||||
struct chdir_data *args = (void *)v;
|
struct chdir_data *args = (void *)v;
|
||||||
dir_chdir0(args->new_path);
|
dir_chdir0(args->new_path);
|
||||||
args->done = TRUE;
|
args->done = TRUE;
|
||||||
chdir_blocking++;
|
chdir_enter();
|
||||||
if (NIL_P(chdir_thread))
|
|
||||||
chdir_thread = rb_thread_current();
|
|
||||||
return args->yield_path ? rb_yield(args->new_path) : rb_yield_values2(0, NULL);
|
return args->yield_path ? rb_yield(args->new_path) : rb_yield_values2(0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1067,9 +1101,7 @@ chdir_restore(VALUE v)
|
|||||||
{
|
{
|
||||||
struct chdir_data *args = (void *)v;
|
struct chdir_data *args = (void *)v;
|
||||||
if (args->done) {
|
if (args->done) {
|
||||||
chdir_blocking--;
|
chdir_leave();
|
||||||
if (chdir_blocking == 0)
|
|
||||||
chdir_thread = Qnil;
|
|
||||||
dir_chdir0(args->old_path);
|
dir_chdir0(args->old_path);
|
||||||
}
|
}
|
||||||
return Qnil;
|
return Qnil;
|
||||||
@ -1078,14 +1110,7 @@ chdir_restore(VALUE v)
|
|||||||
static VALUE
|
static VALUE
|
||||||
chdir_path(VALUE path, bool yield_path)
|
chdir_path(VALUE path, bool yield_path)
|
||||||
{
|
{
|
||||||
if (chdir_blocking > 0) {
|
if (chdir_alone_block_p()) {
|
||||||
if (rb_thread_current() != chdir_thread)
|
|
||||||
rb_raise(rb_eRuntimeError, "conflicting chdir during another chdir block");
|
|
||||||
if (!rb_block_given_p())
|
|
||||||
rb_warn("conflicting chdir during another chdir block");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rb_block_given_p()) {
|
|
||||||
struct chdir_data args;
|
struct chdir_data args;
|
||||||
|
|
||||||
args.old_path = rb_str_encode_ospath(rb_dir_getwd());
|
args.old_path = rb_str_encode_ospath(rb_dir_getwd());
|
||||||
@ -1215,9 +1240,7 @@ fchdir_yield(VALUE v)
|
|||||||
struct fchdir_data *args = (void *)v;
|
struct fchdir_data *args = (void *)v;
|
||||||
dir_fchdir(args->fd);
|
dir_fchdir(args->fd);
|
||||||
args->done = TRUE;
|
args->done = TRUE;
|
||||||
chdir_blocking++;
|
chdir_enter();
|
||||||
if (NIL_P(chdir_thread))
|
|
||||||
chdir_thread = rb_thread_current();
|
|
||||||
return rb_yield_values(0);
|
return rb_yield_values(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1226,9 +1249,7 @@ fchdir_restore(VALUE v)
|
|||||||
{
|
{
|
||||||
struct fchdir_data *args = (void *)v;
|
struct fchdir_data *args = (void *)v;
|
||||||
if (args->done) {
|
if (args->done) {
|
||||||
chdir_blocking--;
|
chdir_leave();
|
||||||
if (chdir_blocking == 0)
|
|
||||||
chdir_thread = Qnil;
|
|
||||||
dir_fchdir(RB_NUM2INT(dir_fileno(args->old_dir)));
|
dir_fchdir(RB_NUM2INT(dir_fileno(args->old_dir)));
|
||||||
}
|
}
|
||||||
dir_close(args->old_dir);
|
dir_close(args->old_dir);
|
||||||
@ -1292,14 +1313,7 @@ dir_s_fchdir(VALUE klass, VALUE fd_value)
|
|||||||
{
|
{
|
||||||
int fd = RB_NUM2INT(fd_value);
|
int fd = RB_NUM2INT(fd_value);
|
||||||
|
|
||||||
if (chdir_blocking > 0) {
|
if (chdir_alone_block_p()) {
|
||||||
if (rb_thread_current() != chdir_thread)
|
|
||||||
rb_raise(rb_eRuntimeError, "conflicting chdir during another chdir block");
|
|
||||||
if (!rb_block_given_p())
|
|
||||||
rb_warn("conflicting chdir during another chdir block");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rb_block_given_p()) {
|
|
||||||
struct fchdir_data args;
|
struct fchdir_data args;
|
||||||
args.old_dir = dir_s_alloc(klass);
|
args.old_dir = dir_s_alloc(klass);
|
||||||
dir_initialize(NULL, args.old_dir, rb_fstring_cstr("."), Qnil);
|
dir_initialize(NULL, args.old_dir, rb_fstring_cstr("."), Qnil);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user