cgi: stdout POLLHUP holy grail
This a) directly discovers cgi stdout POLLUP and b) modulates rx flow control on CGI STDOUT according to the outgoing writeable service. When the outgoing writeable service finally sees 0 read() waiting for it even though it was signalled for POLLIN, it knows it is a POLLHUP. Critically when it sees POLLHUP like that, it leaves the rx flow control defeating any further stdout POLLIN signalling while the rest of the CGI lifecycle completes, eliminating busywaiting during the CGI.
This commit is contained in:
parent
04ed8d2673
commit
d78c93254b
4 changed files with 27 additions and 11 deletions
|
@ -246,9 +246,14 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
|
||||
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||
#ifdef LWS_WITH_CGI
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI) {
|
||||
if (lws_cgi_write_split_stdout_headers(wsi) < 0)
|
||||
if (wsi->reason_bf & (LWS_CB_REASON_AUX_BF__CGI_HEADERS | LWS_CB_REASON_AUX_BF__CGI)) {
|
||||
n = lws_cgi_write_split_stdout_headers(wsi);
|
||||
if (n < 0) {
|
||||
lwsl_debug("LWS_CB_REASON_AUX_BF__CGI forcing close\n");
|
||||
return -1;
|
||||
}
|
||||
if (!n)
|
||||
lws_rx_flow_control(wsi->cgi->stdwsi[LWS_STDOUT], 1);
|
||||
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_HEADERS)
|
||||
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__CGI_HEADERS;
|
||||
|
@ -258,6 +263,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
}
|
||||
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_CHUNK_END) {
|
||||
lwsl_debug("writing chunk terminator and exiting\n");
|
||||
n = lws_write(wsi, (unsigned char *)"0\x0d\x0a\x0d\x0a",
|
||||
5, LWS_WRITE_HTTP);
|
||||
/* always close after sending it */
|
||||
|
@ -363,6 +369,8 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
/* TBD stdin rx flow control */
|
||||
break;
|
||||
case LWS_STDOUT:
|
||||
/* quench POLLIN on STDOUT until MASTER got writeable */
|
||||
lws_rx_flow_control(args->stdwsi[LWS_STDOUT], 0);
|
||||
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI;
|
||||
/* when writing to MASTER would not block */
|
||||
lws_callback_on_writable(wsi);
|
||||
|
@ -385,6 +393,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
wsi->cgi->explicitly_chunked, (uint64_t)wsi->cgi->content_length);
|
||||
if (!wsi->cgi->explicitly_chunked && !wsi->cgi->content_length) {
|
||||
/* send terminating chunk */
|
||||
lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: looking to send terminating chunk\n");
|
||||
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END;
|
||||
lws_callback_on_writable(wsi);
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3);
|
||||
|
|
|
@ -3028,8 +3028,13 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
|
|||
return -1;
|
||||
}
|
||||
wsi->cgi->content_length_seen += m;
|
||||
} else {
|
||||
if (wsi->cgi_stdout_zero_length) {
|
||||
lwsl_debug("%s: failed to read anything: stdout is POLLHUP'd\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
wsi->cgi_stdout_zero_length = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3153,7 +3158,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
|
|||
|
||||
if (!cgi->content_length) {
|
||||
/*
|
||||
* well, if he sends chunked... give him 5s after the
|
||||
* well, if he sends chunked... give him 2s after the
|
||||
* cgi terminated to send buffered
|
||||
*/
|
||||
cgi->chunked_grace++;
|
||||
|
@ -3192,7 +3197,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
|
|||
/* we deferred killing him after reaping his PID */
|
||||
if (cgi->chunked_grace) {
|
||||
cgi->chunked_grace++;
|
||||
if (cgi->chunked_grace < 5)
|
||||
if (cgi->chunked_grace < 2)
|
||||
continue;
|
||||
goto finish_him;
|
||||
}
|
||||
|
@ -3214,7 +3219,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
|
|||
|
||||
if (!cgi->content_length) {
|
||||
/*
|
||||
* well, if he sends chunked... give him 5s after the
|
||||
* well, if he sends chunked... give him 2s after the
|
||||
* cgi terminated to send buffered
|
||||
*/
|
||||
cgi->chunked_grace++;
|
||||
|
|
|
@ -1671,6 +1671,7 @@ struct lws {
|
|||
unsigned int ipv6:1;
|
||||
unsigned int parent_carries_io:1;
|
||||
unsigned int parent_pending_cb_on_writable:1;
|
||||
unsigned int cgi_stdout_zero_length:1;
|
||||
|
||||
#if defined(LWS_WITH_ESP8266)
|
||||
unsigned int pending_send_completion:3;
|
||||
|
|
|
@ -902,7 +902,7 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
|
|||
wsi, buf, pt->ah_pool[n].rxpos,
|
||||
pt->ah_pool[n].rxlen,
|
||||
pt->ah_pool[n].pos);
|
||||
|
||||
buf[0] = '\0';
|
||||
m = 0;
|
||||
do {
|
||||
c = lws_token_to_string(m);
|
||||
|
@ -915,11 +915,12 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
|
|||
continue;
|
||||
}
|
||||
|
||||
lws_hdr_copy(wsi, buf, sizeof buf, m);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
if (lws_hdr_copy(wsi, buf, sizeof buf, m) > 0) {
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
lwsl_notice(" %s = %s\n",
|
||||
(const char *)c, buf);
|
||||
lwsl_notice(" %s = %s\n",
|
||||
(const char *)c, buf);
|
||||
}
|
||||
m++;
|
||||
} while (1);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue