[Nut-upsdev] [PATCH] disable nonblocking mode on serial port

Jim Paris jim at jtan.com
Sun Oct 5 19:35:25 UTC 2008


>> It's wrong to open a device with O_NONBLOCK and then write to it and
>> expect it to always succeed.
>
> If you know that there should be room to write a single character in the 
> output buffer of the UART, this isn't unreasonable to expect. The delays 
> in ser_send_pace() should allow for plenty of time to empty even the 
> smallest buffer, so this will always be the case.

That seems like a strange workaround to have to use, when the hardware
and driver are perfectly capable of knowing when the buffer is
actually empty, and just blocking (in case of !O_NONBLOCK) or
providing a signal (through select) when it's actually OK to send.
The whole serial_send_pace could potentially be discarded entirely -- 
how many drivers actually need it because of slow UPS hardware,
versus drivers that just need it to avoid EAGAIN?

>> One needs to at deal with EAGAIN.
>
> No, we don't. This isn't the generic case for a POSIX write() command,  
> we know that we're dealing with a UART that must have at least room for a 
> single character.  If sufficient time has passed since the character was 
> written, EAGAIN is not a proper response from the USB to serial driver 
> (even if POSIX allows it).

Why would you purposely ignore POSIX just because you think you have
valid assumptions?  If you follow POSIX, things will work regardless
of whether you've assumed correctly.  Doing things right is not hard.

You could be dealing with unusual USB->serial devices, as in my case.
USB bulk transfers have potentially unbounded latency due to bus
conditions.  Someone else might have a setup that includes forwarding
the serial port through a TCP/IP link to another machine.  Why assume?

>> If we can agree on that we can figure out a solution that we're
>> both happy with :)
>
> I'm afraid I feel that this is more a bug in the USB to serial  
> implementation, than a flaw in NUT.

I will agree that my USB to serial converter is buggy.  I have
problems getting it to work reliably, so I've switched to a pl2303
based device for now, and it seems to be working better with the stock
NUT (both cyberpower and powerpanel).

However, I can guarantee you that the reponse to a bug report that
starts:
  "I opened a serial port using O_NONBLOCK and write() returns -EAGAIN"
will be "That is clearly not a bug".

>> One solution would be to get rid of O_NONBLOCK as I did.
>
> No. This fails to deal with stalled connections in case flow control is 
> used. NUT drivers are single threaded, so blocking just about anywhere 
> also means that the connection to the server will be affected.

OK, agreed, if flow control is in use then the write can block
forever and so that solution is no good.

> But still I really don't think this is where the problem is. Running
> the powerpanel driver with debugging enabled at level three would
> help in finding where things go wrong.

As I mentioned above, my USB to serial converter seems buggy.  
Powerpanel wouldn't even run (it often hangs for quite a while when
opening the port, sometimes before even printing "Trying binary
protocol").  I have switched to another, and things seem OK.

So I will agree that with a more well-behaved serial port, the
assumptions made in NUT are OK.  But I still think the behaviour is
technically wrong and I would really like to see a select() with a
timeout on the writes.  Would you consider a patch or should
I just shelve this idea for now and stick with my alternate adapter?

-jim



More information about the Nut-upsdev mailing list