int private_vstream_fflush(ACL_VSTREAM *stream) { unsigned char *ptr; int n; acl_assert(stream); if (stream->wbuf == NULL || stream->wbuf_dlen == 0) return 0; ptr = stream->wbuf; while (stream->wbuf_dlen > 0) { n = __vstream_sys_write(stream, ptr, (int) stream->wbuf_dlen); if (n <= 0) { if (acl_last_error() == ACL_EINTR || acl_last_error() == ACL_EAGAIN) { continue; } return (ACL_VSTREAM_EOF); } stream->wbuf_dlen -= n; ptr += n; } acl_assert(stream->wbuf_dlen >= 0); return (int) (ptr - stream->wbuf); }
bool queue_file::move_file(const char* queueName, const char* extName) { acl::string buf(256); bool once_again = false; while (true) { buf.clear(); buf << m_home << PATH_SEP << queueName << PATH_SEP << m_queueSub << PATH_SEP << m_partName << "." << extName; #ifdef WIN32 // 在win32下必须先关闭文件句柄 this->close(); #endif if (rename(m_filePath.c_str(), buf.c_str()) == 0) break; // 如果返回错误原因是目标路径不存在,则尝试创建目录结构 if (once_again || acl_last_error() != ENOENT) { logger_error("move from %s to %s error(%s), errno: %d, %d", m_filePath.c_str(), buf.c_str(), acl_last_serror(), acl_last_error(), ENOENT); return (false); } // 设置重试标志位 once_again = true; buf.clear(); buf << m_home << PATH_SEP << queueName << PATH_SEP << m_queueSub; // 创建队列目录 if (acl_make_dirs(buf.c_str(), 0700) == -1) { logger_error("mkdir: %s error(%s)", buf.c_str(), acl_last_serror()); return false; } } #ifdef WIN32 // win32 下需要重新再打开 return (open(m_home, queueName, m_queueSub, m_partName, extName)); #else if (m_queueName != queueName) ACL_SAFE_STRNCPY(m_queueName, queueName, sizeof(m_queueName)); if (m_extName != extName) ACL_SAFE_STRNCPY(m_extName, extName, sizeof(m_extName)); m_filePath.clear(); m_filePath << m_home << PATH_SEP << m_queueName << PATH_SEP << m_queueSub << PATH_SEP << m_partName << "." << m_extName; #endif return (true); }
static void enable_listen(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) { const char *myname = "enable_listen"; ACL_SOCKET sock; DWORD ReceiveLen = 0; sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED); memset(&fdp->event_read->overlapped, 0, sizeof(fdp->event_read->overlapped)); fdp->stream->type |= ACL_VSTREAM_TYPE_LISTEN_IOCP; fdp->stream->iocp_sock = sock; if (AcceptEx(ACL_VSTREAM_SOCK(fdp->stream), sock, fdp->event_read->myAddrBlock, 0, ACCEPT_ADDRESS_LENGTH, ACCEPT_ADDRESS_LENGTH, &ReceiveLen, &fdp->event_read->overlapped) == FALSE && acl_last_error() !=ERROR_IO_PENDING) { acl_msg_warn("%s(%d): AcceptEx error(%s)", myname, __LINE__, acl_last_serror()); } }
int socket_stream::sock_read(void *ctx, unsigned char *buf, size_t len) { #ifdef HAS_POLARSSL socket_stream* cli = (socket_stream*) ctx; ACL_VSTREAM* stream = cli->get_vstream(); acl_assert(stream); int ret, timeout = 120; if ((ret = acl_socket_read(ACL_VSTREAM_SOCK(stream), buf, len, timeout, stream, NULL)) < 0) { int errnum = acl_last_error(); if (ret == ACL_EINTR || ret == ACL_EWOULDBLOCK #if ACL_EWOULDBLOCK != ACL_EAGAIN || ret == ACL_EAGAIN #endif ) return POLARSSL_ERR_NET_WANT_READ; else if (errnum == ACL_ECONNRESET || errno == EPIPE) return POLARSSL_ERR_NET_CONN_RESET; else return POLARSSL_ERR_NET_RECV_FAILED; } return ret; #else (void) ctx; (void) buf; (void) len; return -1; #endif }
int polarssl_io::sock_read(void *ctx, unsigned char *buf, size_t len) { #ifdef HAS_POLARSSL polarssl_io* io = (polarssl_io*) ctx; int ret, timeout = 120; ACL_VSTREAM* vs = io->stream_->get_vstream(); ACL_SOCKET fd = ACL_VSTREAM_SOCK(vs); ret = acl_socket_read(fd, buf, len, timeout, vs, NULL); if (ret < 0) { int errnum = acl_last_error(); if (ret == ACL_EINTR || ret == ACL_EWOULDBLOCK #if ACL_EWOULDBLOCK != ACL_EAGAIN || ret == ACL_EAGAIN #endif ) return POLARSSL_ERR_NET_WANT_READ; else if (errnum == ACL_ECONNRESET || errno == EPIPE) return POLARSSL_ERR_NET_CONN_RESET; else return POLARSSL_ERR_NET_RECV_FAILED; } return ret; #else (void) ctx; (void) buf; (void) len; logger_error("HAS_POLARSSL not defined!"); return -1; #endif }
int acl_set_eugid(uid_t euid, gid_t egid) { int saved_error = acl_last_error(); char tbuf[256]; if (geteuid() != 0 && seteuid(0)) { acl_msg_error("set_eugid: seteuid(0): %s", acl_last_strerror(tbuf, sizeof(tbuf))); return -1; } if (setegid(egid) < 0) { acl_msg_error("set_eugid: setegid(%ld): %s", (long) egid, acl_last_strerror(tbuf, sizeof(tbuf))); return -1; } if (setgroups(1, &egid) < 0) { acl_msg_error("set_eugid: setgroups(%ld): %s", (long) egid, acl_last_strerror(tbuf, sizeof(tbuf))); return -1; } if (euid != 0 && seteuid(euid) < 0) { acl_msg_error("set_eugid: seteuid(%ld): %s", (long) euid, acl_last_strerror(tbuf, sizeof(tbuf))); return -1; } if (acl_msg_verbose) acl_msg_info("set_eugid: euid %ld egid %ld", (long) euid, (long) egid); acl_set_error(saved_error); return 0; }
int ssl_aio_stream::__ssl_send(ACL_SOCKET, const void *buf, size_t len, int, ACL_VSTREAM*, void *ctx) { #ifdef HAS_POLARSSL ssl_aio_stream* cli = (ssl_aio_stream*) ctx; int ret; while ((ret = ::ssl_write((ssl_context*) cli->ssl_, (unsigned char*) buf, len)) <= 0) { if (ret == POLARSSL_ERR_NET_WANT_READ || ret == POLARSSL_ERR_NET_WANT_WRITE) { if (acl_last_error() != ACL_EWOULDBLOCK) acl_set_error(ACL_EWOULDBLOCK); } return ACL_VSTREAM_EOF; } return ret; #else (void) buf; (void) len; (void) ctx; return -1; #endif }
static int poll_write_wait(ACL_SOCKET fd, int timeout) { const char *myname = "poll_write_wait"; struct pollfd fds; int delay = timeout * 1000; fds.events = POLLOUT | POLLHUP | POLLERR; fds.fd = fd; for (;;) { switch (poll(&fds, 1, delay)) { case -1: if (acl_last_error() != ACL_EINTR) { char tbuf[256]; acl_msg_error("%s: poll error(%s)", myname, acl_last_strerror(tbuf, sizeof(tbuf))); return (-1); } continue; case 0: acl_set_error(ACL_ETIMEDOUT); return (-1); default: if ((fds.revents & (POLLHUP | POLLERR)) || !(fds.revents & POLLOUT)) { return (-1); } return (0); } } }
int acl_readable(ACL_SOCKET fd) { const char *myname = "poll_read_wait"; struct pollfd fds; int delay = 0; fds.events = POLLIN; fds.fd = fd; acl_set_error(0); for (;;) { switch (poll(&fds, 1, delay)) { case -1: if (acl_last_error() == ACL_EINTR) continue; acl_msg_error("%s(%d), %s: poll error(%s), fd: %d", __FILE__, __LINE__, myname, acl_last_serror(), (int) fd); return -1; case 0: return 0; default: if ((fds.revents & POLLIN)) { return 1; } else if (fds.revents & (POLLHUP | POLLERR)) { return 1; } else { return 0; } } } }
acl_off_t acl_lseek(ACL_FILE_HANDLE fh, acl_off_t offset, int whence) { const char *myname = "acl_lseek"; LARGE_INTEGER li; DWORD method; if (whence == SEEK_CUR) method = FILE_CURRENT; else if (whence == SEEK_SET) method = FILE_BEGIN; else if (whence == SEEK_END) method = FILE_END; else { acl_msg_error("%s(%d): invalid whence(%d)", myname, __LINE__, whence); return -1; } li.QuadPart = offset; li.LowPart = SetFilePointer(fh, li.LowPart, &li.HighPart, method); if (li.LowPart == 0xFFFFFFFF && acl_last_error() != NO_ERROR) { li.QuadPart = -1; } return li.QuadPart; }
int acl_sane_socketpair(int domain, int type, int protocol, ACL_SOCKET result[2]) { static int socketpair_ok_errors[] = { EINTR, 0, }; int count; int err; int ret; /* * Solaris socketpair() can fail with EINTR. */ while ((ret = socketpair(domain, type, protocol, result)) < 0) { for (count = 0; /* void */ ; count++) { if ((err = socketpair_ok_errors[count]) == 0) return (ret); if (acl_last_error() == err) { char tbuf[256]; acl_msg_warn("socketpair: %s (trying again)", acl_last_strerror(tbuf, sizeof(tbuf))); sleep(1); break; } } } return (ret); }
int ssl_aio_stream::__sock_send(void *ctx, const unsigned char *buf, size_t len) { #ifdef HAS_POLARSSL ssl_aio_stream* cli = (ssl_aio_stream*) ctx; ACL_VSTREAM* stream = cli->get_vstream(); acl_assert(stream); int ret, errnum; if ((ret = acl_socket_write(ACL_VSTREAM_SOCK(stream), buf, len, 0, stream, NULL)) < 0) { errnum = acl_last_error(); if (errnum == ACL_EINTR) return POLARSSL_ERR_NET_WANT_WRITE; else if (errnum == ACL_EWOULDBLOCK) return POLARSSL_ERR_NET_WANT_WRITE; #if ACL_EWOULDBLOCK != ACL_EAGAIN else if (errnum == ACL_EAGAIN) return POLARSSL_ERR_NET_WANT_WRITE; #endif else if (errnum == ACL_ECONNRESET || errno == EPIPE) return POLARSSL_ERR_NET_CONN_RESET; else return POLARSSL_ERR_NET_SEND_FAILED; } return ret; #else (void) ctx; (void) buf; (void) len; return -1; #endif }
int acl_timed_connect(ACL_SOCKET sock, const struct sockaddr * sa, socklen_t len, int timeout) { int err; /* * Sanity check. Just like with timed_wait(), the timeout must be a * positive number. */ if (timeout < 0) acl_msg_panic("timed_connect: bad timeout: %d", timeout); /* * Start the connection, and handle all possible results. */ if (acl_sane_connect(sock, sa, len) == 0) return (0); errno = acl_last_error(); #ifdef ACL_UNIX if (errno != ACL_EINPROGRESS) return (-1); #elif defined(ACL_WINDOWS) if (errno != ACL_EINPROGRESS && errno != ACL_EWOULDBLOCK) return (-1); #endif /* * A connection is in progress. Wait for a limited amount of time for * something to happen. If nothing happens, report an error. */ if (acl_write_wait(sock, timeout) < 0) return (-1); /* * Something happened. Some Solaris 2 versions have getsockopt() itself * return the error, instead of returning it via the parameter list. */ len = sizeof(err); if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len) < 0) { #ifdef SUNOS5 /* * Solaris 2.4's socket emulation doesn't allow you * to determine the error from a failed non-blocking * connect and just returns EPIPE. Create a fake * error message for connect. -- [email protected] */ if (errno == EPIPE) acl_set_error(ACL_ENOTCONN); #endif return (-1); } if (err != 0) { acl_set_error(err); return (-1); } else return (0); }
int acl_read_wait(ACL_SOCKET fd, int timeout) { const char *myname = "acl_read_wait"; struct pollfd fds; int delay = timeout * 1000; fds.events = POLLIN | POLLHUP | POLLERR; fds.fd = fd; acl_set_error(0); for (;;) { switch (poll(&fds, 1, delay)) { case -1: if (acl_last_error() == ACL_EINTR) continue; acl_msg_error("%s(%d), %s: poll error(%s), fd: %d", __FILE__, __LINE__, myname, acl_last_serror(), (int) fd); return -1; case 0: acl_set_error(ACL_ETIMEDOUT); return -1; default: if (fds.revents & (POLLHUP | POLLERR)) return -1; else if ((fds.revents & POLLIN)) return 0; else return -1; } } }
int acl_readable(ACL_SOCKET fd) { const char *myname = "acl_readable"; struct timeval tv; fd_set rfds, xfds; int errnum; /* * Sanity checks. */ if ((unsigned) fd >= FD_SETSIZE) acl_msg_fatal("%s(%d), %s: fd %d does not fit in " "FD_SETSIZE: %d", __FILE__, __LINE__, myname, (int) fd, FD_SETSIZE); /* * Initialize. */ FD_ZERO(&rfds); FD_SET(fd, &rfds); FD_ZERO(&xfds); FD_SET(fd, &xfds); tv.tv_sec = 0; tv.tv_usec = 0; acl_set_error(0); /* * Loop until we have an authoritative answer. */ for (;;) { switch (select((int) fd + 1, &rfds, (fd_set *) 0, &xfds, &tv)) { case -1: errnum = acl_last_error(); #ifdef ACL_WINDOWS if (errnum == WSAEINPROGRESS || errnum == WSAEWOULDBLOCK || errnum == ACL_EINTR) { continue; } #else if (errnum == ACL_EINTR) continue; #endif acl_msg_error("%s(%d), %s: select error(%s), fd: %d", __FILE__, __LINE__, myname, acl_last_serror(), (int) fd); return -1; case 0: return 0; default: return FD_ISSET(fd, &rfds); } } }
int acl_read_wait(ACL_SOCKET fd, int timeout) { const char *myname = "acl_read_wait"; struct pollfd fds; int delay = timeout * 1000; time_t begin; fds.events = POLLIN | POLLHUP | POLLERR; fds.fd = fd; acl_set_error(0); for (;;) { time(&begin); switch (poll(&fds, 1, delay)) { case -1: if (acl_last_error() == ACL_EINTR) continue; acl_msg_error("%s(%d), %s: poll error(%s), fd: %d", __FILE__, __LINE__, myname, acl_last_serror(), (int) fd); return -1; case 0: acl_msg_warn("%s(%d), %s: poll timeout: %s, fd: %d, " "delay: %d, spent: %ld", __FILE__, __LINE__, myname, acl_last_serror(), fd, delay, (long) (time(NULL) - begin)); acl_set_error(ACL_ETIMEDOUT); return -1; default: if (fds.revents & (POLLHUP | POLLERR)) { acl_msg_warn("%s(%d), %s: poll error: %s, " "fd: %d, delay: %d, spent: %ld", __FILE__, __LINE__, myname, acl_last_serror(), fd, delay, (long) (time(NULL) - begin)); return -1; } else if ((fds.revents & POLLIN)) return 0; else { acl_msg_warn("%s(%d), %s: poll error: %s, " "fd: %d, delay: %d, spent: %ld", __FILE__, __LINE__, myname, acl_last_serror(), fd, delay, (long) (time(NULL) - begin)); return -1; } } } }
static int __loop_writen(ACL_VSTREAM *stream, const void *vptr, size_t dlen) { const unsigned char *ptr; int n; ptr = (const unsigned char *) vptr; while (dlen > 0) { n = __vstream_sys_write(stream, ptr, (int) dlen); if (n <= 0) { if (acl_last_error() == ACL_EINTR || acl_last_error() == ACL_EAGAIN) { continue; } return (ACL_VSTREAM_EOF); } dlen -= n; ptr += n; } return (int) (ptr - (const unsigned char *) vptr); }
static int __read_wait(ACL_SOCKET fd, int timeout) { fd_set read_fds; fd_set except_fds; struct timeval tv; struct timeval *tp; #ifdef ACL_UNIX /* * Sanity checks. */ acl_assert(FD_SETSIZE > (unsigned) fd); #endif /* * Use select() so we do not depend on alarm() and on signal() handlers. * Restart the select when interrupted by some signal. Some select() * implementations reduce the time to wait when interrupted, which is * exactly what we want. */ FD_ZERO(&read_fds); FD_SET(fd, &read_fds); FD_ZERO(&except_fds); FD_SET(fd, &except_fds); if (timeout >= 0) { tv.tv_usec = 0; tv.tv_sec = timeout; tp = &tv; } else tp = 0; for (;;) { switch (select((int) fd + 1, &read_fds, (fd_set *) 0, &except_fds, tp)) { case -1: if (acl_last_error() != ACL_EINTR) return -1; continue; case 0: acl_set_error(ACL_ETIMEDOUT); return (-1); default: return (0); } } }
const char *acl_last_serror(void) { char *buf; int error = acl_last_error(); static int __buf_size = 4096; (void) acl_pthread_once(&once_control, thread_buf_init); buf = acl_pthread_getspecific(__errbuf_key); if (buf == NULL) { buf = acl_mymalloc(__buf_size); acl_pthread_setspecific(__errbuf_key, buf); if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) { __main_buf = buf; atexit(main_free_buf); } } return acl_strerror(error, buf, __buf_size); }
static void enable_write(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) { const char *myname = "enable_write"; ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(fdp->stream); DWORD sendBytes; fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_WRITE; fdp->flag |= EVENT_FDTABLE_FLAG_WRITE; if (fdp->h_iocp == NULL) { fdp->h_iocp = CreateIoCompletionPort((HANDLE) sockfd, ev->h_iocp, (DWORD) fdp, 0); if (fdp->h_iocp != ev->h_iocp) acl_msg_fatal("%s(%d): CreateIoCompletionPort error(%s)", myname, __LINE__, acl_last_serror()); fdp->flag |= EVENT_FDTABLE_FLAG_IOCP; } if (fdp->event_write == NULL) { fdp->event_write = (IOCP_EVENT*) acl_mymalloc(sizeof(IOCP_EVENT)); fdp->event_write->fdp = fdp; } else if (fdp->event_write->type == IOCP_EVENT_WRITE) { return; } fdp->event_write->type = IOCP_EVENT_WRITE; if ((fdp->stream->flag & ACL_VSTREAM_FLAG_CONNECTING)) { enable_connect(ev, fdp); fdp->stream->flag &= ~ACL_VSTREAM_FLAG_CONNECTING; return; } memset(&fdp->event_write->overlapped, 0, sizeof(fdp->event_write->overlapped)); if (WriteFile((HANDLE) sockfd, NULL, 0, &sendBytes, &fdp->event_write->overlapped) == FALSE && acl_last_error() != ERROR_IO_PENDING) { acl_msg_warn("%s(%d): WriteFile error(%s), sockfd(%d)", myname, __LINE__, acl_last_serror(), sockfd); } }
void acl_doze(unsigned delay) { #ifdef ACL_UNIX struct timeval tv; tv.tv_sec = delay / 1000; tv.tv_usec = (delay - tv.tv_sec * 1000) * 1000; while (select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv) < 0) if (acl_last_error() != ACL_EINTR) { char tbuf[256]; acl_msg_fatal("doze: select: %s", acl_last_strerror(tbuf, sizeof(tbuf))); } #elif defined(WIN32) Sleep(delay); #else #error "unknown OS" #endif }
static void enable_read(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) { const char *myname = "enable_read"; ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(fdp->stream); DWORD recvBytes; fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_READ; fdp->flag |= EVENT_FDTABLE_FLAG_READ; if (fdp->h_iocp == NULL) { fdp->h_iocp = CreateIoCompletionPort((HANDLE) sockfd, ev->h_iocp, (DWORD) fdp, 0); if (fdp->h_iocp != ev->h_iocp) acl_msg_fatal("%s(%d): CreateIoCompletionPort error(%s)", myname, __LINE__, acl_last_serror()); fdp->flag |= EVENT_FDTABLE_FLAG_IOCP; } if (fdp->event_read == NULL) { fdp->event_read = (IOCP_EVENT*) acl_mymalloc(sizeof(IOCP_EVENT)); fdp->event_read->fdp = fdp; } else if (fdp->event_read->type == IOCP_EVENT_READ) { return; } fdp->event_read->type = IOCP_EVENT_READ; if ((fdp->stream->type & ACL_VSTREAM_TYPE_LISTEN)) { enable_listen(ev, fdp); return; } memset(&fdp->event_read->overlapped, 0, sizeof(fdp->event_read->overlapped)); if (ReadFile((HANDLE) sockfd, NULL, 0, &recvBytes, &fdp->event_read->overlapped) == FALSE && acl_last_error() != ERROR_IO_PENDING) { acl_msg_warn("%s(%d): ReadFile error(%s)", myname, __LINE__, acl_last_serror()); } }
int acl_write_buf(ACL_SOCKET fd, const char *buf, int len, int timeout) { int count; while (len > 0) { if (timeout > 0 && acl_write_wait(fd, timeout) < 0) return -1; count = acl_socket_write(fd, buf, len, 0, NULL, NULL); if (count < 0) { if (acl_last_error() == ACL_EAGAIN && timeout > 0) continue; return -1; } if (count == 0) acl_msg_fatal("write returned 0"); buf += count; len -= count; } return len; }
void acl_set_ugid(uid_t uid, gid_t gid) { int saved_error = acl_last_error(); char tbuf[256]; if (geteuid() != 0) if (seteuid(0) < 0) acl_msg_fatal("seteuid(0): %s", acl_last_strerror(tbuf, sizeof(tbuf))); if (setgid(gid) < 0) acl_msg_fatal("setgid(%ld): %s", (long) gid, acl_last_strerror(tbuf, sizeof(tbuf))); if (setgroups(1, &gid) < 0) acl_msg_fatal("setgroups(1, &%ld): %s", (long) gid, acl_last_strerror(tbuf, sizeof(tbuf))); if (setuid(uid) < 0) acl_msg_fatal("setuid(%ld): %s", (long) uid, acl_last_strerror(tbuf, sizeof(tbuf))); if (acl_msg_verbose > 1) acl_msg_info("setugid: uid %ld gid %ld", (long) uid, (long) gid); acl_set_error(saved_error); }
int acl_write_wait(ACL_SOCKET fd, int timeout) { const char *myname = "acl_write_wait"; struct pollfd fds; int delay = timeout * 1000; fds.events = POLLOUT | POLLHUP | POLLERR; fds.fd = fd; acl_set_error(0); for (;;) { switch (poll(&fds, 1, delay)) { case -1: if (acl_last_error() == ACL_EINTR) continue; acl_msg_error("%s(%d), %s: poll error(%s), fd: %d", __FILE__, __LINE__, myname, acl_last_serror(), (int) fd); return -1; case 0: acl_set_error(ACL_ETIMEDOUT); return -1; default: if ((fds.revents & (POLLHUP | POLLERR))) { acl_msg_error("%s(%d), %s: fd: %d," "POLLHUP: %s, POLLERR: %s", __FILE__, __LINE__, myname, fd, fds.revents & POLLHUP ? "yes" : "no", fds.revents & POLLERR ? "yes" : "no"); return -1; } if (fds.revents & POLLOUT) return 0; acl_msg_error("%s(%d), %s: unknown error, fd: %d", __FILE__, __LINE__, myname, fd); return -1; } } }
int acl_readable(ACL_SOCKET fd) { struct pollfd fds; int delay = 0; fds.events = POLLIN | POLLPRI; fds.fd = fd; acl_set_error(0); for (;;) { switch (__sys_poll(&fds, 1, delay)) { #ifdef ACL_WINDOWS case SOCKET_ERROR: #else case -1: #endif if (acl_last_error() == ACL_EINTR) continue; acl_msg_error("%s(%d), %s: poll error(%s), fd: %d", __FILE__, __LINE__, __FUNCTION__, acl_last_serror(), (int) fd); return -1; case 0: return 0; default: if ((fds.revents & POLLIN)) { return 1; } else if (fds.revents & (POLLHUP | POLLERR)) { return 1; } else { return 0; } } } }
static void event_loop(ACL_EVENT *eventp) { const char *myname = "event_loop"; EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; ACL_EVENT_NOTIFY_TIME timer_fn; void *timer_arg; ACL_EVENT_TIMER *timer; int delay, nready; ACL_EVENT_FDTABLE *fdp; EVENT_BUFFER *bp; delay = (int) (eventp->delay_sec * 1000 + eventp->delay_usec / 1000); if (delay < 0) delay = 0; /* 0 milliseconds at least */ /* 调整事件引擎的时间截 */ SET_TIME(eventp->present); /* 根据定时器任务的最近任务计算 epoll/kqueue/devpoll 的检测超时上限 */ if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { acl_int64 n = (timer->when - eventp->present) / 1000; if (n <= 0) delay = 0; else if ((int) n < delay) { delay = (int) n; if (delay <= 0) /* xxx */ delay = 100; } } /* 设置描述字对象的状态,添加/删除之前设置的描述字对象 */ event_set_all(eventp); if (eventp->fdcnt == 0) { if (eventp->fdcnt_ready == 0) sleep(1); goto TAG_DONE; } /* 如果已经有描述字准备好则检测超时时间置 0 */ if (eventp->fdcnt_ready > 0) delay = 0; /* 调用 epoll/kquque/devpoll 系统调用检测可用描述字 */ EVENT_BUFFER_READ(nready, ev->event_fd, ev->event_buf, ev->event_fdslots, delay); if (eventp->nested++ > 0) acl_msg_fatal("%s(%d): recursive call, nested: %d", myname, __LINE__, eventp->nested); if (nready < 0) { if (acl_last_error() != ACL_EINTR) { acl_msg_fatal("%s(%d), %s: select: %s", __FILE__, __LINE__, myname, acl_last_serror()); } goto TAG_DONE; } else if (nready == 0) goto TAG_DONE; /* 检查检测结果 */ for (bp = ev->event_buf; bp < ev->event_buf + nready; bp++) { #ifdef USE_FDMAP ACL_SOCKET sockfd; sockfd = EVENT_GET_FD(bp); fdp = acl_fdmap_ctx(ev->fdmap, sockfd); if (fdp == NULL || fdp->stream == NULL) continue; if (sockfd != ACL_VSTREAM_SOCK(fdp->stream)) acl_msg_fatal("%s(%d): sockfd(%d) != %d", myname, __LINE__, sockfd, ACL_VSTREAM_SOCK(fdp->stream)); #else fdp = (ACL_EVENT_FDTABLE *) EVENT_GET_CTX(bp); if (fdp == NULL || fdp->stream == NULL) continue; #endif /* 如果该描述字对象已经在被设置为异常或超时状态则继续 */ if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) continue; /* 检查描述字是否可读 */ if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) && EVENT_TEST_READ(bp)) { /* 该描述字可读则设置 ACL_VSTREAM 的系统可读标志从而触发 * ACL_VSTREAM 流在读时调用系统的 read 函数 */ fdp->stream->sys_read_ready = 1; /* 给该描述字对象附加可读属性 */ if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) { fdp->event_type |= ACL_EVENT_READ; if (fdp->listener) fdp->event_type |= ACL_EVENT_ACCEPT; fdp->fdidx_ready = eventp->fdcnt_ready; eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; } } /* 检查描述字是否可写 */ if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) && EVENT_TEST_WRITE(bp)) { /* 给该描述字对象附加可写属性 */ if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) { fdp->event_type |= ACL_EVENT_WRITE; fdp->fdidx_ready = eventp->fdcnt_ready; eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; } } #ifdef EVENT_TEST_ERROR if (EVENT_TEST_ERROR(bp)) { /* 如果出现异常则设置异常属性 */ if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) { fdp->event_type |= ACL_EVENT_XCPT; fdp->fdidx_ready = eventp->fdcnt_ready; eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; } } #endif } TAG_DONE: /* * Deliver timer events. Requests are sorted: we can stop when we reach * the future or the list end. Allow the application to update the timer * queue while it is being called back. To this end, we repeatedly pop * the first request off the timer queue before delivering the event to * the application. */ /* 调整事件引擎的时间截 */ SET_TIME(eventp->present); while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { if (timer->when > eventp->present) break; timer_fn = timer->callback; timer_arg = timer->context; /* 定时器时间间隔 > 0 且允许定时器被循环调用,则重设定时器 */ if (timer->delay > 0 && timer->keep) { timer->ncount++; eventp->timer_request(eventp, timer->callback, timer->context, timer->delay, timer->keep); } else { acl_ring_detach(&timer->ring); /* first this */ timer->nrefer--; if (timer->nrefer != 0) acl_msg_fatal("%s(%d): nrefer(%d) != 0", myname, __LINE__, timer->nrefer); acl_myfree(timer); } timer_fn(ACL_EVENT_TIME, eventp, timer_arg); } /* 处理准备好的描述字事件 */ if (eventp->fdcnt_ready > 0) event_fire(eventp); eventp->nested--; }
static void event_loop(ACL_EVENT *eventp) { const char *myname = "event_loop"; EVENT_POLL *ev = (EVENT_POLL *) eventp; ACL_EVENT_TIMER *timer; int nready, i, revents; acl_int64 delay; ACL_EVENT_FDTABLE *fdp; delay = eventp->delay_sec * 1000000 + eventp->delay_usec; if (delay < DELAY_MIN) delay = DELAY_MIN; /* 调整事件引擎的时间截 */ SET_TIME(eventp->present); /* 根据定时器任务的最近任务计算 poll 的检测超时上限 */ if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { acl_int64 n = timer->when - eventp->present; if (n <= 0) delay = 0; else if (n < delay) delay = n; } /* 调用 event_prepare 检查有多少个描述字需要通过 poll 进行检测 */ if (event_prepare(eventp) == 0) { /* 说明无须 poll 检测 */ if (eventp->ready_cnt == 0) /* 为避免循环过快,休眠一下 */ acl_doze(delay > DELAY_MIN ? (int) delay / 1000 : 1); goto TAG_DONE; } /* 如果已经有描述字准备好则 poll 检测超时时间置 0 */ if (eventp->ready_cnt > 0) delay = 0; /* 调用 poll 系统调用检测可用描述字 */ nready = poll(ev->fds, eventp->fdcnt, (int) (delay / 1000)); if (eventp->nested++ > 0) { acl_msg_error("%s(%d): recursive call", myname, __LINE__); exit (1); } if (nready < 0) { if (acl_last_error() != ACL_EINTR) { acl_msg_error("%s(%d), %s: select: %s", __FILE__, __LINE__, myname, acl_last_serror()); exit (1); } goto TAG_DONE; } else if (nready == 0) goto TAG_DONE; /* 检查 poll 的检测结果集合 */ for (i = 0; i < eventp->fdcnt; i++) { fdp = acl_fdmap_ctx(ev->fdmap, ev->fds[i].fd); if (fdp == NULL || fdp->stream == NULL) continue; /* 如果该描述字对象已经在被设置为异常或超时状态则继续 */ if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) continue; revents = ev->fds[i].revents; /* 检查描述字是否出现异常 */ if ((revents & (POLLHUP | POLLERR)) != 0) { fdp->event_type |= ACL_EVENT_XCPT; fdp->fdidx_ready = eventp->ready_cnt; eventp->ready[eventp->ready_cnt++] = fdp; continue; } /* 检查描述字是否可读 */ if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) && (revents & POLLIN) ) { /* 给该描述字对象附加可读属性 */ if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) { fdp->event_type |= ACL_EVENT_READ; fdp->fdidx_ready = eventp->ready_cnt; eventp->ready[eventp->ready_cnt++] = fdp; } if (fdp->listener) fdp->event_type |= ACL_EVENT_ACCEPT; /* 该描述字可读则设置 ACL_VSTREAM 的系统可读标志从而 * 触发 ACL_VSTREAM 流在读时调用系统的 read 函数 */ else fdp->stream->read_ready = 1; } /* 检查描述字是否可写 */ if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) && (revents & POLLOUT)) { /* 给该描述字对象附加可写属性 */ if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) { fdp->event_type |= ACL_EVENT_WRITE; fdp->fdidx_ready = eventp->ready_cnt; eventp->ready[eventp->ready_cnt++] = fdp; } } } TAG_DONE: event_timer_trigger(eventp); /* 处理准备好的描述字事件 */ if (eventp->ready_cnt > 0) event_fire(eventp); eventp->nested--; }
static void event_loop(ACL_EVENT *eventp) { const char *myname = "event_loop"; EVENT_SELECT_THR *event_thr = (EVENT_SELECT_THR *) eventp; ACL_EVENT_NOTIFY_FN worker_fn; void *worker_arg; ACL_SOCKET sockfd; ACL_EVENT_TIMER *timer; int select_delay, nready, i; ACL_EVENT_FDTABLE *fdp; ACL_RING timer_ring, *entry_ptr; struct timeval tv, *tvp; fd_set rmask; /* enabled read events */ fd_set wmask; /* enabled write events */ fd_set xmask; /* for bad news mostly */ acl_ring_init(&timer_ring); SET_TIME(eventp->event_present); THREAD_LOCK(&event_thr->event.tm_mutex); /* * Find out when the next timer would go off. Timer requests are sorted. * If any timer is scheduled, adjust the delay appropriately. */ if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { select_delay = (int) (timer->when - eventp->event_present + 1000000 - 1) / 1000000; if (select_delay < 0) { select_delay = 0; } else if (eventp->delay_sec >= 0 && select_delay > eventp->delay_sec) { select_delay = eventp->delay_sec; } } else { select_delay = eventp->delay_sec; } THREAD_UNLOCK(&event_thr->event.tm_mutex); THREAD_LOCK(&event_thr->event.tb_mutex); if (event_thr_prepare(eventp) == 0) { if (eventp->fdcnt_ready == 0) { if (select_delay <= 0) select_delay = 1; sleep(select_delay); } THREAD_UNLOCK(&event_thr->event.tb_mutex); goto TAG_DONE; } if (eventp->fdcnt_ready > 0) { tv.tv_sec = 0; tv.tv_usec = 0; tvp = &tv; } else if (select_delay < 0) { tvp = NULL; } else { tv.tv_sec = select_delay; tv.tv_usec = eventp->delay_usec; tvp = &tv; } rmask = event_thr->rmask; wmask = event_thr->wmask; xmask = event_thr->xmask; THREAD_UNLOCK(&event_thr->event.tb_mutex); event_thr->event.blocked = 1; nready = select(eventp->maxfd + 1, &rmask, &wmask, &xmask, tvp); event_thr->event.blocked = 0; if (nready < 0) { if (acl_last_error() != ACL_EINTR) { char ebuf[256]; acl_msg_fatal("%s(%d), %s: event_loop: select: %s", __FILE__, __LINE__, myname, acl_last_strerror(ebuf, sizeof(ebuf))); } goto TAG_DONE; } else if (nready == 0) goto TAG_DONE; THREAD_LOCK(&event_thr->event.tb_mutex); for (i = 0; i < eventp->fdcnt; i++) { fdp = eventp->fdtabs[i]; /* if fdp has been set in eventp->fdtabs_ready ? */ if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) continue; sockfd = ACL_VSTREAM_SOCK(fdp->stream); if (FD_ISSET(sockfd, &xmask)) { fdp->event_type |= ACL_EVENT_XCPT; fdp->fdidx_ready = eventp->fdcnt_ready; eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; continue; } if (FD_ISSET(sockfd, &rmask)) { fdp->stream->sys_read_ready = 1; /* has been set in fdtabs_ready ? */ if ((fdp->event_type & ACL_EVENT_READ) == 0) { fdp->event_type |= ACL_EVENT_READ; fdp->fdidx_ready = eventp->fdcnt_ready; eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; } } else if (fdp->w_callback && FD_ISSET(sockfd, &wmask)) { fdp->event_type |= ACL_EVENT_WRITE; fdp->fdidx_ready = eventp->fdcnt_ready; eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; } } THREAD_UNLOCK(&event_thr->event.tb_mutex); TAG_DONE: /* * Deliver timer events. Requests are sorted: we can stop when we reach * the future or the list end. Allow the application to update the timer * queue while it is being called back. To this end, we repeatedly pop * the first request off the timer queue before delivering the event to * the application. */ SET_TIME(eventp->event_present); THREAD_LOCK(&event_thr->event.tm_mutex); while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { if (timer->when > eventp->event_present) break; acl_ring_detach(&timer->ring); /* first this */ acl_ring_prepend(&timer_ring, &timer->ring); } THREAD_UNLOCK(&event_thr->event.tm_mutex); while (1) { entry_ptr = acl_ring_pop_head(&timer_ring); if (entry_ptr == NULL) break; timer = ACL_RING_TO_TIMER(entry_ptr); worker_fn = timer->callback; worker_arg = timer->context; worker_fn(ACL_EVENT_TIME, worker_arg); acl_myfree(timer); } event_thr_fire(eventp); }
static void event_loop(ACL_EVENT *eventp) { const char *myname = "event_loop"; EVENT_SELECT *ev = (EVENT_SELECT *) eventp; ACL_EVENT_NOTIFY_TIME timer_fn; void *timer_arg; ACL_SOCKET sockfd; ACL_EVENT_TIMER *timer; int nready, i; acl_int64 delay; ACL_EVENT_FDTABLE *fdp; struct timeval tv, *tvp; fd_set rmask; /* enabled read events */ fd_set wmask; /* enabled write events */ fd_set xmask; /* for bad news mostly */ delay = eventp->delay_sec * 1000000 + eventp->delay_usec; /* 调整事件引擎的时间截 */ SET_TIME(eventp->present); /* 根据定时器任务的最近任务计算 select 的检测超时上限 */ if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { acl_int64 n = timer->when - eventp->present; if (n <= 0) delay = 0; else if (n < delay) delay = n; } /* 调用 event_prepare 检查有多少个描述字需要通过 select 进行检测 */ if (event_prepare(eventp) == 0) { if (eventp->ready_cnt == 0) { delay /= 1000000; if (delay <= 0) delay = 1; /* 为避免循环过快,休眠一下 */ sleep((int) delay); } goto TAG_DONE; } if (eventp->ready_cnt > 0) { tv.tv_sec = 0; tv.tv_usec = 0; tvp = &tv; } else if (delay >= 0) { #if defined(ACL_WINDOWS) tv.tv_sec = (long) delay / 1000000; tv.tv_usec = (unsigned long) (delay - tv.tv_sec * 1000000); #else tv.tv_sec = (time_t) delay / 1000000; tv.tv_usec = (suseconds_t) (delay - tv.tv_sec * 1000000); #endif tvp = &tv; } else tvp = NULL; rmask = ev->rmask; wmask = ev->wmask; xmask = ev->xmask; /* 调用 select 系统调用检测可用描述字 */ #ifdef ACL_WINDOWS nready = select(0, &rmask, &wmask, &xmask, tvp); #else nready = select(eventp->maxfd + 1, &rmask, &wmask, &xmask, tvp); #endif if (eventp->nested++ > 0) acl_msg_fatal("%s(%d): recursive call(%d)", myname, __LINE__, eventp->nested); if (nready < 0) { if (acl_last_error() != ACL_EINTR) { acl_msg_fatal("%s(%d), %s: select: %s", __FILE__, __LINE__, myname, acl_last_serror()); } goto TAG_DONE; } else if (nready == 0) goto TAG_DONE; /* 检查 select 的检测结果集合 */ /* if some fdp was cleared from eventp->fdtabs in timer callback, * which has no effection on the rest fdp in eventp->fdtabs */ for (i = 0; i < eventp->fdcnt; i++) { fdp = eventp->fdtabs[i]; /* 如果该描述字对象已经在被设置为异常或超时状态则继续 */ if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) continue; sockfd = ACL_VSTREAM_SOCK(fdp->stream); /* 检查描述字是否出现异常 */ if (FD_ISSET(sockfd, &xmask)) { fdp->event_type |= ACL_EVENT_XCPT; fdp->fdidx_ready = eventp->ready_cnt; eventp->ready[eventp->ready_cnt++] = fdp; continue; } /* 检查描述字是否可读 */ if (FD_ISSET(sockfd, &rmask)) { /* 给该描述字对象附加可读属性 */ if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) { fdp->event_type |= ACL_EVENT_READ; fdp->fdidx_ready = eventp->ready_cnt; eventp->ready[eventp->ready_cnt++] = fdp; } if (fdp->listener) fdp->event_type |= ACL_EVENT_ACCEPT; /* 该描述字可读则设置 ACL_VSTREAM 的系统可读标志从而 * 触发 ACL_VSTREAM 流在读时调用系统的 read 函数 */ else fdp->stream->read_ready = 1; } /* 检查描述字是否可写 */ if (FD_ISSET(sockfd, &wmask)) { /* 给该描述字对象附加可写属性 */ if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) { fdp->event_type |= ACL_EVENT_WRITE; fdp->fdidx_ready = eventp->ready_cnt; eventp->ready[eventp->ready_cnt++] = fdp; } } } TAG_DONE: /* 调整事件引擎的时间截 */ SET_TIME(eventp->present); /* 优先处理定时器中的任务 */ while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { if (timer->when > eventp->present) break; timer_fn = timer->callback; timer_arg = timer->context; /* 如果定时器的时间间隔 > 0 且允许定时器被循环调用, * 则再重设定时器 */ if (timer->delay > 0 && timer->keep) { timer->ncount++; eventp->timer_request(eventp, timer->callback, timer->context, timer->delay, timer->keep); } else { acl_ring_detach(&timer->ring); /* first this */ timer->nrefer--; if (timer->nrefer != 0) acl_msg_fatal("%s(%d): nrefer(%d) != 0", myname, __LINE__, timer->nrefer); acl_myfree(timer); } timer_fn(ACL_EVENT_TIME, eventp, timer_arg); } /* 处理准备好的描述字事件 */ if (eventp->ready_cnt > 0) event_fire(eventp); eventp->nested--; }