QWinEventNotifier: migrate to new thread pool API

Change-Id: I2fb1ba7254ecfd502a22c706404f92dd1bc3a584
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
This commit is contained in:
Alex Trotsenko 2021-03-24 20:56:06 +02:00
parent 8f6d8d7cd8
commit 007addc0cc
2 changed files with 47 additions and 38 deletions

View File

@ -117,10 +117,7 @@ QWinEventNotifier::QWinEventNotifier(QObject *parent)
QWinEventNotifier::QWinEventNotifier(HANDLE hEvent, QObject *parent)
: QObject(*new QWinEventNotifierPrivate(hEvent, false), parent)
{
Q_D(QWinEventNotifier);
d->registerWaitObject();
d->enabled = true;
setEnabled(true);
}
/*!
@ -198,9 +195,20 @@ void QWinEventNotifier::setEnabled(bool enable)
// event shall be ignored.
d->winEventActPosted.testAndSetRelaxed(QWinEventNotifierPrivate::Posted,
QWinEventNotifierPrivate::IgnorePosted);
d->registerWaitObject();
} else if (d->waitHandle != NULL) {
d->unregisterWaitObject();
// The notifier can't be registered, if 'enabled' flag was false.
// The code in the else branch ensures that.
Q_ASSERT(!d->registered);
SetThreadpoolWait(d->waitObject, d->handleToEvent, NULL);
d->registered = true;
} else if (d->registered) {
// Stop waiting for an event. However, there may be a callback queued
// already after the call.
SetThreadpoolWait(d->waitObject, NULL, NULL);
// So, to avoid a race condition after a possible call to
// setEnabled(true), wait for a possibly outstanding callback
// to complete.
WaitForThreadpoolWaitCallbacks(d->waitObject, TRUE);
d->registered = false;
}
}
@ -226,12 +234,16 @@ bool QWinEventNotifier::event(QEvent * e)
// again.
if (d->winEventActPosted.fetchAndStoreRelaxed(QWinEventNotifierPrivate::NotPosted)
== QWinEventNotifierPrivate::Posted && d->enabled) {
d->unregisterWaitObject();
// Clear the flag, as the wait object is implicitly unregistered
// when the callback is queued.
d->registered = false;
emit activated(d->handleToEvent, QPrivateSignal());
if (d->enabled && d->waitHandle == NULL)
d->registerWaitObject();
if (d->enabled && !d->registered) {
SetThreadpoolWait(d->waitObject, d->handleToEvent, NULL);
d->registered = true;
}
}
return true;
default:
@ -240,8 +252,25 @@ bool QWinEventNotifier::event(QEvent * e)
return QObject::event(e);
}
void CALLBACK QWinEventNotifierPrivate::wfsoCallback(void *context, BOOLEAN /*ignore*/)
QWinEventNotifierPrivate::QWinEventNotifierPrivate(HANDLE h, bool e)
: handleToEvent(h), enabled(e), registered(false)
{
waitObject = CreateThreadpoolWait(waitCallback, this, NULL);
if (waitObject == NULL)
qErrnoWarning("QWinEventNotifier:: CreateThreadpollWait failed.");
}
QWinEventNotifierPrivate::~QWinEventNotifierPrivate()
{
CloseThreadpoolWait(waitObject);
}
void QWinEventNotifierPrivate::waitCallback(PTP_CALLBACK_INSTANCE instance, PVOID context,
PTP_WAIT wait, TP_WAIT_RESULT waitResult)
{
Q_UNUSED(instance);
Q_UNUSED(wait);
Q_UNUSED(waitResult);
QWinEventNotifierPrivate *nd = reinterpret_cast<QWinEventNotifierPrivate *>(context);
// Do not post an event, if an event is already in the message queue. Note
@ -252,23 +281,4 @@ void CALLBACK QWinEventNotifierPrivate::wfsoCallback(void *context, BOOLEAN /*ig
}
}
bool QWinEventNotifierPrivate::registerWaitObject()
{
if (RegisterWaitForSingleObject(&waitHandle, handleToEvent, wfsoCallback, this,
INFINITE, WT_EXECUTEONLYONCE) == 0) {
qErrnoWarning("QWinEventNotifier: RegisterWaitForSingleObject failed.");
return false;
}
return true;
}
void QWinEventNotifierPrivate::unregisterWaitObject()
{
// Unregister the wait handle and wait for pending callbacks to finish.
if (UnregisterWaitEx(waitHandle, INVALID_HANDLE_VALUE))
waitHandle = NULL;
else
qErrnoWarning("QWinEventNotifier: UnregisterWaitEx failed.");
}
QT_END_NAMESPACE

View File

@ -63,21 +63,20 @@ class QWinEventNotifierPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QWinEventNotifier)
public:
QWinEventNotifierPrivate()
: handleToEvent(0), enabled(false) {}
QWinEventNotifierPrivate(HANDLE h, bool e)
: handleToEvent(h), enabled(e) {}
QWinEventNotifierPrivate() : QWinEventNotifierPrivate(0, false) {}
QWinEventNotifierPrivate(HANDLE h, bool e);
virtual ~QWinEventNotifierPrivate();
static void CALLBACK wfsoCallback(void *context, BOOLEAN /*ignore*/);
bool registerWaitObject();
void unregisterWaitObject();
static void CALLBACK waitCallback(PTP_CALLBACK_INSTANCE instance, PVOID context,
PTP_WAIT wait, TP_WAIT_RESULT waitResult);
HANDLE handleToEvent;
HANDLE waitHandle = NULL;
PTP_WAIT waitObject = NULL;
enum PostingState { NotPosted = 0, Posted, IgnorePosted };
QAtomicInt winEventActPosted;
bool enabled;
bool registered;
};
QT_END_NAMESPACE