/** Functions that wait. */ #include "pqxx-source.hxx" // The header is still broken on MinGW. :-( #if defined(PQXX_HAVE_SLEEP_FOR) # include #endif // For WSAPoll(): #if __has_include() # include # define PQXX_HAVE_SELECT #endif #if __has_include() # include #endif #if __has_include() # include #endif // For poll(): #if __has_include() # include #endif // For select() on recent POSIX systems. #if __has_include() # include # define PQXX_HAVE_SELECT #endif // For select() on some older POSIX systems. #if __has_include() # include # define PQXX_HAVE_SELECT #endif #if __has_include() # include #endif #if __has_include() # include #endif #include "pqxx/internal/header-pre.hxx" #include "pqxx/internal/wait.hxx" #include "pqxx/util.hxx" #include "pqxx/internal/header-post.hxx" namespace { template T to_milli(unsigned seconds, unsigned microseconds) { return pqxx::check_cast( (seconds * 1000) + (microseconds / 1000), "Wait timeout value out of bounds."); } #if defined(PQXX_HAVE_SELECT) /// Set a bit on an fd_set. [[maybe_unused]] void set_fdbit(fd_set &bits, int fd) { # ifdef _MSC_VER // Suppress pointless, unfixable warnings in Visual Studio. # pragma warning(push) # pragma warning(disable : 4389) // Signed/unsigned mismatch. # pragma warning(disable : 4127) // Conditional expression is constant. # endif FD_SET(fd, &bits); # ifdef _MSV_VER // Restore prevalent warning settings. # pragma warning(pop) # endif } #endif } // namespace void pqxx::internal::wait_fd( int fd, bool for_read, bool for_write, unsigned seconds, unsigned microseconds) { // WSAPoll is available in winsock2.h only for versions of Windows >= 0x0600 #if defined(_WIN32) && (_WIN32_WINNT >= 0x0600) short const events{static_cast( (for_read ? POLLRDNORM : 0) | (for_write ? POLLWRNORM : 0))}; WSAPOLLFD fdarray{SOCKET(fd), events, 0}; WSAPoll(&fdarray, 1u, to_milli(seconds, microseconds)); // TODO: Check for errors. #elif defined(PQXX_HAVE_POLL) auto const events{static_cast( POLLERR | POLLHUP | POLLNVAL | (for_read ? POLLIN : 0) | (for_write ? POLLOUT : 0))}; pollfd pfd{fd, events, 0}; poll(&pfd, 1, to_milli(seconds, microseconds)); // TODO: Check for errors. #else // No poll()? Our last option is select(). fd_set read_fds; FD_ZERO(&read_fds); if (for_read) set_fdbit(read_fds, fd); fd_set write_fds; FD_ZERO(&write_fds); if (for_write) set_fdbit(write_fds, fd); fd_set except_fds; FD_ZERO(&except_fds); set_fdbit(except_fds, fd); timeval tv = {seconds, microseconds}; select(fd + 1, &read_fds, &write_fds, &except_fds, &tv); // TODO: Check for errors. #endif } void PQXX_COLD pqxx::internal::wait_for(unsigned int microseconds) { #if defined(PQXX_HAVE_SLEEP_FOR) std::this_thread::sleep_for(std::chrono::microseconds{microseconds}); #else // MinGW still does not have a functioning header. Work around this // using select(). // Not worth optimising for though -- they'll have to fix it at some point. timeval tv{microseconds / 1'000'000u, microseconds % 1'000'000u}; select(0, nullptr, nullptr, nullptr, &tv); #endif }