1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

use RB_VM_LOCK_ENTER()

We found that we need to make Ruby objects while locking the environ
to ENV operation atomically, so we decided to use `RB_VM_LOCK_ENTER()`
instead of `env_lock`.
This commit is contained in:
Koichi Sasada 2021-12-14 17:28:25 +09:00
parent a4a3528eb7
commit 0eafba3610
Notes: git 2021-12-15 15:05:03 +09:00
2 changed files with 369 additions and 329 deletions

View file

@ -7180,6 +7180,8 @@ hash.$(OBJEXT): {$(VPATH)}symbol.h
hash.$(OBJEXT): {$(VPATH)}thread_native.h hash.$(OBJEXT): {$(VPATH)}thread_native.h
hash.$(OBJEXT): {$(VPATH)}transient_heap.h hash.$(OBJEXT): {$(VPATH)}transient_heap.h
hash.$(OBJEXT): {$(VPATH)}util.h hash.$(OBJEXT): {$(VPATH)}util.h
hash.$(OBJEXT): {$(VPATH)}vm_debug.h
hash.$(OBJEXT): {$(VPATH)}vm_sync.h
inits.$(OBJEXT): $(hdrdir)/ruby.h inits.$(OBJEXT): $(hdrdir)/ruby.h
inits.$(OBJEXT): $(hdrdir)/ruby/ruby.h inits.$(OBJEXT): $(hdrdir)/ruby/ruby.h
inits.$(OBJEXT): $(top_srcdir)/internal/compilers.h inits.$(OBJEXT): $(top_srcdir)/internal/compilers.h

484
hash.c
View file

@ -45,6 +45,7 @@
#include "transient_heap.h" #include "transient_heap.h"
#include "ruby/thread_native.h" #include "ruby/thread_native.h"
#include "ruby/ractor.h" #include "ruby/ractor.h"
#include "vm_sync.h"
#ifndef HASH_DEBUG #ifndef HASH_DEBUG
#define HASH_DEBUG 0 #define HASH_DEBUG 0
@ -4810,16 +4811,8 @@ extern char **environ;
#define ENVNMATCH(s1, s2, n) (memcmp((s1), (s2), (n)) == 0) #define ENVNMATCH(s1, s2, n) (memcmp((s1), (s2), (n)) == 0)
#endif #endif
static rb_nativethread_lock_t env_lock; #define ENV_LOCK() RB_VM_LOCK_ENTER()
#define ENV_UNLOCK() RB_VM_LOCK_LEAVE()
static 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 * static inline rb_encoding *
env_encoding(void) env_encoding(void)
@ -4840,12 +4833,6 @@ env_enc_str_new(const char *ptr, long len, rb_encoding *enc)
return str; return str;
} }
static VALUE
env_enc_str_new_cstr(const char *ptr, rb_encoding *enc)
{
return env_enc_str_new(ptr, strlen(ptr), enc);
}
static VALUE static VALUE
env_str_new(const char *ptr, long len) env_str_new(const char *ptr, long len)
{ {
@ -4859,14 +4846,35 @@ env_str_new2(const char *ptr)
return env_str_new(ptr, strlen(ptr)); return env_str_new(ptr, strlen(ptr));
} }
static const char TZ_ENV[] = "TZ";
static VALUE static VALUE
env_name_new(const char *name, const char *ptr) getenv_with_lock(const char *name)
{ {
return env_enc_str_new_cstr(ptr, env_encoding()); VALUE ret;
ENV_LOCK();
{
const char *val = getenv(name);
ret = env_str_new2(val);
}
ENV_UNLOCK();
return ret;
} }
static bool
has_env_with_lock(const char *name)
{
const char *val;
ENV_LOCK();
{
val = getenv(name);
}
ENV_UNLOCK();
return val ? true : false;
}
static const char TZ_ENV[] = "TZ";
static void * static void *
get_env_cstr( get_env_cstr(
VALUE str, VALUE str,
@ -4919,17 +4927,13 @@ static VALUE
env_delete(VALUE name) env_delete(VALUE name)
{ {
const char *nam = env_name(name); const char *nam = env_name(name);
const char *val = getenv_with_lock(nam);
reset_by_modified_env(nam); reset_by_modified_env(nam);
VALUE val = getenv_with_lock(nam);
if (val) { if (!NIL_P(val)) {
VALUE value = env_str_new2(val);
ruby_setenv(nam, 0); ruby_setenv(nam, 0);
return value;
} }
return Qnil; return val;
} }
/* /*
@ -4982,14 +4986,9 @@ env_delete_m(VALUE obj, VALUE name)
static VALUE static VALUE
rb_f_getenv(VALUE obj, VALUE name) rb_f_getenv(VALUE obj, VALUE name)
{ {
const char *nam, *env; const char *nam = env_name(name);
VALUE env = getenv_with_lock(nam);
nam = env_name(name); return env;
env = getenv_with_lock(nam);
if (env) {
return env_name_new(nam, env);
}
return Qnil;
} }
/* /*
@ -5022,7 +5021,8 @@ env_fetch(int argc, VALUE *argv, VALUE _)
{ {
VALUE key; VALUE key;
long block_given; long block_given;
const char *nam, *env; const char *nam;
VALUE env;
rb_check_arity(argc, 1, 2); rb_check_arity(argc, 1, 2);
key = argv[0]; key = argv[0];
@ -5032,14 +5032,15 @@ env_fetch(int argc, VALUE *argv, VALUE _)
} }
nam = env_name(key); nam = env_name(key);
env = getenv_with_lock(nam); env = getenv_with_lock(nam);
if (!env) {
if (NIL_P(env)) {
if (block_given) return rb_yield(key); if (block_given) return rb_yield(key);
if (argc == 1) { if (argc == 1) {
rb_key_err_raise(rb_sprintf("key not found: \"%"PRIsVALUE"\"", key), envtbl, key); rb_key_err_raise(rb_sprintf("key not found: \"%"PRIsVALUE"\"", key), envtbl, key);
} }
return argv[1]; return argv[1];
} }
return env_name_new(nam, env); return env;
} }
int int
@ -5064,17 +5065,17 @@ in_origenv(const char *str)
static int static int
envix(const char *nam) envix(const char *nam)
{ {
// should be locked
register int i, len = strlen(nam); register int i, len = strlen(nam);
char **env; char **env;
rb_native_mutex_lock(&env_lock);
env = GET_ENVIRON(environ); env = GET_ENVIRON(environ);
for (i = 0; env[i]; i++) { for (i = 0; env[i]; i++) {
if (ENVNMATCH(env[i],nam,len) && env[i][len] == '=') if (ENVNMATCH(env[i],nam,len) && env[i][len] == '=')
break; /* memcmp must come first to avoid */ break; /* memcmp must come first to avoid */
} /* potential SEGV's */ } /* potential SEGV's */
FREE_ENVIRON(environ); FREE_ENVIRON(environ);
rb_native_mutex_unlock(&env_lock);
return i; return i;
} }
#endif #endif
@ -5175,13 +5176,17 @@ ruby_setenv(const char *name, const char *value)
wname[len-1] = L'='; wname[len-1] = L'=';
#endif #endif
} }
rb_native_mutex_lock(&env_lock);
ENV_LOCK();
{
#ifndef HAVE__WPUTENV_S #ifndef HAVE__WPUTENV_S
failed = _wputenv(wname); failed = _wputenv(wname);
#else #else
failed = _wputenv_s(wname, wvalue); failed = _wputenv_s(wname, wvalue);
#endif #endif
rb_native_mutex_unlock(&env_lock); }
ENV_UNLOCK();
ALLOCV_END(buf); ALLOCV_END(buf);
/* even if putenv() failed, clean up and try to delete the /* even if putenv() failed, clean up and try to delete the
* variable from the system area. */ * variable from the system area. */
@ -5196,21 +5201,31 @@ ruby_setenv(const char *name, const char *value)
} }
#elif defined(HAVE_SETENV) && defined(HAVE_UNSETENV) #elif defined(HAVE_SETENV) && defined(HAVE_UNSETENV)
if (value) { if (value) {
rb_native_mutex_lock(&env_lock); int ret;
bool setenv_fail = setenv(name, value, 1); ENV_LOCK();
rb_native_mutex_unlock(&env_lock); {
if (setenv_fail) ret = setenv(name, value, 1);
rb_sys_fail_str(rb_sprintf("setenv(%s)", name)); }
ENV_UNLOCK();
if (ret) rb_sys_fail_str(rb_sprintf("setenv(%s)", name));
} }
else { else {
#ifdef VOID_UNSETENV #ifdef VOID_UNSETENV
ENV_LOCK();
{
unsetenv(name); unsetenv(name);
}
ENV_UNLOCK();
#else #else
rb_native_mutex_lock(&env_lock); int ret;
bool unsetenv_fail = unsetenv(name); ENV_LOCK();
rb_native_mutex_unlock(&env_lock); {
if (unsetenv_fail) ret = unsetenv(name);
rb_sys_fail_str(rb_sprintf("unsetenv(%s)", name)); }
ENV_UNLOCK();
if (ret) rb_sys_fail_str(rb_sprintf("unsetenv(%s)", name));
#endif #endif
} }
#elif defined __sun #elif defined __sun
@ -5218,7 +5233,6 @@ ruby_setenv(const char *name, const char *value)
/* The below code was tested on Solaris 10 by: /* The below code was tested on Solaris 10 by:
% ./configure ac_cv_func_setenv=no ac_cv_func_unsetenv=no % ./configure ac_cv_func_setenv=no ac_cv_func_unsetenv=no
*/ */
rb_native_mutex_lock(&env_lock);
size_t len, mem_size; size_t len, mem_size;
char **env_ptr, *str, *mem_ptr; char **env_ptr, *str, *mem_ptr;
@ -5231,6 +5245,9 @@ ruby_setenv(const char *name, const char *value)
rb_sys_fail_str(rb_sprintf("malloc("PRIuSIZE")", mem_size)); rb_sys_fail_str(rb_sprintf("malloc("PRIuSIZE")", mem_size));
snprintf(mem_ptr, mem_size, "%s=%s", name, value); snprintf(mem_ptr, mem_size, "%s=%s", name, value);
} }
ENV_LOCK();
{
for (env_ptr = GET_ENVIRON(environ); (str = *env_ptr) != 0; ++env_ptr) { for (env_ptr = GET_ENVIRON(environ); (str = *env_ptr) != 0; ++env_ptr) {
if (!strncmp(str, name, len) && str[len] == '=') { if (!strncmp(str, name, len) && str[len] == '=') {
if (!in_origenv(str)) free(str); if (!in_origenv(str)) free(str);
@ -5238,22 +5255,29 @@ ruby_setenv(const char *name, const char *value)
break; break;
} }
} }
}
ENV_UNLOCK();
if (value) { if (value) {
bool putenv_fail = putenv(mem_ptr); int ret;
rb_native_mutex_unlock(&env_lock); ENV_LOCK();
if (putenv_fail) { {
ret = putenv(mem_ptr);
}
ENV_UNLOCK();
if (ret) {
free(mem_ptr); free(mem_ptr);
rb_sys_fail_str(rb_sprintf("putenv(%s)", name)); rb_sys_fail_str(rb_sprintf("putenv(%s)", name));
} }
} }
else {
rb_native_mutex_unlock(&env_lock);
}
#else /* WIN32 */ #else /* WIN32 */
size_t len; size_t len;
int i; int i;
i=envix(name); /* where does it go? */ ENV_LOCK();
{
i = envix(name); /* where does it go? */
if (environ == origenviron) { /* need we copy environment? */ if (environ == origenviron) { /* need we copy environment? */
int j; int j;
@ -5267,6 +5291,7 @@ ruby_setenv(const char *name, const char *value)
tmpenv[max] = 0; tmpenv[max] = 0;
environ = tmpenv; /* tell exec where it is now */ environ = tmpenv; /* tell exec where it is now */
} }
if (environ[i]) { if (environ[i]) {
char **envp = origenviron; char **envp = origenviron;
while (*envp && *envp != environ[i]) envp++; while (*envp && *envp != environ[i]) envp++;
@ -5277,17 +5302,22 @@ ruby_setenv(const char *name, const char *value)
environ[i] = environ[i+1]; environ[i] = environ[i+1];
i++; i++;
} }
return; goto finish;
} }
} }
else { /* does not exist yet */ else { /* does not exist yet */
if (!value) return; if (!value) goto finish;
REALLOC_N(environ, char*, i+2); /* just expand it a bit */ REALLOC_N(environ, char*, i+2); /* just expand it a bit */
environ[i+1] = 0; /* make sure it's null terminated */ environ[i+1] = 0; /* make sure it's null terminated */
} }
len = strlen(name) + strlen(value) + 2; len = strlen(name) + strlen(value) + 2;
environ[i] = ALLOC_N(char, len); environ[i] = ALLOC_N(char, len);
snprintf(environ[i],len,"%s=%s",name,value); /* all that work just for this */ snprintf(environ[i],len,"%s=%s",name,value); /* all that work just for this */
finish:;
}
ENV_UNLOCK();
#endif /* WIN32 */ #endif /* WIN32 */
} }
@ -5368,53 +5398,29 @@ env_aset(VALUE nm, VALUE val)
return val; return val;
} }
static int
env_entry_count(void)
{
int i;
char **env;
env = GET_ENVIRON(environ);
for (i=0; env[i]; i++)
;
FREE_ENVIRON(environ);
return i;
}
static void
copy_env_pairs(const char **arr, int size)
{
char **env;
env = GET_ENVIRON(environ);
for (int i = 0; i < size; i++) {
const char *p = *env;
arr[i] = p;
env++;
}
FREE_ENVIRON(environ);
}
static VALUE static VALUE
env_keys(int raw) env_keys(int raw)
{ {
VALUE ary;
rb_encoding *enc = raw ? 0 : rb_locale_encoding(); rb_encoding *enc = raw ? 0 : rb_locale_encoding();
VALUE ary = rb_ary_new();
ary = rb_ary_new(); ENV_LOCK();
rb_native_mutex_lock(&env_lock); {
int pair_count = env_entry_count(); char **env = GET_ENVIRON(environ);
const char *env_pairs[pair_count]; while (*env) {
copy_env_pairs(env_pairs, pair_count); char *s = strchr(*env, '=');
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) { if (s) {
const char *p = *env;
size_t l = s - p; size_t l = s - p;
VALUE e = raw ? rb_utf8_str_new(p, l) : env_enc_str_new(p, l, enc); VALUE e = raw ? rb_utf8_str_new(p, l) : env_enc_str_new(p, l, enc);
rb_ary_push(ary, e); rb_ary_push(ary, e);
} }
env++;
} }
FREE_ENVIRON(environ);
}
ENV_UNLOCK();
return ary; return ary;
} }
@ -5443,7 +5449,8 @@ rb_env_size(VALUE ehash, VALUE args, VALUE eobj)
char **env; char **env;
long cnt = 0; long cnt = 0;
rb_native_mutex_lock(&env_lock); ENV_LOCK();
{
env = GET_ENVIRON(environ); env = GET_ENVIRON(environ);
for (; *env ; ++env) { for (; *env ; ++env) {
if (strchr(*env, '=')) { if (strchr(*env, '=')) {
@ -5451,7 +5458,9 @@ rb_env_size(VALUE ehash, VALUE args, VALUE eobj)
} }
} }
FREE_ENVIRON(environ); FREE_ENVIRON(environ);
rb_native_mutex_unlock(&env_lock); }
ENV_UNLOCK();
return LONG2FIX(cnt); return LONG2FIX(cnt);
} }
@ -5489,22 +5498,23 @@ env_each_key(VALUE ehash)
static VALUE static VALUE
env_values(void) env_values(void)
{ {
VALUE ary; VALUE ary = rb_ary_new();
ary = rb_ary_new(); ENV_LOCK();
rb_native_mutex_lock(&env_lock); {
int pair_count = env_entry_count(); char **env = GET_ENVIRON(environ);
const char *env_pairs[pair_count];
copy_env_pairs(env_pairs, pair_count);
rb_native_mutex_unlock(&env_lock);
for (int current_pair = 0; current_pair < pair_count; current_pair++) { while (*env) {
const char *p = env_pairs[current_pair]; char *s = strchr(*env, '=');
char *s = strchr(p, '=');
if (s) { if (s) {
rb_ary_push(ary, env_str_new2(s+1)); rb_ary_push(ary, env_str_new2(s+1));
} }
env++;
} }
FREE_ENVIRON(environ);
}
ENV_UNLOCK();
return ary; return ary;
} }
@ -5578,26 +5588,27 @@ env_each_value(VALUE ehash)
static VALUE static VALUE
env_each_pair(VALUE ehash) env_each_pair(VALUE ehash)
{ {
VALUE ary;
long i; long i;
RETURN_SIZED_ENUMERATOR(ehash, 0, 0, rb_env_size); RETURN_SIZED_ENUMERATOR(ehash, 0, 0, rb_env_size);
ary = rb_ary_new(); VALUE ary = rb_ary_new();
rb_native_mutex_lock(&env_lock);
int pair_count = env_entry_count();
const char *env_pairs[pair_count];
copy_env_pairs(env_pairs, pair_count);
rb_native_mutex_unlock(&env_lock);
for (int current_pair = 0; current_pair < pair_count; current_pair++) { ENV_LOCK();
const char *p = env_pairs[current_pair]; {
char *s = strchr(p, '='); char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
if (s) { if (s) {
rb_ary_push(ary, env_str_new(p, s-p)); rb_ary_push(ary, env_str_new(*env, s-*env));
rb_ary_push(ary, env_str_new2(s+1)); rb_ary_push(ary, env_str_new2(s+1));
} }
env++;
} }
FREE_ENVIRON(environ);
}
ENV_UNLOCK();
if (rb_block_pair_yield_optimizable()) { if (rb_block_pair_yield_optimizable()) {
for (i=0; i<RARRAY_LEN(ary); i+=2) { for (i=0; i<RARRAY_LEN(ary); i+=2) {
@ -5609,6 +5620,7 @@ env_each_pair(VALUE ehash)
rb_yield(rb_assoc_new(RARRAY_AREF(ary, i), RARRAY_AREF(ary, i+1))); rb_yield(rb_assoc_new(RARRAY_AREF(ary, i), RARRAY_AREF(ary, i+1)));
} }
} }
return ehash; return ehash;
} }
@ -5937,30 +5949,31 @@ env_to_s(VALUE _)
static VALUE static VALUE
env_inspect(VALUE _) env_inspect(VALUE _)
{ {
VALUE str, i; VALUE i;
VALUE str = rb_str_buf_new2("{");
str = rb_str_buf_new2("{"); ENV_LOCK();
rb_native_mutex_lock(&env_lock); {
int pair_count = env_entry_count(); char **env = GET_ENVIRON(environ);
const char *env_pairs[pair_count]; while (*env) {
copy_env_pairs(env_pairs, pair_count); char *s = strchr(*env, '=');
rb_native_mutex_unlock(&env_lock);
for (int current_pair = 0; current_pair < pair_count; current_pair++) { if (env != environ) {
const char *p = env_pairs[current_pair];
char *s = strchr(p, '=');
if (current_pair != 0) {
rb_str_buf_cat2(str, ", "); rb_str_buf_cat2(str, ", ");
} }
if (s) { if (s) {
rb_str_buf_cat2(str, "\""); rb_str_buf_cat2(str, "\"");
rb_str_buf_cat(str, p, s-p); rb_str_buf_cat(str, *env, s-*env);
rb_str_buf_cat2(str, "\"=>"); rb_str_buf_cat2(str, "\"=>");
i = rb_inspect(rb_str_new2(s+1)); i = rb_inspect(rb_str_new2(s+1));
rb_str_buf_append(str, i); rb_str_buf_append(str, i);
} }
env++;
} }
FREE_ENVIRON(environ);
}
ENV_UNLOCK();
rb_str_buf_cat2(str, "}"); rb_str_buf_cat2(str, "}");
return str; return str;
@ -5978,23 +5991,23 @@ env_inspect(VALUE _)
static VALUE static VALUE
env_to_a(VALUE _) env_to_a(VALUE _)
{ {
VALUE ary; VALUE ary = rb_ary_new();
ary = rb_ary_new(); ENV_LOCK();
rb_native_mutex_lock(&env_lock); {
int pair_count = env_entry_count(); char **env = GET_ENVIRON(environ);
const char *env_pairs[pair_count]; while (*env) {
copy_env_pairs(env_pairs, pair_count); char *s = strchr(*env, '=');
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) { if (s) {
rb_ary_push(ary, rb_assoc_new(env_str_new(p, s-p), rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s-*env),
env_str_new2(s+1))); env_str_new2(s+1)));
} }
env++;
} }
FREE_ENVIRON(environ);
}
ENV_UNLOCK();
return ary; return ary;
} }
@ -6012,6 +6025,22 @@ env_none(VALUE _)
return Qnil; return Qnil;
} }
static int
env_size_with_lock(void)
{
int i;
ENV_LOCK();
{
char **env = GET_ENVIRON(environ);
for (i=0; env[i]; i++);
FREE_ENVIRON(environ);
}
ENV_UNLOCK();
return i;
}
/* /*
* call-seq: * call-seq:
* ENV.length -> an_integer * ENV.length -> an_integer
@ -6025,10 +6054,7 @@ env_none(VALUE _)
static VALUE static VALUE
env_size(VALUE _) env_size(VALUE _)
{ {
rb_native_mutex_lock(&env_lock); return INT2FIX(env_size_with_lock());
int i = env_entry_count();
rb_native_mutex_unlock(&env_lock);
return INT2FIX(i);
} }
/* /*
@ -6044,18 +6070,19 @@ env_size(VALUE _)
static VALUE static VALUE
env_empty_p(VALUE _) env_empty_p(VALUE _)
{ {
char **env; bool empty = true;
rb_native_mutex_lock(&env_lock); ENV_LOCK();
env = GET_ENVIRON(environ); {
if (env[0] == 0) { char **env = GET_ENVIRON(environ);
FREE_ENVIRON(environ); if (env[0] != 0) {
rb_native_mutex_unlock(&env_lock); empty = false;
return Qtrue;
} }
FREE_ENVIRON(environ); FREE_ENVIRON(environ);
rb_native_mutex_unlock(&env_lock); }
return Qfalse; ENV_UNLOCK();
return RBOOL(empty);
} }
/* /*
@ -6086,10 +6113,8 @@ env_empty_p(VALUE _)
static VALUE static VALUE
env_has_key(VALUE env, VALUE key) env_has_key(VALUE env, VALUE key)
{ {
const char *s; const char *s = env_name(key);
return RBOOL(has_env_with_lock(s));
s = env_name(key);
return RBOOL(getenv_with_lock(s));
} }
/* /*
@ -6115,12 +6140,15 @@ env_has_key(VALUE env, VALUE key)
static VALUE static VALUE
env_assoc(VALUE env, VALUE key) env_assoc(VALUE env, VALUE key)
{ {
const char *s, *e; const char *s = env_name(key);
VALUE e = getenv_with_lock(s);
s = env_name(key); if (!NIL_P(e)) {
e = getenv_with_lock(s); return rb_assoc_new(key, e);
if (e) return rb_assoc_new(key, env_str_new2(e)); }
else {
return Qnil; return Qnil;
}
} }
/* /*
@ -6138,27 +6166,30 @@ env_assoc(VALUE env, VALUE key)
static VALUE static VALUE
env_has_value(VALUE dmy, VALUE obj) env_has_value(VALUE dmy, VALUE obj)
{ {
char **env;
obj = rb_check_string_type(obj); obj = rb_check_string_type(obj);
if (NIL_P(obj)) return Qnil; if (NIL_P(obj)) return Qnil;
rb_native_mutex_lock(&env_lock);
env = GET_ENVIRON(environ); VALUE ret = Qfalse;
ENV_LOCK();
{
char **env = GET_ENVIRON(environ);
while (*env) { while (*env) {
char *s = strchr(*env, '='); char *s = strchr(*env, '=');
if (s++) { if (s++) {
long len = strlen(s); long len = strlen(s);
if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) { if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) {
FREE_ENVIRON(environ); ret = Qtrue;
rb_native_mutex_unlock(&env_lock); break;
return Qtrue;
} }
} }
env++; env++;
} }
FREE_ENVIRON(environ); FREE_ENVIRON(environ);
rb_native_mutex_unlock(&env_lock); }
return Qfalse; ENV_UNLOCK();
return ret;
} }
/* /*
@ -6178,29 +6209,32 @@ env_has_value(VALUE dmy, VALUE obj)
static VALUE static VALUE
env_rassoc(VALUE dmy, VALUE obj) env_rassoc(VALUE dmy, VALUE obj)
{ {
char **env;
obj = rb_check_string_type(obj); obj = rb_check_string_type(obj);
if (NIL_P(obj)) return Qnil; if (NIL_P(obj)) return Qnil;
rb_native_mutex_lock(&env_lock);
env = GET_ENVIRON(environ); VALUE result = Qnil;
ENV_LOCK();
{
char **env = GET_ENVIRON(environ);
while (*env) { while (*env) {
const char *p = *env; const char *p = *env;
char *s = strchr(p, '='); char *s = strchr(p, '=');
if (s++) { if (s++) {
long len = strlen(s); long len = strlen(s);
if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) { if (RSTRING_LEN(obj) == len && strncmp(s, RSTRING_PTR(obj), len) == 0) {
FREE_ENVIRON(environ); result = rb_assoc_new(rb_str_new(p, s-p-1), obj);
rb_native_mutex_unlock(&env_lock); break;
VALUE result = rb_assoc_new(rb_str_new(p, s-p-1), obj);
return result;
} }
} }
env++; env++;
} }
FREE_ENVIRON(environ); FREE_ENVIRON(environ);
rb_native_mutex_unlock(&env_lock); }
return Qnil; ENV_UNLOCK();
return result;
} }
/* /*
@ -6222,49 +6256,50 @@ env_rassoc(VALUE dmy, VALUE obj)
static VALUE static VALUE
env_key(VALUE dmy, VALUE value) env_key(VALUE dmy, VALUE value)
{ {
VALUE str;
SafeStringValue(value); SafeStringValue(value);
rb_native_mutex_lock(&env_lock); VALUE str = Qnil;
int pair_count = env_entry_count();
const char *env_pairs[pair_count];
copy_env_pairs(env_pairs, pair_count);
rb_native_mutex_unlock(&env_lock);
for (int current_pair = 0; current_pair < pair_count; current_pair++) { ENV_LOCK();
const char *p = env_pairs[current_pair]; {
char *s = strchr(p, '='); char **env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
if (s++) { if (s++) {
long len = strlen(s); long len = strlen(s);
if (RSTRING_LEN(value) == len && strncmp(s, RSTRING_PTR(value), len) == 0) { if (RSTRING_LEN(value) == len && strncmp(s, RSTRING_PTR(value), len) == 0) {
str = env_str_new(p, s-p-1); str = env_str_new(*env, s-*env-1);
break;
}
}
env++;
}
FREE_ENVIRON(environ);
}
ENV_UNLOCK();
return str; return str;
}
}
}
return Qnil;
} }
static VALUE static VALUE
env_to_hash(void) env_to_hash(void)
{ {
VALUE hash; VALUE hash = rb_hash_new();
hash = rb_hash_new(); ENV_LOCK();
rb_native_mutex_lock(&env_lock); {
int pair_count = env_entry_count(); char **env = GET_ENVIRON(environ);
const char *env_pairs[pair_count]; while (*env) {
copy_env_pairs(env_pairs, pair_count); char *s = strchr(*env, '=');
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) { if (s) {
rb_hash_aset(hash, env_str_new(p, s-p), rb_hash_aset(hash, env_str_new(*env, s-*env),
env_str_new2(s+1)); env_str_new2(s+1));
} }
env++;
} }
FREE_ENVIRON(environ);
}
ENV_UNLOCK();
return hash; return hash;
} }
@ -6400,26 +6435,29 @@ env_freeze(VALUE self)
static VALUE static VALUE
env_shift(VALUE _) env_shift(VALUE _)
{ {
char **env;
VALUE result = Qnil; VALUE result = Qnil;
VALUE key = Qnil;
rb_native_mutex_lock(&env_lock); ENV_LOCK();
env = GET_ENVIRON(environ); {
char **env = GET_ENVIRON(environ);
if (*env) { if (*env) {
const char *p = *env; const char *p = *env;
rb_native_mutex_unlock(&env_lock);
char *s = strchr(p, '='); char *s = strchr(p, '=');
if (s) { if (s) {
VALUE key = env_str_new(p, s-p); key = env_str_new(p, s-p);
VALUE val = env_str_new2(getenv_with_lock(RSTRING_PTR(key))); VALUE val = env_str_new2(getenv(RSTRING_PTR(key)));
env_delete(key);
result = rb_assoc_new(key, val); result = rb_assoc_new(key, val);
} }
rb_native_mutex_lock(&env_lock); }
FREE_ENVIRON(environ);
}
ENV_UNLOCK();
if (!NIL_P(key)) {
env_delete(key);
} }
FREE_ENVIRON(environ);
rb_native_mutex_unlock(&env_lock);
return result; return result;
} }