Hi,

At Fri, 6 Sep 2002 12:29:51 +0900,
Jos Backus wrote:
> I am encountering a problem similar to the one mentioned here,
> 
> http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&th=16d3eb9718c73a88&rnum=1
> http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&th=ec398d145e0e36c1&rnum=2
> 
> except that mine happens with the fwrite() call in io_write(). A script using
> two threads occasionally sees an exception being raised when calling IO#puts.
> The code in io.c looks like this:
> 
>     n = fwrite(RSTRING(str)->ptr, 1, RSTRING(str)->len, f);
>     if (n != RSTRING(str)->len && ferror(f)) {
>         rb_sys_fail(fptr->path);
>     }
> 
> How do I fix this? I don't suppose it's possible to wrap the fwrite() call
> with TRAP_BEG/ TRAP_END, and if ferror(f) and errno == EINTR or ERESTART, just
> ignore the result and skip raising the exception? What do I return from
> io_write() in this case?

Once I made a patch for non-blocking IO, which contained
retrying fwrite().  And now added ERESTART condition.

Does this help you?


Index: io.c =================================================================== RCS file: /cvs/ruby/src/ruby/io.c,v retrieving revision 1.156 diff -u -2 -p -r1.156 io.c --- io.c 6 Sep 2002 01:58:32 -0000 1.156 +++ io.c 8 Sep 2002 23:30:18 -0000 @@ -262,4 +262,24 @@ io_fflush(f, fptr) } +void +rb_io_wait_readable(f) + int f; +{ + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(f, &rfds); + rb_thread_select(f + 1, &rfds, NULL, NULL, NULL); +} + +void +rb_io_wait_writable(f) + int f; +{ + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(f, &wfds); + rb_thread_select(f + 1, NULL, &wfds, NULL, NULL); +} + /* writing functions */ static VALUE @@ -269,5 +289,6 @@ io_write(io, str) OpenFile *fptr; FILE *f; - long n; + long n, r; + register char *ptr; rb_secure(4); @@ -285,21 +306,38 @@ io_write(io, str) f = GetWriteFile(fptr); + ptr = RSTRING(str)->ptr; + n = RSTRING(str)->len; + do { #ifdef __human68k__ - { - register char *ptr = RSTRING(str)->ptr; - n = RSTRING(str)->len; - while (--n >= 0) - if (fputc(*ptr++, f) == EOF) - break; - n = ptr - RSTRING(str)->ptr; - } - if (n != RSTRING(str)->len && ferror(f)) - rb_sys_fail(fptr->path); + if (fputc(*ptr++, f) == EOF) { + if (ferror(f)) rb_sys_fail(fptr->path); + break; + } + --n; #else - n = fwrite(RSTRING(str)->ptr, 1, RSTRING(str)->len, f); - if (n != RSTRING(str)->len && ferror(f)) { - rb_sys_fail(fptr->path); - } + r = fwrite(ptr, 1, n, f); + ptr += r; + n -= r; + if (ferror(f)) { + switch (errno) { + case EINTR: +#if defined(ERESTART) + case ERESTART: +#endif + clearerr(f); + continue; + case EAGAIN: +#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: #endif + clearerr(f); + rb_io_wait_writable(fileno(f)); + continue; + } + rb_sys_fail(fptr->path); + } +#endif + } while (n > 0); + n = ptr - RSTRING(str)->ptr; if (fptr->mode & FMODE_SYNC) { io_fflush(f, fptr); @@ -545,4 +583,28 @@ rb_io_to_io(io) /* reading functions */ +static void +io_read_retryable(f, path) + FILE *f; + const char *path; +{ + switch (errno) { + case EINTR: +#if defined(ERESTART) + case ERESTART: +#endif + clearerr(f); + break; + case EAGAIN: +#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + clearerr(f); + rb_io_wait_readable(fileno(f)); + break; + default: + rb_sys_fail(path); + break; + } +} long @@ -586,4 +648,5 @@ rb_io_fread(ptr, len, f) switch (errno) { case EINTR: + clearerr(f); continue; case EAGAIN: @@ -591,4 +654,5 @@ rb_io_fread(ptr, len, f) case EWOULDBLOCK: #endif + clearerr(f); return len - n; } @@ -655,4 +719,5 @@ read_all(fptr, siz) if (pos > 0 && n == 0 && bytes == 0) { if (feof(fptr->f)) return Qnil; + if (!ferror(fptr->f)) return rb_str_new(0, 0); rb_sys_fail(fptr->path); } @@ -766,6 +831,6 @@ appendline(fptr, delim, strp) if (c == EOF) { if (ferror(f)) { - if (errno == EINTR) continue; - rb_sys_fail(fptr->path); + io_read_retryable(f, fptr->path); + continue; } return c; @@ -1079,6 +1144,6 @@ rb_io_each_byte(io) if (c == EOF) { if (ferror(f)) { - if (errno == EINTR) continue; - rb_sys_fail(fptr->path); + io_read_retryable(f, fptr->path); + continue; } break; @@ -1110,6 +1175,6 @@ rb_io_getc(io) if (c == EOF) { if (ferror(f)) { - if (errno == EINTR) goto retry; - rb_sys_fail(fptr->path); + io_read_retryable(f, fptr->path); + goto retry; } return Qnil;
-- Nobu Nakada