mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-19 23:22:16 +03:00
ClientContext: don’t read DataSource in TCP callback
Previously, _write_some function would be called each time TCP stack notifies the application that some data was delivered (via the `sent` callback). In turn, _write_some would obtain more data to be sent from the DataSource. In case of a DataSource backed by a Stream, this would read from a stream. Some libraries (such as SD) may call `yield` and other blocking operations from Stream read function, which can not be used in TCP stack callbacks. This change moves the data sending loop back into the Arduino task, with a negligible loss of performance. TCP callback now wakes the main task via `esp_schedule`, which performs stream read and provides more data to the TCP stack. Possible future optimization would be to buffer Stream data ahead of time. That way, buffered data could be sent immediately from the TCP callback. On the other hand, this optimization would need extra TCP_MSS of temporary storage, per connection. Fixes #2399.
This commit is contained in:
parent
03baea27ef
commit
7de81270a3
@ -317,9 +317,7 @@ protected:
|
|||||||
|
|
||||||
void _cancel_write()
|
void _cancel_write()
|
||||||
{
|
{
|
||||||
if (_datasource) {
|
if (_send_waiting) {
|
||||||
delete _datasource;
|
|
||||||
_datasource = nullptr;
|
|
||||||
esp_schedule();
|
esp_schedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -327,14 +325,22 @@ protected:
|
|||||||
size_t _write_from_source(DataSource* ds)
|
size_t _write_from_source(DataSource* ds)
|
||||||
{
|
{
|
||||||
assert(_datasource == nullptr);
|
assert(_datasource == nullptr);
|
||||||
|
assert(_send_waiting == 0);
|
||||||
_datasource = ds;
|
_datasource = ds;
|
||||||
_written = 0;
|
_written = 0;
|
||||||
_write_some();
|
do {
|
||||||
while (_datasource && !_noblock) {
|
_write_some();
|
||||||
_send_waiting = true;
|
|
||||||
|
if (!_datasource->available() || _noblock || state() == CLOSED) {
|
||||||
|
delete _datasource;
|
||||||
|
_datasource = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++_send_waiting;
|
||||||
esp_yield();
|
esp_yield();
|
||||||
}
|
} while(true);
|
||||||
_send_waiting = false;
|
_send_waiting = 0;
|
||||||
return _written;
|
return _written;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,31 +356,36 @@ protected:
|
|||||||
can_send = 0;
|
can_send = 0;
|
||||||
}
|
}
|
||||||
size_t will_send = (can_send < left) ? can_send : left;
|
size_t will_send = (can_send < left) ? can_send : left;
|
||||||
bool did_write = false;
|
DEBUGV(":wr %d %d %d\r\n", will_send, left, _written);
|
||||||
while( will_send ) {
|
bool need_output = false;
|
||||||
|
while( will_send && _datasource) {
|
||||||
size_t next_chunk =
|
size_t next_chunk =
|
||||||
will_send > _write_chunk_size ? _write_chunk_size : will_send;
|
will_send > _write_chunk_size ? _write_chunk_size : will_send;
|
||||||
const uint8_t* buf = _datasource->get_buffer(next_chunk);
|
const uint8_t* buf = _datasource->get_buffer(next_chunk);
|
||||||
|
if (state() == CLOSED) {
|
||||||
|
need_output = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
err_t err = tcp_write(_pcb, buf, next_chunk, TCP_WRITE_FLAG_COPY);
|
err_t err = tcp_write(_pcb, buf, next_chunk, TCP_WRITE_FLAG_COPY);
|
||||||
|
DEBUGV(":wrc %d %d %d\r\n", next_chunk, will_send, err);
|
||||||
_datasource->release_buffer(buf, next_chunk);
|
_datasource->release_buffer(buf, next_chunk);
|
||||||
if (err == ERR_OK) {
|
if (err == ERR_OK) {
|
||||||
_written += next_chunk;
|
_written += next_chunk;
|
||||||
did_write = true;
|
need_output = true;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
will_send -= next_chunk;
|
will_send -= next_chunk;
|
||||||
}
|
}
|
||||||
if( did_write ) tcp_output(_pcb);
|
if( need_output ) {
|
||||||
|
tcp_output(_pcb);
|
||||||
if (!_datasource->available() || _noblock) {
|
|
||||||
delete _datasource;
|
|
||||||
_datasource = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _write_some_from_cb()
|
void _write_some_from_cb()
|
||||||
{
|
{
|
||||||
_write_some();
|
if (_send_waiting == 1) {
|
||||||
if (!_datasource && _send_waiting) {
|
_send_waiting--;
|
||||||
esp_schedule();
|
esp_schedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -490,7 +501,7 @@ private:
|
|||||||
size_t _written = 0;
|
size_t _written = 0;
|
||||||
size_t _write_chunk_size = 256;
|
size_t _write_chunk_size = 256;
|
||||||
bool _noblock = false;
|
bool _noblock = false;
|
||||||
bool _send_waiting = false;
|
int _send_waiting = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif//CLIENTCONTEXT_H
|
#endif//CLIENTCONTEXT_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user