Simplify RunLoop

Instead of transforming between return value and callback, pass
the wrapped callback on to the invoked function as the last argument.

This eliminates the need for multiple invokeWithArgument overloads
and permits invoked functions to be asynchronous.
This commit is contained in:
John Firebaugh
2015-06-11 19:03:19 -04:00
parent 3ab682e627
commit fc64e97bce
8 changed files with 149 additions and 216 deletions

View File

@@ -17,9 +17,9 @@ public:
EXPECT_EQ(val, 1);
}
int fn2() {
void fn2(std::function<void (int)> cb) {
EXPECT_EQ(tid, std::this_thread::get_id());
return 1;
cb(1);
}
void transferIn(std::unique_ptr<int> val) {
@@ -27,15 +27,15 @@ public:
EXPECT_EQ(*val, 1);
}
std::unique_ptr<int> transferOut() {
void transferOut(std::function<void (std::unique_ptr<int>)> cb) {
EXPECT_EQ(tid, std::this_thread::get_id());
return std::make_unique<int>(1);
cb(std::make_unique<int>(1));
}
std::unique_ptr<int> transferInOut(std::unique_ptr<int> val) {
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);
return std::move(val);
cb(std::move(val));
}
void transferInShared(std::shared_ptr<int> val) {
@@ -43,21 +43,21 @@ public:
EXPECT_EQ(*val, 1);
}
std::shared_ptr<int> transferOutShared() {
void transferOutShared(std::function<void (std::shared_ptr<int>)> cb) {
EXPECT_EQ(tid, std::this_thread::get_id());
return std::make_shared<int>(1);
cb(std::make_shared<int>(1));
}
std::string transferString(const std::string& string) {
void transferString(const std::string& string, std::function<void (std::string)> cb) {
EXPECT_EQ(tid, std::this_thread::get_id());
EXPECT_EQ(string, "test");
return string;
cb(string);
}
bool checkContext() const {
return ThreadContext::currentlyOn(ThreadType::Worker)
void checkContext(std::function<void (bool)> cb) const {
cb(ThreadContext::currentlyOn(ThreadType::Worker)
&& ThreadContext::getName() == "Test"
&& ThreadContext::getPriority() == ThreadPriority::Low;
&& ThreadContext::getPriority() == ThreadPriority::Low);
}
const std::thread::id tid;
@@ -74,35 +74,35 @@ TEST(Thread, invoke) {
Thread<TestObject> thread({"Test", ThreadType::Map, ThreadPriority::Regular}, tid);
thread.invoke(&TestObject::fn1, 1);
requests.push_back(thread.invokeWithResult<int>(&TestObject::fn2, [&] (int result) {
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.invokeWithResult<std::unique_ptr<int>>(&TestObject::transferOut, [&] (std::unique_ptr<int> result) {
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.invokeWithResult<std::unique_ptr<int>>(&TestObject::transferInOut, [&] (std::unique_ptr<int> result) {
requests.push_back(thread.invokeWithCallback(&TestObject::transferInOut, [&] (std::unique_ptr<int> result) {
EXPECT_EQ(tid, std::this_thread::get_id());
EXPECT_EQ(*result, 1);
}, std::make_unique<int>(1)));
thread.invoke(&TestObject::transferInShared, std::make_shared<int>(1));
requests.push_back(thread.invokeWithResult<std::shared_ptr<int>>(&TestObject::transferOutShared, [&] (std::shared_ptr<int> result) {
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.invokeWithResult(&TestObject::fn1, [&] {
thread.invokeWithCallback(&TestObject::fn2, [&] (int) {
ADD_FAILURE();
}, 1);
});
std::string test("test");
requests.push_back(thread.invokeWithResult<std::string>(&TestObject::transferString, [&] (std::string result){
requests.push_back(thread.invokeWithCallback(&TestObject::transferString, [&] (std::string result){
EXPECT_EQ(tid, std::this_thread::get_id());
EXPECT_EQ(result, "test");
loop.stop();
@@ -128,7 +128,7 @@ TEST(Thread, context) {
loop.invoke([&] {
Thread<TestObject> thread({"Test", ThreadType::Worker, ThreadPriority::Low}, tid);
requests.push_back(thread.invokeWithResult<bool>(&TestObject::checkContext, [&] (bool inTestThreadContext) {
requests.push_back(thread.invokeWithCallback(&TestObject::checkContext, [&] (bool inTestThreadContext) {
EXPECT_EQ(inTestThreadContext, true);
loop.stop();
}));
@@ -139,8 +139,13 @@ TEST(Thread, context) {
class TestWorker {
public:
TestWorker(uv_loop_t*) {}
void send(std::function<void ()> fn) { fn(); }
TestWorker(uv_loop_t*) {
}
void send(std::function<void ()> fn, std::function<void ()> cb) {
fn();
cb();
}
};
TEST(Thread, ExecutesAfter) {
@@ -150,7 +155,7 @@ TEST(Thread, ExecutesAfter) {
bool didWork = false;
bool didAfter = false;
auto request = thread.invokeWithResult(&TestWorker::send, [&] {
auto request = thread.invokeWithCallback(&TestWorker::send, [&] {
didAfter = true;
loop.stop();
}, [&] {
@@ -170,7 +175,7 @@ TEST(Thread, WorkRequestDeletionWaitsForWorkToComplete) {
std::promise<void> started;
bool didWork = false;
auto request = thread.invokeWithResult(&TestWorker::send, [&] {}, [&] {
auto request = thread.invokeWithCallback(&TestWorker::send, [&] {}, [&] {
started.set_value();
usleep(10000);
didWork = true;
@@ -188,7 +193,7 @@ TEST(Thread, WorkRequestDeletionCancelsAfter) {
std::promise<void> started;
bool didAfter = false;
auto request = thread.invokeWithResult(&TestWorker::send, [&] {
auto request = thread.invokeWithCallback(&TestWorker::send, [&] {
didAfter = true;
}, [&] {
started.set_value();
@@ -206,12 +211,12 @@ TEST(Thread, WorkRequestDeletionCancelsImmediately) {
std::promise<void> started;
auto request1 = thread.invokeWithResult(&TestWorker::send, [&] {}, [&] {
auto request1 = thread.invokeWithCallback(&TestWorker::send, [&] {}, [&] {
usleep(10000);
started.set_value();
});
auto request2 = thread.invokeWithResult(&TestWorker::send, [&] {}, [&] {
auto request2 = thread.invokeWithCallback(&TestWorker::send, [&] {}, [&] {
ADD_FAILURE() << "Second work item should not be invoked";
});
request2.reset();

View File

@@ -15,8 +15,9 @@ TEST_F(Storage, DatabaseDoesNotExist) {
SQLiteCache::Impl cache(nullptr, "test/fixtures/404/cache.db");
std::unique_ptr<Response> res = cache.get({ Resource::Unknown, "mapbox://test" });
EXPECT_EQ(nullptr, res.get());
cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
EXPECT_EQ(nullptr, res.get());
});
auto observer = Log::removeObserver();
EXPECT_EQ(1ul, dynamic_cast<FixtureLogObserver*>(observer.get())->count({ EventSeverity::Error, Event::Database, 14, "unable to open database file" }));
@@ -56,8 +57,9 @@ TEST_F(Storage, DatabaseCreate) {
SQLiteCache::Impl cache(nullptr, "test/fixtures/database/cache.db");
std::unique_ptr<Response> res = cache.get({ Resource::Unknown, "mapbox://test" });
EXPECT_EQ(nullptr, res.get());
cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
EXPECT_EQ(nullptr, res.get());
});
Log::removeObserver();
}
@@ -115,8 +117,9 @@ TEST_F(Storage, DatabaseLockedRead) {
// First request should fail.
Log::setObserver(std::make_unique<FixtureLogObserver>());
std::unique_ptr<Response> res = cache.get({ Resource::Unknown, "mapbox://test" });
EXPECT_EQ(nullptr, res.get());
cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
EXPECT_EQ(nullptr, res.get());
});
// Make sure that we got a few "database locked" errors
auto observer = Log::removeObserver();
@@ -131,8 +134,9 @@ TEST_F(Storage, DatabaseLockedRead) {
// First, try getting a file (the cache value should not exist).
Log::setObserver(std::make_unique<FixtureLogObserver>());
std::unique_ptr<Response> res = cache.get({ Resource::Unknown, "mapbox://test" });
EXPECT_EQ(nullptr, res.get());
cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
EXPECT_EQ(nullptr, res.get());
});
// Make sure that we got a no errors
Log::removeObserver();
@@ -157,8 +161,9 @@ TEST_F(Storage, DatabaseLockedWrite) {
auto response = std::make_shared<Response>();
cache.put({ Resource::Unknown, "mapbox://test" }, response);
std::unique_ptr<Response> res = cache.get({ Resource::Unknown, "mapbox://test" });
EXPECT_EQ(nullptr, res.get());
cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
EXPECT_EQ(nullptr, res.get());
});
auto observer = Log::removeObserver();
auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
@@ -175,9 +180,10 @@ TEST_F(Storage, DatabaseLockedWrite) {
auto response = std::make_shared<Response>();
response->data = "Demo";
cache.put({ Resource::Unknown, "mapbox://test" }, response);
std::unique_ptr<Response> res = cache.get({ Resource::Unknown, "mapbox://test" });
EXPECT_NE(nullptr, res.get());
EXPECT_EQ("Demo", res->data);
cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
EXPECT_NE(nullptr, res.get());
EXPECT_EQ("Demo", res->data);
});
// Make sure that we got a no errors
Log::removeObserver();
@@ -206,8 +212,9 @@ TEST_F(Storage, DatabaseLockedRefresh) {
auto response = std::make_shared<Response>();
response->data = "Demo";
cache.put({ Resource::Unknown, "mapbox://test" }, response);
std::unique_ptr<Response> res = cache.get({ Resource::Unknown, "mapbox://test" });
EXPECT_EQ(nullptr, res.get());
cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
EXPECT_EQ(nullptr, res.get());
});
auto observer = Log::removeObserver();
auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
@@ -221,8 +228,9 @@ TEST_F(Storage, DatabaseLockedRefresh) {
auto response = std::make_shared<Response>();
response->data = "Demo";
cache.refresh({ Resource::Unknown, "mapbox://test" }, response->expires);
std::unique_ptr<Response> res = cache.get({ Resource::Unknown, "mapbox://test" });
EXPECT_EQ(nullptr, res.get());
cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
EXPECT_EQ(nullptr, res.get());
});
// Make sure that we got the right errors.
auto observer = Log::removeObserver();
@@ -249,9 +257,10 @@ TEST_F(Storage, DatabaseDeleted) {
auto response = std::make_shared<Response>();
response->data = "Demo";
cache.put({ Resource::Unknown, "mapbox://test" }, response);
std::unique_ptr<Response> res = cache.get({ Resource::Unknown, "mapbox://test" });
EXPECT_NE(nullptr, res.get());
EXPECT_EQ("Demo", res->data);
cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
EXPECT_NE(nullptr, res.get());
EXPECT_EQ("Demo", res->data);
});
Log::removeObserver();
}
@@ -265,9 +274,10 @@ TEST_F(Storage, DatabaseDeleted) {
auto response = std::make_shared<Response>();
response->data = "Demo";
cache.put({ Resource::Unknown, "mapbox://test" }, response);
std::unique_ptr<Response> res = cache.get({ Resource::Unknown, "mapbox://test" });
EXPECT_NE(nullptr, res.get());
EXPECT_EQ("Demo", res->data);
cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
EXPECT_NE(nullptr, res.get());
EXPECT_EQ("Demo", res->data);
});
auto observer = Log::removeObserver();
auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
@@ -294,9 +304,10 @@ TEST_F(Storage, DatabaseInvalid) {
auto response = std::make_shared<Response>();
response->data = "Demo";
cache.put({ Resource::Unknown, "mapbox://test" }, response);
std::unique_ptr<Response> res = cache.get({ Resource::Unknown, "mapbox://test" });
EXPECT_NE(nullptr, res.get());
EXPECT_EQ("Demo", res->data);
cache.get({ Resource::Unknown, "mapbox://test" }, [] (std::unique_ptr<Response> res) {
EXPECT_NE(nullptr, res.get());
EXPECT_EQ("Demo", res->data);
});
auto observer = Log::removeObserver();
auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());