AmendHub

Download:

jcs

/

subtext

/

amendments

/

152

telnet: Fast-track single-byte writes, spin a bit after sending

If our send succeeds and returns quickly, we can avoid having to
return and wait for uthread to cycle back to us. Since sends can take
a very long time, we can't simply switch to synchronous TCPSend calls
or we'll hang forever on a dead connection.
 
We can also avoid zeroing the full tcp_wds structure each time, since
it is zeroed at the node allocation and we only need to zero wds[1]
ptr and length.

jcs made amendment 152 about 1 year ago
--- telnet.c Thu Jun 16 12:54:06 2022 +++ telnet.c Fri Jun 17 13:39:41 2022 @@ -301,6 +301,10 @@ telnet_idle(void) break; } + /* + * Send buffered data any time we can, the user might not be + * in an explicit session_flush() like during chat + */ telnet_output(node->session); break; } @@ -568,6 +572,7 @@ telnet_output(struct session *session) struct telnet_node *node = (struct telnet_node *)session->cookie; short n, error; unsigned char c; + unsigned long now; if (session->obuflen == 0 || session->ending) return 0; @@ -592,29 +597,35 @@ process_result: return node->obuflen; } - /* copy obuf to node buffer, escaping IACs */ - for (node->escaped_obuflen = 0, node->obuflen = 0; - node->obuflen < session->obuflen && node->escaped_obuflen < sizeof(node->obuf); - node->obuflen++) { - c = session->obuf[node->obuflen]; - - if (!node->sending_iac && c == IAC) { - node->obuf[node->escaped_obuflen++] = IAC; - node->obuf[node->escaped_obuflen++] = IAC; - } else - node->obuf[node->escaped_obuflen++] = c; + if (session->obuflen == 1 && session->obuf[0] != IAC) { + node->obuf[0] = session->obuf[0]; + node->escaped_obuflen = node->obuflen = 1; + } else { + /* copy obuf to node buffer, escaping IACs */ + for (node->escaped_obuflen = 0, node->obuflen = 0; + node->obuflen < session->obuflen && + node->escaped_obuflen < sizeof(node->obuf); + node->obuflen++) { + c = session->obuf[node->obuflen]; + + if (!node->sending_iac && c == IAC) { + node->obuf[node->escaped_obuflen++] = IAC; + node->obuf[node->escaped_obuflen++] = IAC; + } else + node->obuf[node->escaped_obuflen++] = c; + } } - + /* * _TCPSend only knows how many wds pointers were passed in when it - * reads the next one and its pointer is zero (or size is zero?), so - * even though we're only sending one wds, memory after wds[0] - * has to be zeroed out. + * reads the next one and its pointer is zero (or size is zero?) */ - memset(&node->tcp_wds, 0, sizeof(node->tcp_wds)); node->tcp_wds[0].ptr = (Ptr)&node->obuf; node->tcp_wds[0].length = node->escaped_obuflen; + node->tcp_wds[1].ptr = 0; + node->tcp_wds[1].length = 0; + now = Ticks; error = _TCPSend(&node->send_pb, node->stream, node->tcp_wds, nil, nil, true); if (error) { @@ -622,10 +633,12 @@ process_result: session->ending = 1; } - /* if we sent quickly enough, we won't have to cycle again */ - if (node->send_pb.ioResult <= 0) - goto process_result; - + /* if we can send in less than 500ms, avoid a uthread switch */ + while (Ticks - now <= 30) { + if (node->send_pb.ioResult <= 0) + goto process_result; + } + return 0; }