If I open a a file as os.open( '/dev/ttyS2', O_RDWR | O_NDELAY )
, is there any way that I can check when my 'write()' commands have finished? Or, can I open a file for non-blocking read but blocking write?
views:
71answers:
6OS API write() returns count of written bytes. Checking this value against size of your input you can see when all input is sent.
Open two file descriptors to the same location - one for non-blocking reads and the other for blocking writes.
The O_NDELAY flag always affects both reading and writing. To achieve a blocking write on a non-blocking file you can select (Python module) the file and write when it becomes writable in a loop.
If you are writing to a tty (as you are in your example), you can use termios.tcdrain
to wait until all written bytes have been transmitted.
Your write
systems calls will still be non-blocking, so you will need to handle EWOULDBLOCK
/EAGAIN
errors, and use select(2)
, poll(2)
or epoll(7)
to know when you can write to the file descriptor. These are designed to be used with non-blocking file descriptors.
You have a misunderstanding of what non-blocking means. It does not imply asynchronous operation - you can have any combination of asynchronous/synchronous and blocking/non-blocking.
A write()
just hands data off to the kernel to take care of. When write()
returns successfully, the kernel has now taken care of the data - this is true regardless of whether the file descriptor is blocking or non-blocking. Whether or not the kernel has actually finished writing it at this point is a separate matter (usually, the answer is "no" - most file descriptors are asynchronous).
A write()
cannot complete if the kernel has no more room to buffer the data you want to write, and this is the case that is affected by non-blocking versus blocking - in the blocking case, the write()
will block until space is available. In the non-blocking case, write()
will return an error (EAGAIN
), and it is up to you to retry it later.
If you wish to wait until all data written to a terminal device has actually been sent to the hardware, use tcdrain()
- but this is likely to be unnecessary. Alternatively, if you wish write()
to block until your data is accepted by the kernel, then you can use fcntl()
to temporarily set the file descriptor to blocking.