summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r--src/corelib/kernel/qbasictimer.cpp2
-rw-r--r--src/corelib/kernel/qcfsocketnotifier.cpp14
-rw-r--r--src/corelib/kernel/qcore_mac.mm49
-rw-r--r--src/corelib/kernel/qcore_mac_p.h1
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp81
-rw-r--r--src/corelib/kernel/qcoreevent.cpp8
-rw-r--r--src/corelib/kernel/qdeadlinetimer.cpp2
-rw-r--r--src/corelib/kernel/qelapsedtimer.cpp52
-rw-r--r--src/corelib/kernel/qelapsedtimer_generic.cpp3
-rw-r--r--src/corelib/kernel/qeventdispatcher_cf.mm2
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp44
-rw-r--r--src/corelib/kernel/qeventdispatcher_win_p.h3
-rw-r--r--src/corelib/kernel/qeventloop.cpp10
-rw-r--r--src/corelib/kernel/qfunctions_winrt.h27
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp42
-rw-r--r--src/corelib/kernel/qmetaobject.cpp37
-rw-r--r--src/corelib/kernel/qmetatype.cpp24
-rw-r--r--src/corelib/kernel/qmetatype_p.h7
-rw-r--r--src/corelib/kernel/qobject.cpp140
-rw-r--r--src/corelib/kernel/qobject_p.h36
-rw-r--r--src/corelib/kernel/qsharedmemory_p.h10
-rw-r--r--src/corelib/kernel/qsharedmemory_systemv.cpp2
-rw-r--r--src/corelib/kernel/qsystemsemaphore_posix.cpp2
-rw-r--r--src/corelib/kernel/qtimer.cpp2
-rw-r--r--src/corelib/kernel/qtranslator.cpp56
25 files changed, 422 insertions, 234 deletions
diff --git a/src/corelib/kernel/qbasictimer.cpp b/src/corelib/kernel/qbasictimer.cpp
index 623ecb9b8b..eceaa0fb7f 100644
--- a/src/corelib/kernel/qbasictimer.cpp
+++ b/src/corelib/kernel/qbasictimer.cpp
@@ -79,7 +79,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn QBasicTimer::QBasicTimer()
- Contructs a basic timer.
+ Constructs a basic timer.
\sa start()
*/
diff --git a/src/corelib/kernel/qcfsocketnotifier.cpp b/src/corelib/kernel/qcfsocketnotifier.cpp
index 920ec9cd86..13fe30d0cd 100644
--- a/src/corelib/kernel/qcfsocketnotifier.cpp
+++ b/src/corelib/kernel/qcfsocketnotifier.cpp
@@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE
Socket Notifiers
*************************************************************************/
void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef,
- const void *, void *info)
+ const void *data, void *info)
{
QCFSocketNotifier *cfSocketNotifier = static_cast<QCFSocketNotifier *>(info);
@@ -61,7 +61,15 @@ void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CF
// notification after we've successfully disabled the CFSocket, but our Qt
// notifier is now gone. The upshot is we have to check the notifier
// every time.
- if (callbackType == kCFSocketReadCallBack) {
+ if (callbackType == kCFSocketConnectCallBack) {
+ // The data pointer will be non-null on connection error
+ if (data) {
+ if (socketInfo->readNotifier)
+ QCoreApplication::sendEvent(socketInfo->readNotifier, &notifierEvent);
+ if (socketInfo->writeNotifier)
+ QCoreApplication::sendEvent(socketInfo->writeNotifier, &notifierEvent);
+ }
+ } else if (callbackType == kCFSocketReadCallBack) {
if (socketInfo->readNotifier && socketInfo->readEnabled) {
socketInfo->readEnabled = false;
QCoreApplication::sendEvent(socketInfo->readNotifier, &notifierEvent);
@@ -152,7 +160,7 @@ void QCFSocketNotifier::registerSocketNotifier(QSocketNotifier *notifier)
// Create CFSocket, specify that we want both read and write callbacks (the callbacks
// are enabled/disabled later on).
- const int callbackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack;
+ const int callbackTypes = kCFSocketConnectCallBack | kCFSocketReadCallBack | kCFSocketWriteCallBack;
CFSocketContext context = {0, this, 0, 0, 0};
socketInfo->socket = CFSocketCreateWithNative(kCFAllocatorDefault, nativeSocket, callbackTypes, qt_mac_socket_callback, &context);
if (CFSocketIsValid(socketInfo->socket) == false) {
diff --git a/src/corelib/kernel/qcore_mac.mm b/src/corelib/kernel/qcore_mac.mm
index 33c64bc474..0b64deff4b 100644
--- a/src/corelib/kernel/qcore_mac.mm
+++ b/src/corelib/kernel/qcore_mac.mm
@@ -54,6 +54,7 @@
#include <cxxabi.h>
#include <objc/runtime.h>
#include <mach-o/dyld.h>
+#include <sys/sysctl.h>
#include <qdebug.h>
@@ -116,7 +117,7 @@ bool AppleUnifiedLogger::messageHandler(QtMsgType msgType, const QMessageLogCont
const bool isDefault = !context.category || !strcmp(context.category, "default");
os_log_t log = isDefault ? OS_LOG_DEFAULT :
- cachedLog(subsystem, QString::fromLatin1(context.category));
+ os_log_create(subsystem.toLatin1().constData(), context.category);
os_log_type_t logType = logTypeForMessageType(msgType);
if (!os_log_type_enabled(log, logType))
@@ -152,29 +153,6 @@ os_log_type_t AppleUnifiedLogger::logTypeForMessageType(QtMsgType msgType)
return OS_LOG_TYPE_DEFAULT;
}
-os_log_t AppleUnifiedLogger::cachedLog(const QString &subsystem, const QString &category)
-{
- static QBasicMutex mutex;
- const auto locker = qt_scoped_lock(mutex);
-
- static QHash<QPair<QString, QString>, os_log_t> logs;
- const auto cacheKey = qMakePair(subsystem, category);
- os_log_t log = logs.value(cacheKey);
-
- if (!log) {
- log = os_log_create(subsystem.toLatin1().constData(),
- category.toLatin1().constData());
- logs.insert(cacheKey, log);
-
- // Technically we should release the os_log_t resource when done
- // with it, but since we don't know when a category is disabled
- // we keep all cached os_log_t instances until shutdown, where
- // the OS will clean them up for us.
- }
-
- return log;
-}
-
#endif // QT_USE_APPLE_UNIFIED_LOGGING
// -------------------------------------------------------------------------
@@ -351,6 +329,15 @@ bool qt_mac_applicationIsInDarkMode()
#endif
return false;
}
+
+bool qt_mac_runningUnderRosetta()
+{
+ int translated = 0;
+ auto size = sizeof(translated);
+ if (sysctlbyname("sysctl.proc_translated", &translated, &size, nullptr, 0) == 0)
+ return translated;
+ return false;
+}
#endif
bool qt_apple_isApplicationExtension()
@@ -386,8 +373,8 @@ bool qt_apple_isSandboxed()
{
static bool isSandboxed = []() {
QCFType<SecStaticCodeRef> staticCode = nullptr;
- NSURL *bundleUrl = [[NSBundle mainBundle] bundleURL];
- if (SecStaticCodeCreateWithPath((__bridge CFURLRef)bundleUrl,
+ NSURL *executableUrl = NSBundle.mainBundle.executableURL;
+ if (SecStaticCodeCreateWithPath((__bridge CFURLRef)executableUrl,
kSecCSDefaultFlags, &staticCode) != errSecSuccess)
return false;
@@ -619,6 +606,14 @@ void qt_apple_check_os_version()
const NSOperatingSystemVersion required = (NSOperatingSystemVersion){
version / 10000, version / 100 % 100, version % 100};
const NSOperatingSystemVersion current = NSProcessInfo.processInfo.operatingSystemVersion;
+
+#if defined(Q_OS_MACOS)
+ // Check for compatibility version, in which case we can't do a
+ // comparison to the deployment target, which might be e.g. 11.0
+ if (current.majorVersion == 10 && current.minorVersion >= 16)
+ return; // FIXME: Find a way to detect the real OS version
+#endif
+
if (![NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:required]) {
NSDictionary *plist = NSBundle.mainBundle.infoDictionary;
NSString *applicationName = plist[@"CFBundleDisplayName"];
@@ -654,7 +649,7 @@ void QMacKeyValueObserver::removeObserver() {
KeyValueObserver *QMacKeyValueObserver::observer = [[KeyValueObserver alloc] init];
QT_END_NAMESPACE
-@implementation KeyValueObserver
+@implementation QT_MANGLE_NAMESPACE(KeyValueObserver)
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context
{
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index 96a2ff8567..a851c3e742 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -172,6 +172,7 @@ private:
Q_CORE_EXPORT QChar qt_mac_qtKey2CocoaKey(Qt::Key key);
Q_CORE_EXPORT Qt::Key qt_mac_cocoaKey2QtKey(QChar keyCode);
Q_CORE_EXPORT bool qt_mac_applicationIsInDarkMode();
+Q_CORE_EXPORT bool qt_mac_runningUnderRosetta();
#endif
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index a97b68f372..d671f70bd3 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -398,10 +398,11 @@ static bool quitLockRefEnabled = true;
#endif
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
-// Check whether the command line arguments match those passed to main()
-// by comparing to the global __argv/__argc (MS extension).
-// Deep comparison is required since argv/argc is rebuilt by WinMain for
-// GUI apps or when using MinGW due to its globbing.
+// Check whether the command line arguments passed to QCoreApplication
+// match those passed into main(), to see if the user has modified them
+// before passing them on to us. We do this by comparing to the global
+// __argv/__argc (MS extension). Deep comparison is required since
+// argv/argc is rebuilt by our WinMain entrypoint.
static inline bool isArgvModified(int argc, char **argv)
{
if (__argc != argc || !__argv /* wmain() */)
@@ -1156,7 +1157,7 @@ static bool doNotify(QObject *receiver, QEvent *event)
bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiver, QEvent *event)
{
// We can't access the application event filters outside of the main thread (race conditions)
- Q_ASSERT(receiver->d_func()->threadData.loadRelaxed()->thread.loadAcquire() == mainThread());
+ Q_ASSERT(receiver->d_func()->threadData.loadAcquire()->thread.loadRelaxed() == mainThread());
if (extraData) {
// application event filters are only called for objects in the GUI thread
@@ -1251,8 +1252,8 @@ bool QCoreApplication::closingDown()
/*!
- Processes all pending events for the calling thread according to
- the specified \a flags until there are no more events to process.
+ Processes some pending events for the calling thread according to
+ the specified \a flags.
You can call this function occasionally when your program is busy
performing a long operation (e.g. copying a file).
@@ -1299,6 +1300,9 @@ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags)
\note Unlike the \l{QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags)}{processEvents()}
overload, this function also processes events that are posted while the function runs.
+ \note All events that were queued before the timeout will be processed,
+ however long it takes.
+
\threadsafe
\sa exec(), QTimer, QEventLoop::processEvents()
@@ -2048,6 +2052,8 @@ void QCoreApplication::quit()
The function returns \c true on success and false on failure.
+ \note QCoreApplication does \e not take ownership of \a translationFile.
+
\sa removeTranslator(), translate(), QTranslator::load(), {Dynamic Translation}
*/
@@ -2430,32 +2436,46 @@ QStringList QCoreApplication::arguments()
qWarning("QCoreApplication::arguments: Please instantiate the QApplication object first");
return list;
}
- const int ac = self->d_func()->argc;
- char ** const av = self->d_func()->argv;
- list.reserve(ac);
-
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
- // On Windows, it is possible to pass Unicode arguments on
- // the command line. To restore those, we split the command line
- // and filter out arguments that were deleted by derived application
- // classes by index.
- QString cmdline = QString::fromWCharArray(GetCommandLine());
const QCoreApplicationPrivate *d = self->d_func();
- if (d->origArgv) {
- const QStringList allArguments = qWinCmdArgs(cmdline);
- Q_ASSERT(allArguments.size() == d->origArgc);
- for (int i = 0; i < d->origArgc; ++i) {
- if (contains(ac, av, d->origArgv[i]))
- list.append(allArguments.at(i));
+
+ const int argc = d->argc;
+ char ** const argv = d->argv;
+ list.reserve(argc);
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ const bool argsModifiedByUser = d->origArgv == nullptr;
+ if (!argsModifiedByUser) {
+ // On Windows, it is possible to pass Unicode arguments on
+ // the command line, but we don't implement any of the wide
+ // entry-points (wmain/wWinMain), so get the arguments from
+ // the Windows API instead of using argv. Note that we only
+ // do this when argv were not modified by the user in main().
+ QString cmdline = QString::fromWCharArray(GetCommandLine());
+ QStringList commandLineArguments = qWinCmdArgs(cmdline);
+
+ // Even if the user didn't modify argv before passing them
+ // on to QCoreApplication, derived QApplications might have.
+ // If that's the case argc will differ from origArgc.
+ if (argc != d->origArgc) {
+ // Note: On MingGW the arguments from GetCommandLine are
+ // not wildcard expanded (if wildcard expansion is enabled),
+ // as opposed to the arguments in argv. This means we can't
+ // compare commandLineArguments to argv/origArgc, but
+ // must remove elements by value, based on whether they
+ // were filtered out from argc.
+ for (int i = 0; i < d->origArgc; ++i) {
+ if (!contains(argc, argv, d->origArgv[i]))
+ commandLineArguments.removeAll(QString::fromLocal8Bit(d->origArgv[i]));
+ }
}
- return list;
+
+ return commandLineArguments;
} // Fall back to rebuilding from argv/argc when a modified argv was passed.
#endif // defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
- for (int a = 0; a < ac; ++a) {
- list << QString::fromLocal8Bit(av[a]);
- }
+ for (int a = 0; a < argc; ++a)
+ list << QString::fromLocal8Bit(argv[a]);
return list;
}
@@ -2748,9 +2768,10 @@ QStringList QCoreApplication::libraryPathsLocked()
/*!
- Sets the list of directories to search when loading libraries to
- \a paths. All existing paths will be deleted and the path list
- will consist of the paths given in \a paths.
+ Sets the list of directories to search when loading plugins with
+ QLibrary to \a paths. All existing paths will be deleted and the
+ path list will consist of the paths given in \a paths and the path
+ to the application.
The library paths are reset to the default when an instance of
QCoreApplication is destructed.
diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp
index e3326f00d7..fb3a5c4ec9 100644
--- a/src/corelib/kernel/qcoreevent.cpp
+++ b/src/corelib/kernel/qcoreevent.cpp
@@ -250,7 +250,7 @@ QT_BEGIN_NAMESPACE
\value WindowStateChange The \l{QWindow::windowState()}{window's state} (minimized, maximized or full-screen) has changed (QWindowStateChangeEvent).
\value WindowTitleChange The window title has changed.
\value WindowUnblocked The window is unblocked after a modal dialog exited.
- \value WinIdChange The window system identifer for this native widget has changed.
+ \value WinIdChange The window system identifier for this native widget has changed.
\value ZOrderChange The widget's z-order has changed. This event is never sent to top level windows.
User events should have values between \c User and \c{MaxUser}:
@@ -292,7 +292,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- Contructs an event object of type \a type.
+ Constructs an event object of type \a type.
*/
QEvent::QEvent(Type type)
: d(nullptr), t(type), posted(false), spont(false), m_accept(true)
@@ -421,6 +421,8 @@ struct QBasicAtomicBitField {
QBasicAtomicInteger<uint> next;
QBasicAtomicInteger<uint> data[NumInts];
+ constexpr QBasicAtomicBitField() = default;
+
bool allocateSpecific(int which) noexcept
{
QBasicAtomicInteger<uint> &entry = data[which / BitsPerInt];
@@ -461,7 +463,7 @@ struct QBasicAtomicBitField {
typedef QBasicAtomicBitField<QEvent::MaxUser - QEvent::User + 1> UserEventTypeRegistry;
-static UserEventTypeRegistry userEventTypeRegistry;
+static UserEventTypeRegistry userEventTypeRegistry {};
static inline int registerEventTypeZeroBased(int id) noexcept
{
diff --git a/src/corelib/kernel/qdeadlinetimer.cpp b/src/corelib/kernel/qdeadlinetimer.cpp
index 520153b2e5..a627590c7c 100644
--- a/src/corelib/kernel/qdeadlinetimer.cpp
+++ b/src/corelib/kernel/qdeadlinetimer.cpp
@@ -891,7 +891,7 @@ QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcep
\relates QDeadlineTimer
Returns true if the deadline on \a d1 and the deadline in \a d2 are
- diferent, false otherwise. The timer type used to create the two deadlines
+ different, false otherwise. The timer type used to create the two deadlines
is ignored. This function is equivalent to:
\snippet code/src_corelib_kernel_qdeadlinetimer.cpp 9
diff --git a/src/corelib/kernel/qelapsedtimer.cpp b/src/corelib/kernel/qelapsedtimer.cpp
index 57825583dd..230bcac33f 100644
--- a/src/corelib/kernel/qelapsedtimer.cpp
+++ b/src/corelib/kernel/qelapsedtimer.cpp
@@ -111,18 +111,6 @@ QT_BEGIN_NAMESPACE
that the clock used is the same as QElapsedTimer (see
QElapsedTimer::clockType()).
- \section2 32-bit overflows
-
- Some of the clocks used by QElapsedTimer have a limited range and may
- overflow after hitting the upper limit (usually 32-bit). QElapsedTimer
- deals with this overflow issue and presents a consistent timing. However,
- when extracting the time since reference from QElapsedTimer, two
- different processes in the same machine may have different understanding
- of how much time has actually elapsed.
-
- The information on which clocks types may overflow and how to remedy that
- issue is documented along with the clock types.
-
\sa QTime, QTimer, QDeadlineTimer
*/
@@ -138,10 +126,13 @@ QT_BEGIN_NAMESPACE
used.
\value SystemTime The human-readable system time. This clock is not monotonic.
- \value MonotonicClock The system's monotonic clock, usually found in Unix systems. This clock is monotonic and does not overflow.
- \value TickCounter The system's tick counter, used on Windows systems. This clock may overflow.
- \value MachAbsoluteTime The Mach kernel's absolute time (\macos and iOS). This clock is monotonic and does not overflow.
- \value PerformanceCounter The high-resolution performance counter provided by Windows. This clock is monotonic and does not overflow.
+ \value MonotonicClock The system's monotonic clock, usually found in Unix systems.
+ This clock is monotonic.
+ \value TickCounter Not used anymore.
+ \value MachAbsoluteTime The Mach kernel's absolute time (\macos and iOS).
+ This clock is monotonic.
+ \value PerformanceCounter The performance counter provided by Windows.
+ This clock is monotonic.
\section2 SystemTime
@@ -159,26 +150,6 @@ QT_BEGIN_NAMESPACE
arbitrary point in the past. This clock type is used on Unix systems
which support POSIX monotonic clocks (\tt{_POSIX_MONOTONIC_CLOCK}).
- This clock does not overflow.
-
- \section2 TickCounter
-
- The tick counter clock type is based on the system's or the processor's
- tick counter, multiplied by the duration of a tick. This clock type is
- used on Windows platforms. If the high-precision performance
- counter is available on Windows, the \tt{PerformanceCounter} clock type
- is used instead.
-
- The TickCounter clock type is the only clock type that may overflow.
- Windows Vista and Windows Server 2008 support the extended 64-bit tick
- counter, which allows avoiding the overflow.
-
- On Windows systems, the clock overflows after 2^32 milliseconds, which
- corresponds to roughly 49.7 days. This means two processes' reckoning of
- the time since the reference may be different by multiples of 2^32
- milliseconds. When comparing such values, it's recommended that the high
- 32 bits of the millisecond count be masked off.
-
\section2 MachAbsoluteTime
This clock type is based on the absolute time presented by Mach kernels,
@@ -187,17 +158,14 @@ QT_BEGIN_NAMESPACE
a POSIX monotonic clock with values differing from the Mach absolute
time.
- This clock is monotonic and does not overflow.
+ This clock is monotonic.
\section2 PerformanceCounter
This clock uses the Windows functions \tt{QueryPerformanceCounter} and
- \tt{QueryPerformanceFrequency} to access the system's high-precision
- performance counter. Since this counter may not be available on all
- systems, QElapsedTimer will fall back to the \tt{TickCounter} clock
- automatically, if this clock cannot be used.
+ \tt{QueryPerformanceFrequency} to access the system's performance counter.
- This clock is monotonic and does not overflow.
+ This clock is monotonic.
\sa clockType(), isMonotonic()
*/
diff --git a/src/corelib/kernel/qelapsedtimer_generic.cpp b/src/corelib/kernel/qelapsedtimer_generic.cpp
index fe959e3c94..5a93735c49 100644
--- a/src/corelib/kernel/qelapsedtimer_generic.cpp
+++ b/src/corelib/kernel/qelapsedtimer_generic.cpp
@@ -81,7 +81,8 @@ void QElapsedTimer::start() noexcept
}
/*!
- Restarts the timer and returns the time elapsed since the previous start.
+ Restarts the timer and returns the number of milliseconds elapsed since
+ the previous start.
This function is equivalent to obtaining the elapsed time with elapsed()
and then starting the timer again with start(), but it does so in one
single operation, avoiding the need to obtain the clock value twice.
diff --git a/src/corelib/kernel/qeventdispatcher_cf.mm b/src/corelib/kernel/qeventdispatcher_cf.mm
index b482269df2..5812442c91 100644
--- a/src/corelib/kernel/qeventdispatcher_cf.mm
+++ b/src/corelib/kernel/qeventdispatcher_cf.mm
@@ -89,7 +89,7 @@ QT_USE_NAMESPACE
QT_NAMESPACE_ALIAS_OBJC_CLASS(RunLoopModeTracker);
-@implementation RunLoopModeTracker {
+@implementation QT_MANGLE_NAMESPACE(RunLoopModeTracker) {
QStack<CFStringRef> m_runLoopModes;
}
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index 65fc7870f2..c9d0f03619 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -98,7 +98,7 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
QEventDispatcherWin32Private::QEventDispatcherWin32Private()
: threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0),
- getMessageHook(0), sendPostedEventsTimerId(0), wakeUps(0),
+ sendPostedEventsTimerId(0), wakeUps(0),
activateNotifiersPosted(false), winEventNotifierActivatedEvent(NULL)
{
}
@@ -265,30 +265,23 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
static const UINT mask = inputQueueMask();
if (HIWORD(GetQueueStatus(mask)) == 0)
q->sendPostedEvents();
+ else
+ d->startPostedEventsTimer();
return 0;
} // switch (message)
return DefWindowProc(hwnd, message, wp, lp);
}
-LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp)
+void QEventDispatcherWin32Private::startPostedEventsTimer()
{
- QEventDispatcherWin32 *q = qobject_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance());
- Q_ASSERT(q != 0);
- QEventDispatcherWin32Private *d = q->d_func();
- MSG *msg = reinterpret_cast<MSG *>(lp);
- // Windows unexpectedly passes PM_NOYIELD flag to the hook procedure,
- // if ::PeekMessage(..., PM_REMOVE | PM_NOYIELD) is called from the event loop.
- // So, retrieve 'removed' tag as a bit field.
- const bool messageRemoved = (wp & PM_REMOVE) != 0;
-
- if (msg->hwnd == d->internalHwnd && msg->message == WM_QT_SENDPOSTEDEVENTS
- && messageRemoved && d->sendPostedEventsTimerId == 0) {
+ // we received WM_QT_SENDPOSTEDEVENTS, so allow posting it again
+ wakeUps.storeRelaxed(0);
+ if (sendPostedEventsTimerId == 0) {
// Start a timer to deliver posted events when the message queue is emptied.
- d->sendPostedEventsTimerId = SetTimer(d->internalHwnd, SendPostedEventsTimerId,
- USER_TIMER_MINIMUM, NULL);
+ sendPostedEventsTimerId = SetTimer(internalHwnd, SendPostedEventsTimerId,
+ USER_TIMER_MINIMUM, NULL);
}
- return d->getMessageHook ? CallNextHookEx(0, code, wp, lp) : 0;
}
// Provide class name and atom for the message window used by
@@ -469,14 +462,6 @@ void QEventDispatcherWin32::createInternalHwnd()
return;
d->internalHwnd = qt_create_internal_window(this);
- // setup GetMessage hook needed to drive our posted events
- d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId());
- if (Q_UNLIKELY(!d->getMessageHook)) {
- int errorCode = GetLastError();
- qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %ls",
- errorCode, qUtf16Printable(qt_error_string(errorCode)));
- }
-
// start all normal timers
for (int i = 0; i < d->timerVec.count(); ++i)
d->registerTimer(d->timerVec.at(i));
@@ -520,13 +505,17 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
wakeUp(); // trigger a call to sendPostedEvents()
}
- d->interrupt.storeRelaxed(false);
+ // We don't know _when_ the interrupt occurred so we have to honor it.
+ const bool wasInterrupted = d->interrupt.fetchAndStoreRelaxed(false);
emit awake();
// To prevent livelocks, send posted events once per iteration.
// QCoreApplication::sendPostedEvents() takes care about recursions.
sendPostedEvents();
+ if (wasInterrupted)
+ return false;
+
auto threadData = d->threadData.loadRelaxed();
bool canWait;
bool retVal = false;
@@ -578,6 +567,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
}
if (haveMessage) {
if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
+ d->startPostedEventsTimer();
// Set result to 'true' because the message was sent by wakeUp().
retVal = true;
continue;
@@ -1022,10 +1012,6 @@ void QEventDispatcherWin32::closingDown()
d->closingDown = true;
- if (d->getMessageHook)
- UnhookWindowsHookEx(d->getMessageHook);
- d->getMessageHook = 0;
-
if (d->sendPostedEventsTimerId != 0)
KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
d->sendPostedEventsTimerId = 0;
diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h
index dbb30ab568..bd007f8262 100644
--- a/src/corelib/kernel/qeventdispatcher_win_p.h
+++ b/src/corelib/kernel/qeventdispatcher_win_p.h
@@ -114,7 +114,6 @@ protected:
private:
friend LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
- friend LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int, WPARAM, LPARAM);
};
struct QSockNot {
@@ -168,11 +167,11 @@ public:
// internal window handle used for socketnotifiers/timers/etc
HWND internalHwnd;
- HHOOK getMessageHook;
// for controlling when to send posted events
UINT_PTR sendPostedEventsTimerId;
QAtomicInt wakeUps;
+ void startPostedEventsTimer();
// timers
WinTimerVec timerVec;
diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp
index 5a5dfb06aa..5d793ce72a 100644
--- a/src/corelib/kernel/qeventloop.cpp
+++ b/src/corelib/kernel/qeventloop.cpp
@@ -50,6 +50,9 @@
#ifdef Q_OS_WASM
#include <emscripten.h>
+#if QT_CONFIG(thread)
+#include <emscripten/threading.h>
+#endif
#endif
QT_BEGIN_NAMESPACE
@@ -118,8 +121,8 @@ QEventLoop::~QEventLoop()
/*!
- Processes pending events that match \a flags until there are no
- more events to process. Returns \c true if pending events were handled;
+ Processes some pending events that match \a flags.
+ Returns \c true if pending events were handled;
otherwise returns \c false.
This function is especially useful if you have a long running
@@ -295,6 +298,9 @@ void QEventLoop::exit(int returnCode)
// QEventLoop::exec() never returns in emscripten. We implement approximate behavior here.
// QTBUG-70185
if (threadData->loopLevel == 1) {
+#if QT_CONFIG(thread)
+ if (emscripten_is_main_browser_thread())
+#endif
emscripten_force_exit(returnCode);
} else {
d->inExec = false;
diff --git a/src/corelib/kernel/qfunctions_winrt.h b/src/corelib/kernel/qfunctions_winrt.h
index d0c44be683..d29bd81d4e 100644
--- a/src/corelib/kernel/qfunctions_winrt.h
+++ b/src/corelib/kernel/qfunctions_winrt.h
@@ -167,8 +167,11 @@ enum AwaitStyle
ProcessMainThreadEvents = 2
};
-template <typename T>
-static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, AwaitStyle awaitStyle, uint timeout)
+using EarlyExitConditionFunction = std::function<bool(void)>;
+
+template<typename T>
+static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, AwaitStyle awaitStyle,
+ uint timeout, EarlyExitConditionFunction func)
{
Microsoft::WRL::ComPtr<IAsyncInfo> asyncInfo;
HRESULT hr = asyncOp.As(&asyncInfo);
@@ -183,6 +186,8 @@ static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, Awai
case ProcessMainThreadEvents:
while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == AsyncStatus::Started) {
QCoreApplication::processEvents();
+ if (func && func())
+ return E_ABORT;
if (timeout && t.hasExpired(timeout))
return ERROR_TIMEOUT;
}
@@ -191,6 +196,8 @@ static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, Awai
if (QAbstractEventDispatcher *dispatcher = QThread::currentThread()->eventDispatcher()) {
while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == AsyncStatus::Started) {
dispatcher->processEvents(QEventLoop::AllEvents);
+ if (func && func())
+ return E_ABORT;
if (timeout && t.hasExpired(timeout))
return ERROR_TIMEOUT;
}
@@ -221,20 +228,24 @@ static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, Awai
return hr;
}
-template <typename T>
-static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, AwaitStyle awaitStyle = YieldThread, uint timeout = 0)
+template<typename T>
+static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp,
+ AwaitStyle awaitStyle = YieldThread, uint timeout = 0,
+ EarlyExitConditionFunction func = nullptr)
{
- HRESULT hr = _await_impl(asyncOp, awaitStyle, timeout);
+ HRESULT hr = _await_impl(asyncOp, awaitStyle, timeout, func);
if (FAILED(hr))
return hr;
return asyncOp->GetResults();
}
-template <typename T, typename U>
-static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, U *results, AwaitStyle awaitStyle = YieldThread, uint timeout = 0)
+template<typename T, typename U>
+static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, U *results,
+ AwaitStyle awaitStyle = YieldThread, uint timeout = 0,
+ EarlyExitConditionFunction func = nullptr)
{
- HRESULT hr = _await_impl(asyncOp, awaitStyle, timeout);
+ HRESULT hr = _await_impl(asyncOp, awaitStyle, timeout, func);
if (FAILED(hr))
return hr;
diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp
index 7d278c69f2..817effe742 100644
--- a/src/corelib/kernel/qjnihelpers.cpp
+++ b/src/corelib/kernel/qjnihelpers.cpp
@@ -48,6 +48,7 @@
#include "qcoreapplication.h"
#include <QtCore/qrunnable.h>
+#include <QReadWriteLock>
#include <deque>
#include <memory>
@@ -80,6 +81,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(QtAndroidPrivate::OnBindListener*, g_onBindListener, (
Q_GLOBAL_STATIC(QMutex, g_onBindListenerMutex);
Q_GLOBAL_STATIC(QSemaphore, g_waitForServiceSetupSemaphore);
Q_GLOBAL_STATIC(QAtomicInt, g_serviceSetupLockers);
+Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex);
class PermissionsResultClass : public QObject
{
@@ -326,6 +328,41 @@ static void setNativeActivity(JNIEnv *env, jclass, jobject activity)
}
}
+static jboolean updateNativeActivity(JNIEnv *env, jclass = nullptr)
+{
+
+ jclass jQtNative = env->FindClass("org/qtproject/qt5/android/QtNative");
+ if (exceptionCheck(env))
+ return JNI_FALSE;
+
+ jmethodID activityMethodID =
+ env->GetStaticMethodID(jQtNative, "activity", "()Landroid/app/Activity;");
+ if (exceptionCheck(env))
+ return JNI_FALSE;
+
+ jobject activity = env->CallStaticObjectMethod(jQtNative, activityMethodID);
+ if (exceptionCheck(env))
+ return JNI_FALSE;
+
+ QWriteLocker locker(g_updateMutex());
+
+ if (g_jActivity) {
+ env->DeleteGlobalRef(g_jActivity);
+ g_jActivity = nullptr;
+ }
+
+ if (activity) {
+ g_jActivity = env->NewGlobalRef(activity);
+ env->DeleteLocalRef(activity);
+ }
+
+ env->DeleteLocalRef(jQtNative);
+ if (exceptionCheck(env))
+ return JNI_FALSE;
+
+ return JNI_TRUE;
+}
+
static void setNativeService(JNIEnv *env, jclass, jobject service)
{
if (g_jService != 0)
@@ -402,6 +439,7 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
{"setNativeActivity", "(Landroid/app/Activity;)V", reinterpret_cast<void *>(setNativeActivity)},
{"setNativeService", "(Landroid/app/Service;)V", reinterpret_cast<void *>(setNativeService)},
{"sendRequestPermissionsResult", "(I[Ljava/lang/String;[I)V", reinterpret_cast<void *>(sendRequestPermissionsResult)},
+ {"updateNativeActivity", "()Z", reinterpret_cast<void *>(updateNativeActivity) },
};
const bool regOk = (env->RegisterNatives(jQtNative, methods, sizeof(methods) / sizeof(methods[0])) == JNI_OK);
@@ -423,6 +461,7 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
jobject QtAndroidPrivate::activity()
{
+ QReadLocker locker(g_updateMutex());
return g_jActivity;
}
@@ -433,12 +472,13 @@ jobject QtAndroidPrivate::service()
jobject QtAndroidPrivate::context()
{
+ QReadLocker locker(g_updateMutex());
if (g_jActivity)
return g_jActivity;
if (g_jService)
return g_jService;
- return 0;
+ return nullptr;
}
JavaVM *QtAndroidPrivate::javaVM()
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index 47fcada302..b33987c2f0 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -166,6 +166,13 @@ static inline const QByteArray stringData(const QMetaObject *mo, int index)
return data;
}
+static inline QLatin1String stringDataView(const QMetaObject *mo, int index)
+{
+ const QByteArrayData &d = mo->d.stringdata[index];
+ const char *string = reinterpret_cast<const char *>(d.data());
+ return QLatin1String(string, d.size);
+}
+
static inline const char *rawStringData(const QMetaObject *mo, int index)
{
return stringData(mo, index).data();
@@ -2819,6 +2826,28 @@ int QMetaEnum::keysToValue(const char *keys, bool *ok) const
return value;
}
+namespace
+{
+template <typename String, typename Container, typename Separator>
+void join_reversed(String &s, const Container &c, Separator sep)
+{
+ if (c.empty())
+ return;
+ qsizetype len = qsizetype(c.size()) - 1; // N - 1 separators
+ for (auto &e : c)
+ len += qsizetype(e.size()); // N parts
+ s.reserve(len);
+ bool first = true;
+ for (auto rit = c.rbegin(), rend = c.rend(); rit != rend; ++rit) {
+ const auto &e = *rit;
+ if (!first)
+ s.append(sep);
+ first = false;
+ s.append(e.data(), e.size());
+ }
+}
+} // unnamed namespace
+
/*!
Returns a byte array of '|'-separated keys that represents the
given \a value.
@@ -2833,17 +2862,17 @@ QByteArray QMetaEnum::valueToKeys(int value) const
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
int count = mobj->d.data[handle + offset];
int data = mobj->d.data[handle + offset + 1];
+ QVarLengthArray<QLatin1String, sizeof(int) * CHAR_BIT> parts;
int v = value;
// reverse iterate to ensure values like Qt::Dialog=0x2|Qt::Window are processed first.
for (int i = count - 1; i >= 0; --i) {
int k = mobj->d.data[data + 2*i + 1];
if ((k != 0 && (v & k) == k ) || (k == value)) {
v = v & ~k;
- if (!keys.isEmpty())
- keys.prepend('|');
- keys.prepend(stringData(mobj, mobj->d.data[data + 2*i]));
+ parts.push_back(stringDataView(mobj, mobj->d.data[data + 2 * i]));
}
}
+ join_reversed(keys, parts, '|');
return keys;
}
@@ -3184,7 +3213,7 @@ QVariant QMetaProperty::read(const QObject *object) const
If \a value is not of the same type type as the property, a conversion
is attempted. An empty QVariant() is equivalent to a call to reset()
- if this property is resetable, or setting a default-constructed object
+ if this property is resettable, or setting a default-constructed object
otherwise.
\sa read(), reset(), isWritable()
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 21254108e3..33240dd335 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -414,19 +414,21 @@ struct DefinedTypesFilter {
\fn const QMetaObject *QMetaType::metaObject() const
\since 5.5
- return a QMetaObject relative to this type.
+ Returns a QMetaObject relative to this type.
If the type is a pointer type to a subclass of QObject, flags() contains
- QMetaType::PointerToQObject and this function returns the corresponding QMetaObject. This can
- be used to in combinaison with QMetaObject::construct to create QObject of this type.
-
- If the type is a Q_GADGET, flags() contains QMetaType::IsGadget, and this function returns its
- QMetaObject. This can be used to retrieve QMetaMethod and QMetaProperty and use them on a
- pointer of this type. (given by QVariant::data for example)
-
- If the type is an enumeration, flags() contains QMetaType::IsEnumeration, and this function
- returns the QMetaObject of the enclosing object if the enum was registered as a Q_ENUM or
- \nullptr otherwise
+ QMetaType::PointerToQObject and this function returns the corresponding QMetaObject.
+ This can be used in combination with QMetaObject::newInstance() to create QObjects of this type.
+
+ If the type is a Q_GADGET, flags() contains QMetaType::IsGadget.
+ If the type is a pointer to a Q_GADGET, flags() contains QMetaType::PointerToGadget.
+ In both cases, this function returns its QMetaObject.
+ This can be used to retrieve QMetaMethod and QMetaProperty and use them on a
+ pointer of this type for example, as given by QVariant::data().
+
+ If the type is an enumeration, flags() contains QMetaType::IsEnumeration.
+ In this case, this function returns the QMetaObject of the enclosing
+ object if the enum was registered as a Q_ENUM or \nullptr otherwise.
\sa QMetaType::metaObjectForType(), QMetaType::flags()
*/
diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h
index d743d5a5c7..50e5654221 100644
--- a/src/corelib/kernel/qmetatype_p.h
+++ b/src/corelib/kernel/qmetatype_p.h
@@ -108,6 +108,11 @@ public: \
#define QT_DECLARE_WIDGETS_MODULE_TYPES_ITER(TypeName, TypeId, Name) \
QT_ASSIGN_TYPE_TO_MODULE(Name, QModulesPrivate::Widgets);
+QT_WARNING_PUSH
+#if defined(Q_CC_CLANG) && Q_CC_CLANG >= 900
+QT_WARNING_DISABLE_CLANG("-Wconstant-logical-operand")
+#endif
+
QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(QT_DECLARE_CORE_MODULE_TYPES_ITER)
QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_DECLARE_CORE_MODULE_TYPES_ITER)
QT_FOR_EACH_STATIC_CORE_CLASS(QT_DECLARE_CORE_MODULE_TYPES_ITER)
@@ -115,6 +120,8 @@ QT_FOR_EACH_STATIC_CORE_POINTER(QT_DECLARE_CORE_MODULE_TYPES_ITER)
QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_DECLARE_CORE_MODULE_TYPES_ITER)
QT_FOR_EACH_STATIC_GUI_CLASS(QT_DECLARE_GUI_MODULE_TYPES_ITER)
QT_FOR_EACH_STATIC_WIDGETS_CLASS(QT_DECLARE_WIDGETS_MODULE_TYPES_ITER)
+
+QT_WARNING_POP
} // namespace QModulesPrivate
#undef QT_DECLARE_CORE_MODULE_TYPES_ITER
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 4a4fdc4ace..4fccf8dd56 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -71,6 +71,7 @@
#include <qtcore_tracepoints_p.h>
#include <new>
+#include <mutex>
#include <ctype.h>
#include <limits.h>
@@ -390,8 +391,14 @@ void QObjectPrivate::ConnectionData::removeConnection(QObjectPrivate::Connection
Q_ASSERT(c != orphaned.loadRelaxed());
// add c to orphanedConnections
- c->nextInOrphanList = orphaned.loadRelaxed();
- orphaned.storeRelaxed(c);
+ Connection *o = nullptr;
+ /* No ABA issue here: When adding a node, we only care about the list head, it doesn't
+ * matter if the tail changes.
+ */
+ do {
+ o = orphaned.loadRelaxed();
+ c->nextInOrphanList = o;
+ } while (!orphaned.testAndSetRelease(o, c));
#ifndef QT_NO_DEBUG
found = false;
@@ -406,21 +413,32 @@ void QObjectPrivate::ConnectionData::removeConnection(QObjectPrivate::Connection
}
-void QObjectPrivate::ConnectionData::cleanOrphanedConnectionsImpl(QObject *sender)
+void QObjectPrivate::ConnectionData::cleanOrphanedConnectionsImpl(QObject *sender, LockPolicy lockPolicy)
{
+ QBasicMutex *senderMutex = signalSlotLock(sender);
ConnectionOrSignalVector *c = nullptr;
{
- QBasicMutexLocker l(signalSlotLock(sender));
+ std::unique_lock<QBasicMutex> lock(*senderMutex, std::defer_lock_t{});
+ if (lockPolicy == NeedToLock)
+ lock.lock();
if (ref.loadAcquire() > 1)
return;
// Since ref == 1, no activate() is in process since we locked the mutex. That implies,
// that nothing can reference the orphaned connection objects anymore and they can
// be safely deleted
- c = orphaned.loadRelaxed();
- orphaned.storeRelaxed(nullptr);
+ c = orphaned.fetchAndStoreRelaxed(nullptr);
+ }
+ if (c) {
+ // Deleting c might run arbitrary user code, so we must not hold the lock
+ if (lockPolicy == AlreadyLockedAndTemporarilyReleasingLock) {
+ senderMutex->unlock();
+ deleteOrphaned(c);
+ senderMutex->lock();
+ } else {
+ deleteOrphaned(c);
+ }
}
- deleteOrphaned(c);
}
void QObjectPrivate::ConnectionData::deleteOrphaned(QObjectPrivate::ConnectionOrSignalVector *o)
@@ -992,7 +1010,7 @@ QObject::~QObject()
emit destroyed(this);
}
- if (d->declarativeData) {
+ if (!d->isDeletingChildren && d->declarativeData) {
if (static_cast<QAbstractDeclarativeDataImpl*>(d->declarativeData)->ownedByQml1) {
if (QAbstractDeclarativeData::destroyed_qml1)
QAbstractDeclarativeData::destroyed_qml1(d->declarativeData, this);
@@ -1022,7 +1040,7 @@ QObject::~QObject()
QBasicMutex *m = signalSlotLock(c->receiver.loadRelaxed());
bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
- if (c->receiver.loadAcquire()) {
+ if (c == connectionList.first.loadAcquire() && c->receiver.loadAcquire()) {
cd->removeConnection(c);
Q_ASSERT(connectionList.first.loadRelaxed() != c);
}
@@ -1060,14 +1078,29 @@ QObject::~QObject()
}
senderData->removeConnection(node);
+ /*
+ When we unlock, another thread has the chance to delete/modify sender data.
+ Thus we need to call cleanOrphanedConnections before unlocking. We use the
+ variant of the function which assumes that the lock is already held to avoid
+ a deadlock.
+ We need to hold m, the sender lock. Considering that we might execute arbitrary user
+ code, we should already release the signalSlotMutex here – unless they are the same.
+ */
+ const bool locksAreTheSame = signalSlotMutex == m;
+ if (!locksAreTheSame)
+ locker.unlock();
+ senderData->cleanOrphanedConnections(
+ sender,
+ QObjectPrivate::ConnectionData::AlreadyLockedAndTemporarilyReleasingLock
+ );
if (needToUnlock)
m->unlock();
- if (slotObj) {
+ if (locksAreTheSame) // otherwise already unlocked
locker.unlock();
+ if (slotObj)
slotObj->destroyIfLastRef();
- locker.relock();
- }
+ locker.relock();
}
// invalidate all connections on the object and make sure
@@ -1547,7 +1580,7 @@ void QObject::moveToThread(QThread *targetThread)
QThreadData *currentData = QThreadData::current();
QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : nullptr;
- QThreadData *thisThreadData = d->threadData.loadRelaxed();
+ QThreadData *thisThreadData = d->threadData.loadAcquire();
if (!thisThreadData->thread.loadAcquire() && currentData == targetData) {
// one exception to the rule: we allow moving objects with no thread affinity to the current thread
currentData = d->threadData;
@@ -2292,7 +2325,7 @@ void QObject::removeEventFilter(QObject *obj)
event loop was still running: the Qt event loop will delete those objects
as soon as the new nested event loop starts.
- \b{Note:} It is safe to call this function more than once; when the
+ \note It is safe to call this function more than once; when the
first deferred deletion event is delivered, any pending events for the
object are removed from the event queue.
@@ -2300,6 +2333,10 @@ void QObject::removeEventFilter(QObject *obj)
*/
void QObject::deleteLater()
{
+#ifdef QT_DEBUG
+ if (qApp == this)
+ qWarning("You are deferring the delete of QCoreApplication, this may not work as expected.");
+#endif
QCoreApplication::postEvent(this, new QDeferredDeleteEvent());
}
@@ -2423,6 +2460,7 @@ static bool check_method_code(int code, const QObject *object,
return true;
}
+Q_DECL_COLD_FUNCTION
static void err_method_notfound(const QObject *object,
const char *method, const char *func)
{
@@ -2444,6 +2482,7 @@ static void err_method_notfound(const QObject *object,
}
+Q_DECL_COLD_FUNCTION
static void err_info_about_objects(const char * func,
const QObject * sender,
const QObject * receiver)
@@ -2583,7 +2622,7 @@ int QObject::receivers(const char *signal) const
if (!d->isSignalConnected(signal_index))
return receivers;
- if (d->declarativeData && QAbstractDeclarativeData::receivers) {
+ if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::receivers) {
receivers += QAbstractDeclarativeData::receivers(d->declarativeData, this,
signal_index);
}
@@ -4175,7 +4214,7 @@ void QObject::dumpObjectTree()
/*!
Dumps a tree of children to the debug output.
- \note before Qt 5.9, this function was not const.
+ \note Before Qt 5.9, this function was not const.
\sa dumpObjectInfo()
*/
@@ -4206,7 +4245,7 @@ void QObject::dumpObjectInfo()
Dumps information about signal connections, etc. for this object
to the debug output.
- \note before Qt 5.9, this function was not const.
+ \note Before Qt 5.9, this function was not const.
\sa dumpObjectTree()
*/
@@ -4223,7 +4262,7 @@ void QObject::dumpObjectInfo() const
qDebug(" SIGNALS OUT");
QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
- if (cd && cd->signalVectorCount()) {
+ if (cd && cd->signalVectorCount() > 0) {
QObjectPrivate::SignalVector *signalVector = cd->signalVector.loadRelaxed();
for (int signal_index = 0; signal_index < signalVector->count(); ++signal_index) {
const QObjectPrivate::Connection *c = signalVector->at(signal_index).first.loadRelaxed();
@@ -5106,12 +5145,18 @@ bool QObject::disconnect(const QMetaObject::Connection &connection)
connections = QObjectPrivate::get(c->sender)->connections.loadRelaxed();
Q_ASSERT(connections);
connections->removeConnection(c);
- }
- connections->cleanOrphanedConnections(c->sender);
-
- c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(),
- c->signal_index));
+ c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(), c->signal_index));
+ // We must not hold the receiver mutex, else we risk dead-locking; we also only need the sender mutex
+ // It is however vital to hold the senderMutex before calling cleanOrphanedConnections, as otherwise
+ // another thread might modify/delete the connection
+ if (receiverMutex != senderMutex) {
+ receiverMutex->unlock();
+ }
+ connections->cleanOrphanedConnections(c->sender, QObjectPrivate::ConnectionData::AlreadyLockedAndTemporarilyReleasingLock);
+ senderMutex->unlock(); // now both sender and receiver mutex have been manually unlocked
+ locker.dismiss(); // so we dismiss the QOrderedMutexLocker
+ }
const_cast<QMetaObject::Connection &>(connection).d_ptr = nullptr;
c->deref(); // has been removed from the QMetaObject::Connection object
@@ -5206,12 +5251,33 @@ bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject
/*!
\internal
- Used by QML to connect a signal by index to a slot implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass).
+ Used by QML to connect a signal by index to a slot implemented in JavaScript
+ (wrapped in a custom QSlotObjectBase subclass).
+
+ This version of connect assumes that sender and receiver are the same object.
The signal_index is an index relative to the number of methods.
*/
QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type)
{
+ return QObjectPrivate::connect(sender, signal_index, sender, slotObj, type);
+}
+
+/*!
+ \internal
+ Used by QML to connect a signal by index to a slot implemented in JavaScript
+ (wrapped in a custom QSlotObjectBase subclass).
+
+ This is an overload that should be used when \a sender and \a receiver are
+ different objects.
+
+ The signal_index is an index relative to the number of methods.
+ */
+QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index,
+ const QObject *receiver,
+ QtPrivate::QSlotObjectBase *slotObj,
+ Qt::ConnectionType type)
+{
if (!sender) {
qWarning("QObject::connect: invalid nullptr parameter");
if (slotObj)
@@ -5221,7 +5287,8 @@ QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signa
const QMetaObject *senderMetaObject = sender->metaObject();
signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
- return QObjectPrivate::connectImpl(sender, signal_index, sender, /*slot*/nullptr, slotObj, type, /*types*/nullptr, senderMetaObject);
+ return QObjectPrivate::connectImpl(sender, signal_index, receiver, /*slot*/ nullptr, slotObj,
+ type, /*types*/ nullptr, senderMetaObject);
}
/*!
@@ -5229,13 +5296,34 @@ QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signa
Used by QML to disconnect a signal by index that's connected to a slot implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass)
In the QML case the slot is not a pointer to a pointer to the function to disconnect, but instead it is a pointer to an array of internal values
required for the disconnect.
+
+ This version of disconnect assumes that sender and receiver are the same object.
*/
bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, void **slot)
{
+ return QObjectPrivate::disconnect(sender, signal_index, sender, slot);
+}
+
+/*!
+ \internal
+
+ Used by QML to disconnect a signal by index that's connected to a slot
+ implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass) In the
+ QML case the slot is not a pointer to a pointer to the function to disconnect,
+ but instead it is a pointer to an array of internal values required for the
+ disconnect.
+
+ This is an overload that should be used when \a sender and \a receiver are
+ different objects.
+ */
+bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, const QObject *receiver,
+ void **slot)
+{
const QMetaObject *senderMetaObject = sender->metaObject();
signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
- return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, sender, -1, slot);
+ return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1,
+ slot);
}
/*! \class QMetaObject::Connection
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index 2caa6835b5..13ffb88999 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -268,7 +268,10 @@ public:
~ConnectionData()
{
- deleteOrphaned(orphaned.loadRelaxed());
+ Q_ASSERT(ref.loadRelaxed() == 0);
+ auto *c = orphaned.fetchAndStoreRelaxed(nullptr);
+ if (c)
+ deleteOrphaned(c);
SignalVector *v = signalVector.loadRelaxed();
if (v)
free(v);
@@ -277,12 +280,19 @@ public:
// must be called on the senders connection data
// assumes the senders and receivers lock are held
void removeConnection(Connection *c);
- void cleanOrphanedConnections(QObject *sender)
+ enum LockPolicy {
+ NeedToLock,
+ // Beware that we need to temporarily release the lock
+ // and thus calling code must carefully consider whether
+ // invariants still hold.
+ AlreadyLockedAndTemporarilyReleasingLock
+ };
+ void cleanOrphanedConnections(QObject *sender, LockPolicy lockPolicy = NeedToLock)
{
if (orphaned.loadRelaxed() && ref.loadAcquire() == 1)
- cleanOrphanedConnectionsImpl(sender);
+ cleanOrphanedConnectionsImpl(sender, lockPolicy);
}
- void cleanOrphanedConnectionsImpl(QObject *sender);
+ void cleanOrphanedConnectionsImpl(QObject *sender, LockPolicy lockPolicy);
ConnectionList &connectionsForSignal(int signal)
{
@@ -307,8 +317,14 @@ public:
signalVector.storeRelaxed(newVector);
if (vector) {
- vector->nextInOrphanList = orphaned.loadRelaxed();
- orphaned.storeRelaxed(ConnectionOrSignalVector::fromSignalVector(vector));
+ Connection *o = nullptr;
+ /* No ABA issue here: When adding a node, we only care about the list head, it doesn't
+ * matter if the tail changes.
+ */
+ do {
+ o = orphaned.loadRelaxed();
+ vector->nextInOrphanList = o;
+ } while (!orphaned.testAndSetRelease(o, ConnectionOrSignalVector::fromSignalVector(vector)));
}
}
int signalVectorCount() const {
@@ -364,7 +380,13 @@ public:
QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
const int *types, const QMetaObject *senderMetaObject);
static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
+ static QMetaObject::Connection connect(const QObject *sender, int signal_index,
+ const QObject *receiver,
+ QtPrivate::QSlotObjectBase *slotObj,
+ Qt::ConnectionType type);
static bool disconnect(const QObject *sender, int signal_index, void **slot);
+ static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver,
+ void **slot);
void ensureConnectionData()
{
@@ -422,7 +444,7 @@ inline void QObjectPrivate::checkForIncompatibleLibraryVersion(int version) cons
inline bool QObjectPrivate::isDeclarativeSignalConnected(uint signal_index) const
{
- return declarativeData && QAbstractDeclarativeData::isSignalConnected
+ return !isDeletingChildren && declarativeData && QAbstractDeclarativeData::isSignalConnected
&& QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index);
}
diff --git a/src/corelib/kernel/qsharedmemory_p.h b/src/corelib/kernel/qsharedmemory_p.h
index e6e989abda..0c13375094 100644
--- a/src/corelib/kernel/qsharedmemory_p.h
+++ b/src/corelib/kernel/qsharedmemory_p.h
@@ -56,14 +56,20 @@
#include <QtCore/qstring.h>
#ifdef QT_NO_SHAREDMEMORY
-# ifndef QT_NO_SYSTEMSEMAPHORE
+# ifndef QT_NO_SYSTEMSEMAPHORE
+
+QT_BEGIN_NAMESPACE
+
namespace QSharedMemoryPrivate
{
int createUnixKeyFile(const QString &fileName);
QString makePlatformSafeKey(const QString &key,
const QString &prefix = QLatin1String("qipc_sharedmemory_"));
}
-#endif
+
+QT_END_NAMESPACE
+
+# endif
#else
#include "qsystemsemaphore.h"
diff --git a/src/corelib/kernel/qsharedmemory_systemv.cpp b/src/corelib/kernel/qsharedmemory_systemv.cpp
index 0ba5f65641..b9adb4300c 100644
--- a/src/corelib/kernel/qsharedmemory_systemv.cpp
+++ b/src/corelib/kernel/qsharedmemory_systemv.cpp
@@ -109,7 +109,7 @@ key_t QSharedMemoryPrivate::handle()
0 already existed
1 created
*/
-int QSharedMemoryPrivate::createUnixKeyFile(const QString &fileName)
+int QT_PREPEND_NAMESPACE(QSharedMemoryPrivate)::createUnixKeyFile(const QString &fileName)
{
int fd = qt_safe_open(QFile::encodeName(fileName).constData(),
O_EXCL | O_CREAT | O_RDWR, 0640);
diff --git a/src/corelib/kernel/qsystemsemaphore_posix.cpp b/src/corelib/kernel/qsystemsemaphore_posix.cpp
index 9fbf5779b8..2bff5de4e5 100644
--- a/src/corelib/kernel/qsystemsemaphore_posix.cpp
+++ b/src/corelib/kernel/qsystemsemaphore_posix.cpp
@@ -70,7 +70,7 @@ bool QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode)
return true; // we already have a semaphore
if (fileName.isEmpty()) {
- errorString = QCoreApplication::tr("%1: key is empty", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle"));
+ errorString = QCoreApplication::translate("%1: key is empty", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle"));
error = QSystemSemaphore::KeyError;
return false;
}
diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp
index 25ce0c032f..79c7b2628c 100644
--- a/src/corelib/kernel/qtimer.cpp
+++ b/src/corelib/kernel/qtimer.cpp
@@ -222,6 +222,8 @@ void QTimer::start()
If \l singleShot is true, the timer will be activated only once.
+ \note Keeping the event loop busy with a zero-timer is bound to
+ cause trouble and highly erratic behavior of the UI.
*/
void QTimer::start(int msec)
{
diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp
index d7d670b5bc..bdcd016630 100644
--- a/src/corelib/kernel/qtranslator.cpp
+++ b/src/corelib/kernel/qtranslator.cpp
@@ -601,9 +601,14 @@ bool QTranslatorPrivate::do_load(const QString &realname, const QString &directo
}
}
- if (ok && d->do_load(reinterpret_cast<const uchar *>(d->unmapPointer), d->unmapLength, directory)) {
- d->filePath = realname;
- return true;
+ if (ok) {
+ const QString base_dir =
+ !directory.isEmpty() ? directory : QFileInfo(realname).absolutePath();
+ if (d->do_load(reinterpret_cast<const uchar *>(d->unmapPointer), d->unmapLength,
+ base_dir)) {
+ d->filePath = realname;
+ return true;
+ }
}
#if defined(QT_USE_MMAP)
@@ -647,46 +652,30 @@ static QString find_translation(const QLocale & locale,
QString realname;
realname += path + filename + prefix; // using += in the hope for some reserve capacity
const int realNameBaseSize = realname.size();
- QStringList fuzzyLocales;
// see http://www.unicode.org/reports/tr35/#LanguageMatching for inspiration
+ // For each language_country returned by locale.uiLanguages(), add
+ // also a lowercase version to the list. Since these languages are
+ // used to create file names, this is important on case-sensitive
+ // file systems, where otherwise a file called something like
+ // "prefix_en_us.qm" won't be found under the "en_US" locale. Note
+ // that the Qt resource system is always case-sensitive, even on
+ // Windows (in other words: this codepath is *not* UNIX-only).
QStringList languages = locale.uiLanguages();
-#if defined(Q_OS_UNIX)
for (int i = languages.size()-1; i >= 0; --i) {
QString lang = languages.at(i);
QString lowerLang = lang.toLower();
if (lang != lowerLang)
languages.insert(i+1, lowerLang);
}
-#endif
- // try explicit locales names first
for (QString localeName : qAsConst(languages)) {
localeName.replace(QLatin1Char('-'), QLatin1Char('_'));
- realname += localeName + suffixOrDotQM;
- if (is_readable_file(realname))
- return realname;
-
- realname.truncate(realNameBaseSize + localeName.size());
- if (is_readable_file(realname))
- return realname;
-
- realname.truncate(realNameBaseSize);
- fuzzyLocales.append(localeName);
- }
-
- // start guessing
- for (const QString &fuzzyLocale : qAsConst(fuzzyLocales)) {
- QStringRef localeName(&fuzzyLocale);
+ // try the complete locale name first and progressively truncate from
+ // the end until a matching language tag is found (with or without suffix)
for (;;) {
- int rightmost = localeName.lastIndexOf(QLatin1Char('_'));
- // no truncations? fail
- if (rightmost <= 0)
- break;
- localeName.truncate(rightmost);
-
realname += localeName + suffixOrDotQM;
if (is_readable_file(realname))
return realname;
@@ -696,6 +685,11 @@ static QString find_translation(const QLocale & locale,
return realname;
realname.truncate(realNameBaseSize);
+
+ int rightmost = localeName.lastIndexOf(QLatin1Char('_'));
+ if (rightmost <= 0)
+ break; // no truncations anymore, break
+ localeName.truncate(rightmost);
}
}
@@ -754,10 +748,10 @@ static QString find_translation(const QLocale & locale,
\li \c /opt/foolib/foo.es
\li \c /opt/foolib/foo.fr_CA.qm
\li \c /opt/foolib/foo.fr_CA
- \li \c /opt/foolib/foo.de.qm
- \li \c /opt/foolib/foo.de
\li \c /opt/foolib/foo.fr.qm
\li \c /opt/foolib/foo.fr
+ \li \c /opt/foolib/foo.de.qm
+ \li \c /opt/foolib/foo.de
\li \c /opt/foolib/foo.qm
\li \c /opt/foolib/foo.
\li \c /opt/foolib/foo
@@ -1120,7 +1114,7 @@ void QTranslatorPrivate::clear()
If \a n is not -1, it is used to choose an appropriate form for
the translation (e.g. "%n file found" vs. "%n files found").
- If you need to programatically insert translations into a
+ If you need to programmatically insert translations into a
QTranslator, this function can be reimplemented.
\sa load()