arduino / arduino/ArduinoCore-API

Issues with Print::print() and partial writes

Abierto
#64 14 comentarios 0 reacciones 1 asignado Reclamado por @cmaglie Ver en GitHub
Lenguaje dominante
C++
Estrellas
306
Forks
150
Métricas de merge de PR
Sin PR fusionados en 30 d

Descripción

quoting @bperrybap here
http://forum.arduino.cc/index.php?topic=357312.msg2481770#msg2481770

```
While there was an issue in the i2c library that was triggered by this new Print
class code, there is a still a fundamental issue with new new Print class code.
The issue is that the Print class code is actually composed of two parts.
The low level functions like read()/write() and the higher level output formatting
functions like print(). And both layers support partial/incomplete i/o.
(outputting less than the maximum asked to output)
I believe that if print() is allowed to support partial/incomplete i/o, that we will be
fighting related issues for years.

What seems to have happened is that in 1.6.6. write() was updated to properly
support incomplete i/o and print() is now seeing issues because it doesn't
support incomplete i/o.
(An error is essentially a single type of incomplete i/o)

Yes it was a coding error in a library in this case, but it brings up a larger issue
related to partial/incomplete i/o and the print() functions.

Currently, I don't believe that the write() API is mandated to always swallow all
the data provided unless there is an error.

So the issues becomes, how to deal with print() when write() does
incomplete/partial i/o?

Looking forward, unless the write() API mandates blocking when low level
buffers are full or updating the Print class print() functions to ensure blocking,
when write() returns after incomplete i/o, I think we will see more issues in
the future.

While it is ok for functions like write() to support and potentially even require
supporting incomplete i/o, it is not appropriate for functions like print() to force
this same requirement back up to its callers.
This is because callers of write() know the full contents of what is being output.
The callers of print() do not know the full contents of what is being output since
print() is performing output formatting.
In other words suppose I do something like:

foo.print(bar);

and the variable bar is an big integer number and is is 1234567

Now suppose that the low level i/o library buffer is full and rather than block
(spin) waiting for enough room to take all the requested output, decides to
take only what it can.
Suppose that was only 4 bytes.
So the low level i/o library write() will return 4 and then foo.print() will now
return 4. What the heck is a sketch or any other potentially caller of print()
code, supposed to do with that?
It has no way of resuming the output nor does it even know how many total
output characters there were.

The point is that if the API is going to support incomplete i/o, it MUST have
a option to enable/disable this mechanism for functions like print() to not
return until all output characters have been handed off.
(The only exception is a fatal error where the i/o would never complete)
I argued this point (enable/disable incomplete/async i/o) a year or so ago
when we were looking at and arguing over the buffer available function calls.

There must be a way to allow users of the Print class, specifically the print()
functions to have a mechanism to be assured that when the print() function
returns that all the characters have been handed off.
This is an absolute requirement since only print() knows what characters
are to be output when formatting is done. The caller has no idea.

It is unacceptable to require all users of the print() calls to have to support
incomplete i/o. And even if they do support incomplete i/o, there is no way
to complete the i/o for output that was formatted by print() like number output.

Suppose somebody writes an i/o library that decides to do very limited
output buffering and simply returns 0 when the output buffer is full vs
blocking? This is allowed by the API but a sketch would never be able to
print numbers using print() calls when the numbers were more digits than
output buffer could hold, even if the sketch code add in all the complexities
to support incomplete i/o for print() functions.

I'm strongly suggesting that print() use blocking i/o.
If non blocking print() i/o behavior is supported by print() (which I don't even
think is possible since print() does output formatting), then there needs to be
an API to enable incomplete i/o for an object (disabled by default) so that
sketches can get the existing blocking behavior by default which preserves
backward compatibility and keeps user sketches simple.
But I'd still recommend that print() be kept simple and always be blocking
since there is no real technical way to support incomplete i/o with print()
functions. Return on errors, yes, but not incomplete i/o.

With regard to errors vs partial i/o. That brings up another API issue.
The write() API should be able to distinguish between errors and incomplete
i/o. for example, if the hardware is broken and it can't transmit, how can that
be indicated?
Currently, if you return zero, then that could mean the low level buffers are
full (incomplete i/o) or it could mean an actual error.
A negative value would be better to indicate an error.
```

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.