Skip to content

Commit 9a11bc5

Browse files
hsbtk0kubun
authored andcommitted
Merge etc 1.4.6
1 parent 84d4932 commit 9a11bc5

File tree

3 files changed

+113
-42
lines changed

3 files changed

+113
-42
lines changed

ext/etc/etc.c

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ static VALUE sGroup;
5656
#endif
5757
RUBY_EXTERN char *getlogin(void);
5858

59-
#define RUBY_ETC_VERSION "1.4.5"
59+
#define RUBY_ETC_VERSION "1.4.6"
6060

6161
#define SYMBOL_LIT(str) ID2SYM(rb_intern_const(str ""))
6262

@@ -1163,14 +1163,26 @@ Init_etc(void)
11631163
{
11641164
VALUE mEtc;
11651165

1166-
#ifdef HAVE_RB_EXT_RACTOR_SAFE
1167-
RB_EXT_RACTOR_SAFE(true);
1168-
#endif
11691166
mEtc = rb_define_module("Etc");
11701167
/* The version */
11711168
rb_define_const(mEtc, "VERSION", rb_str_new_cstr(RUBY_ETC_VERSION));
11721169
init_constants(mEtc);
11731170

1171+
/* Ractor-safe methods */
1172+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
1173+
RB_EXT_RACTOR_SAFE(true);
1174+
#endif
1175+
rb_define_module_function(mEtc, "systmpdir", etc_systmpdir, 0);
1176+
rb_define_module_function(mEtc, "uname", etc_uname, 0);
1177+
rb_define_module_function(mEtc, "sysconf", etc_sysconf, 1);
1178+
rb_define_module_function(mEtc, "confstr", etc_confstr, 1);
1179+
rb_define_method(rb_cIO, "pathconf", io_pathconf, 1);
1180+
rb_define_module_function(mEtc, "nprocessors", etc_nprocessors, 0);
1181+
1182+
/* Non-Ractor-safe methods, see https://bugs.ruby-lang.org/issues/21115 */
1183+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
1184+
RB_EXT_RACTOR_SAFE(false);
1185+
#endif
11741186
rb_define_module_function(mEtc, "getlogin", etc_getlogin, 0);
11751187

11761188
rb_define_module_function(mEtc, "getpwuid", etc_getpwuid, -1);
@@ -1186,13 +1198,9 @@ Init_etc(void)
11861198
rb_define_module_function(mEtc, "setgrent", etc_setgrent, 0);
11871199
rb_define_module_function(mEtc, "endgrent", etc_endgrent, 0);
11881200
rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0);
1201+
1202+
/* Uses RbConfig::CONFIG so does not work in a Ractor */
11891203
rb_define_module_function(mEtc, "sysconfdir", etc_sysconfdir, 0);
1190-
rb_define_module_function(mEtc, "systmpdir", etc_systmpdir, 0);
1191-
rb_define_module_function(mEtc, "uname", etc_uname, 0);
1192-
rb_define_module_function(mEtc, "sysconf", etc_sysconf, 1);
1193-
rb_define_module_function(mEtc, "confstr", etc_confstr, 1);
1194-
rb_define_method(rb_cIO, "pathconf", io_pathconf, 1);
1195-
rb_define_module_function(mEtc, "nprocessors", etc_nprocessors, 0);
11961204

11971205
sPasswd = rb_struct_define_under(mEtc, "Passwd",
11981206
"name",
@@ -1303,4 +1311,8 @@ Init_etc(void)
13031311
rb_extend_object(sGroup, rb_mEnumerable);
13041312
rb_define_singleton_method(sGroup, "each", etc_each_group, 0);
13051313
#endif
1314+
1315+
#if defined(HAVE_GETPWENT) || defined(HAVE_GETGRENT)
1316+
(void)safe_setup_str;
1317+
#endif
13061318
}

ext/etc/extconf.rb

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,30 @@
1010
have_library("sun", "getpwnam") # NIS (== YP) interface for IRIX 4
1111
have_func("uname((struct utsname *)NULL)", headers)
1212
have_func("getlogin")
13-
have_func("getpwent")
14-
have_func("getgrent")
13+
if have_func("getpwent")
14+
have_struct_member('struct passwd', 'pw_gecos', 'pwd.h')
15+
have_struct_member('struct passwd', 'pw_change', 'pwd.h')
16+
have_struct_member('struct passwd', 'pw_quota', 'pwd.h')
17+
if have_struct_member('struct passwd', 'pw_age', 'pwd.h')
18+
case what_type?('struct passwd', 'pw_age', 'pwd.h')
19+
when "string"
20+
f = "safe_setup_str"
21+
when "long long"
22+
f = "LL2NUM"
23+
else
24+
f = "INT2NUM"
25+
end
26+
$defs.push("-DPW_AGE2VAL="+f)
27+
end
28+
have_struct_member('struct passwd', 'pw_class', 'pwd.h')
29+
have_struct_member('struct passwd', 'pw_comment', 'pwd.h') unless /cygwin/ === RUBY_PLATFORM
30+
have_struct_member('struct passwd', 'pw_expire', 'pwd.h')
31+
have_struct_member('struct passwd', 'pw_passwd', 'pwd.h')
32+
end
33+
if have_func("getgrent")
34+
have_struct_member('struct group', 'gr_passwd', 'grp.h')
35+
end
36+
1537
if (sysconfdir = RbConfig::CONFIG["sysconfdir"] and
1638
!RbConfig.expand(sysconfdir.dup, "prefix"=>"", "DESTDIR"=>"").empty?)
1739
$defs.push("-DSYSCONFDIR=#{Shellwords.escape(sysconfdir.dump)}")
@@ -21,26 +43,6 @@
2143
have_func("confstr")
2244
have_func("fpathconf")
2345

24-
have_struct_member('struct passwd', 'pw_gecos', 'pwd.h')
25-
have_struct_member('struct passwd', 'pw_change', 'pwd.h')
26-
have_struct_member('struct passwd', 'pw_quota', 'pwd.h')
27-
if have_struct_member('struct passwd', 'pw_age', 'pwd.h')
28-
case what_type?('struct passwd', 'pw_age', 'pwd.h')
29-
when "string"
30-
f = "safe_setup_str"
31-
when "long long"
32-
f = "LL2NUM"
33-
else
34-
f = "INT2NUM"
35-
end
36-
$defs.push("-DPW_AGE2VAL="+f)
37-
end
38-
have_struct_member('struct passwd', 'pw_class', 'pwd.h')
39-
have_struct_member('struct passwd', 'pw_comment', 'pwd.h') unless /cygwin/ === RUBY_PLATFORM
40-
have_struct_member('struct passwd', 'pw_expire', 'pwd.h')
41-
have_struct_member('struct passwd', 'pw_passwd', 'pwd.h')
42-
have_struct_member('struct group', 'gr_passwd', 'grp.h')
43-
4446
# for https://github.com/ruby/etc
4547
srcdir = File.expand_path("..", __FILE__)
4648
constdefs = "#{srcdir}/constdefs.h"
@@ -58,7 +60,7 @@
5860
# TODO: remove when dropping 2.7 support, as exported since 3.0
5961
have_func('rb_deprecate_constant(Qnil, "None")')
6062

61-
have_func("rb_io_descriptor")
63+
have_func("rb_io_descriptor", "ruby/io.h")
6264

6365
$distcleanfiles << "constdefs.h"
6466

test/etc/test_etc.rb

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def test_passwd
2121
assert_instance_of(String, s.shell)
2222
assert_kind_of(Integer, s.change) if s.respond_to?(:change)
2323
assert_kind_of(Integer, s.quota) if s.respond_to?(:quota)
24-
assert(s.age.is_a?(Integer) || s.age.is_a?(String)) if s.respond_to?(:age)
24+
assert(s.age.is_a?(Integer) || s.age.is_a?(String), s.age) if s.respond_to?(:age)
2525
assert_instance_of(String, s.uclass) if s.respond_to?(:uclass)
2626
assert_instance_of(String, s.comment) if s.respond_to?(:comment)
2727
assert_kind_of(Integer, s.expire) if s.respond_to?(:expire)
@@ -160,7 +160,7 @@ def test_pathconf
160160
end
161161
IO.pipe {|r, w|
162162
val = w.pathconf(Etc::PC_PIPE_BUF)
163-
assert(val.nil? || val.kind_of?(Integer))
163+
assert_kind_of(Integer, val) if val
164164
}
165165
end if defined?(Etc::PC_PIPE_BUF)
166166

@@ -173,28 +173,85 @@ def test_sysconfdir
173173
assert_operator(File, :absolute_path?, Etc.sysconfdir)
174174
end if File.method_defined?(:absolute_path?)
175175

176-
def test_ractor
176+
# All Ractor-safe methods should be tested here
177+
def test_ractor_parallel
178+
omit "This test is flaky and intermittently failing now on ModGC workflow" if ENV['GITHUB_WORKFLOW'] == 'ModGC'
179+
180+
assert_ractor(<<~RUBY, require: 'etc', timeout: 60)
181+
10.times.map do
182+
Ractor.new do
183+
100.times do
184+
raise unless String === Etc.systmpdir
185+
raise unless Hash === Etc.uname
186+
if defined?(Etc::SC_CLK_TCK)
187+
raise unless Integer === Etc.sysconf(Etc::SC_CLK_TCK)
188+
end
189+
if defined?(Etc::CS_PATH)
190+
raise unless String === Etc.confstr(Etc::CS_PATH)
191+
end
192+
if defined?(Etc::PC_PIPE_BUF)
193+
IO.pipe { |r, w|
194+
val = w.pathconf(Etc::PC_PIPE_BUF)
195+
raise unless val.nil? || val.kind_of?(Integer)
196+
}
197+
end
198+
raise unless Integer === Etc.nprocessors
199+
end
200+
end
201+
end.each(&:join)
202+
RUBY
203+
end
204+
205+
def test_ractor_unsafe
206+
assert_ractor(<<~RUBY, require: 'etc')
207+
r = Ractor.new do
208+
begin
209+
Etc.passwd
210+
rescue => e
211+
e.class
212+
end
213+
end.value
214+
assert_equal Ractor::UnsafeError, r
215+
RUBY
216+
end
217+
218+
def test_ractor_passwd
219+
omit("https://bugs.ruby-lang.org/issues/21115")
177220
return unless Etc.passwd # => skip test if no platform support
178221
Etc.endpwent
179222

180223
assert_ractor(<<~RUBY, require: 'etc')
181-
ractor = Ractor.new do
224+
ractor = Ractor.new port = Ractor::Port.new do |port|
182225
Etc.passwd do |s|
183-
Ractor.yield :sync
184-
Ractor.yield s.name
226+
port << :sync
227+
port << s.name
185228
break :done
186229
end
187230
end
188-
ractor.take # => :sync
231+
port.receive # => :sync
189232
assert_raise RuntimeError, /parallel/ do
190233
Etc.passwd {}
191234
end
192-
name = ractor.take # => first name
193-
ractor.take # => :done
235+
name = port.receive # => first name
236+
ractor.join # => :done
194237
name2 = Etc.passwd do |s|
195238
break s.name
196239
end
197240
assert_equal(name2, name)
198241
RUBY
199242
end
243+
244+
def test_ractor_getgrgid
245+
omit("https://bugs.ruby-lang.org/issues/21115")
246+
247+
assert_ractor(<<~RUBY, require: 'etc')
248+
20.times.map do
249+
Ractor.new do
250+
1000.times do
251+
raise unless Etc.getgrgid(Process.gid).gid == Process.gid
252+
end
253+
end
254+
end.each(&:join)
255+
RUBY
256+
end
200257
end

0 commit comments

Comments
 (0)