summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake/core-files.cmake3
-rw-r--r--cmake/test-files.cmake1
-rw-r--r--platform/default/online_file_source.cpp1
-rw-r--r--src/mbgl/util/logging.cpp2
-rw-r--r--src/mbgl/util/thread.hpp173
-rw-r--r--src/mbgl/util/thread_context.cpp13
-rw-r--r--src/mbgl/util/thread_context.hpp22
-rw-r--r--test/util/thread.test.cpp296
8 files changed, 1 insertions, 510 deletions
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake
index 729d3f7da3..220e25d35e 100644
--- a/cmake/core-files.cmake
+++ b/cmake/core-files.cmake
@@ -603,9 +603,6 @@ set(MBGL_CORE_FILES
src/mbgl/util/stopwatch.cpp
src/mbgl/util/stopwatch.hpp
src/mbgl/util/string.cpp
- src/mbgl/util/thread.hpp
- src/mbgl/util/thread_context.cpp
- src/mbgl/util/thread_context.hpp
src/mbgl/util/thread_local.hpp
src/mbgl/util/threaded_object.hpp
src/mbgl/util/throttler.cpp
diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake
index da1c046485..f85ca03333 100644
--- a/cmake/test-files.cmake
+++ b/cmake/test-files.cmake
@@ -131,7 +131,6 @@ set(MBGL_TEST_FILES
test/util/projection.test.cpp
test/util/run_loop.test.cpp
test/util/text_conversions.test.cpp
- test/util/thread.test.cpp
test/util/threaded_object.test.cpp
test/util/thread_local.test.cpp
test/util/tile_cover.test.cpp
diff --git a/platform/default/online_file_source.cpp b/platform/default/online_file_source.cpp
index d7649a348c..4f5483d794 100644
--- a/platform/default/online_file_source.cpp
+++ b/platform/default/online_file_source.cpp
@@ -6,7 +6,6 @@
#include <mbgl/util/logging.hpp>
#include <mbgl/util/constants.hpp>
-#include <mbgl/util/thread.hpp>
#include <mbgl/util/mapbox.hpp>
#include <mbgl/util/exception.hpp>
#include <mbgl/util/chrono.hpp>
diff --git a/src/mbgl/util/logging.cpp b/src/mbgl/util/logging.cpp
index 939f1def64..0552eb36cb 100644
--- a/src/mbgl/util/logging.cpp
+++ b/src/mbgl/util/logging.cpp
@@ -1,6 +1,6 @@
#include <mbgl/util/logging.hpp>
#include <mbgl/util/enum.hpp>
-#include <mbgl/util/thread.hpp>
+#include <mbgl/util/platform.hpp>
#include <cstdio>
#include <cstdarg>
diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp
deleted file mode 100644
index 4afaab6b7a..0000000000
--- a/src/mbgl/util/thread.hpp
+++ /dev/null
@@ -1,173 +0,0 @@
-#pragma once
-
-#include <cassert>
-#include <future>
-#include <thread>
-#include <atomic>
-#include <utility>
-#include <functional>
-
-#include <mbgl/util/run_loop.hpp>
-#include <mbgl/util/thread_context.hpp>
-#include <mbgl/util/platform.hpp>
-#include <mbgl/util/util.hpp>
-
-namespace mbgl {
-namespace util {
-
-// Manages a thread with Object.
-
-// Upon creation of this object, it launches a thread, creates an object of type Object in that
-// thread, and then calls .start(); on that object. When the Thread<> object is destructed, the
-// Object's .stop() function is called, and the destructor waits for thread termination. The
-// Thread<> constructor blocks until the thread and the Object are fully created, so after the
-// object creation, it's safe to obtain the Object stored in this thread.
-
-template <class Object>
-class Thread {
-public:
- Thread(const Thread&) = delete;
- Thread(Thread&&) = delete;
- Thread& operator=(const Thread&) = delete;
- Thread& operator=(Thread&&) = delete;
-
- template <class... Args>
- Thread(const ThreadContext&, Args&&... args);
- ~Thread();
-
- // Invoke object->fn(args...) asynchronously.
- template <typename Fn, class... Args>
- void invoke(Fn fn, Args&&... args) {
- loop->invoke(bind(fn), std::forward<Args>(args)...);
- }
-
- // Invoke object->fn(args...) asynchronously. The final argument to fn must be a callback.
- // The provided callback is wrapped such that it is invoked, in the current thread (which
- // must have a RunLoop), once for each time the invocation of fn invokes the wrapper, each
- // time forwarding the passed arguments, until such time as the AsyncRequest is cancelled.
- template <typename Fn, class... Args>
- std::unique_ptr<AsyncRequest>
- invokeWithCallback(Fn fn, Args&&... args) {
- return loop->invokeWithCallback(bind(fn), std::forward<Args>(args)...);
- }
-
- // Invoke object->fn(args...) asynchronously, but wait for the result.
- template <typename Fn, class... Args>
- auto invokeSync(Fn fn, Args&&... args) {
- assert(!paused);
-
- using R = std::result_of_t<Fn(Object, Args&&...)>;
- std::packaged_task<R ()> task(std::bind(fn, object, args...));
- std::future<R> future = task.get_future();
- loop->invoke(std::move(task));
- return future.get();
- }
-
- void pause() {
- MBGL_VERIFY_THREAD(tid);
-
- assert(!paused);
-
- paused = std::make_unique<std::promise<void>>();
- resumed = std::make_unique<std::promise<void>>();
-
- auto pausing = paused->get_future();
-
- loop->invoke([this] {
- auto resuming = resumed->get_future();
- paused->set_value();
- resuming.get();
- });
-
- pausing.get();
- }
-
- void resume() {
- MBGL_VERIFY_THREAD(tid);
-
- assert(paused);
-
- resumed->set_value();
-
- resumed.reset();
- paused.reset();
- }
-
-private:
- MBGL_STORE_THREAD(tid);
-
- template <typename Fn>
- auto bind(Fn fn) {
- return [fn, this] (auto &&... args) {
- return (object->*fn)(std::forward<decltype(args)>(args)...);
- };
- }
-
- template <typename P, std::size_t... I>
- void run(P&& params, std::index_sequence<I...>);
-
- std::promise<void> running;
- std::promise<void> joinable;
-
- std::unique_ptr<std::promise<void>> paused;
- std::unique_ptr<std::promise<void>> resumed;
-
- std::thread thread;
-
- Object* object = nullptr;
- RunLoop* loop = nullptr;
-};
-
-template <class Object>
-template <class... Args>
-Thread<Object>::Thread(const ThreadContext& context, Args&&... args) {
- // Note: We're using std::tuple<> to store the arguments because GCC 4.9 has a bug
- // when expanding parameters packs captured in lambdas.
- std::tuple<Args...> params = std::forward_as_tuple(::std::forward<Args>(args)...);
-
- thread = std::thread([&] {
- platform::setCurrentThreadName(context.name);
-
- if (context.priority == ThreadPriority::Low) {
- platform::makeThreadLowPriority();
- }
-
- run(std::move(params), std::index_sequence_for<Args...>{});
- });
-
- running.get_future().get();
-}
-
-template <class Object>
-template <typename P, std::size_t... I>
-void Thread<Object>::run(P&& params, std::index_sequence<I...>) {
- RunLoop loop_(RunLoop::Type::New);
- loop = &loop_;
-
- Object object_(std::get<I>(std::forward<P>(params))...);
- object = &object_;
-
- running.set_value();
- loop_.run();
-
- loop = nullptr;
- object = nullptr;
-
- joinable.get_future().get();
-}
-
-template <class Object>
-Thread<Object>::~Thread() {
- MBGL_VERIFY_THREAD(tid);
-
- if (paused) {
- resume();
- }
-
- loop->stop();
- joinable.set_value();
- thread.join();
-}
-
-} // namespace util
-} // namespace mbgl
diff --git a/src/mbgl/util/thread_context.cpp b/src/mbgl/util/thread_context.cpp
deleted file mode 100644
index fe64c2a686..0000000000
--- a/src/mbgl/util/thread_context.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <mbgl/util/thread_context.hpp>
-#include <utility>
-
-namespace mbgl {
-namespace util {
-
-ThreadContext::ThreadContext(std::string name_, ThreadPriority priority_)
- : name(std::move(name_)),
- priority(priority_) {
-}
-
-} // namespace util
-} // namespace mbgl
diff --git a/src/mbgl/util/thread_context.hpp b/src/mbgl/util/thread_context.hpp
deleted file mode 100644
index a51dede404..0000000000
--- a/src/mbgl/util/thread_context.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#pragma once
-
-#include <string>
-
-namespace mbgl {
-namespace util {
-
-enum class ThreadPriority : bool {
- Regular,
- Low,
-};
-
-struct ThreadContext {
-public:
- ThreadContext(std::string name, ThreadPriority priority = ThreadPriority::Regular);
-
- std::string name;
- ThreadPriority priority;
-};
-
-} // namespace util
-} // namespace mbgl
diff --git a/test/util/thread.test.cpp b/test/util/thread.test.cpp
deleted file mode 100644
index 972bddf383..0000000000
--- a/test/util/thread.test.cpp
+++ /dev/null
@@ -1,296 +0,0 @@
-#include <mbgl/util/thread.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-#include <mbgl/test/util.hpp>
-
-#include <atomic>
-
-using namespace mbgl::util;
-
-class TestObject {
-public:
- TestObject(std::thread::id otherTid)
- : tid(std::this_thread::get_id()) {
- EXPECT_NE(tid, otherTid);
- }
-
- void fn1(int val) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(val, 1);
- }
-
- void fn2(std::function<void (int)> cb) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- cb(1);
- }
-
- void transferIn(std::unique_ptr<int> val) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(*val, 1);
- }
-
- void transferOut(std::function<void (std::unique_ptr<int>)> cb) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- cb(std::make_unique<int>(1));
- }
-
- void transferInOut(std::unique_ptr<int> val, std::function<void (std::unique_ptr<int>)> cb) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(*val, 1);
- cb(std::move(val));
- }
-
- void transferInShared(std::shared_ptr<int> val) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(*val, 1);
- }
-
- void transferOutShared(std::function<void (std::shared_ptr<int>)> cb) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- cb(std::make_shared<int>(1));
- }
-
- void transferString(const std::string& string, std::function<void (std::string)> cb) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(string, "test");
- cb(string);
- }
-
- void checkContext(std::function<void (bool)> cb) const {
- cb(tid == std::this_thread::get_id());
- }
-
- const std::thread::id tid;
-};
-
-TEST(Thread, invoke) {
- const std::thread::id tid = std::this_thread::get_id();
-
- RunLoop loop;
- std::vector<std::unique_ptr<mbgl::AsyncRequest>> requests;
-
- loop.invoke([&] {
- EXPECT_EQ(tid, std::this_thread::get_id());
- Thread<TestObject> thread({"Test"}, tid);
-
- thread.invoke(&TestObject::fn1, 1);
- requests.push_back(thread.invokeWithCallback(&TestObject::fn2, [&] (int result) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(result, 1);
- }));
-
- thread.invoke(&TestObject::transferIn, std::make_unique<int>(1));
- requests.push_back(thread.invokeWithCallback(&TestObject::transferOut, [&] (std::unique_ptr<int> result) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(*result, 1);
- }));
-
- requests.push_back(thread.invokeWithCallback(&TestObject::transferInOut, std::make_unique<int>(1), [&] (std::unique_ptr<int> result) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(*result, 1);
- }));
-
- thread.invoke(&TestObject::transferInShared, std::make_shared<int>(1));
- requests.push_back(thread.invokeWithCallback(&TestObject::transferOutShared, [&] (std::shared_ptr<int> result) {
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(*result, 1);
- }));
-
- // Cancelled request
- thread.invokeWithCallback(&TestObject::fn2, [&] (int) {
- ADD_FAILURE();
- });
-
- std::string test("test");
- requests.push_back(thread.invokeWithCallback(&TestObject::transferString, test, [&] (std::string result){
- EXPECT_EQ(tid, std::this_thread::get_id());
- EXPECT_EQ(result, "test");
- loop.stop();
- }));
- test.clear();
- });
-
- loop.run();
-}
-
-TEST(Thread, context) {
- const std::thread::id tid = std::this_thread::get_id();
-
- RunLoop loop;
- std::vector<std::unique_ptr<mbgl::AsyncRequest>> requests;
-
- loop.invoke([&] {
- Thread<TestObject> thread({"Test"}, tid);
-
- requests.push_back(thread.invokeWithCallback(&TestObject::checkContext, [&] (bool inTestThreadContext) {
- EXPECT_EQ(inTestThreadContext, true);
- loop.stop();
- }));
- });
-
- loop.run();
-}
-
-class TestWorker {
-public:
- TestWorker() = default;
-
- void send(std::function<void ()> fn, std::function<void ()> cb) {
- fn();
- cb();
- }
-};
-
-TEST(Thread, ExecutesAfter) {
- RunLoop loop;
- Thread<TestWorker> thread({"Test"});
-
- bool didWork = false;
- bool didAfter = false;
-
- auto request = thread.invokeWithCallback(&TestWorker::send, [&] {
- didWork = true;
- }, [&] {
- didAfter = true;
- loop.stop();
- });
-
- loop.run();
-
- EXPECT_TRUE(didWork);
- EXPECT_TRUE(didAfter);
-}
-
-TEST(Thread, WorkRequestDeletionWaitsForWorkToComplete) {
- RunLoop loop;
-
- Thread<TestWorker> thread({"Test"});
-
- std::promise<void> started;
- bool didWork = false;
-
- auto request = thread.invokeWithCallback(&TestWorker::send, [&] {
- started.set_value();
- usleep(10000);
- didWork = true;
- }, [&] {});
-
- started.get_future().get();
- request.reset();
- EXPECT_TRUE(didWork);
-}
-
-TEST(Thread, WorkRequestDeletionCancelsAfter) {
- RunLoop loop;
- Thread<TestWorker> thread({"Test"});
-
- std::promise<void> started;
- bool didAfter = false;
-
- auto request = thread.invokeWithCallback(&TestWorker::send, [&] {
- started.set_value();
- }, [&] {
- didAfter = true;
- });
-
- started.get_future().get();
- request.reset();
- loop.runOnce();
- EXPECT_FALSE(didAfter);
-}
-
-TEST(Thread, WorkRequestDeletionCancelsImmediately) {
- RunLoop loop;
- Thread<TestWorker> thread({"Test"});
-
- std::promise<void> started;
-
- auto request1 = thread.invokeWithCallback(&TestWorker::send, [&] {
- usleep(10000);
- started.set_value();
- }, [&] {});
-
- auto request2 = thread.invokeWithCallback(&TestWorker::send, [&] {
- ADD_FAILURE() << "Second work item should not be invoked";
- }, [&] {});
- request2.reset();
-
- started.get_future().get();
- request1.reset();
-}
-
-TEST(Thread, DeletePausedThread) {
- RunLoop loop;
-
- std::atomic_bool flag(false);
-
- auto thread = std::make_unique<Thread<TestWorker>>(ThreadContext{"Test"});
- thread->pause();
- thread->invoke(&TestWorker::send, [&] { flag = true; }, [] {});
-
- // Should not hang.
- thread.reset();
-
- // Should process the queue before destruction.
- ASSERT_TRUE(flag);
-}
-
-TEST(Thread, Pause) {
- RunLoop loop;
-
- std::atomic_bool flag(false);
-
- Thread<TestWorker> thread1({"Test1"});
- thread1.pause();
-
- Thread<TestWorker> thread2({"Test2"});
-
- for (unsigned i = 0; i < 100; ++i) {
- thread1.invoke(&TestWorker::send, [&] { flag = true; }, [] {});
- thread2.invoke(&TestWorker::send, [&] { ASSERT_FALSE(flag); }, [] {});
- }
-
- // Queue a message at the end of thread2 queue.
- thread2.invoke(&TestWorker::send, [&] { loop.stop(); }, [] {});
- loop.run();
-}
-
-TEST(Thread, Resume) {
- RunLoop loop;
-
- std::atomic_bool flag(false);
-
- Thread<TestWorker> thread({"Test"});
- thread.pause();
-
- for (unsigned i = 0; i < 100; ++i) {
- thread.invoke(&TestWorker::send, [&] { flag = true; }, [] {});
- }
-
- // Thread messages are ondered, when we resume, this is going
- // to me the last thing to run on the message queue.
- thread.invoke(&TestWorker::send, [&] { loop.stop(); }, [] {});
-
- // This test will be flaky if the thread doesn't get paused.
- ASSERT_FALSE(flag);
-
- thread.resume();
- loop.run();
-
- ASSERT_TRUE(flag);
-}
-
-TEST(Thread, PauseResume) {
- RunLoop loop;
-
- Thread<TestWorker> thread({"Test"});
-
- // Test if multiple pause/resume work.
- for (unsigned i = 0; i < 100; ++i) {
- thread.pause();
- thread.resume();
- }
-
- thread.invoke(&TestWorker::send, [&] { loop.stop(); }, [] {});
- loop.run();
-}