From: nobu@...
Date: 2017-01-05T01:16:33+00:00
Subject: [ruby-core:78974] [Ruby trunk Bug#13085] io.c io_fwrite creates	garbage

Issue #13085 has been updated by Nobuyoshi Nakada.


No.
Your patch releases the GVL while unfreezing the string to be written.
If the write operation is blocked, other threads can clobber that string.

----------------------------------------
Bug #13085: io.c io_fwrite creates garbage
https://bugs.ruby-lang.org/issues/13085#change-62391

* Author: Eric Wong
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: 
* Backport: 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN
----------------------------------------
Relying on rb_str_new_frozen for unconverted strings does not
save memory because copy-on-write is always triggered in
read-write I/O loops were subsequent IO#read calls will
clobber the given write buffer.

  buf = ''.b
  while input.read(16384, buf)
    output.write(buf)
  end

This generates a lot of garbage starting with Ruby 2.2 (r44471).
For my use case, even IO.copy_stream generates garbage, since
I wrap "write" to do Digest calculation in a single pass.

I tried using rb_str_replace and reusing the string as a hidden
(klass == 0) thread-local, but rb_str_replace attempts CoW
optimization by creating new frozen objects, too:

  https://80x24.org/spew/20161229004417.12304-1-e@80x24.org/raw


So, I'm not sure what to do, temporal locking seems wrong for
writing strings (I guess it's for reading?).  I get
test_threaded_flush failures with the following:

  https://80x24.org/spew/20161229005701.9712-1-e@80x24.org/raw


IO#syswrite has the same problem with garbage.  I can use
IO#write_nonblock on fast filesystems while holding GVL,
I guess...


---Files--------------------------------
0001-io.c-io_fwrite-temporarily-freeze-string-when-writin.patch (2.6 KB)


-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>