qcore_unix: port qt_safe_poll to QDeadlineTimer

Remove qt_poll_msecs() since the "forever" state can be simply expressed
with a QDeadlineTimer::Forever arg, instead of passing a nullptr
timespec, and the negative timeouts treated as "run forever" is also
encapsulated by QDealineTimer.

Use the QDealineTimer(qint64) constructor in the call sites where
the timeout could be negative, so that it creates a Forever timer (the
QDeadlineTimer(chrono::duration) constructor uses
setRemainingTime(duration) which handles negative timeouts by creating
expired timers).

Remove qt_gettime() (and do_gettime()).

Drive-by changes:
- Fix a narrowing conversion warning, qt_make_pollfd() takes an int
- Remove an unused include

Change-Id: I096319af5e191e28c3d39295fb1aafe9d69841e6
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Ahmad Samir 2023-04-29 15:07:14 +03:00
parent df2e07549e
commit ceee7acf43
8 changed files with 32 additions and 96 deletions

View File

@ -221,7 +221,7 @@ QProcessPoller::QProcessPoller(const QProcessPrivate &proc)
int QProcessPoller::poll(const QDeadlineTimer &deadline)
{
return qt_poll_msecs(pfds, n_pfds, deadline.remainingTime());
return qt_safe_poll(pfds, n_pfds, deadline);
}
struct QChildProcess
@ -1092,15 +1092,15 @@ void QProcessPrivate::killProcess()
bool QProcessPrivate::waitForStarted(const QDeadlineTimer &deadline)
{
const qint64 msecs = deadline.remainingTime();
#if defined (QPROCESS_DEBUG)
const qint64 msecs = deadline.remainingTime();
qDebug("QProcessPrivate::waitForStarted(%lld) waiting for child to start (fd = %d)",
msecs, childStartedPipe[0]);
#endif
pollfd pfd = qt_make_pollfd(childStartedPipe[0], POLLIN);
if (qt_poll_msecs(&pfd, 1, msecs) == 0) {
if (qt_safe_poll(&pfd, 1, deadline) == 0) {
setError(QProcess::Timedout);
#if defined (QPROCESS_DEBUG)
qDebug("QProcessPrivate::waitForStarted(%lld) == false (timed out)", msecs);

View File

@ -4,7 +4,6 @@
#include <QtCore/private/qglobal_p.h>
#include "qcore_unix_p.h"
#include "qelapsedtimer.h"
#include <stdlib.h>
@ -65,48 +64,10 @@ int qt_open64(const char *pathname, int flags, mode_t mode)
#ifndef QT_BOOTSTRAPPED
static inline void do_gettime(qint64 *sec, qint64 *frac)
{
timespec ts;
clockid_t clk = CLOCK_REALTIME;
#if defined(CLOCK_MONOTONIC_RAW)
clk = CLOCK_MONOTONIC_RAW;
#elif defined(CLOCK_MONOTONIC)
clk = CLOCK_MONOTONIC;
#endif
clock_gettime(clk, &ts);
*sec = ts.tv_sec;
*frac = ts.tv_nsec;
}
// also used in qeventdispatcher_unix.cpp
struct timespec qt_gettime() noexcept
{
qint64 sec, frac;
do_gettime(&sec, &frac);
timespec tv;
tv.tv_sec = sec;
tv.tv_nsec = frac;
return tv;
}
#if QT_CONFIG(poll_pollts)
# define ppoll pollts
#endif
static inline bool time_update(struct timespec *tv, const struct timespec &start,
const struct timespec &timeout)
{
// clock source is (hopefully) monotonic, so we can recalculate how much timeout is left;
// if it isn't monotonic, we'll simply hope that it hasn't jumped, because we have no alternative
struct timespec now = qt_gettime();
*tv = timeout + start - now;
return tv->tv_sec >= 0;
}
[[maybe_unused]]
static inline int timespecToMillisecs(const struct timespec *ts)
{
@ -141,31 +102,27 @@ static inline int qt_ppoll(struct pollfd *fds, nfds_t nfds, const struct timespe
using select(2) where necessary. In that case, returns -1 and sets errno
to EINVAL if passed any descriptor greater than or equal to FD_SETSIZE.
*/
int qt_safe_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
int qt_safe_poll(struct pollfd *fds, nfds_t nfds, QDeadlineTimer deadline)
{
if (!timeout_ts) {
if (deadline.isForever()) {
// no timeout -> block forever
int ret;
EINTR_LOOP(ret, qt_ppoll(fds, nfds, nullptr));
return ret;
}
timespec start = qt_gettime();
timespec timeout = *timeout_ts;
using namespace std::chrono;
nanoseconds remaining = deadline.remainingTimeAsDuration();
// loop and recalculate the timeout as needed
forever {
const int ret = qt_ppoll(fds, nfds, &timeout);
do {
timespec ts = durationToTimespec(remaining);
const int ret = qt_ppoll(fds, nfds, &ts);
if (ret != -1 || errno != EINTR)
return ret;
remaining = deadline.remainingTimeAsDuration();
} while (remaining > 0ns);
// recalculate the timeout
if (!time_update(&timeout, start, *timeout_ts)) {
// timeout during update
// or clock reset, fake timeout error
return 0;
}
}
return 0;
}
#endif // QT_BOOTSTRAPPED

View File

@ -20,6 +20,7 @@
#include <QtCore/private/qglobal_p.h>
#include "qatomic.h"
#include "qbytearray.h"
#include "qdeadlinetimer.h"
#ifndef Q_OS_UNIX
# error "qcore_unix_p.h included on a non-Unix system"
@ -376,8 +377,6 @@ static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options)
# define _POSIX_MONOTONIC_CLOCK -1
#endif
// in qelapsedtimer_mac.cpp or qtimestamp_unix.cpp
timespec qt_gettime() noexcept;
QByteArray qt_readlink(const char *path);
/* non-static */
@ -395,20 +394,7 @@ inline bool qt_haveLinuxProcfs()
#endif
}
Q_CORE_EXPORT int qt_safe_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts);
static inline int qt_poll_msecs(struct pollfd *fds, nfds_t nfds, int timeout)
{
timespec ts, *pts = nullptr;
if (timeout >= 0) {
ts.tv_sec = timeout / 1000;
ts.tv_nsec = (timeout % 1000) * 1000 * 1000;
pts = &ts;
}
return qt_safe_poll(fds, nfds, pts);
}
Q_CORE_EXPORT int qt_safe_poll(struct pollfd *fds, nfds_t nfds, QDeadlineTimer deadline);
static inline struct pollfd qt_make_pollfd(int fd, short events)
{

View File

@ -428,20 +428,18 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
if (d->interrupt.loadRelaxed())
return false;
// If canWait is true, and include_timers is false or there are no pending
// timers, call qt_safe_poll() with a nullptr so that it waits until there
// are events to process (see QEventLoop::WaitForMoreEvents).
timespec *tm = nullptr;
timespec wait_tm = { 0, 0 };
if (!canWait) {
tm = &wait_tm;
} else if (include_timers) {
std::optional<std::chrono::milliseconds> msecs = d->timerList.timerWait();
if (msecs) {
wait_tm = durationToTimespec(*msecs);
tm = &wait_tm;
QDeadlineTimer deadline;
if (canWait) {
if (include_timers) {
std::optional<std::chrono::milliseconds> msecs = d->timerList.timerWait();
deadline = msecs ? QDeadlineTimer{*msecs}
: QDeadlineTimer(QDeadlineTimer::Forever);
} else {
deadline = QDeadlineTimer(QDeadlineTimer::Forever);
}
} else {
// Using the default-constructed `deadline`, which is already expired,
// ensures the code in the do-while loop in qt_safe_poll runs at least once.
}
d->pollfds.clear();
@ -455,8 +453,7 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
d->pollfds.append(d->threadPipe.prepare());
int nevents = 0;
switch (qt_safe_poll(d->pollfds.data(), d->pollfds.size(), tm)) {
switch (qt_safe_poll(d->pollfds.data(), d->pollfds.size(), deadline)) {
case -1:
qErrnoWarning("qt_safe_poll");
if (QT_CONFIG(poll_exit_on_error))

View File

@ -279,8 +279,7 @@ void QLocalServerPrivate::_q_onNewConnection()
void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut)
{
pollfd pfd = qt_make_pollfd(listenSocket, POLLIN);
switch (qt_poll_msecs(&pfd, 1, msec)) {
switch (qt_safe_poll(&pfd, 1, QDeadlineTimer(msec))) {
case 0:
if (timedOut)
*timedOut = true;

View File

@ -25,7 +25,6 @@ using namespace std::chrono_literals;
#define QT_CONNECT_TIMEOUT 30000
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@ -593,9 +592,7 @@ bool QLocalSocket::waitForConnected(int msec)
auto remainingTime = deadline.remainingTimeAsDuration();
do {
timespec ts = durationToTimespec(remainingTime);
const int result = qt_safe_poll(&pfd, 1, &ts);
const int result = qt_safe_poll(&pfd, 1, deadline);
if (result == -1)
d->setErrorAndEmit(QLocalSocket::UnknownSocketError,
"QLocalSocket::waitForConnected"_L1);

View File

@ -1364,7 +1364,7 @@ int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool check
if (checkWrite)
pfd.events |= POLLOUT;
const int ret = qt_poll_msecs(&pfd, 1, deadline.remainingTime());
const int ret = qt_safe_poll(&pfd, 1, deadline);
if (ret <= 0)
return ret;

View File

@ -402,8 +402,8 @@ public slots:
dataSent = serverSocket->waitForBytesWritten(-1);
if (dataSent) {
pollfd pfd = qt_make_pollfd(socket->socketDescriptor(), POLLIN);
dataReadable = (1 == qt_safe_poll(&pfd, 1, nullptr));
pollfd pfd = qt_make_pollfd(int(socket->socketDescriptor()), POLLIN);
dataReadable = (1 == qt_safe_poll(&pfd, 1, QDeadlineTimer::Forever));
}
if (!dataReadable) {