2929
3030#define ENABLE_ECONV_NEWLINE_OPTION 1
3131#define SRC_ENC_TO_DST_ENC_KEY_SIZE 128
32+ STATIC_ASSERT (encoding_namelen , SRC_ENC_TO_DST_ENC_KEY_SIZE > (ENCODING_NAMELEN_MAX * 2 + 1 ));
3233
3334/* VALUE rb_cEncoding = rb_define_class("Encoding", rb_cObject); */
3435static VALUE rb_eUndefinedConversionError ;
@@ -211,7 +212,7 @@ rb_free_transcoder_table(void)
211212}
212213
213214static void
214- gen_src_to_dst_encodings_key (const char key_buf [ SRC_ENC_TO_DST_ENC_KEY_SIZE ] , const char * sname , const char * dname )
215+ gen_src_to_dst_encodings_key (const char * key_buf , const char * sname , const char * dname )
215216{
216217 char * p = (char * )key_buf ;
217218 size_t slen = strlen (sname );
@@ -231,6 +232,7 @@ make_transcoder_entry(const char *sname, const char *dname)
231232 st_table * table2 ;
232233 transcoder_entry_t * entry = NULL ;
233234
235+ // TODO: we should be able to remove this table soon
234236 RB_VM_LOCKING () {
235237 if (!st_lookup (transcoder_table , (st_data_t )sname , & val )) {
236238 val = (st_data_t )st_init_strcasetable ();
@@ -251,10 +253,20 @@ make_transcoder_entry(const char *sname, const char *dname)
251253 }
252254 char key_buf [SRC_ENC_TO_DST_ENC_KEY_SIZE ] = { 0 };
253255 gen_src_to_dst_encodings_key (key_buf , sname , dname );
254- VALUE tbl = fast_transcoder_entry_table ;
255- VALUE new_tbl = rb_managed_id_table_dup (tbl );
256- rb_managed_id_table_insert (new_tbl , rb_intern (key_buf ), (VALUE )entry );
257- RUBY_ATOMIC_VALUE_SET (fast_transcoder_entry_table , new_tbl ); // TODO: use CAS
256+ ID key = rb_intern (key_buf );
257+ while (1 ) {
258+ VALUE tbl = fast_transcoder_entry_table ;
259+ VALUE entry_got ;
260+ if (rb_managed_id_table_lookup (tbl , key , & entry_got )) {
261+ break ;
262+ } else {
263+ VALUE new_tbl = rb_managed_id_table_dup (tbl );
264+ rb_managed_id_table_insert (new_tbl , key , (VALUE )entry );
265+ if (RUBY_ATOMIC_VALUE_CAS (fast_transcoder_entry_table , tbl , new_tbl ) == tbl ) {
266+ break ;
267+ }
268+ }
269+ }
258270 return entry ;
259271}
260272
@@ -266,11 +278,11 @@ get_transcoder_entry(const char *sname, const char *dname)
266278 char key_buf [SRC_ENC_TO_DST_ENC_KEY_SIZE ] = { 0 };
267279 gen_src_to_dst_encodings_key (key_buf , sname , dname );
268280 VALUE entry_val ;
269- // TODO: once we CAS in `make_transcoder_entry`, we no longer need to check regular transcoder_table after
270281 if (rb_managed_id_table_lookup (fast_transcoder_entry_table , rb_intern (key_buf ), & entry_val )) {
271282 return (transcoder_entry_t * )entry_val ;
272283 }
273284
285+ // TODO: we should be able to remove this table soon
274286 RB_VM_LOCKING () {
275287 if (st_lookup (transcoder_table , (st_data_t )sname , & val )) {
276288 table2 = (st_table * )val ;
@@ -1065,11 +1077,12 @@ rb_econv_open0(rb_encoding *senc, const char *sname, rb_encoding *denc, const ch
10651077 int num_trans ;
10661078 rb_econv_t * ec ;
10671079
1080+ // load encodings, if necessary
10681081 if (* sname && (!senc || !senc -> max_enc_len )) {
1069- rb_enc_find_index (sname ); // loads encoding
1082+ rb_enc_find_index (sname );
10701083 }
10711084 if (* dname && (!denc || !denc -> max_enc_len )) {
1072- rb_enc_find_index (dname ); // loads encoding
1085+ rb_enc_find_index (dname );
10731086 }
10741087
10751088 if (* sname == '\0' && * dname == '\0' ) {
0 commit comments