The writev
function takes an array of struct iovec as input argument
writev(int fd, const struct iovec *iov, int iovcnt);
The input is a list of memory buffers that need to be written to a file (say). What I want to know is:
Does writev internally do this:
for (each element in iov)
write(element)
such that every element of iov
is written to file in a separate I/O call? Or does writev
write everything to file in a single I/O call?
Per the standards, the for loop you mentioned is not a valid implementation of writev
, for several reasons:
PIPE_BUF
, the pipe write is required to be atomic, but the loop would break the atomicity requirement. This issue cannot be worked around except by moving all the iov entries into a single buffer before writing when the total length is at most PIPE_BUF
.writev
call would be required to perform a partial write without blocking. As far as I know, this issue would be impossible to work around in the general case.I'm not sure about point #3, but it definitely exists in the opposite direction, when reading. Calling read
in a loop could block if a terminal has some data (shorter than the total iov length) available followed by an EOF indicator; calling readv
should return immediately with a partial read in this case. However, due to a bug in Linux, readv
on terminals is actually implemented as a read
loop in kernelspace, and it does exhibit this blocking bug. I had to work around this bug in implementing musl's stdio:
http://git.etalabs.net/cgi-bin/gitweb.cgi?p=musl;a=commit;h=2cff36a84f268c09f4c9dc5a1340652c8e298dc0
To answer the last part of your question:
Or does
writev
write everything to file in a single I/O call?
In all cases, a conformant writev
implementation will be a single syscall. Getting down to how it's implemented on Linux: for ordinary files and for most devices, the underlying file driver has methods that implement iov-style io directly, without any sort of internal loop. But the terminal driver on Linux is highly outdated and lacks the modern io methods, causing the kernel to fallback to a write/read loop for writev
/readv
when operating on a terminal.
The direct way to know how code works is read the source code.
see http://www.oschina.net/code/explore/glibc-2.9/sysdeps/posix/writev.c
It simplely alloca() or malloc() a buffer, copy all vectors into it, and call write() once.
That how it works. Nothing mysterious.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With