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

ruby-changes:6505

From: nobu <ko1@a...>
Date: Fri, 11 Jul 2008 06:48:40 +0900 (JST)
Subject: [ruby-changes:6505] Ruby:r18021 (mvm): * vm_core.h (rb_thread_t): per-thread cwd support. [EXPERIMENTAL]

nobu	2008-07-11 06:45:17 +0900 (Fri, 11 Jul 2008)

  New Revision: 18021

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=18021

  Log:
    * vm_core.h (rb_thread_t): per-thread cwd support.  [EXPERIMENTAL]
    
    * io.c (rb_sysopen), dir.c (dir_s_chdir),
      file.c (ruby_readlink, ruby_absolute_path_p),
      thread.c (thread_create_core, ruby_thread_getcwd, ruby_getcwd),
      vm.c (Init_VM): ditto.
    
    * string.c (rb_str_wrap): wrap a heap pointer with string.
    
    * thread.c (ruby_system_alone): returns if only current VM is running.

  Modified files:
    branches/mvm/ChangeLog
    branches/mvm/common.mk
    branches/mvm/dir.c
    branches/mvm/file.c
    branches/mvm/include/ruby/intern.h
    branches/mvm/include/ruby/mvm.h
    branches/mvm/io.c
    branches/mvm/string.c
    branches/mvm/thread.c
    branches/mvm/util.c
    branches/mvm/vm.c
    branches/mvm/vm_core.h

Index: mvm/include/ruby/mvm.h
===================================================================
--- mvm/include/ruby/mvm.h	(revision 18020)
+++ mvm/include/ruby/mvm.h	(revision 18021)
@@ -39,4 +39,6 @@
 VALUE *ruby_vm_specific_ptr(rb_vm_t *, int);
 VALUE *rb_vm_specific_ptr(int);
 
+char *ruby_thread_getcwd(rb_thread_t *);
+
 #endif /* RUBY_MVM_H */
Index: mvm/include/ruby/intern.h
===================================================================
--- mvm/include/ruby/intern.h	(revision 18020)
+++ mvm/include/ruby/intern.h	(revision 18021)
@@ -292,6 +292,7 @@
 int rb_thread_fd_writable(int);
 void rb_thread_fd_close(int);
 int rb_thread_alone(void);
+int ruby_system_alone(void);
 void rb_thread_polling(void);
 void rb_thread_sleep(int);
 void rb_thread_sleep_forever(void);
@@ -523,6 +524,7 @@
 VALUE rb_vsprintf(const char*, va_list);
 VALUE rb_str_format(int, const VALUE *, VALUE);
 /* string.c */
+VALUE rb_str_wrap(char*, long);
 VALUE rb_str_new(const char*, long);
 VALUE rb_str_new2(const char*);
 VALUE rb_str_new3(VALUE);
@@ -625,6 +627,7 @@
 VALUE rb_barrier_new(void);
 VALUE rb_barrier_wait(VALUE self);
 VALUE rb_barrier_release(VALUE self);
+char *rb_thread_cwd(void);
 /* time.c */
 VALUE rb_time_new(time_t, long);
 VALUE rb_time_nano_new(time_t, long);
Index: mvm/ChangeLog
===================================================================
--- mvm/ChangeLog	(revision 18020)
+++ mvm/ChangeLog	(revision 18021)
@@ -1,3 +1,16 @@
+Fri Jul 11 06:45:14 2008  Nobuyoshi Nakada  <nobu@r...>
+
+	* vm_core.h (rb_thread_t): per-thread cwd support.  [EXPERIMENTAL]
+
+	* io.c (rb_sysopen), dir.c (dir_s_chdir),
+	  file.c (ruby_readlink, ruby_absolute_path_p),
+	  thread.c (thread_create_core, ruby_thread_getcwd, ruby_getcwd),
+	  vm.c (Init_VM): ditto.
+
+	* string.c (rb_str_wrap): wrap a heap pointer with string.
+
+	* thread.c (ruby_system_alone): returns if only current VM is running.
+
 Fri Jul 11 06:44:06 2008  Nobuyoshi Nakada  <nobu@r...>
 
 	* dir.c (fcntl.h): needed for AT_FDCWD.
Index: mvm/vm_core.h
===================================================================
--- mvm/vm_core.h	(revision 18020)
+++ mvm/vm_core.h	(revision 18021)
@@ -405,6 +405,14 @@
 
 #define RUBY_VM_VALUE_CACHE_SIZE 0x1000
 #define USE_VALUE_CACHE 0
+#if defined HAVE_DIRFD && defined HAVE_OPENAT
+#define USE_OPENAT 1
+#else
+#define USE_OPENAT 0
+#endif
+#if USE_OPENAT
+#include <fcntl.h>
+#endif
 
 struct rb_unblock_callback {
     rb_unblock_function_t *func;
@@ -474,6 +482,13 @@
     VALUE *value_cache_ptr;
 #endif
 
+    struct {
+#if USE_OPENAT
+	int fd;
+#endif
+	char *path;
+    } cwd;
+
     struct rb_thread_struct *join_list_next;
     struct rb_thread_struct *join_list_head;
 
Index: mvm/string.c
===================================================================
--- mvm/string.c	(revision 18020)
+++ mvm/string.c	(revision 18021)
@@ -374,6 +374,27 @@
 }
 
 VALUE
+rb_str_wrap(char *ptr, long len)
+{
+    VALUE str;
+
+    if (!ptr) {
+	rb_raise(rb_eArgError, "NULL pointer given");
+    }
+    if (len < 0) {
+	rb_raise(rb_eArgError, "negative string size (or size too big)");
+    }
+
+    str = str_alloc(rb_cString);
+    RSTRING(str)->as.heap.aux.capa = len;
+    RSTRING(str)->as.heap.ptr = ptr;
+    STR_SET_NOEMBED(str);
+    STR_SET_LEN(str, len);
+    RSTRING_PTR(str)[len] = '\0';
+    return str;
+}
+
+VALUE
 rb_str_new(const char *ptr, long len)
 {
     return str_new(rb_cString, ptr, len);
Index: mvm/io.c
===================================================================
--- mvm/io.c	(revision 18020)
+++ mvm/io.c	(revision 18021)
@@ -3395,7 +3395,12 @@
 }
 
 struct sysopen_struct {
-    char *fname;
+#if USE_OPENAT
+    int base;
+#else
+    VALUE fullpath;
+#endif
+    const char *fname;
     int flag;
     unsigned int mode;
 };
@@ -3404,29 +3409,50 @@
 sysopen_func(void *ptr)
 {
     struct sysopen_struct *data = ptr;
+#if USE_OPENAT
+    return (VALUE)openat(data->base, data->fname, data->flag, data->mode);
+#else
     return (VALUE)open(data->fname, data->flag, data->mode);
+#endif
 }
 
+static void
+rb_sysopen_prepare(struct sysopen_struct *data, const char *fname, int flags, unsigned int mode)
+{
+#if USE_OPENAT
+    data->base = GET_THREAD()->cwd.fd;
+#else
+    if (ruby_absolute_path_p(fname)) {
+	data->base = Qnil;
+    }
+    else {
+	data->base = rb_file_expand_path(rb_str_new2(fname), Qnil);
+	fname = RSTRING_PTR(data->base);
+    }
+#endif
+    data->fname = fname;
+    data->flag = flags;
+    data->mode = mode;
+}
+
 static int
-rb_sysopen_internal(char *fname, int flags, unsigned int mode)
+rb_sysopen_internal(struct sysopen_struct *data)
 {
-    struct sysopen_struct data;
-    data.fname = fname;
-    data.flag = flags;
-    data.mode = mode;
-    return (int)rb_thread_blocking_region(sysopen_func, &data, RB_UBF_DFL, 0);
+    return (int)rb_thread_blocking_region(sysopen_func, data, RB_UBF_DFL, 0);
 }
 
 static int
 rb_sysopen(char *fname, int flags, unsigned int mode)
 {
     int fd;
+    struct sysopen_struct data;
 
-    fd = rb_sysopen_internal(fname, flags, mode);
+    rb_sysopen_prepare(&data, fname, flags, mode); 
+    fd = rb_sysopen_internal(&data);
     if (fd < 0) {
 	if (errno == EMFILE || errno == ENFILE) {
 	    rb_gc();
-	    fd = rb_sysopen_internal(fname, flags, mode);
+	    fd = rb_sysopen_internal(&data);
 	}
 	if (fd < 0) {
 	    rb_sys_fail(fname);
Index: mvm/thread.c
===================================================================
--- mvm/thread.c	(revision 18020)
+++ mvm/thread.c	(revision 18021)
@@ -310,6 +310,12 @@
     --system_working;
 }
 
+int
+ruby_system_alone(void)
+{
+    return system_working <= 1;
+}
+
 static void
 thread_cleanup_func_before_exec(void *th_ptr)
 {
@@ -455,6 +461,10 @@
     native_mutex_initialize(&th->interrupt_lock);
     /* kick thread */
     st_insert(th->vm->living_threads, thval, (st_data_t) th->thread_id);
+#if USE_OPENAT
+    th->cwd.fd = openat(GET_THREAD()->cwd.fd, ".", O_RDONLY);
+#endif
+    th->cwd.path = strdup(GET_THREAD()->cwd.path);
     native_thread_create(th);
     return thval;
 }
@@ -3420,6 +3430,28 @@
     return result;
 }
 
+char *
+ruby_thread_getcwd(rb_thread_t *th)
+{
+#if USE_OPENAT && defined HAVE_READLINK
+    extern char *ruby_readlink(const char *, long *);
+    static const char fdpat[] = "/proc/self/fd/%d";
+    char fdname[sizeof(fdpat) + sizeof(int) * 5 / 2], *cwd;
+    long len;
+
+    snprintf(fdname, sizeof(fdname), fdpat, th->cwd.fd);
+    cwd = ruby_readlink(fdname, &len);
+    if (cwd) return cwd;
+#endif
+    return ruby_strdup(th->cwd.path);
+}
+
+char *
+ruby_getcwd(void)
+{
+    return ruby_thread_getcwd(GET_THREAD());
+}
+
 /*
  *  +Thread+ encapsulates the behavior of a thread of
  *  execution, including the main thread of the Ruby script.
Index: mvm/common.mk
===================================================================
--- mvm/common.mk	(revision 18020)
+++ mvm/common.mk	(revision 18021)
@@ -446,7 +446,7 @@
 complex.$(OBJEXT): {$(VPATH)}complex.c $(RUBY_H_INCLUDES) \
   {$(VPATH)}st.h
 dir.$(OBJEXT): {$(VPATH)}dir.c $(RUBY_H_INCLUDES) \
-  {$(VPATH)}st.h {$(VPATH)}util.h
+  {$(VPATH)}st.h {$(VPATH)}util.h $(VM_CORE_H_INCLUDES)
 dln.$(OBJEXT): {$(VPATH)}dln.c $(RUBY_H_INCLUDES) \
   {$(VPATH)}st.h {$(VPATH)}dln.h
 dmydln.$(OBJEXT): {$(VPATH)}dmydln.c dln.$(OBJEXT)
Index: mvm/dir.c
===================================================================
--- mvm/dir.c	(revision 18020)
+++ mvm/dir.c	(revision 18021)
@@ -13,6 +13,7 @@
 
 #include "ruby/ruby.h"
 #include "ruby/encoding.h"
+#include "vm_core.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -701,18 +702,46 @@
 static void
 dir_chdir(VALUE path)
 {
-    if (chdir(RSTRING_PTR(path)) < 0)
+    rb_thread_t *th = GET_THREAD();
+#if USE_OPENAT
+    int dir = openat(th->cwd.fd, RSTRING_PTR(path), O_RDONLY);
+    if (dir < 0)
 	rb_sys_fail(RSTRING_PTR(path));
+    if (ruby_system_alone() && rb_thread_alone()) {
+	if (fchdir(dir) < 0) {
+	    rb_sys_fail(RSTRING_PTR(path));
+	}
+    }
+    close(th->cwd.fd);
+    th->cwd.fd = dir;
+#else
+    VALUE fullpath;
+    struct stat st;
+    const char *dir;
+    char *olddir = th->cwd.path;
+
+    RB_GC_GUARD(fullpath) = rb_file_expand_path(path, Qnil);
+    dir = RSTRING_PTR(fullpath);
+    if (eaccess(dir, X_OK) != 0 || stat(dir, &st) != 0 ||
+	(!S_ISDIR(st.st_mode) && (errno = ENOTDIR))) {
+	rb_sys_fail(RSTRING_PTR(path));
+    }
+    if (ruby_system_alone() && rb_thread_alone()) {
+	if (chdir(dir) < 0) {
+	    rb_sys_fail(RSTRING_PTR(path));
+	}
+    }
+    th->cwd.path = ruby_strdup(dir);
+    xfree(olddir);
+#endif
 }
 
-static int chdir_blocking = 0;
-static VALUE chdir_thread = Qnil;
-
 struct chdir_data {
-    VALUE old_path, new_path;
-#if defined HAVE_DIRFD && defined HAVE_FCHDIR
-    DIR *old_dir;
+    VALUE new_path;
+#if USE_OPENAT
+    int old_dir;
 #endif
+    VALUE old_path;
     int done;
 };
 
@@ -721,9 +750,6 @@
 {
     dir_chdir(args->new_path);
     args->done = Qtrue;
-    chdir_blocking++;
-    if (chdir_thread == Qnil)
-	chdir_thread = rb_thread_current();
     return rb_yield(args->new_path);
 }
 
@@ -731,15 +757,12 @@
 chdir_restore(struct chdir_data *args)
 {
     if (args->done) {
-	chdir_blocking--;
-	if (chdir_blocking == 0)
-	    chdir_thread = Qnil;
 #if defined HAVE_DIRFD && defined HAVE_FCHDIR
-	if (fchdir(dirfd(args->old_dir)) < 0) {
-	    closedir(args->old_dir);
+	if (fchdir(args->old_dir) < 0) {
+	    close(args->old_dir);
 	    rb_sys_fail(RSTRING_PTR(args->old_path));
 	}
-	closedir(args->old_dir);
+	close(args->old_dir);
 #else
 	dir_chdir(args->old_path);
 #endif
@@ -747,26 +770,15 @@
     return Qnil;
 }
 
-static void
-dir_chdir_check(void)
-{
-    if (chdir_blocking > 0) {
-	if (!rb_block_given_p() || rb_thread_current() != chdir_thread)
-	    rb_warn("conflicting chdir during another chdir block");
-    }
-}
-
 static VALUE
 dir_chdir_block(VALUE path)
 {
     struct chdir_data args;
-    char *cwd = my_getcwd();
-
-    args.old_path = rb_tainted_str_new2(cwd); xfree(cwd);
+#if USE_OPENAT
+    args.old_dir = openat(GET_THREAD()->cwd.fd, ".", O_RDONLY);
+#endif
+    args.old_path = rb_tainted_str_new2(GET_THREAD()->cwd.path);
     args.new_path = path;
-#if defined HAVE_DIRFD && defined HAVE_FCHDIR
-    args.old_dir = opendir(".");
-#endif
     args.done = Qfalse;
     return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
 }
@@ -828,7 +840,6 @@
 	path = rb_str_new2(dist);
     }
 
-    dir_chdir_check();
     if (rb_block_given_p()) {
 	return dir_chdir_block(path);
     }
@@ -1935,11 +1946,6 @@
 }
 
 VALUE rb_openat(int argc, VALUE *argv, int base, const char *path);
-#if defined HAVE_DIRFD && defined HAVE_OPENAT && defined AT_FDCWD
-#define USE_OPENAT 1
-#else
-#define USE_OPENAT 0
-#endif
 
 /*
  *  call-seq:
Index: mvm/util.c
===================================================================
--- mvm/util.c	(revision 18020)
+++ mvm/util.c	(revision 18021)
@@ -739,35 +739,6 @@
     return tmp;
 }
 
-char *
-ruby_getcwd(void)
-{
-#ifdef HAVE_GETCWD
-    int size = 200;
-    char *buf = xmalloc(size);
-
-    while (!getcwd(buf, size)) {
-	if (errno != ERANGE) {
-	    xfree(buf);
-	    rb_sys_fail("getcwd");
-	}
-	size *= 2;
-	buf = xrealloc(buf, size);
-    }
-#else
-# ifndef PATH_MAX
-#  define PATH_MAX 8192
-# endif
-    char *buf = xmalloc(PATH_MAX+1);
-
-    if (!getwd(buf)) {
-	xfree(buf);
-	rb_sys_fail("getwd");
-    }
-#endif
-    return buf;
-}
-
 /****************************************************************
  *
  * The author of this software is David M. Gay.
Index: mvm/vm.c
===================================================================
--- mvm/vm.c	(revision 18020)
+++ mvm/vm.c	(revision 18021)
@@ -1829,6 +1829,10 @@
 	th->cfp->iseq = iseq;
 	th->cfp->pc = iseq->iseq_encoded;
 	vm_init_redefined_flag(vm);
+#if USE_OPENAT
+	th->cwd.fd = openat(AT_FDCWD, ".", O_RDONLY);
+#endif
+	th->cwd.path = ruby_getcwd();
     }
 }
 
Index: mvm/file.c
===================================================================
--- mvm/file.c	(revision 18020)
+++ mvm/file.c	(revision 18021)
@@ -2256,6 +2256,41 @@
 #endif
 }
 
+#ifdef HAVE_READLINK
+char *
+ruby_readlink(const char *path, long *len)
+{
+    char *buf, *tmp;
+    int size = 100;
+    int rv;
+ 
+    buf = malloc(size);
+    if (!buf) return 0;
+    while ((rv = readlink(path, buf, size)) == size
+#ifdef _AIX
+	    || (rv < 0 && errno == ERANGE) /* quirky behavior of GPFS */
+#endif
+	) {
+	size *= 2;
+	tmp = realloc(buf, size);
+	if (!tmp) {
+	    free(buf);
+	    return 0;
+	}
+    }
+    if (rv < 0) {
+	free(buf);
+	return 0;
+    }
+    buf[rv] = '\0';
+    if (size > rv + 1) {
+	buf = realloc(buf, rv + 1);
+    }
+    *len = rv;
+    return buf;
+}
+#endif
+
 /*
  *  call-seq:
  *     File.readlink(link_name) -> file_name
@@ -2272,29 +2307,15 @@
 {
 #ifdef HAVE_READLINK
     char *buf;
-    int size = 100;
-    int rv;
-    VALUE v;
+    long rv;
 
     rb_secure(2);
     FilePathValue(path);
-    buf = xmalloc(size);
-    while ((rv = readlink(RSTRING_PTR(path), buf, size)) == size
-#ifdef _AIX
-	    || (rv < 0 && errno == ERANGE) /* quirky behavior of GPFS */
-#endif
-	) {
-	size *= 2;
-	buf = xrealloc(buf, size);
-    }
-    if (rv < 0) {
-	xfree(buf);
+    buf = ruby_readlink(RSTRING_PTR(path), &rv);
+    if (!buf) {
 	rb_sys_fail(RSTRING_PTR(path));
     }
-    v = rb_tainted_str_new(buf, rv);
-    xfree(buf);
-
-    return v;
+    return rb_str_wrap(buf, rv);
 #else
     rb_notimplement();
     return Qnil;		/* not reached */
@@ -2608,7 +2629,8 @@
     (void)(extenc || (extenc = rb_default_external_encoding())),\
     rb_enc_associate(result, extenc))
 
-static int is_absolute_path(const char*);
+#define is_absolute_path(path) ruby_absolute_path_p(path)
+int ruby_absolute_path_p(const char*);
 
 static VALUE
 file_expand_path(VALUE fname, VALUE dname, VALUE result)
@@ -4347,8 +4369,8 @@
     rb_define_const(rb_mFConst, name, value);
 }
 
-static int
-is_absolute_path(const char *path)
+int
+ruby_absolute_path_p(const char *path)
 {
 #ifdef DOSISH_DRIVE_LETTER
     if (has_drive_letter(path) && isdirsep(path[2])) return 1;

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

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