Skip to content

Commit f378052

Browse files
luke-gruberjhawthorn
authored andcommitted
Fixes to encoding/transcoding for ractors.
Not all ractor-related encoding issues were fixed by 1afc07e. I found more by running my test-all branch with 3 ractors for each test.
1 parent e3e8725 commit f378052

File tree

6 files changed

+113
-17
lines changed

6 files changed

+113
-17
lines changed

depend

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1401,7 +1401,6 @@ compile.$(OBJEXT): $(top_srcdir)/prism/pack.h
14011401
compile.$(OBJEXT): $(top_srcdir)/prism/parser.h
14021402
compile.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
14031403
compile.$(OBJEXT): $(top_srcdir)/prism/prism.h
1404-
compile.$(OBJEXT): $(top_srcdir)/prism/prism.h
14051404
compile.$(OBJEXT): $(top_srcdir)/prism/regexp.h
14061405
compile.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
14071406
compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
@@ -17727,6 +17726,7 @@ transcode.$(OBJEXT): $(hdrdir)/ruby/ruby.h
1772717726
transcode.$(OBJEXT): $(top_srcdir)/internal/array.h
1772817727
transcode.$(OBJEXT): $(top_srcdir)/internal/class.h
1772917728
transcode.$(OBJEXT): $(top_srcdir)/internal/compilers.h
17729+
transcode.$(OBJEXT): $(top_srcdir)/internal/encoding.h
1773017730
transcode.$(OBJEXT): $(top_srcdir)/internal/gc.h
1773117731
transcode.$(OBJEXT): $(top_srcdir)/internal/inits.h
1773217732
transcode.$(OBJEXT): $(top_srcdir)/internal/object.h

encoding.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,16 @@ enc_registered(struct enc_table *enc_table, const char *name)
459459
return -1;
460460
}
461461

462+
int
463+
rb_enc_registered(const char *name)
464+
{
465+
int idx;
466+
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
467+
idx = enc_registered(enc_table, name);
468+
}
469+
return idx;
470+
}
471+
462472
void
463473
rb_encdb_declare(const char *name)
464474
{
@@ -1600,8 +1610,10 @@ enc_set_default_encoding(struct default_encoding *def, VALUE encoding, const cha
16001610
/* Already set */
16011611
overridden = TRUE;
16021612

1613+
int index = 0;
16031614
if (!NIL_P(encoding)) {
16041615
enc_check_encoding(encoding); // loads it if necessary. Needs to be done outside of VM lock.
1616+
index = rb_enc_to_index(rb_to_encoding(encoding));
16051617
}
16061618

16071619
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
@@ -1619,7 +1631,7 @@ enc_set_default_encoding(struct default_encoding *def, VALUE encoding, const cha
16191631
(st_data_t)UNSPECIFIED_ENCODING);
16201632
}
16211633
else {
1622-
def->index = rb_enc_to_index(rb_to_encoding(encoding));
1634+
def->index = index;
16231635
def->enc = 0;
16241636
enc_alias_internal(enc_table, name, def->index);
16251637
}

internal/encoding.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ void rb_encdb_declare(const char *name);
2929
void rb_enc_set_base(const char *name, const char *orig);
3030
int rb_enc_set_dummy(int index);
3131
void rb_enc_raw_set(VALUE obj, rb_encoding *enc);
32+
int rb_enc_registered(const char *name);
3233

3334
PUREFUNC(int rb_data_is_encoding(VALUE obj));
3435

test/ruby/test_encoding.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,23 @@ def test_ractor_lazy_load_encoding_concurrently
157157
assert rs.empty?
158158
end;
159159
end
160+
161+
def test_ractor_set_default_external_string
162+
assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
163+
begin;
164+
$-w = nil
165+
rs = []
166+
7.times do |i|
167+
rs << Ractor.new(i) do |i|
168+
Encoding.default_external = "us-ascii"
169+
end
170+
end
171+
172+
while rs.any?
173+
r, _obj = Ractor.select(*rs)
174+
rs.delete(r)
175+
end
176+
assert rs.empty?
177+
end;
178+
end
160179
end

test/ruby/test_transcode.rb

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2361,6 +2361,52 @@ def test_ractor_lazy_load_encoding_random
23612361
end;
23622362
end
23632363

2364+
def test_ractor_asciicompat_encoding_exists
2365+
assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
2366+
begin;
2367+
rs = []
2368+
7.times do
2369+
rs << Ractor.new do
2370+
string = "ISO-2022-JP"
2371+
encoding = Encoding.find(string)
2372+
20_000.times do
2373+
Encoding::Converter.asciicompat_encoding(string)
2374+
Encoding::Converter.asciicompat_encoding(encoding)
2375+
end
2376+
end
2377+
end
2378+
2379+
while rs.any?
2380+
r, _obj = Ractor.select(*rs)
2381+
rs.delete(r)
2382+
end
2383+
assert rs.empty?
2384+
end;
2385+
end
2386+
2387+
def test_ractor_asciicompat_encoding_doesnt_exist
2388+
assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
2389+
begin;
2390+
rs = []
2391+
NO_EXIST = "I".freeze
2392+
7.times do
2393+
rs << Ractor.new do
2394+
50.times do
2395+
if (val = Encoding::Converter.asciicompat_encoding(NO_EXIST))
2396+
raise "Got #{val}, expected nil"
2397+
end
2398+
end
2399+
end
2400+
end
2401+
2402+
while rs.any?
2403+
r, _obj = Ractor.select(*rs)
2404+
rs.delete(r)
2405+
end
2406+
assert rs.empty?
2407+
end;
2408+
end
2409+
23642410
private
23652411

23662412
def assert_conversion_both_ways_utf8(utf8, raw, encoding)

transcode.c

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "internal/object.h"
2020
#include "internal/string.h"
2121
#include "internal/transcode.h"
22+
#include "internal/encoding.h"
2223
#include "ruby/encoding.h"
2324
#include "vm_sync.h"
2425

@@ -1826,7 +1827,9 @@ rb_econv_asciicompat_encoding(const char *ascii_incompat_name)
18261827
st_table *table2;
18271828
struct asciicompat_encoding_t data = {0};
18281829

1829-
RB_VM_LOCKING() {
1830+
unsigned int lev;
1831+
RB_VM_LOCK_ENTER_LEV(&lev);
1832+
{
18301833
if (st_lookup(transcoder_table, (st_data_t)ascii_incompat_name, &v)) {
18311834
table2 = (st_table *)v;
18321835
/*
@@ -1839,12 +1842,25 @@ rb_econv_asciicompat_encoding(const char *ascii_incompat_name)
18391842
if (table2->num_entries == 1) {
18401843
data.ascii_incompat_name = ascii_incompat_name;
18411844
data.ascii_compat_name = NULL;
1842-
st_foreach(table2, asciicompat_encoding_i, (st_data_t)&data);
1845+
if (rb_multi_ractor_p()) {
1846+
/*
1847+
* We need to unlock in case `load_transcoder_entry` actually loads the encoding
1848+
* and table2 could be inserted into when we unlock.
1849+
*/
1850+
st_table *dup_table2 = st_copy(table2);
1851+
RB_VM_LOCK_LEAVE_LEV(&lev);
1852+
st_foreach(dup_table2, asciicompat_encoding_i, (st_data_t)&data);
1853+
st_free_table(dup_table2);
1854+
RB_VM_LOCK_ENTER_LEV(&lev);
1855+
}
1856+
else {
1857+
st_foreach(table2, asciicompat_encoding_i, (st_data_t)&data);
1858+
}
18431859
}
18441860

18451861
}
1846-
18471862
}
1863+
RB_VM_LOCK_LEAVE_LEV(&lev);
18481864

18491865
return data.ascii_compat_name; // can be NULL
18501866
}
@@ -2989,10 +3005,16 @@ static rb_encoding *
29893005
make_encoding(const char *name)
29903006
{
29913007
rb_encoding *enc;
2992-
RB_VM_LOCKING() {
2993-
enc = rb_enc_find(name);
2994-
if (!enc)
2995-
enc = make_dummy_encoding(name);
3008+
enc = rb_enc_find(name);
3009+
if (!enc) {
3010+
RB_VM_LOCKING() {
3011+
if (rb_enc_registered(name)) {
3012+
enc = NULL;
3013+
}
3014+
else {
3015+
enc = make_dummy_encoding(name);
3016+
}
3017+
}
29963018
}
29973019
return enc;
29983020
}
@@ -3029,14 +3051,10 @@ econv_s_asciicompat_encoding(VALUE klass, VALUE arg)
30293051
VALUE enc = Qnil;
30303052

30313053
enc_arg(&arg, &arg_name, &arg_enc);
3032-
3033-
RB_VM_LOCKING() {
3034-
result_name = rb_econv_asciicompat_encoding(arg_name);
3035-
3036-
if (result_name) {
3037-
result_enc = make_encoding(result_name);
3038-
enc = rb_enc_from_encoding(result_enc);
3039-
}
3054+
result_name = rb_econv_asciicompat_encoding(arg_name);
3055+
if (result_name) {
3056+
result_enc = make_encoding(result_name);
3057+
enc = rb_enc_from_encoding(result_enc);
30403058
}
30413059
return enc;
30423060
}

0 commit comments

Comments
 (0)