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

ruby-changes:70222

From: Rohit <ko1@a...>
Date: Wed, 15 Dec 2021 15:04:57 +0900 (JST)
Subject: [ruby-changes:70222] d3d156c21e (master): Add locks for ENV

https://git.ruby-lang.org/ruby.git/commit/?id=d3d156c21e

From d3d156c21ecf0a602d366209b3e2da665c3ec389 Mon Sep 17 00:00:00 2001
From: Rohit Menon <rohitmenon@v...>
Date: Thu, 1 Jul 2021 20:04:52 -0400
Subject: Add locks for ENV

---
 hash.c | 229 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 183 insertions(+), 46 deletions(-)

diff --git a/hash.c b/hash.c
index 270ddfb5225..e58d21587df 100644
--- a/hash.c
+++ b/hash.c
@@ -43,6 +43,7 @@ https://github.com/ruby/ruby/blob/trunk/hash.c#L43
 #include "ruby_assert.h"
 #include "symbol.h"
 #include "transient_heap.h"
+#include "ruby/thread_native.h"
 
 #ifndef HASH_DEBUG
 #define HASH_DEBUG 0
@@ -4808,6 +4809,17 @@ extern char **environ; https://github.com/ruby/ruby/blob/trunk/hash.c#L4809
 #define ENVNMATCH(s1, s2, n) (memcmp((s1), (s2), (n)) == 0)
 #endif
 
+rb_nativethread_lock_t env_lock;
+
+const char*
+getenv_with_lock(const char *name)
+{
+    rb_native_mutex_lock(&env_lock);
+    char *result = getenv(name);
+    rb_native_mutex_unlock(&env_lock);
+    return result;
+}
+
 static inline rb_encoding *
 env_encoding(void)
 {
@@ -4906,7 +4918,7 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/hash.c#L4918
 env_delete(VALUE name)
 {
     const char *nam = env_name(name);
-    const char *val = getenv(nam);
+    const char *val = getenv_with_lock(nam);
 
     reset_by_modified_env(nam);
 
@@ -4972,7 +4984,7 @@ rb_f_getenv(VALUE obj, VALUE name) https://github.com/ruby/ruby/blob/trunk/hash.c#L4984
     const char *nam, *env;
 
     nam = env_name(name);
-    env = getenv(nam);
+    env = getenv_with_lock(nam);
     if (env) {
 	return env_name_new(nam, env);
     }
@@ -5018,7 +5030,7 @@ env_fetch(int argc, VALUE *argv, VALUE _) https://github.com/ruby/ruby/blob/trunk/hash.c#L5030
 	rb_warn("block supersedes default value argument");
     }
     nam = env_name(key);
-    env = getenv(nam);
+    env = getenv_with_lock(nam);
     if (!env) {
 	if (block_given) return rb_yield(key);
 	if (argc == 1) {
@@ -5054,12 +5066,14 @@ envix(const char *nam) https://github.com/ruby/ruby/blob/trunk/hash.c#L5066
     register int i, len = strlen(nam);
     char **env;
 
+    rb_native_mutex_lock(&env_lock);
     env = GET_ENVIRON(environ);
     for (i = 0; env[i]; i++) {
 	if (ENVNMATCH(env[i],nam,len) && env[i][len] == '=')
 	    break;			/* memcmp must come first to avoid */
     }					/* potential SEGV's */
     FREE_ENVIRON(environ);
+    rb_native_mutex_unlock(&env_lock);
     return i;
 }
 #endif
@@ -5160,11 +5174,13 @@ ruby_setenv(const char *name, const char *value) https://github.com/ruby/ruby/blob/trunk/hash.c#L5174
 	wname[len-1] = L'=';
 #endif
     }
+    rb_native_mutex_lock(&env_lock);
 #ifndef HAVE__WPUTENV_S
     failed = _wputenv(wname);
 #else
     failed = _wputenv_s(wname, wvalue);
 #endif
+    rb_native_mutex_unlock(&env_lock);
     ALLOCV_END(buf);
     /* even if putenv() failed, clean up and try to delete the
      * variable from the system area. */
@@ -5178,6 +5194,7 @@ ruby_setenv(const char *name, const char *value) https://github.com/ruby/ruby/blob/trunk/hash.c#L5194
 	invalid_envname(name);
     }
 #elif defined(HAVE_SETENV) && defined(HAVE_UNSETENV)
+    rb_native_mutex_lock(&env_lock);
     if (value) {
 	if (setenv(name, value, 1))
 	    rb_sys_fail_str(rb_sprintf("setenv(%s)", name));
@@ -5190,11 +5207,13 @@ ruby_setenv(const char *name, const char *value) https://github.com/ruby/ruby/blob/trunk/hash.c#L5207
 	    rb_sys_fail_str(rb_sprintf("unsetenv(%s)", name));
 #endif
     }
+    rb_native_mutex_unlock(&env_lock);
 #elif defined __sun
     /* Solaris 9 (or earlier) does not have setenv(3C) and unsetenv(3C). */
     /* The below code was tested on Solaris 10 by:
          % ./configure ac_cv_func_setenv=no ac_cv_func_unsetenv=no
     */
+    rb_native_mutex_lock(&env_lock);
     size_t len, mem_size;
     char **env_ptr, *str, *mem_ptr;
 
@@ -5220,6 +5239,7 @@ ruby_setenv(const char *name, const char *value) https://github.com/ruby/ruby/blob/trunk/hash.c#L5239
 	    rb_sys_fail_str(rb_sprintf("putenv(%s)", name));
 	}
     }
+    rb_native_mutex_unlock(&env_lock);
 #else  /* WIN32 */
     size_t len;
     int i;
@@ -5347,18 +5367,31 @@ env_keys(int raw) https://github.com/ruby/ruby/blob/trunk/hash.c#L5367
     rb_encoding *enc = raw ? 0 : rb_locale_encoding();
 
     ary = rb_ary_new();
+    rb_native_mutex_lock(&env_lock);
     env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
+    int pair_count = 0;
+    while(*(env+pair_count)) {
+	pair_count++;
+    }
+    VALUE env_pairs[pair_count];
+    for(int i = 0; i < pair_count; i++)
+    {
+	const char *p = *env;
+	env_pairs[i] = p;
+	env++;
+    }
+    FREE_ENVIRON(environ);
+    rb_native_mutex_unlock(&env_lock);
+    for(int current_pair = 0; current_pair < pair_count; current_pair++)
+    {
+	const char *p = env_pairs[current_pair];
+	char *s = strchr(p, '=');
 	if (s) {
-            const char *p = *env;
             size_t l = s - p;
             VALUE e = raw ? rb_utf8_str_new(p, l) : env_enc_str_new(p, l, enc);
             rb_ary_push(ary, e);
 	}
-	env++;
     }
-    FREE_ENVIRON(environ);
     return ary;
 }
 
@@ -5387,6 +5420,7 @@ rb_env_size(VALUE ehash, VALUE args, VALUE eobj) https://github.com/ruby/ruby/blob/trunk/hash.c#L5420
     char **env;
     long cnt = 0;
 
+    rb_native_mutex_lock(&env_lock);
     env = GET_ENVIRON(environ);
     for (; *env ; ++env) {
 	if (strchr(*env, '=')) {
@@ -5394,6 +5428,7 @@ rb_env_size(VALUE ehash, VALUE args, VALUE eobj) https://github.com/ruby/ruby/blob/trunk/hash.c#L5428
 	}
     }
     FREE_ENVIRON(environ);
+    rb_native_mutex_unlock(&env_lock);
     return LONG2FIX(cnt);
 }
 
@@ -5435,15 +5470,29 @@ env_values(void) https://github.com/ruby/ruby/blob/trunk/hash.c#L5470
     char **env;
 
     ary = rb_ary_new();
+    rb_native_mutex_lock(&env_lock);
     env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
+    int pair_count = 0;
+    while (*(env+pair_count)) {
+	pair_count++;
+    }
+    VALUE env_pairs[pair_count];
+    for(int i = 0; i < pair_count; i++)
+    {
+	const char *p = *env;
+	env_pairs[i] = p;
+	env++;
+    }
+    FREE_ENVIRON(environ);
+    rb_native_mutex_unlock(&env_lock);
+    for(int current_pair = 0; current_pair < pair_count; current_pair++)
+    {
+	const char *p = env_pairs[current_pair];
+	char *s = strchr(p, '=');
 	if (s) {
 	    rb_ary_push(ary, env_str_new2(s+1));
 	}
-	env++;
     }
-    FREE_ENVIRON(environ);
     return ary;
 }
 
@@ -5524,16 +5573,30 @@ env_each_pair(VALUE ehash) https://github.com/ruby/ruby/blob/trunk/hash.c#L5573
     RETURN_SIZED_ENUMERATOR(ehash, 0, 0, rb_env_size);
 
     ary = rb_ary_new();
+    rb_native_mutex_lock(&env_lock);
     env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
+    int pair_count = 0;
+    while (*(env+pair_count)) {
+	pair_count++;
+    }
+    VALUE env_pairs[pair_count];
+    for(int i = 0; i < pair_count; i++)
+    {
+	const char *p = *env;
+	env_pairs[i] = p;
+	env++;
+    }
+    FREE_ENVIRON(environ);
+    rb_native_mutex_unlock(&env_lock);
+    for(int current_pair = 0; current_pair < pair_count; current_pair++)
+    {
+	const char *p = env_pairs[current_pair];
+	char *s = strchr(p, '=');
 	if (s) {
-	    rb_ary_push(ary, env_str_new(*env, s-*env));
+	    rb_ary_push(ary, env_str_new(p, s-p));
 	    rb_ary_push(ary, env_str_new2(s+1));
 	}
-	env++;
     }
-    FREE_ENVIRON(environ);
 
     if (rb_block_pair_yield_optimizable()) {
 	for (i=0; i<RARRAY_LEN(ary); i+=2) {
@@ -5877,23 +5940,37 @@ env_inspect(VALUE _) https://github.com/ruby/ruby/blob/trunk/hash.c#L5940
     VALUE str, i;
 
     str = rb_str_buf_new2("{");
+    rb_native_mutex_lock(&env_lock);
     env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
+    int pair_count = 0;
+    while (*(env+pair_count)) {
+	pair_count++;
+    }
+    VALUE env_pairs[pair_count];
+    for(int i = 0; i < pair_count; i++)
+    {
+	const char *p = *env;
+	env_pairs[i] = p;
+	env++;
+    }
+    FREE_ENVIRON(environ);
+    rb_native_mutex_unlock(&env_lock);
+    for(int current_pair = 0; current_pair < pair_count; current_pair++)
+    {
+	const char *p = env_pairs[current_pair];
+	char *s = strchr(p, '=');
 
-	if (env != environ) {
+	if (current_pair != 0) {
 	    rb_str_buf_cat2(str, ", ");
 	}
 	if (s) {
 	    rb_str_buf_cat2(str, "\"");
-	    rb_str_buf_cat(str, *env, s-*env);
+	    rb_str_buf_cat(str, p, s-p);
 	    rb_str_buf_cat2(str, "\"=>");
 	    i = rb_inspect(rb_str_new2(s+1));
 	    rb_str_buf_append(str, i);
 	}
-	env++;
     }
-    FREE_ENVIRON(environ);
     rb_str_buf_cat2(str, "}");
 
     return str;
@@ -5915,16 +5992,30 @@ env_to_a(VALUE _) https://github.com/ruby/ruby/blob/trunk/hash.c#L5992
     VALUE ary;
 
     ary = rb_ary_new();
+    rb_native_mutex_lock(&env_lock);
     env = GET_ENVIRON(environ);
-    while (*env) {
-	char *s = strchr(*env, '=');
+    int pair_count = 0;
+    while (*(env+pair_count)) {
+	pair_count++;
+    }
+    VALUE env_pairs[pair_count];
+    for(int i = 0; i < pair_count; i++)
+    {
+	const char *p = *env;
+	env_pairs[i] = p;
+	env++;
+    }
+    FREE_ENVIRON(environ);
+    rb_native_mutex_unlock(&env_lock);
+    for(int current_pair = 0; current_pair < pair_count; current_pair++)
+    {
+	const char *p = env_pairs[current_pair];
+	char *s = strchr(p, '=');
 	if (s) {
-	    rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s-*env),
+	    rb_ary_push(ary, rb_assoc_new(env_str_new(p, s-p),
 					  env_str_new2(s+1)));
 	}
-	env++;
     }
-    FREE_ENVIRON(environ);
     return ary;
 }
 
@@ -5958,10 +6049,12 @@ env_size(VALUE _) https://github.com/ruby/ruby/blob/trunk/hash.c#L6049
     int i;
     char **env;
 
+    rb_native_mutex_lock(&env_lock);
     env = GET_ENVIRON(environ);
     for (i=0; env[i]; i++)
 	;
     FREE_ENVIRON(environ);
+    rb_native_mutex_unlock(&env_lock);
     return INT2FIX(i);
 }
 
@@ -5980,12 +6073,15 @@ env_empty_p(VALUE _) https://github.com/ (... truncated)

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

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