Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/uv-unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ typedef struct {
uv__io_t io_watcher; \
void* write_queue[2]; \
void* write_completed_queue[2]; \
int use_sendmmsg; \

#define UV_PIPE_PRIVATE_FIELDS \
const char* pipe_fname; /* strdup'ed */
Expand Down
9 changes: 8 additions & 1 deletion include/uv.h
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,14 @@ enum uv_udp_flags {
* (provided they all set the flag) but only the last one to bind will receive
* any traffic, in effect "stealing" the port from the previous listener.
*/
UV_UDP_REUSEADDR = 4
UV_UDP_REUSEADDR = 4,
/*
* Indicates that this socket should use sendmmsg() to process
* multiple messages at once. Only available on linux. It's 512
* because the flags you pass to uv_udp_init_ex hold the address
* family in the lower eight bits.
*/
UV_UDP_DISCORD_USE_SENDMMSG = 512
};

typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status);
Expand Down
77 changes: 72 additions & 5 deletions src/unix/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
int domain,
unsigned int flags);

#if defined(DISCORD_ENABLE_SENDMMSG)
#define DISCORD_SENDMMSG_BATCHSIZE 64
static void uv__udp_sendmmsg(uv_udp_t* handle);
#endif // DISCORD_ENABLE_SENDMMSG

void uv__udp_close(uv_udp_t* handle) {
uv__io_close(handle->loop, &handle->io_watcher);
Expand Down Expand Up @@ -139,7 +143,14 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
uv__udp_recvmsg(handle);

if (revents & UV__POLLOUT) {
uv__udp_sendmsg(handle);
#if defined(DISCORD_ENABLE_SENDMMSG)
if (handle->use_sendmmsg) {
uv__udp_sendmmsg(handle);
} else
#endif
{
uv__udp_sendmsg(handle);
}
uv__udp_run_completed(handle);
}
}
Expand Down Expand Up @@ -249,6 +260,58 @@ static void uv__udp_sendmsg(uv_udp_t* handle) {
}
}

#if defined(DISCORD_ENABLE_SENDMMSG)
static void uv__udp_sendmmsg(uv_udp_t* handle) {
QUEUE* node;
struct msghdr* hdr;
struct mmsghdr hdrs[DISCORD_SENDMMSG_BATCHSIZE];
uv_udp_send_t* reqs[DISCORD_SENDMMSG_BATCHSIZE];
ssize_t send_cnt;
ssize_t send_res;
ssize_t i;

do {
send_cnt = 0;

QUEUE_FOREACH(node, &handle->write_queue) {
assert(node != NULL);

reqs[send_cnt] = QUEUE_DATA(node, uv_udp_send_t, queue);
assert(reqs[send_cnt] != NULL);

memset(&hdrs[send_cnt], 0, sizeof hdrs[send_cnt]);
hdr = &hdrs[send_cnt].msg_hdr;
hdr->msg_name = &reqs[send_cnt]->addr;
hdr->msg_namelen = (reqs[send_cnt]->addr.ss_family == AF_INET6 ?
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
hdr->msg_iov = (struct iovec*) reqs[send_cnt]->bufs;
hdr->msg_iovlen = reqs[send_cnt]->nbufs;

if (++send_cnt == DISCORD_SENDMMSG_BATCHSIZE) {
break;
}
}

do {
send_res = sendmmsg(handle->io_watcher.fd, hdrs, send_cnt, 0);
} while (send_res == -1 && errno == EINTR);

if (send_res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
break;

send_cnt = (send_res == -1) ? send_cnt : send_res;

for (i = 0; i < send_cnt; ++i) {
reqs[i]->status = (send_res == -1 ? -errno : (ssize_t)hdrs[i].msg_len);

QUEUE_REMOVE(&reqs[i]->queue);
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &reqs[i]->queue);
uv__io_feed(handle->loop, &handle->io_watcher);
}
} while (!QUEUE_EMPTY(&handle->write_queue));
}
#endif // DISCORD_ENABLE_SENDMMSG


/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
* refinements for programs that use multicast.
Expand Down Expand Up @@ -386,6 +449,7 @@ int uv__udp_send(uv_udp_send_t* req,
uv_udp_send_cb send_cb) {
int err;
int empty_queue;
int immediate;

assert(nbufs > 0);

Expand Down Expand Up @@ -419,7 +483,12 @@ int uv__udp_send(uv_udp_send_t* req,
QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
uv__handle_start(handle);

if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) {
immediate = empty_queue && !(handle->flags & UV_UDP_PROCESSING);
#if defined(DISCORD_ENABLE_SENDMMSG)
immediate = immediate && !handle->use_sendmmsg;
#endif

if (immediate) {
uv__udp_sendmsg(handle);
} else {
uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT);
Expand Down Expand Up @@ -565,9 +634,6 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
return -EINVAL;

if (flags & ~0xFF)
return -EINVAL;

if (domain != AF_UNSPEC) {
err = uv__socket(domain, SOCK_DGRAM, 0);
if (err < 0)
Expand All @@ -582,6 +648,7 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
handle->recv_cb = NULL;
handle->send_queue_size = 0;
handle->send_queue_count = 0;
handle->use_sendmmsg = flags & UV_UDP_DISCORD_USE_SENDMMSG;
uv__io_init(&handle->io_watcher, uv__udp_io, fd);
QUEUE_INIT(&handle->write_queue);
QUEUE_INIT(&handle->write_completed_queue);
Expand Down