John-Paul Bader <[email protected]> wrote: > Hmm, > > my C skills are really weak but this patch suppresses any IO errors > right? At least on BSD? Can you explain what exactly it is doing? Just > want to understand entirely.
>From the beginning (a bit long, feel free to ask me for more clarification, too much of this is second nature to me by now and I may glance over important details...): There are two standard ways of doing IO in C: stdio.h (fwrite(3)/ fread(3)/fseek(2) ...) and the lower-level Unix system calls found in unistd.h (write(2)/read(2)/lseek(2)...) stdio.h functions are wrappers that do buffering in userspace and wrap the underlying unistd.h syscalls. They should not be used interchangeably on the same file descriptors. Unfortunately, Ruby 1.8 makes this mistake and uses them interchangeably in some places: bad. So when working with regular files, file offsets maintained in userspace via stdio did not get properly synchronized to the underlying kernel-level file offsets. That's why the fseeko(lseek()) was added to fix an issue exposed by Unicorn. lseek() was used to read the offset from the kernel, and then fseeko() is then used to synchronize the userspace offset to that of the kernel. All of this works well for seekable regular files. Now, sockets and pipes aren't seekable, so you'll get an error from the kernel if you try to seek on them. Errors from system calls are stored in "errno", a global variable that stores the error of the last system call executed. So since attempting to seek on an unseekable file sets errno, it clobbers the previous clean (or the "safe" value of EAGAIN[1]) errno. Eventually, this caused rb_sys_fail() function to be called, which raises a Ruby exception matching the current value of errno. [1] - EAGAIN (and EWOULDBLOCK on some systems) basically means "try calling this same function again, later". It gets returned when kernel buffers (not the userspace ones) are full if attempting to write, or empty if attempting to read. Since Ruby 1.8 relies on non-blocking I/O for sockets/pipes, the "blocking" write methods are coded to (eventually) retry on EAGAIN. > I thought your diff was the ruby diff of r26253 and didn't realize it > was yours ;) Actually, it's not mine, I just submitted the ticket that fixed one bug and introduced the one you hit :) -- Eric Wong _______________________________________________ Unicorn mailing list - [email protected] http://rubyforge.org/mailman/listinfo/mongrel-unicorn Do not quote signatures (like this one) or top post when replying
