Created
January 25, 2020 11:00
-
-
Save markpapadakis/2559599cdc4a6aa4160f6560ad5b0577 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
bool Microservice::tx(connection *const c) { | |
int fd = c->fd; | |
_l1: | |
auto it = c->out.head; | |
auto index = c->out.head_data_index; | |
if (!it->next) { | |
// fast-path | |
const auto size = it->size; | |
int r = writev(fd, it->data + c->out.head_data_index, size - index); | |
if (-1 == r) { | |
if (EINTR == errno) { | |
return true; | |
} else if (EAGAIN == errno) { | |
need_write_avail(c); | |
return true; | |
} else { | |
return shutdown(c, __LINE__); | |
} | |
} | |
if (r == it->remaining_bytes) { | |
// fast-path of fast-path | |
// all remaining data of this payload were written to the socket buffer successfully | |
// we also don't need to check if we have flushed the whole payload again | |
if (c->flags & (1u << unsigned(connection::Flags::close_on_flush))) { | |
return shutdown(c, __LINE__); | |
} | |
put_outgoing_payload(it); | |
did_flush_payload(c); | |
c->out.reset(); | |
if (did_flush(c)) { | |
goto _l1; | |
} | |
stop_need_write_avail(c); | |
try_make_inactive(c); | |
return true; | |
} | |
// we know that the whole payload wasn't transferred so our | |
// for() loop here is tighter; no need to check for payload transmission | |
it->remaining_bytes -= r; | |
// we won't need to check if we have written the whole thing into the socket buffer | |
for (;;) { | |
auto &span = it->data[index]; | |
if (r >= span.iov_len) { | |
++index; | |
r -= span.iov_len; | |
} else { | |
span.iov_base = static_cast<char *>(span.iov_base) + r; | |
span.iov_len -= r; | |
c->out.head_data_index = index; | |
break; | |
} | |
} | |
need_write_avail(c); | |
return true; | |
} | |
struct iovec iov[128], *out; | |
bool have_cork = false; | |
for (;;) { | |
// fill iov[] | |
{ | |
const auto n = it->size - index; | |
const auto end = iov + sizeof_array(iov); | |
auto p = it->next; | |
memcpy(iov, it->data + index, n * sizeof(iovec)); | |
out = iov + n; | |
while (p) { | |
const auto n = std::min<size_t>(std::distance(out, end), p->size); | |
memcpy(out, p->data, n * sizeof(iovec)); | |
out += n; | |
if (out == end) { | |
break; | |
} | |
p = p->next; | |
} | |
if (p && !have_cork) { | |
have_cork = true; | |
Switch::SetTCPCork(fd, 1); | |
} | |
} | |
const auto size = std::distance(iov, out); | |
int r = writev(fd, iov, size); | |
if (-1 == r) { | |
if (errno == EINTR) { | |
if (have_cork) { | |
Switch::SetTCPCork(fd, 0); | |
} | |
return true; | |
} else if (errno == EAGAIN) { | |
if (have_cork) { | |
Switch::SetTCPCork(fd, 0); | |
} | |
need_write_avail(c); | |
return true; | |
} else { | |
return shutdown(c, __LINE__); | |
} | |
} | |
for (;;) { | |
const auto bytes = it->remaining_bytes; | |
if (r >= bytes) { | |
auto next = it->next; | |
put_outgoing_payload(it); | |
did_flush_payload(c); | |
if (next == nullptr) { | |
if (have_cork) { | |
Switch::SetTCPCork(fd, 0); | |
} | |
if (c->flags & (1u << unsigned(connection::Flags::close_on_flush))) { | |
return shutdown(c, __LINE__); | |
} | |
c->out.reset(); | |
if (did_flush(c)) { | |
goto _l1; | |
} | |
stop_need_write_avail(c); | |
try_make_inactive(c); | |
return true; | |
} | |
r -= bytes; | |
it = next; | |
index = 0; | |
continue; | |
} | |
auto &span = it->data[index]; | |
it->remaining_bytes -= r; | |
span.iov_base = static_cast<char *>(span.iov_base) + r; | |
span.iov_len -= r; | |
break; | |
} | |
c->out.head_data_index = index; | |
c->out.head = it; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment