From 6c87c2a9ae5614b3db5b5a574f579c5082790263 Mon Sep 17 00:00:00 2001 From: Arsentiy Milchakov Date: Thu, 10 Aug 2017 16:31:03 +0300 Subject: [PATCH] [platform] added possibility to change gui thread --- android/jni/Android.mk | 4 +- .../com/mapswithme/maps/MwmApplication.cpp | 16 +++--- .../jni/com/mapswithme/platform/GuiThread.cpp | 48 ++++++++++++++++++ .../jni/com/mapswithme/platform/GuiThread.hpp | 25 ++++++++++ .../jni/com/mapswithme/platform/Platform.cpp | 49 ++++++++++++++----- .../jni/com/mapswithme/platform/Platform.hpp | 28 +++++++++-- .../com/mapswithme/maps/MwmApplication.java | 6 +-- base/CMakeLists.txt | 1 + base/base.pro | 1 + base/task_loop.hpp | 17 +++++++ base/worker_thread.cpp | 20 ++++++++ base/worker_thread.hpp | 19 ++----- platform/CMakeLists.txt | 4 ++ platform/gui_thread.hpp | 13 +++++ platform/gui_thread_apple.mm | 31 ++++++++++++ platform/gui_thread_linux.cpp | 24 +++++++++ platform/platform.hpp | 14 +++++- platform/platform.pro | 12 +++-- platform/platform_android.cpp | 3 +- platform/platform_ios.mm | 21 +++++++- platform/platform_linux.cpp | 2 + platform/platform_mac.mm | 18 ++++++- platform/platform_qt.cpp | 20 +++++--- xcode/base/base.xcodeproj/project.pbxproj | 4 ++ .../platform.xcodeproj/project.pbxproj | 8 +++ 25 files changed, 349 insertions(+), 59 deletions(-) create mode 100644 android/jni/com/mapswithme/platform/GuiThread.cpp create mode 100644 android/jni/com/mapswithme/platform/GuiThread.hpp create mode 100644 base/task_loop.hpp create mode 100644 platform/gui_thread.hpp create mode 100644 platform/gui_thread_apple.mm create mode 100644 platform/gui_thread_linux.cpp diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 6ab7db89a4..597bb7cd5f 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -71,6 +71,7 @@ LOCAL_HEADER_FILES := \ com/mapswithme/opengl/androidoglcontext.hpp \ com/mapswithme/opengl/androidoglcontextfactory.hpp \ com/mapswithme/opengl/gl3stub.h \ + com/mapswithme/platform/GuiThread.hpp \ com/mapswithme/platform/Platform.hpp \ LOCAL_SRC_FILES := \ @@ -108,11 +109,12 @@ LOCAL_SRC_FILES := \ com/mapswithme/opengl/androidoglcontextfactory.cpp \ com/mapswithme/opengl/gl3stub.c \ com/mapswithme/platform/HttpThread.cpp \ - com/mapswithme/platform/SocketImpl.cpp \ + com/mapswithme/platform/GuiThread.cpp \ com/mapswithme/platform/Language.cpp \ com/mapswithme/platform/MarketingService.cpp \ com/mapswithme/platform/Platform.cpp \ com/mapswithme/platform/PThreadImpl.cpp \ + com/mapswithme/platform/SocketImpl.cpp \ com/mapswithme/util/Config.cpp \ com/mapswithme/util/HttpClient.cpp \ com/mapswithme/util/LoggerFactory.cpp \ diff --git a/android/jni/com/mapswithme/maps/MwmApplication.cpp b/android/jni/com/mapswithme/maps/MwmApplication.cpp index f05cce95b1..c8a71849b9 100644 --- a/android/jni/com/mapswithme/maps/MwmApplication.cpp +++ b/android/jni/com/mapswithme/maps/MwmApplication.cpp @@ -1,9 +1,11 @@ -#include "Framework.hpp" +#include "android/jni/com/mapswithme/maps/Framework.hpp" -#include "../core/jni_helper.hpp" -#include "../util/crashlytics.h" +#include "android/jni/com/mapswithme/util/crashlytics.h" -#include "../platform/Platform.hpp" +#include "android/jni/com/mapswithme/platform/GuiThread.hpp" +#include "android/jni/com/mapswithme/platform/Platform.hpp" + +#include "android/jni/com/mapswithme/core/jni_helper.hpp" crashlytics_context_t * g_crashlytics; @@ -32,11 +34,11 @@ extern "C" g_framework = new android::Framework(); } - // static void nativeProcessFunctor(long functorPointer); + // static void nativeProcessTask(long taskPointer); JNIEXPORT void JNICALL - Java_com_mapswithme_maps_MwmApplication_nativeProcessFunctor(JNIEnv * env, jclass clazz, jlong functorPointer) + Java_com_mapswithme_maps_MwmApplication_nativeProcessTask(JNIEnv * env, jclass clazz, jlong taskPointer) { - android::Platform::Instance().ProcessFunctor(functorPointer); + android::GuiThread::ProcessTask(taskPointer); } // static void nativeAddLocalization(String name, String value); diff --git a/android/jni/com/mapswithme/platform/GuiThread.cpp b/android/jni/com/mapswithme/platform/GuiThread.cpp new file mode 100644 index 0000000000..a032ca9ce7 --- /dev/null +++ b/android/jni/com/mapswithme/platform/GuiThread.cpp @@ -0,0 +1,48 @@ +#include "android/jni/com/mapswithme/platform/GuiThread.hpp" + +#include "android/jni/com/mapswithme/core/jni_helper.hpp" + +#include + +namespace android +{ +GuiThread::GuiThread(jobject processObject) +{ + JNIEnv * env = jni::GetEnv(); + + m_object = env->NewGlobalRef(processObject); + ASSERT(m_object, ()); + + m_method = env->GetMethodID(env->GetObjectClass(m_object), "forwardToMainThread", "(J)V"); + ASSERT(m_method, ()); +} + +GuiThread::~GuiThread() +{ + JNIEnv * env = jni::GetEnv(); + env->DeleteGlobalRef(m_object); +} + +// static +void GuiThread::ProcessTask(jlong task) +{ + std::unique_ptr t(reinterpret_cast(task)); + (*t)(); +} + +bool GuiThread::Push(Task && task) +{ + // Pointer will be deleted in ProcessTask. + auto t = new Task(std::move(task)); + jni::GetEnv()->CallVoidMethod(m_object, m_method, reinterpret_cast(t)); + return true; +} + +bool GuiThread::Push(Task const & task) +{ + // Pointer will be deleted in ProcessTask. + auto t = new Task(task); + jni::GetEnv()->CallVoidMethod(m_object, m_method, reinterpret_cast(t)); + return true; +} +} // namespace android diff --git a/android/jni/com/mapswithme/platform/GuiThread.hpp b/android/jni/com/mapswithme/platform/GuiThread.hpp new file mode 100644 index 0000000000..72a3031246 --- /dev/null +++ b/android/jni/com/mapswithme/platform/GuiThread.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "base/task_loop.hpp" + +#include + +namespace android +{ +class GuiThread : public base::TaskLoop +{ +public: + explicit GuiThread(jobject processObject); + ~GuiThread(); + + static void ProcessTask(jlong task); + + // TaskLoop overrides: + bool Push(Task && task) override; + bool Push(Task const & task) override; + +private: + jobject m_object = nullptr; + jmethodID m_method = nullptr; +}; +} // namespace android diff --git a/android/jni/com/mapswithme/platform/Platform.cpp b/android/jni/com/mapswithme/platform/Platform.cpp index 302fe328c5..24ea7273c6 100644 --- a/android/jni/com/mapswithme/platform/Platform.cpp +++ b/android/jni/com/mapswithme/platform/Platform.cpp @@ -1,14 +1,17 @@ -#include "Platform.hpp" +#include "android/jni/com/mapswithme/platform/Platform.hpp" +#include "android/jni/com/mapswithme/platform/GuiThread.hpp" -#include "../core/jni_helper.hpp" +#include "android/jni/com/mapswithme/core/jni_helper.hpp" #include "platform/settings.hpp" #include "base/logging.hpp" +#include "base/macros.hpp" #include "base/stl_add.hpp" #include "base/string_utils.hpp" #include +#include #include @@ -38,9 +41,14 @@ std::string Platform::GetMemoryInfo() const return jni::ToNativeString(env, memInfoString); } -void Platform::RunOnGuiThread(TFunctor const & fn) +void Platform::RunOnGuiThread(base::TaskLoop::Task && task) { - android::Platform::Instance().RunOnGuiThread(fn); + android::Platform::Instance().RunOnGuiThread(std::move(task)); +} + +void Platform::RunOnGuiThread(base::TaskLoop::Task const & task) +{ + android::Platform::Instance().RunOnGuiThread(task); } Platform::EConnectionType Platform::ConnectionStatus() @@ -72,6 +80,11 @@ Platform::ChargingStatus Platform::GetChargingStatus() env->CallStaticIntMethod(clazzBatteryState, getChargingMethodId)); } +void Platform::SetGuiThread(unique_ptr guiThread) +{ + android::Platform::Instance().SetGuiThread(move(guiThread)); +} + namespace android { void Platform::Initialize(JNIEnv * env, @@ -83,10 +96,11 @@ void Platform::Initialize(JNIEnv * env, { m_functorProcessObject = env->NewGlobalRef(functorProcessObject); jclass const functorProcessClass = env->GetObjectClass(functorProcessObject); - m_functorProcessMethod = env->GetMethodID(functorProcessClass, "forwardToMainThread", "(J)V"); m_sendPushWooshTagsMethod = env->GetMethodID(functorProcessClass, "sendPushWooshTags", "(Ljava/lang/String;[Ljava/lang/String;)V"); m_myTrackerTrackMethod = env->GetStaticMethodID(g_myTrackerClazz, "trackEvent", "(Ljava/lang/String;)V"); + m_guiThread = my::make_unique(m_functorProcessObject); + std::string const flavor = jni::ToNativeString(env, flavorName); std::string const build = jni::ToNativeString(env, buildType); LOG(LINFO, ("Flavor name:", flavor)); @@ -123,6 +137,14 @@ void Platform::Initialize(JNIEnv * env, (void) ConnectionStatus(); } +Platform::~Platform() +{ + JNIEnv * env = jni::GetEnv(); + + if (m_functorProcessObject) + env->DeleteGlobalRef(m_functorProcessObject); +} + void Platform::ProcessFunctor(jlong functionPointer) { TFunctor * fn = reinterpret_cast(functionPointer); @@ -169,15 +191,11 @@ Platform & Platform::Instance() return platform; } -void Platform::RunOnGuiThread(TFunctor const & fn) -{ - // Pointer will be deleted in Platform::ProcessFunctor - TFunctor * functor = new TFunctor(fn); - jni::GetEnv()->CallVoidMethod(m_functorProcessObject, m_functorProcessMethod, reinterpret_cast(functor)); -} - void Platform::SendPushWooshTag(std::string const & tag, std::vector const & values) { + ASSERT(m_functorProcessObject, ()); + ASSERT(m_sendPushWooshTagsMethod, ()); + if (values.empty()) return; @@ -189,6 +207,8 @@ void Platform::SendPushWooshTag(std::string const & tag, std::vector const & params) { + ASSERT(m_myTrackerTrackMethod, ()); + JNIEnv * env = jni::GetEnv(); std::string eventData = tag; for (auto const & item : params) @@ -198,6 +218,11 @@ void Platform::SendMarketingEvent(std::string const & tag, std::map guiThread) +{ + m_guiThread = std::move(guiThread); +} + int GetAndroidSdkVersion() { char osVersion[PROP_VALUE_MAX + 1]; diff --git a/android/jni/com/mapswithme/platform/Platform.hpp b/android/jni/com/mapswithme/platform/Platform.hpp index 9e36a73894..82dfcaba52 100644 --- a/android/jni/com/mapswithme/platform/Platform.hpp +++ b/android/jni/com/mapswithme/platform/Platform.hpp @@ -4,6 +4,13 @@ #include "platform/platform.hpp" +#include + +namespace base +{ +class TaskLoop; +} + namespace android { class Platform : public ::Platform @@ -16,6 +23,8 @@ public: jstring flavorName, jstring buildType, bool isTablet); + ~Platform(); + void ProcessFunctor(jlong functionPointer); void OnExternalStorageStatusChanged(bool isAvailable); @@ -27,18 +36,27 @@ public: void SetSettingsDir(std::string const & dir); bool HasAvailableSpaceForWriting(uint64_t size) const; - void RunOnGuiThread(TFunctor const & fn); + + template + void RunOnGuiThread(Task && task) + { + ASSERT(m_guiThread, ()); + m_guiThread->Push(std::forward(task)); + } void SendPushWooshTag(std::string const & tag, std::vector const & values); void SendMarketingEvent(std::string const & tag, std::map const & params); + void SetGuiThread(std::unique_ptr guiThread); + static Platform & Instance(); private: - jobject m_functorProcessObject; - jmethodID m_functorProcessMethod; - jmethodID m_sendPushWooshTagsMethod; - jmethodID m_myTrackerTrackMethod; + jobject m_functorProcessObject = nullptr; + jmethodID m_sendPushWooshTagsMethod = nullptr; + jmethodID m_myTrackerTrackMethod = nullptr; + + std::unique_ptr m_guiThread; }; extern int GetAndroidSdkVersion(); diff --git a/android/src/com/mapswithme/maps/MwmApplication.java b/android/src/com/mapswithme/maps/MwmApplication.java index cd6c322240..d0bd07b110 100644 --- a/android/src/com/mapswithme/maps/MwmApplication.java +++ b/android/src/com/mapswithme/maps/MwmApplication.java @@ -424,14 +424,14 @@ public class MwmApplication extends Application } @SuppressWarnings("unused") - void forwardToMainThread(final long functorPointer) + void forwardToMainThread(final long taskPointer) { Message m = Message.obtain(mMainLoopHandler, new Runnable() { @Override public void run() { - nativeProcessFunctor(functorPointer); + nativeProcessTask(taskPointer); } }); m.obj = mMainQueueToken; @@ -443,7 +443,7 @@ public class MwmApplication extends Application String flavorName, String buildType, boolean isTablet); private static native void nativeInitFramework(); - private static native void nativeProcessFunctor(long functorPointer); + private static native void nativeProcessTask(long taskPointer); private static native void nativeAddLocalization(String name, String value); @UiThread diff --git a/base/CMakeLists.txt b/base/CMakeLists.txt index 3db7f7afa9..f343fcb7dc 100644 --- a/base/CMakeLists.txt +++ b/base/CMakeLists.txt @@ -71,6 +71,7 @@ set( suffix_array.hpp sunrise_sunset.cpp sunrise_sunset.hpp + task_loop.hpp thread.cpp thread.hpp thread_checker.cpp diff --git a/base/base.pro b/base/base.pro index 64f3336cb0..30ba11ba74 100644 --- a/base/base.pro +++ b/base/base.pro @@ -89,6 +89,7 @@ HEADERS += \ strings_bundle.hpp \ suffix_array.hpp \ sunrise_sunset.hpp \ + task_loop.hpp \ thread.hpp \ thread_checker.hpp \ thread_pool.hpp \ diff --git a/base/task_loop.hpp b/base/task_loop.hpp new file mode 100644 index 0000000000..df966b0860 --- /dev/null +++ b/base/task_loop.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace base +{ +class TaskLoop +{ +public: + using Task = std::function; + + virtual ~TaskLoop() = default; + + virtual bool Push(Task && task) = 0; + virtual bool Push(Task const & task) = 0; +}; +} // namespace base diff --git a/base/worker_thread.cpp b/base/worker_thread.cpp index dffbdc2ee2..57ef87f3b2 100644 --- a/base/worker_thread.cpp +++ b/base/worker_thread.cpp @@ -16,6 +16,26 @@ WorkerThread::~WorkerThread() m_thread.join(); } +bool WorkerThread::Push(Task && t) +{ + std::lock_guard lk(m_mu); + if (m_shutdown) + return false; + m_queue.emplace(std::forward(t)); + m_cv.notify_one(); + return true; +} + +bool WorkerThread::Push(Task const & t) +{ + std::lock_guard lk(m_mu); + if (m_shutdown) + return false; + m_queue.emplace(t); + m_cv.notify_one(); + return true; +} + void WorkerThread::ProcessTasks() { queue pending; diff --git a/base/worker_thread.hpp b/base/worker_thread.hpp index 2e8b7b374b..e81d038b0c 100644 --- a/base/worker_thread.hpp +++ b/base/worker_thread.hpp @@ -1,6 +1,7 @@ #pragma once #include "base/assert.hpp" +#include "base/task_loop.hpp" #include "base/thread.hpp" #include "base/thread_checker.hpp" @@ -15,7 +16,7 @@ namespace base // // *NOTE* This class IS thread-safe, but it must be destroyed on the // same thread it was created. -class WorkerThread +class WorkerThread : public TaskLoop { public: enum class Exit @@ -24,23 +25,13 @@ public: SkipPending }; - using Task = std::function; - WorkerThread(); - ~WorkerThread(); + ~WorkerThread() override; // Pushes task to the end of the thread's queue. Returns false when // the thread is shut down. - template - bool Push(T && t) - { - std::lock_guard lk(m_mu); - if (m_shutdown) - return false; - m_queue.emplace(std::forward(t)); - m_cv.notify_one(); - return true; - } + bool Push(Task && t) override; + bool Push(Task const & t) override; // Sends a signal to the thread to shut down. Returns false when the // thread was shut down previously. diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt index be3145947c..569c8e9021 100644 --- a/platform/CMakeLists.txt +++ b/platform/CMakeLists.txt @@ -17,6 +17,7 @@ set( file_logging.hpp get_text_by_id.cpp get_text_by_id.hpp + gui_thread.hpp http_client.cpp http_client.hpp http_request.cpp @@ -51,6 +52,7 @@ set( if(${PLATFORM_IPHONE}) append( SRC + gui_thread_apple.mm http_thread_apple.h http_thread_apple.mm http_client_apple.mm @@ -92,6 +94,7 @@ else() # neither iPhone nor Android append( SRC apple_location_service.mm + gui_thread_apple.mm http_client_apple.mm http_thread_apple.h http_thread_apple.mm @@ -104,6 +107,7 @@ else() # neither iPhone nor Android elseif(${PLATFORM_LINUX}) append( SRC + gui_thread_linux.cpp http_client_curl.cpp http_thread_qt.cpp http_thread_qt.hpp diff --git a/platform/gui_thread.hpp b/platform/gui_thread.hpp new file mode 100644 index 0000000000..0acf57991f --- /dev/null +++ b/platform/gui_thread.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "base/task_loop.hpp" + +namespace platform +{ +class GuiThread : public base::TaskLoop +{ +public: + bool Push(Task && task) override; + bool Push(Task const & task) override; +}; +} // namespace platform diff --git a/platform/gui_thread_apple.mm b/platform/gui_thread_apple.mm new file mode 100644 index 0000000000..f2379bd7f5 --- /dev/null +++ b/platform/gui_thread_apple.mm @@ -0,0 +1,31 @@ +#include "platform/gui_thread.hpp" + +#include +#include + +#import + +namespace +{ +void PerformImpl(void * task) +{ + using base::TaskLoop; + std::unique_ptr t(reinterpret_cast(task)); + (*t)(); +} +} + +namespace platform +{ +bool GuiThread::Push(Task && task) +{ + dispatch_async_f(dispatch_get_main_queue(), new Task(std::move(task)), &PerformImpl); + return true; +} + +bool GuiThread::Push(Task const & task) +{ + dispatch_async_f(dispatch_get_main_queue(), new Task(task), &PerformImpl); + return true; +} +} // namespace platform diff --git a/platform/gui_thread_linux.cpp b/platform/gui_thread_linux.cpp new file mode 100644 index 0000000000..86c147d015 --- /dev/null +++ b/platform/gui_thread_linux.cpp @@ -0,0 +1,24 @@ +#include "platform/gui_thread.hpp" + +#include + +#include + +namespace platform +{ +bool GuiThread::Push(Task && task) +{ + // Following hack is used to post on main message loop |fn| when + // |source| is destroyed (at the exit of the code block). + QObject source; + return QObject::connect(&source, &QObject::destroyed, QCoreApplication::instance(), std::move(task)); +} + +bool GuiThread::Push(Task const & task) +{ + // Following hack is used to post on main message loop |fn| when + // |source| is destroyed (at the exit of the code block). + QObject source; + return QObject::connect(&source, &QObject::destroyed, QCoreApplication::instance(), task); +} +} // namespace platform diff --git a/platform/platform.hpp b/platform/platform.hpp index 25c31816cf..fd6782d2ca 100644 --- a/platform/platform.hpp +++ b/platform/platform.hpp @@ -1,16 +1,19 @@ #pragma once #include "platform/country_defines.hpp" +#include "platform/gui_thread.hpp" #include "platform/marketing_service.hpp" #include "coding/reader.hpp" #include "base/exception.hpp" +#include "base/task_loop.hpp" #include "std/bitset.hpp" #include "std/function.hpp" #include "std/map.hpp" #include "std/string.hpp" +#include "std/unique_ptr.hpp" #include "std/utility.hpp" #include "std/vector.hpp" @@ -91,6 +94,8 @@ protected: /// Platform-dependent marketing services. MarketingService m_marketingService; + unique_ptr m_guiThread; + public: Platform(); @@ -188,8 +193,9 @@ public: /// @name Functions for concurrent tasks. //@{ - typedef function TFunctor; - void RunOnGuiThread(TFunctor const & fn); + void RunOnGuiThread(base::TaskLoop::Task && task); + void RunOnGuiThread(base::TaskLoop::Task const & task); + enum Priority { EPriorityBackground, @@ -197,6 +203,7 @@ public: EPriorityDefault, EPriorityHigh }; + using TFunctor = function; void RunAsync(TFunctor const & fn, Priority p = EPriorityDefault); //@} @@ -239,6 +246,9 @@ public: MarketingService & GetMarketingService() { return m_marketingService; } + // Use this method for testing purposes only. + void SetGuiThread(unique_ptr guiThread); + private: void GetSystemFontNames(FilesList & res) const; }; diff --git a/platform/platform.pro b/platform/platform.pro index c355e58bbf..d0f06499a8 100644 --- a/platform/platform.pro +++ b/platform/platform.pro @@ -29,14 +29,17 @@ INCLUDEPATH += $$ROOT_DIR/3party/jansson/src SOURCES += platform_win.cpp \ wifi_info_windows.cpp } else:macx-* { - OBJECTIVE_SOURCES += platform_mac.mm \ - apple_location_service.mm + OBJECTIVE_SOURCES += apple_location_service.mm \ + gui_thread_apple.mm \ + platform_mac.mm } else:linux* { - SOURCES += platform_linux.cpp + SOURCES += gui_thread_linux.cpp \ + platform_linux.cpp } } else:iphone* { OBJECTIVE_SOURCES += marketing_service_ios.mm \ - platform_ios.mm + platform_ios.mm \ + gui_thread_apple.mm } else:android* { SOURCES += platform_android.cpp } else:tizen* { @@ -76,6 +79,7 @@ HEADERS += \ country_file.hpp \ file_logging.hpp \ get_text_by_id.hpp \ + gui_thread.hpp \ http_request.hpp \ http_thread_callback.hpp \ http_client.hpp \ diff --git a/platform/platform_android.cpp b/platform/platform_android.cpp index 93b7011a57..f2783c2073 100644 --- a/platform/platform_android.cpp +++ b/platform/platform_android.cpp @@ -261,7 +261,8 @@ void Platform::SetupMeasurementSystem() const } /// @see implementation of methods below in android/jni/com/.../Platform.cpp -// void Platform::RunOnGuiThread(TFunctor const & fn){} +// void RunOnGuiThread(base::TaskLoop::Task && task); +// void RunOnGuiThread(base::TaskLoop::Task const & task); namespace { diff --git a/platform/platform_ios.mm b/platform/platform_ios.mm index a7699f2d0b..b117f4c6e0 100644 --- a/platform/platform_ios.mm +++ b/platform/platform_ios.mm @@ -1,4 +1,5 @@ #include "platform/constants.hpp" +#include "platform/gui_thread.hpp" #include "platform/measurement_utils.hpp" #include "platform/platform.hpp" #include "platform/platform_unix_impl.hpp" @@ -6,6 +7,8 @@ #include "coding/file_reader.hpp" +#include + #include #include @@ -58,6 +61,8 @@ Platform::Platform() m_tmpDir += "/tmp/"; } + m_guiThread = make_unique(); + UIDevice * device = [UIDevice currentDevice]; NSLog(@"Device: %@, SystemName: %@, SystemVersion: %@", device.model, device.systemName, device.systemVersion); @@ -127,9 +132,16 @@ string Platform::GetMemoryInfo() const return ss.str(); } -void Platform::RunOnGuiThread(TFunctor const & fn) +void Platform::RunOnGuiThread(base::TaskLoop::Task && task) { - dispatch_async_f(dispatch_get_main_queue(), new TFunctor(fn), &PerformImpl); + ASSERT(m_guiThread, ()); + m_guiThread->Push(std::move(task)); +} + +void Platform::RunOnGuiThread(base::TaskLoop::Task const & task) +{ + ASSERT(m_guiThread, ()); + m_guiThread->Push(task); } void Platform::RunAsync(TFunctor const & fn, Priority p) @@ -192,6 +204,11 @@ void Platform::SetupMeasurementSystem() const settings::Set(settings::kMeasurementUnits, units); } +void Platform::SetGuiThread(unique_ptr guiThread) +{ + m_guiThread = std::move(guiThread); +} + //////////////////////////////////////////////////////////////////////// extern Platform & GetPlatform() { diff --git a/platform/platform_linux.cpp b/platform/platform_linux.cpp index ecc42d80c6..a0863e758f 100644 --- a/platform/platform_linux.cpp +++ b/platform/platform_linux.cpp @@ -121,6 +121,8 @@ Platform::Platform() m_tmpDir = "/tmp"; m_tmpDir += '/'; + m_guiThread = make_unique(); + LOG(LDEBUG, ("Resources directory:", m_resourcesDir)); LOG(LDEBUG, ("Writable directory:", m_writableDir)); LOG(LDEBUG, ("Tmp directory:", m_tmpDir)); diff --git a/platform/platform_mac.mm b/platform/platform_mac.mm index 6a92e0c4a6..3524ea3295 100644 --- a/platform/platform_mac.mm +++ b/platform/platform_mac.mm @@ -103,6 +103,8 @@ Platform::Platform() m_tmpDir = [tempDir UTF8String]; m_tmpDir += '/'; + m_guiThread = make_unique(); + LOG(LDEBUG, ("Resources Directory:", m_resourcesDir)); LOG(LDEBUG, ("Writable Directory:", m_writableDir)); LOG(LDEBUG, ("Tmp Directory:", m_tmpDir)); @@ -118,9 +120,16 @@ static void PerformImpl(void * obj) delete f; } -void Platform::RunOnGuiThread(TFunctor const & fn) +void Platform::RunOnGuiThread(base::TaskLoop::Task && task) { - dispatch_async_f(dispatch_get_main_queue(), new TFunctor(fn), &PerformImpl); + ASSERT(m_guiThread, ()); + m_guiThread->Push(std::move(task)); +} + +void Platform::RunOnGuiThread(base::TaskLoop::Task const & task) +{ + ASSERT(m_guiThread, ()); + m_guiThread->Push(task); } void Platform::RunAsync(TFunctor const & fn, Priority p) @@ -163,3 +172,8 @@ Platform::ChargingStatus Platform::GetChargingStatus() return Platform::ChargingStatus::Plugged; } +void Platform::SetGuiThread(unique_ptr guiThread) +{ + m_guiThread = move(guiThread); +} + diff --git a/platform/platform_qt.cpp b/platform/platform_qt.cpp index cba405d065..194722dbf6 100644 --- a/platform/platform_qt.cpp +++ b/platform/platform_qt.cpp @@ -83,21 +83,29 @@ void Platform::SetupMeasurementSystem() const } #if defined(OMIM_OS_LINUX) -void Platform::RunOnGuiThread(TFunctor const & fn) +void Platform::RunOnGuiThread(base::TaskLoop::Task && task) { - // Following hack is used to post on main message loop |fn| when - // |source| is destroyed (at the exit of the code block). - QObject source; - QObject::connect(&source, &QObject::destroyed, QCoreApplication::instance(), fn); + ASSERT(m_guiThread, ()); + m_guiThread->Push(std::move(task)); +} + +void Platform::RunOnGuiThread(base::TaskLoop::Task const & task) +{ + ASSERT(m_guiThread, ()); + m_guiThread->Push(task); } void Platform::RunAsync(TFunctor const & fn, Priority p) { async(fn); } - #endif // defined(OMIM_OS_LINUX) +void Platform::SetGuiThread(unique_ptr guiThread) +{ + m_guiThread = move(guiThread); +} + extern Platform & GetPlatform() { static Platform platform; diff --git a/xcode/base/base.xcodeproj/project.pbxproj b/xcode/base/base.xcodeproj/project.pbxproj index 37966e77ed..d874e62418 100644 --- a/xcode/base/base.xcodeproj/project.pbxproj +++ b/xcode/base/base.xcodeproj/project.pbxproj @@ -44,6 +44,7 @@ 39FD27381CC65AD000AFF551 /* timegm_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39FD26E21CC65A0E00AFF551 /* timegm_test.cpp */; }; 39FD27391CC65AD000AFF551 /* timer_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39FD26E31CC65A0E00AFF551 /* timer_test.cpp */; }; 39FD273B1CC65B1000AFF551 /* libbase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 675341771A3F57BF00A0A8C3 /* libbase.a */; }; + 3D7815731F3A145F0068B6AC /* task_loop.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D7815711F3A145F0068B6AC /* task_loop.hpp */; }; 56B1A0741E69DE4D00395022 /* random.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56B1A0711E69DE4D00395022 /* random.cpp */; }; 56B1A0751E69DE4D00395022 /* random.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56B1A0721E69DE4D00395022 /* random.hpp */; }; 56B1A0761E69DE4D00395022 /* small_set.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56B1A0731E69DE4D00395022 /* small_set.hpp */; }; @@ -162,6 +163,7 @@ 39FD273D1CC65B1000AFF551 /* libplatform.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libplatform.a; path = "../../../omim-xcode-build/Debug/libplatform.a"; sourceTree = ""; }; 39FD27401CC65B2800AFF551 /* libindexer.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libindexer.a; path = "../../../omim-xcode-build/Debug/libindexer.a"; sourceTree = ""; }; 39FD27421CC65B4800AFF551 /* libcoding.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcoding.a; path = "../../../omim-xcode-build/Debug/libcoding.a"; sourceTree = ""; }; + 3D7815711F3A145F0068B6AC /* task_loop.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = task_loop.hpp; sourceTree = ""; }; 56B1A0711E69DE4D00395022 /* random.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = random.cpp; sourceTree = ""; }; 56B1A0721E69DE4D00395022 /* random.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = random.hpp; sourceTree = ""; }; 56B1A0731E69DE4D00395022 /* small_set.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = small_set.hpp; sourceTree = ""; }; @@ -321,6 +323,7 @@ 675341791A3F57BF00A0A8C3 /* base */ = { isa = PBXGroup; children = ( + 3D7815711F3A145F0068B6AC /* task_loop.hpp */, F6F8E3C61EF846CE00F2DE8F /* worker_thread.cpp */, F6F8E3C71EF846CE00F2DE8F /* worker_thread.hpp */, 56B1A0711E69DE4D00395022 /* random.cpp */, @@ -444,6 +447,7 @@ 675342021A3F57E400A0A8C3 /* string_utils.hpp in Headers */, 675341E41A3F57E400A0A8C3 /* matrix.hpp in Headers */, 670E39451C46C76900E9C0A6 /* sunrise_sunset.hpp in Headers */, + 3D7815731F3A145F0068B6AC /* task_loop.hpp in Headers */, 675341F51A3F57E400A0A8C3 /* set_operations.hpp in Headers */, 675342041A3F57E400A0A8C3 /* strings_bundle.hpp in Headers */, 672DD4C81E0425600078E13C /* stl_helpers.hpp in Headers */, diff --git a/xcode/platform/platform.xcodeproj/project.pbxproj b/xcode/platform/platform.xcodeproj/project.pbxproj index 1349f2c77f..55be126a76 100644 --- a/xcode/platform/platform.xcodeproj/project.pbxproj +++ b/xcode/platform/platform.xcodeproj/project.pbxproj @@ -15,6 +15,8 @@ 34C624BE1DABCCD100510300 /* socket.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 34C624BC1DABCCD100510300 /* socket.hpp */; }; 3D30587D1D8320E4004AC712 /* http_client.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D30587B1D8320E4004AC712 /* http_client.hpp */; }; 3D30587F1D880910004AC712 /* http_client_apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D30587E1D880910004AC712 /* http_client_apple.mm */; }; + 3D78156E1F3A14090068B6AC /* gui_thread_apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D78156B1F3A14090068B6AC /* gui_thread_apple.mm */; }; + 3D78156F1F3A14090068B6AC /* gui_thread.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D78156C1F3A14090068B6AC /* gui_thread.hpp */; }; 3D97F64B1D9C05E800380945 /* http_client.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D97F64A1D9C05E800380945 /* http_client.cpp */; }; 3DE8B98F1DEC3115000E6083 /* network_policy.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DE8B98E1DEC3115000E6083 /* network_policy.hpp */; }; 56EB1EDC1C6B6E6C0022D831 /* file_logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56EB1ED81C6B6E6C0022D831 /* file_logging.cpp */; }; @@ -115,6 +117,8 @@ 34F558341DBF273C00A4FC11 /* common-release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "common-release.xcconfig"; path = "../common-release.xcconfig"; sourceTree = ""; }; 3D30587B1D8320E4004AC712 /* http_client.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = http_client.hpp; sourceTree = ""; }; 3D30587E1D880910004AC712 /* http_client_apple.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = http_client_apple.mm; sourceTree = ""; }; + 3D78156B1F3A14090068B6AC /* gui_thread_apple.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = gui_thread_apple.mm; sourceTree = ""; }; + 3D78156C1F3A14090068B6AC /* gui_thread.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = gui_thread.hpp; sourceTree = ""; }; 3D97F64A1D9C05E800380945 /* http_client.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http_client.cpp; sourceTree = ""; }; 3DE8B98E1DEC3115000E6083 /* network_policy.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = network_policy.hpp; sourceTree = ""; }; 56EB1ED81C6B6E6C0022D831 /* file_logging.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_logging.cpp; sourceTree = ""; }; @@ -324,6 +328,8 @@ 6753437A1A3F5CF500A0A8C3 /* platform */ = { isa = PBXGroup; children = ( + 3D78156B1F3A14090068B6AC /* gui_thread_apple.mm */, + 3D78156C1F3A14090068B6AC /* gui_thread.hpp */, 675343861A3F5D5900A0A8C3 /* apple_location_service.mm */, 675343881A3F5D5900A0A8C3 /* chunks_download_strategy.cpp */, 675343891A3F5D5900A0A8C3 /* chunks_download_strategy.hpp */, @@ -438,6 +444,7 @@ 676C84211C64CD3300DC9603 /* mwm_traits.hpp in Headers */, 675343B41A3F5D5A00A0A8C3 /* chunks_download_strategy.hpp in Headers */, 67247FFE1C60BD6500EDE56A /* writable_dir_changer.hpp in Headers */, + 3D78156F1F3A14090068B6AC /* gui_thread.hpp in Headers */, 674125091B4C00CC00A3E828 /* country_defines.hpp in Headers */, 675343CD1A3F5D5A00A0A8C3 /* platform.hpp in Headers */, 6741250F1B4C00CC00A3E828 /* local_country_file.hpp in Headers */, @@ -592,6 +599,7 @@ 56EB1EDE1C6B6E6C0022D831 /* mwm_traits.cpp in Sources */, 3D30587F1D880910004AC712 /* http_client_apple.mm in Sources */, F6DF73581EC9EAE700D8BA0B /* string_storage_base.cpp in Sources */, + 3D78156E1F3A14090068B6AC /* gui_thread_apple.mm in Sources */, 67247FFD1C60BD6500EDE56A /* writable_dir_changer.cpp in Sources */, 34513AFB1DCB37C100471BDA /* marketing_service.cpp in Sources */, 6741250C1B4C00CC00A3E828 /* local_country_file_utils.cpp in Sources */,