Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- bool TrySend(connection *const c)
- {
- iovec iov[128];
- int fd = c->fd;
- sendv:
- auto it = c->respTail;
- int32_t r;
- bool haveCork;
- // If we have multiple requests(therefore multiple writev() calls are likely required)
- // and/or have say data to stream using sendfile(), then we need a cork
- // We don't use sendfile(), but that's how it'd work. Also, if we did need sendfile()
- // c could have been == nullptr.
- if (!it->next) // Fast path: single request(no pipelining)
- {
- r = writev(fd, it->iov + it->iovCur, it->iovCnt - it->iovCur);
- haveCork = false;
- }
- else
- {
- // Need to reduce writev() calls to absolute minimum
- uint8_t i{0};
- auto cur= it->iovCur;
- if (!SwitchNetwork::SetTCPCork(fd, 1))
- haveCork = true;
- do
- {
- if (cur >= 127)
- {
- // Patch, starting from it->iovCnt - 127. Reset it afterwards
- const auto cnt = it->iovCnt;
- for (decltype(it->iovCnt) i = it->iovCur - 127; i != cnt; ++i)
- {
- auto &v = it->iov[i];
- if (v.iov_len >= (1U<<30))
- {
- v.iov_len -= 1U<<30;
- v.iov_base = it->content->At((uint32_t)(uintptr_t)v.iov_base);
- }
- }
- cur = it->iovCur = 0;
- }
- const auto n = Min<uint8_t>(sizeof_array(iov) - i, it->iovCnt - cur);
- (void)memcpy(iov + i, it->iov + it->iovCur, n * sizeof(iovec));
- i+=n;
- cur = 0;
- } while (i != sizeof_array(iov) && (it = it->next));
- // Timings:
- // 5%: 4
- // 10%: 5
- // 25%: 5
- // 50%: 7
- // 75%: 8
- // 90%: 13
- // 95%: 19
- // 99%: 31
- r = writev(c->fd, iov, i);
- }
- if (unlikely(r == -1))
- {
- const auto err = errno;
- if (unlikely(haveCork))
- SwitchNetwork::SetTCPCork(fd, 0);
- if (err == EAGAIN)
- {
- if (!c->needIoAvail)
- {
- c->needIoAvail = true;
- (void)poller.SetDataAndEvents(c->fd, c, POLLIN|POLLOUT);
- }
- }
- else if (err != EINTR)
- {
- Shutdown(c, __LINE__);
- return false;
- }
- return true;
- }
- for (it = c->respTail; r >= it->iov[it->iovCur].iov_len; )
- {
- r-=it->iov[it->iovCur].iov_len;
- if (++(it->iovCur) == it->iovCnt)
- {
- auto *const n = it->next;
- PutResponse(it);
- it = c->respTail = n;
- if (!it)
- {
- if (unlikely(haveCork))
- SwitchNetwork::SetTCPCork(fd, 0);
- if (!c->keepAlive)
- {
- Shutdown(c, __LINE__);
- return false;
- }
- else
- {
- c->respHead = nullptr;
- if (c->needIoAvail)
- {
- (void)poller.SetDataAndEvents(c->fd, c, POLLIN);
- c->needIoAvail = false;
- }
- return true;
- }
- }
- }
- }
- auto &v = it->iov[it->iovCur];
- v.iov_len-=r;
- v.iov_base = (char *)v.iov_base + r;
- // We didn't get to send all the content out - because we are limited in terms of sizeof_array(iov)
- // so we need another short at it
- // Ideally, we 'd have a large enough iov[] anyway.
- //
- // However, this could have been because there is no more space left in the socket send buf
- // so it only accepted as much as it could. In this case, another call to writev() will
- // return EAGAIN.
- //
- // We could probably better deal with this (enter needIoAvail mode if not all scheduled
- // content was dispatched, instead of retrying).
- goto sendv;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement