int lthread_sendfile(int fd, int s, off_t offset, size_t nbytes, struct sf_hdtr *hdtr) { off_t sbytes = 0; int ret = 0; struct lthread *lt = lthread_get_sched()->current_lthread; do { ret = sendfile(fd, s, offset, nbytes, hdtr, &sbytes, 0); if (ret == 0) return (0); if (sbytes) offset += sbytes; sbytes = 0; if (ret == -1 && EAGAIN == errno) _lthread_sched_event(lt, s, LT_EV_WRITE, 0); else if (ret == -1) return (-1); } while (1); }
ssize_t lthread_writev(int fd, struct iovec *iov, int iovcnt) { LTHREAD_SOCKET_CHECK_SCHED(writev(fd, iov, iovcnt)); ssize_t total = 0; int iov_index = 0; struct lthread *lt = lthread_get_sched()->current_lthread; do { _lthread_renice(lt); ssize_t n = writev(fd, iov + iov_index, iovcnt - iov_index); if (n > 0) { int i = 0; total += n; for (i = iov_index; i < iovcnt && n > 0; i++) { if (n < iov[i].iov_len) { iov[i].iov_base += n; iov[i].iov_len -= n; n = 0; } else { n -= iov[i].iov_len; iov_index++; } } } else if (-1 == n && EAGAIN == errno) { _lthread_sched_event(lt, fd, LT_EV_WRITE, 0); } else { return (n); } } while (iov_index < iovcnt); return (total); }
static inline int _lthread_connect(int fd, struct sockaddr *name, socklen_t namelen, uint64_t timeout) { LTHREAD_SOCKET_CHECK_SCHED(connect(fd, name, namelen)); int ret = 0; struct lthread *lt = lthread_get_sched()->current_lthread; while (1) { _lthread_renice(lt); ret = connect(fd, name, namelen); if (ret == 0) break; if (ret == -1 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS)) { _lthread_sched_event(lt, fd, LT_EV_WRITE, timeout); if (lt->state & BIT(LT_ST_EXPIRED)) { errno = ETIMEDOUT; return (-1); } continue; } else { break; } } return (ret); }
int lthread_connect(int fd, struct sockaddr *name, socklen_t namelen, uint64_t timeout) { int ret = 0; struct lthread *lt = lthread_get_sched()->current_lthread; while (1) { _lthread_renice(lt); ret = connect(fd, name, namelen); if (ret == 0) break; if (ret == -1 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == EALREADY)) { _lthread_sched_event(lt, fd, LT_EV_WRITE, timeout); if (lt->state & BIT(LT_ST_EXPIRED)) return (-2); continue; } else { break; } } return (ret); }
int lthread_poll(struct pollfd *fds, nfds_t nfds, int timeout) { int i = 0; if (timeout == 0) return poll(fds, nfds, 0); struct lthread *lt = lthread_get_sched()->current_lthread; /* schedule fd events, pass -1 to avoid yielding */ for (i = 0; i < nfds; i++) { if (fds[i].events & POLLIN) _lthread_sched_event(lt, fds[i].fd, LT_EV_READ, -1); else if (fds[i].events & POLLOUT) _lthread_sched_event(lt, fds[i].fd, LT_EV_WRITE, -1); else assert(0); } lt->ready_fds = 0; lt->fd_wait = -1; /* clear wait_read/write flags set by _lthread_sched_event */ lt->state &= CLEARBIT(LT_ST_WAIT_READ); lt->state &= CLEARBIT(LT_ST_WAIT_WRITE); /* we are waiting on multiple fd events */ lt->state |= BIT(LT_ST_WAIT_MULTI); lt->pollfds = fds; lt->nfds = nfds; /* go to sleep until one or more of the fds are ready or until we timeout */ _lthread_sched_sleep(lt, (uint64_t)timeout); lt->pollfds = NULL; lt->nfds = 0; lt->state &= CLEARBIT(LT_ST_WAIT_MULTI); if (lt->state & BIT(LT_ST_EXPIRED)) return (0); return (lt->ready_fds); }
int lthread_accept(int fd, struct sockaddr *addr, socklen_t *len) { LTHREAD_SOCKET_CHECK_SCHED(accept(fd, addr, len)); int ret = -1; struct lthread *lt = lthread_get_sched()->current_lthread; while (1) { _lthread_renice(lt); ret = accept(fd, addr, len); if (ret == -1 && (errno == ENFILE || errno == EWOULDBLOCK || errno == EMFILE)) { _lthread_sched_event(lt, fd, LT_EV_READ, 0); continue; } if (ret > 0) break; if (ret == -1 && errno == ECONNABORTED) { perror("Cannot accept connection"); continue; } if (ret == -1 && errno != EWOULDBLOCK) { fprintf(stderr, "Cannot accept connection on %d: %s\n", fd, strerror(errno)); return (-1); } } #ifndef __FreeBSD__ if ((fcntl(ret, F_SETFL, O_NONBLOCK)) == -1) { close(ret); perror("Failed to set socket properties"); return (-1); } #endif return (ret); }