QJNIHelper: clean up atomic int and mutex handling

1. Do not use Q_GLOBAL_STATIC to hold QAtomicInt or QMutex, use
   file-static QBasicAtomicInt and QBasicMutex instead. They are
   zero-initialized PODs.
2. Use only QMutexLocker to lock mutexes.

Also wrap the atomic counter into a next...() function, as done
elsewhere.

Change-Id: I4b14ac0de9d4cb6780b1f1372c2b5fc88e918e4c
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
Marc Mutz 2017-02-14 16:52:19 +01:00
parent 5fcdb6c459
commit 265db5ad9b

View File

@ -61,7 +61,7 @@ static jclass g_jNativeClass = Q_NULLPTR;
static jmethodID g_runPendingCppRunnablesMethodID = Q_NULLPTR; static jmethodID g_runPendingCppRunnablesMethodID = Q_NULLPTR;
static jmethodID g_hideSplashScreenMethodID = Q_NULLPTR; static jmethodID g_hideSplashScreenMethodID = Q_NULLPTR;
Q_GLOBAL_STATIC(std::deque<QtAndroidPrivate::Runnable>, g_pendingRunnables); Q_GLOBAL_STATIC(std::deque<QtAndroidPrivate::Runnable>, g_pendingRunnables);
Q_GLOBAL_STATIC(QMutex, g_pendingRunnablesMutex); QBasicMutex g_pendingRunnablesMutex;
class PermissionsResultClass : public QObject class PermissionsResultClass : public QObject
{ {
@ -76,21 +76,24 @@ private:
typedef QHash<int, QSharedPointer<PermissionsResultClass>> PendingPermissionRequestsHash; typedef QHash<int, QSharedPointer<PermissionsResultClass>> PendingPermissionRequestsHash;
Q_GLOBAL_STATIC(PendingPermissionRequestsHash, g_pendingPermissionRequests); Q_GLOBAL_STATIC(PendingPermissionRequestsHash, g_pendingPermissionRequests);
Q_GLOBAL_STATIC(QMutex, g_pendingPermissionRequestsMutex); QBasicMutex g_pendingPermissionRequestsMutex;
Q_GLOBAL_STATIC(QAtomicInt, g_requestPermissionsRequestCode); static int nextRequestCode()
{
static QBasicAtomicInt counter;
return counter.fetchAndAddRelaxed(0);
}
// function called from Java from Android UI thread // function called from Java from Android UI thread
static void runPendingCppRunnables(JNIEnv */*env*/, jobject /*obj*/) static void runPendingCppRunnables(JNIEnv */*env*/, jobject /*obj*/)
{ {
for (;;) { // run all posted runnables for (;;) { // run all posted runnables
g_pendingRunnablesMutex->lock(); QMutexLocker locker(&g_pendingRunnablesMutex);
if (g_pendingRunnables->empty()) { if (g_pendingRunnables->empty()) {
g_pendingRunnablesMutex->unlock();
break; break;
} }
QtAndroidPrivate::Runnable runnable(std::move(g_pendingRunnables->front())); QtAndroidPrivate::Runnable runnable(std::move(g_pendingRunnables->front()));
g_pendingRunnables->pop_front(); g_pendingRunnables->pop_front();
g_pendingRunnablesMutex->unlock(); locker.unlock();
runnable(); // run it outside the sync block! runnable(); // run it outside the sync block!
} }
} }
@ -110,14 +113,13 @@ Q_GLOBAL_STATIC(GenericMotionEventListeners, g_genericMotionEventListeners)
static void sendRequestPermissionsResult(JNIEnv *env, jobject /*obj*/, jint requestCode, static void sendRequestPermissionsResult(JNIEnv *env, jobject /*obj*/, jint requestCode,
jobjectArray permissions, jintArray grantResults) jobjectArray permissions, jintArray grantResults)
{ {
g_pendingPermissionRequestsMutex->lock(); QMutexLocker locker(&g_pendingPermissionRequestsMutex);
auto it = g_pendingPermissionRequests->find(requestCode); auto it = g_pendingPermissionRequests->find(requestCode);
if (it == g_pendingPermissionRequests->end()) { if (it == g_pendingPermissionRequests->end()) {
g_pendingPermissionRequestsMutex->unlock();
// show an error or something ? // show an error or something ?
return; return;
} }
g_pendingPermissionRequestsMutex->unlock(); locker.unlock();
Qt::ConnectionType connection = QThread::currentThread() == it.value()->thread() ? Qt::DirectConnection : Qt::BlockingQueuedConnection; Qt::ConnectionType connection = QThread::currentThread() == it.value()->thread() ? Qt::DirectConnection : Qt::BlockingQueuedConnection;
QtAndroidPrivate::PermissionsHash hash; QtAndroidPrivate::PermissionsHash hash;
@ -132,9 +134,9 @@ static void sendRequestPermissionsResult(JNIEnv *env, jobject /*obj*/, jint requ
hash[permission] = value; hash[permission] = value;
} }
QMetaObject::invokeMethod(it.value().data(), "sendResult", connection, Q_ARG(QtAndroidPrivate::PermissionsHash, hash)); QMetaObject::invokeMethod(it.value().data(), "sendResult", connection, Q_ARG(QtAndroidPrivate::PermissionsHash, hash));
g_pendingPermissionRequestsMutex->lock();
locker.relock();
g_pendingPermissionRequests->erase(it); g_pendingPermissionRequests->erase(it);
g_pendingPermissionRequestsMutex->unlock();
} }
static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event) static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event)
@ -447,10 +449,10 @@ void QtAndroidPrivate::runOnUiThread(QRunnable *runnable, JNIEnv *env)
void QtAndroidPrivate::runOnAndroidThread(const QtAndroidPrivate::Runnable &runnable, JNIEnv *env) void QtAndroidPrivate::runOnAndroidThread(const QtAndroidPrivate::Runnable &runnable, JNIEnv *env)
{ {
g_pendingRunnablesMutex->lock(); QMutexLocker locker(&g_pendingRunnablesMutex);
const bool triggerRun = g_pendingRunnables->empty(); const bool triggerRun = g_pendingRunnables->empty();
g_pendingRunnables->push_back(runnable); g_pendingRunnables->push_back(runnable);
g_pendingRunnablesMutex->unlock(); locker.unlock();
if (triggerRun) if (triggerRun)
env->CallStaticVoidMethod(g_jNativeClass, g_runPendingCppRunnablesMethodID); env->CallStaticVoidMethod(g_jNativeClass, g_runPendingCppRunnablesMethodID);
} }
@ -475,18 +477,16 @@ void QtAndroidPrivate::requestPermissions(JNIEnv *env, const QStringList &permis
return; return;
} }
// Check API 23+ permissions // Check API 23+ permissions
const int requestCode = (*g_requestPermissionsRequestCode)++; const int requestCode = nextRequestCode();
if (!directCall) { if (!directCall) {
g_pendingPermissionRequestsMutex->lock(); QMutexLocker locker(&g_pendingPermissionRequestsMutex);
(*g_pendingPermissionRequests)[requestCode] = QSharedPointer<PermissionsResultClass>::create(callbackFunc); (*g_pendingPermissionRequests)[requestCode] = QSharedPointer<PermissionsResultClass>::create(callbackFunc);
g_pendingPermissionRequestsMutex->unlock();
} }
runOnAndroidThread([permissions, callbackFunc, requestCode, directCall] { runOnAndroidThread([permissions, callbackFunc, requestCode, directCall] {
if (directCall) { if (directCall) {
g_pendingPermissionRequestsMutex->lock(); QMutexLocker locker(&g_pendingPermissionRequestsMutex);
(*g_pendingPermissionRequests)[requestCode] = QSharedPointer<PermissionsResultClass>::create(callbackFunc); (*g_pendingPermissionRequests)[requestCode] = QSharedPointer<PermissionsResultClass>::create(callbackFunc);
g_pendingPermissionRequestsMutex->unlock();
} }
QJNIEnvironmentPrivate env; QJNIEnvironmentPrivate env;