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

* io.c (io_flush_buffer): write and buffer operations should be

monolithic.  [ruby-core:31348]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@28687 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2010-07-20 03:50:41 +00:00
parent 1433c13b25
commit a3419bc919
3 changed files with 56 additions and 32 deletions

View file

@ -1,3 +1,8 @@
Tue Jul 20 12:50:37 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
* io.c (io_flush_buffer): write and buffer operations should be
monolithic. [ruby-core:31348]
Tue Jul 20 12:27:56 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
* lib/fileutils.rb (FileUtils::Entry_#copy): check file name

69
io.c
View file

@ -610,52 +610,57 @@ io_writable_length(rb_io_t *fptr, long l)
}
static VALUE
io_flush_buffer(VALUE arg)
io_flush_buffer_sync(void *arg)
{
rb_io_t *fptr = (rb_io_t *)arg;
rb_io_t *fptr = arg;
long l = io_writable_length(fptr, fptr->wbuf_len);
return rb_write_internal(fptr->fd, fptr->wbuf+fptr->wbuf_off, l);
ssize_t r = write(fptr->fd, fptr->wbuf+fptr->wbuf_off, (size_t)l);
if (fptr->wbuf_len <= r) {
fptr->wbuf_off = 0;
fptr->wbuf_len = 0;
return 0;
}
if (0 <= r) {
fptr->wbuf_off += (int)r;
fptr->wbuf_len -= (int)r;
errno = EAGAIN;
}
return (VALUE)-1;
}
static VALUE
io_flush_buffer_async(VALUE arg)
{
return rb_thread_blocking_region(io_flush_buffer_sync, (void *)arg, RUBY_UBF_IO, 0);
}
static inline int
io_flush_buffer(rb_io_t *fptr)
{
if (fptr->write_lock) {
return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
}
else {
return (int)io_flush_buffer_async((VALUE)fptr);
}
}
static int
io_fflush(rb_io_t *fptr)
{
long r;
rb_io_check_closed(fptr);
if (fptr->wbuf_len == 0)
return 0;
if (!rb_thread_fd_writable(fptr->fd)) {
rb_io_check_closed(fptr);
}
retry:
if (fptr->wbuf_len == 0)
return 0;
if (fptr->write_lock) {
r = rb_mutex_synchronize(fptr->write_lock, io_flush_buffer, (VALUE)fptr);
}
else {
long l = io_writable_length(fptr, fptr->wbuf_len);
r = rb_write_internal(fptr->fd, fptr->wbuf+fptr->wbuf_off, l);
}
/* xxx: Other threads may modify wbuf.
* A lock is required, definitely. */
rb_io_check_closed(fptr);
if (fptr->wbuf_len <= r) {
fptr->wbuf_off = 0;
fptr->wbuf_len = 0;
return 0;
}
if (0 <= r) {
fptr->wbuf_off += (int)r;
fptr->wbuf_len -= (int)r;
errno = EAGAIN;
}
if (rb_io_wait_writable(fptr->fd)) {
while (fptr->wbuf_len > 0 && io_flush_buffer(fptr) != 0) {
if (!rb_io_wait_writable(fptr->fd))
return -1;
rb_io_check_closed(fptr);
goto retry;
}
return -1;
return 0;
}
#ifdef HAVE_RB_FD_INIT
@ -3512,9 +3517,9 @@ rb_io_fptr_finalize(rb_io_t *fptr)
{
if (!fptr) return 0;
fptr->pathv = Qnil;
fptr->write_lock = 0;
if (0 <= fptr->fd)
rb_io_fptr_cleanup(fptr, TRUE);
fptr->write_lock = 0;
if (fptr->rbuf) {
free(fptr->rbuf);
fptr->rbuf = 0;

View file

@ -1609,4 +1609,18 @@ End
t.close
assert_raise(IOError) {t.binmode}
end
def test_threaded_flush
bug3585 = '[ruby-core:31348]'
src = %q{\
t = Thread.new { sleep 3 }
Thread.new {sleep 1; t.kill; p 'hi!'}
t.join
}.gsub(/^\s+/, '')
10.times.map do
Thread.start do
assert_in_out_err([], src, [%q["hi!"]])
end
end.each {|th| th.join}
end
end