summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qpoll.cpp
blob: 58fb0234b47ea535b6040c96ffdf28f57d6e43f4 (plain)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
// Copyright (C) 2016 The Qt Company Ltd.// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only#include"qcore_unix_p.h"#ifdef Q_OS_RTEMS#include <rtems/rtems_bsdnet_internal.h>#endif QT_BEGIN_NAMESPACE #define QT_POLL_READ_MASK (POLLIN | POLLRDNORM)#define QT_POLL_WRITE_MASK (POLLOUT | POLLWRNORM | POLLWRBAND)#define QT_POLL_EXCEPT_MASK (POLLPRI | POLLRDBAND)#define QT_POLL_ERROR_MASK (POLLERR | POLLNVAL)#define QT_POLL_EVENTS_MASK (QT_POLL_READ_MASK | QT_POLL_WRITE_MASK | QT_POLL_EXCEPT_MASK)staticinlineintqt_poll_prepare(struct pollfd *fds, nfds_t nfds, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds){int max_fd = -1;FD_ZERO(read_fds);FD_ZERO(write_fds);FD_ZERO(except_fds);for(nfds_t i =0; i < nfds; i++) {if(fds[i].fd >= FD_SETSIZE) { errno = EINVAL;return-1;}if((fds[i].fd <0) || (fds[i].revents & QT_POLL_ERROR_MASK))continue;if(fds[i].events & QT_POLL_READ_MASK)FD_SET(fds[i].fd, read_fds);if(fds[i].events & QT_POLL_WRITE_MASK)FD_SET(fds[i].fd, write_fds);if(fds[i].events & QT_POLL_EXCEPT_MASK)FD_SET(fds[i].fd, except_fds);if(fds[i].events & QT_POLL_EVENTS_MASK) max_fd =qMax(max_fd, fds[i].fd);}return max_fd +1;}staticinlinevoidqt_poll_examine_ready_read(struct pollfd &pfd){int res;char data;QT_EINTR_LOOP(res, ::recv(pfd.fd, &data,sizeof(data), MSG_PEEK));const int error = (res <0) ? errno :0;if(res ==0) { pfd.revents |= POLLHUP;}else if(res >0|| error == ENOTSOCK || error == ENOTCONN) { pfd.revents |= QT_POLL_READ_MASK & pfd.events;}else{switch(error) {case ESHUTDOWN:case ECONNRESET:case ECONNABORTED:case ENETRESET: pfd.revents |= POLLHUP;break;default: pfd.revents |= POLLERR;break;}}}staticinlineintqt_poll_sweep(struct pollfd *fds, nfds_t nfds, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds){int result =0;for(nfds_t i =0; i < nfds; i++) {if(fds[i].fd <0)continue;if(FD_ISSET(fds[i].fd, read_fds))qt_poll_examine_ready_read(fds[i]);if(FD_ISSET(fds[i].fd, write_fds)) fds[i].revents |= QT_POLL_WRITE_MASK & fds[i].events;if(FD_ISSET(fds[i].fd, except_fds)) fds[i].revents |= QT_POLL_EXCEPT_MASK & fds[i].events;if(fds[i].revents !=0) result++;}return result;}staticinlineboolqt_poll_is_bad_fd(int fd){#ifdef Q_OS_RTEMSif(!rtems_bsdnet_fdToSocket(fd))return true;#endifint ret;QT_EINTR_LOOP(ret,fcntl(fd, F_GETFD));return(ret == -1&& errno == EBADF);}staticinlineintqt_poll_mark_bad_fds(struct pollfd *fds,const nfds_t nfds){int n_marked =0;for(nfds_t i =0; i < nfds; i++) {if(fds[i].fd <0)continue;if(fds[i].revents & QT_POLL_ERROR_MASK)continue;if(qt_poll_is_bad_fd(fds[i].fd)) { fds[i].revents |= POLLNVAL; n_marked++;}}return n_marked;}intqt_poll(struct pollfd *fds, nfds_t nfds,const struct timespec *timeout_ts){if(!fds && nfds) { errno = EFAULT;return-1;} fd_set read_fds, write_fds, except_fds;struct timeval tv, *ptv =nullptr;if(timeout_ts) { tv =timespecToTimeval(*timeout_ts); ptv = &tv;}int n_bad_fds =0;for(nfds_t i =0; i < nfds; i++) { fds[i].revents =0;if(fds[i].fd <0)continue;if(fds[i].fd > FD_SETSIZE) { errno = EINVAL;return-1;}if(fds[i].events & QT_POLL_EVENTS_MASK)continue;if(qt_poll_is_bad_fd(fds[i].fd)) {// Mark bad file descriptors that have no event flags set// here, as we won't be passing them to select below and therefore// need to do the check ourselves fds[i].revents = POLLNVAL; n_bad_fds++;}} forever {const int max_fd =qt_poll_prepare(fds, nfds, &read_fds, &write_fds, &except_fds);if(max_fd <0)return max_fd;if(n_bad_fds >0) { tv.tv_sec =0; tv.tv_usec =0; ptv = &tv;}const int ret = ::select(max_fd, &read_fds, &write_fds, &except_fds, ptv);if(ret ==0)return n_bad_fds;if(ret >0)returnqt_poll_sweep(fds, nfds, &read_fds, &write_fds, &except_fds);if(errno != EBADF)return-1;// We have at least one bad file descriptor that we waited on, find out which and try again n_bad_fds +=qt_poll_mark_bad_fds(fds, nfds);}} QT_END_NAMESPACE 
close