Skip to content

Make fewer syscalls #117

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
43766ff
src/lib/socket.c: If SOCK_NONBLOCK and/or SOCK_CLOEXEC are defined; u…
daurnimator Nov 29, 2015
a4a408d
src/lib/socket.c: Only call 'SETFL' if 'GETFL' doesn't return what we…
daurnimator Nov 29, 2015
69d0851
src/lib/socket.c: Only call 'SETFD' if 'GETFD' doesn't return what we…
daurnimator Nov 29, 2015
0f1725a
src/socket.c: Pass SOCK_NONBLOCK and SOCK_CLOEXEC to socketpair if po…
daurnimator Nov 29, 2015
7ef0d96
src/lib/socket: ftype can fill in only what is unknown
daurnimator Nov 30, 2015
1105656
src/lib/socket.c: Skip so_ftype call when information already available
daurnimator Nov 29, 2015
50e5284
src/lib/socket.c: Assume natural state of newly created socket is all…
daurnimator Nov 30, 2015
060bd60
src/socket.c: reuseaddr can be turned off by default for sockets that…
daurnimator Nov 30, 2015
48e30e1
src/cqueues: Only call kevent() once
daurnimator Jan 6, 2016
68b13be
src/lib/socket: Have a single helper function for all types of shutdo…
daurnimator Nov 2, 2016
5206d2d
src/lib/socket: Remove unread 'shut' struct member
daurnimator Nov 2, 2016
70c05de
src/lib/socket: Use SHUT_RDWR if wanting to shutdown both read and write
daurnimator Nov 2, 2016
080853c
Merge branch 'master' into less-syscalls
daurnimator Nov 3, 2016
dbd0169
Merge branch 'shutdown-rdwr' into less-syscalls
daurnimator Nov 3, 2016
b0413a3
Merge branch '168-fd-leak-in-lso_accept' into less-syscalls
daurnimator Nov 3, 2016
3317f1a
add new so_accept_socket function that accepts() and returns a full s…
daurnimator Nov 3, 2016
1890117
src/cqueues.c: Only move threads to pending queue when their events o…
daurnimator Jun 2, 2018
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
58 changes: 31 additions & 27 deletions src/cqueues.c
Original file line number Diff line number Diff line change
Expand Up @@ -629,44 +629,48 @@ static int kpoll_ctl(struct kpoll *kp, int fd, short *state, short events, void

return 0;
#elif ENABLE_KQUEUE
struct kevent event;

if (*state == events)
return 0;
struct kevent changelist[2];
int nchanges = 0;

if (events & POLLIN) {
if (!(*state & POLLIN)) {
KP_SET(&event, fd, EVFILT_READ, EV_ADD, 0, 0, udata);
KP_SET(changelist+nchanges, fd, EVFILT_READ, EV_ADD, 0, 0, udata);
nchanges++;
}
} else if (*state & POLLIN) {
KP_SET(changelist+nchanges, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
nchanges++;
}

if (0 != kevent(kp->fd, &event, 1, NULL, 0, &(struct timespec){ 0, 0 }))
return errno;
if (events & POLLOUT) {
if (!(*state & POLLOUT)) {
KP_SET(changelist+nchanges, fd, EVFILT_WRITE, EV_ADD, 0, 0, udata);
nchanges++;
}
} else if (*state & POLLOUT) {
KP_SET(changelist+nchanges, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
nchanges++;
}

if (0 == nchanges)
return 0;

if (0 != kevent(kp->fd, changelist, nchanges, NULL, 0, &(struct timespec){ 0, 0 }))
return errno;

if (events & POLLIN) {
if (!(*state & POLLIN)) {
*state |= POLLIN;
}
} else if (*state & POLLIN) {
KP_SET(&event, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);

if (0 != kevent(kp->fd, &event, 1, NULL, 0, &(struct timespec){ 0, 0 }))
return errno;

*state &= ~POLLIN;
}

if (events & POLLOUT) {
if (!(*state & POLLOUT)) {
KP_SET(&event, fd, EVFILT_WRITE, EV_ADD, 0, 0, udata);

if (0 != kevent(kp->fd, &event, 1, NULL, 0, &(struct timespec){ 0, 0 }))
return errno;

*state |= POLLOUT;
}
} else if (*state & POLLOUT) {
KP_SET(&event, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);

if (0 != kevent(kp->fd, &event, 1, NULL, 0, &(struct timespec){ 0, 0 }))
return errno;

*state &= ~POLLOUT;
}

Expand Down Expand Up @@ -1528,14 +1532,14 @@ static cqs_error_t fileno_signal(struct cqueue *Q, struct fileno *fileno, short
int error = 0, _error;

LIST_FOREACH(event, &fileno->events, fle) {
/* XXX: If POLLPRI should we always mark as pending? */
if (event->events & events)
if (event->events & events) {
event->pending = 1;

thread_move(event->thread, &Q->thread.pending);
thread_move(event->thread, &Q->thread.pending);

if ((_error = cqueue_tryalert(Q)))
error = _error;
if ((_error = cqueue_tryalert(Q)))
error = _error;
}
}

return error;
Expand Down
172 changes: 113 additions & 59 deletions src/lib/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -711,34 +711,42 @@ static so_error_t so_ftype(int fd, mode_t *mode, int *domain, int *type, int *pr
struct stat st;
int error;

if (0 != fstat(fd, &st))
return errno;

*mode = S_IFMT & st.st_mode;
if (*mode == 0) {
if (0 != fstat(fd, &st))
return errno;
*mode = S_IFMT & st.st_mode;
}

if (!S_ISSOCK(*mode))
return 0;

if (*domain == 0) {
#if defined SO_DOMAIN
if (0 != getsockopt(fd, SOL_SOCKET, SO_DOMAIN, domain, &(socklen_t){ sizeof *domain })) {
if (errno != ENOPROTOOPT)
return errno;
if (0 != getsockopt(fd, SOL_SOCKET, SO_DOMAIN, domain, &(socklen_t){ sizeof *domain })) {
if (errno != ENOPROTOOPT)
return errno;

if ((error = so_ffamily(fd, domain)))
return error;
}
#else
if ((error = so_ffamily(fd, domain)))
return error;
}
#else
if ((error = so_ffamily(fd, domain)))
return error;
#endif
}

if (0 != getsockopt(fd, SOL_SOCKET, SO_TYPE, type, &(socklen_t){ sizeof *type }))
return errno;
if (*type == 0) {
if (0 != getsockopt(fd, SOL_SOCKET, SO_TYPE, type, &(socklen_t){ sizeof *type }))
return errno;
}

#if defined SO_PROTOCOL
if (0 != getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, protocol, &(socklen_t){ sizeof *protocol })) {
if (errno != ENOPROTOOPT)
return errno;
if (*protocol == 0) {
if (0 != getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, protocol, &(socklen_t){ sizeof *protocol })) {
if (errno != ENOPROTOOPT)
return errno;
}
}
#else
(void)protocol;
Expand All @@ -754,19 +762,28 @@ static int so_type2mask(mode_t, int, int, int);
int so_socket(int domain, int type, const struct so_options *opts, int *_error) {
int error, fd, flags, mask, need;

#if defined SOCK_CLOEXEC
if (-1 == (fd = socket(domain, type|SOCK_CLOEXEC, 0)))
goto syerr;
#else
if (-1 == (fd = socket(domain, type, 0)))
goto syerr;
#endif

flags = so_opts2flags(opts, &mask);
mask &= so_type2mask(S_IFSOCK, domain, type, 0);
need = ~(SO_F_NODELAY|SO_F_NOPUSH|SO_F_NOSIGPIPE|SO_F_OOBINLINE);

if ((error = so_setfl(fd, flags, mask, need)))
#if defined SOCK_NONBLOCK
if (flags & SO_F_NONBLOCK) {
type |= SOCK_NONBLOCK;
}
mask &= ~SO_F_NONBLOCK;
#endif
#if defined SOCK_CLOEXEC
if (flags & SO_F_CLOEXEC) {
type |= SOCK_CLOEXEC;
}
mask &= ~SO_F_CLOEXEC;
#endif

if (-1 == (fd = socket(domain, type, 0)))
goto syerr;

/* assumes natural state of socket is all flags off */
if ((error = so_setfl(fd, flags, mask&flags, need)))
goto error;

return fd;
Expand Down Expand Up @@ -849,7 +866,14 @@ int so_cloexec(int fd, _Bool cloexec) {
#if _WIN32
return 0;
#else
if (-1 == fcntl(fd, F_SETFD, cloexec))
int flags, newflags;

if (-1 == (flags = fcntl(fd, F_GETFD)))
return so_syerr();

newflags = (cloexec ? ~0 : ~FD_CLOEXEC) & (flags | FD_CLOEXEC);

if (flags != newflags && (-1 == fcntl(fd, F_SETFD, flags)))
return so_syerr();

return 0;
Expand All @@ -858,10 +882,14 @@ int so_cloexec(int fd, _Bool cloexec) {


int so_nonblock(int fd, _Bool nonblock) {
int flags, mask = (nonblock)? ~0 : (~O_NONBLOCK);
int flags, newflags;

if (-1 == (flags = fcntl(fd, F_GETFL))
|| -1 == fcntl(fd, F_SETFL, mask & (flags | O_NONBLOCK)))
if (-1 == (flags = fcntl(fd, F_GETFL)))
return so_syerr();

newflags = (nonblock ? ~0 : ~O_NONBLOCK) & (flags | O_NONBLOCK);

if (flags != newflags && (-1 == fcntl(fd, F_SETFL, newflags)))
return so_syerr();

return 0;
Expand Down Expand Up @@ -941,11 +969,15 @@ int so_nopush(int fd, _Bool nopush) {

int so_nosigpipe(int fd, _Bool nosigpipe) {
#if defined O_NOSIGPIPE
int flags, mask = (nosigpipe)? ~0 : (~O_NOSIGPIPE);
int flags, newflags;

if (-1 == (flags = fcntl(fd, F_GETFL))
|| -1 == fcntl(fd, F_SETFL, mask & (flags | O_NOSIGPIPE)))
return errno;
if (-1 == (flags = fcntl(fd, F_GETFL)))
return so_syerr();

newflags = (nosigpipe ? ~0 : ~O_NOSIGPIPE) & (flags | O_NOSIGPIPE);

if (flags != newflags && (-1 == fcntl(fd, F_SETFL, newflags)))
return so_syerr();

return 0;
#elif defined F_SETNOSIGPIPE
Expand Down Expand Up @@ -1252,11 +1284,6 @@ struct socket {

struct so_stat st;

struct {
_Bool rd;
_Bool wr;
} shut;

struct addrinfo *host;

short events;
Expand Down Expand Up @@ -1410,6 +1437,10 @@ static int so_socket_(struct socket *so) {
if (-1 == (so->fd = so_socket(so->host->ai_family, so->host->ai_socktype, &so->opts, &error)))
return error;

so->mode = S_IFSOCK;
so->domain = so->host->ai_family;
so->type = so->host->ai_socktype;
so->protocol = 0;
if ((error = so_ftype(so->fd, &so->mode, &so->domain, &so->type, &so->protocol)))
return error;

Expand Down Expand Up @@ -1616,26 +1647,15 @@ static int so_rstlowat_(struct socket *so) {
} /* so_rstlowat_() */


static int so_shutwr_(struct socket *so) {
if (so->fd != -1 && 0 != shutdown(so->fd, SHUT_WR))
return so_soerr();

so->shut.wr = 1;
so->st.sent.eof = 1;

return 0;
} /* so_shutwr_() */


static _Bool so_isconn(int fd) {
struct sockaddr sa;
socklen_t slen = sizeof sa;

return 0 == getpeername(fd, &sa, &slen) || so_soerr() != SO_ENOTCONN;
} /* so_isconn() */

static int so_shutrd_(struct socket *so) {
if (so->fd != -1 && 0 != shutdown(so->fd, SHUT_RD)) {
static int so_shutdown_(struct socket *so, int how) {
if (so->fd != -1 && 0 != shutdown(so->fd, how)) {
/*
* NOTE: OS X will fail with ENOTCONN if the requested
* SHUT_RD or SHUT_WR flag is already set, including if the
Expand All @@ -1648,7 +1668,9 @@ static int so_shutrd_(struct socket *so) {
return SO_ENOTCONN;
}

so->shut.rd = 1;
if (how == SHUT_WR || how == SHUT_RDWR) {
so->st.sent.eof = 1;
}

return 0;
} /* so_shutrd_() */
Expand Down Expand Up @@ -1755,17 +1777,11 @@ static int so_exec(struct socket *so) {

goto exec;
case SO_S_SHUTWR:
if ((error = so_shutwr_(so)))
goto error;

so->done |= state;

goto exec;
case SO_S_SHUTRD:
if ((error = so_shutrd_(so)))
if ((error = so_shutdown_(so, (so->todo & SO_S_SHUTRD)?(so->todo & SO_S_SHUTWR)?SHUT_RDWR:SHUT_RD:SHUT_WR)))
goto error;

so->done |= state;
so->done |= (so->todo & (SO_S_SHUTWR|SO_S_SHUTRD));

goto exec;
} /* so_exec() */
Expand Down Expand Up @@ -2124,6 +2140,44 @@ int so_accept(struct socket *so, struct sockaddr *saddr, socklen_t *slen, int *e
} /* so_accept() */


struct socket *so_accept_socket(struct socket *accept_so, const struct so_options *opts, int *error_) {
union sockaddr_any saddr;
struct socket *so;
int flags, mask, need, error;

if (!(so = so_make(opts, &error)))
goto error;

if (-1 == (so->fd = so_accept(accept_so, &saddr.sa, &(socklen_t){ sizeof saddr }, &error)))
goto error;

so->mode = S_IFSOCK;
so->domain = saddr.sa.sa_family;

if ((error = so_ftype(so->fd, &so->mode, &so->domain, &so->type, &so->protocol)))
goto error;

flags = so_opts2flags(opts, &mask);
mask &= so_type2mask(so->mode, so->domain, so->type, so->protocol);
need = ~(SO_F_NODELAY|SO_F_NOPUSH|SO_F_NOSIGPIPE|SO_F_OOBINLINE);
/* we accept with CLOEXEC set */
mask &= ~SO_F_CLOEXEC;
/* reuseaddr doesn't matter, the socket is already bound */
mask &= ~SO_F_REUSEADDR;

if ((error = so_rstfl(so->fd, &so->flags, flags, mask, need)))
goto error;

return so;
error:
so_close(so);

*error_ = error;

return 0;
} /* so_accept_socket() */


static void so_resetssl(struct socket *so) {
ssl_discard(&so->ssl.ctx);
so->ssl.state = 0;
Expand Down
2 changes: 2 additions & 0 deletions src/lib/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,8 @@ int so_listen(struct socket *);

int so_accept(struct socket *, struct sockaddr *, socklen_t *, int *);

struct socket *so_accept_socket(struct socket *, const struct so_options *, int *);

struct so_starttls {
SSL_METHOD *method;
SSL_CTX *context;
Expand Down
Loading