/* PIP - Platform Independent Primitives Private PIP wait object Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "piwaitevent_p.h" #ifdef WINDOWS // # ifdef _WIN32_WINNT // # undef _WIN32_WINNT // # define _WIN32_WINNT 0x0600 // # endif # include #else # include # include # include #endif #include "pistring.h" PIWaitEvent::~PIWaitEvent() { destroy(); } void PIWaitEvent::create() { destroy(); #ifdef WINDOWS event = CreateEventA(NULL, TRUE, FALSE, NULL); if (!event) { piCout << "Error with CreateEventA:" << errorString(); } #else for (int i = 0; i < 3; ++i) piZeroMemory(fds[i]); if (::pipe(pipe_fd) < 0) { piCout << "Error with pipe:" << errorString(); } else { fcntl(pipe_fd[ReadEnd], F_SETFL, O_NONBLOCK); fcntl(pipe_fd[WriteEnd], F_SETFL, O_NONBLOCK); } #endif } void PIWaitEvent::destroy() { #ifdef WINDOWS if (event) { CloseHandle(event); event = NULL; } #else for (int i = 0; i < 2; ++i) { if (pipe_fd[i] != 0) { ::close(pipe_fd[i]); pipe_fd[i] = 0; } } #endif } bool PIWaitEvent::wait(int fd, CheckRole role) { if (!isCreate()) return false; #ifdef WINDOWS DWORD ret = WaitForSingleObjectEx(event, INFINITE, TRUE); ResetEvent(event); if (ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED) return false; #else if (fd == -1) return false; int nfds = piMaxi(pipe_fd[ReadEnd], fd) + 1; int fd_index = role; for (int i = 0; i < 3; ++i) FD_ZERO(&(fds[i])); FD_SET(pipe_fd[ReadEnd], &(fds[CheckRead])); FD_SET(fd, &(fds[CheckExeption])); if (fd_index != CheckExeption) FD_SET(fd, &(fds[fd_index])); int sr = ::select(nfds, &(fds[CheckRead]), &(fds[CheckWrite]), &(fds[CheckExeption]), nullptr); int buf = 0; while (::read(pipe_fd[ReadEnd], &buf, sizeof(buf)) > 0) ; // piCout << "wait result" << sr << FD_ISSET(fd, &(fds[CheckExeption])) << FD_ISSET(fd, &(fds[fd_index])); if (sr == EBADF || sr == EINTR) return false; if (FD_ISSET(fd, &(fds[CheckExeption]))) return true; return FD_ISSET(fd, &(fds[fd_index])); #endif return true; } bool PIWaitEvent::sleep(int us) { if (!isCreate()) return false; #ifdef WINDOWS DWORD ret = WaitForSingleObjectEx(event, us / 1000, TRUE); ResetEvent(event); return ret == WAIT_TIMEOUT; #else int nfds = pipe_fd[ReadEnd] + 1; FD_ZERO(&(fds[CheckRead])); FD_SET(pipe_fd[ReadEnd], &(fds[CheckRead])); timeval timeout; timeout.tv_sec = us / 1000000; timeout.tv_usec = us % 1000000; int ret = ::select(nfds, &(fds[CheckRead]), nullptr, nullptr, &timeout); int buf = 0; while (::read(pipe_fd[ReadEnd], &buf, sizeof(buf)) > 0) ; return ret == 0; #endif } void PIWaitEvent::interrupt() { if (!isCreate()) return; #ifdef WINDOWS SetEvent(event); #else auto _r = ::write(pipe_fd[WriteEnd], "", 1); NO_UNUSED(_r); #endif } bool PIWaitEvent::isCreate() const { #ifdef WINDOWS return event; #else return pipe_fd[ReadEnd] != 0; #endif } void * PIWaitEvent::getEvent() const { #ifdef WINDOWS return event; #else return nullptr; #endif }