Tweak CxxMessageQueue to work with unique_ptr

Differential Revision: D4560164

fbshipit-source-id: 8975157f5a14d5849365a9e35922a02ac6dc185b
This commit is contained in:
Marc Horowitz 2017-02-28 14:14:51 -08:00 committed by Facebook Github Bot
parent 406a4c04d3
commit 6bce498bbc
6 changed files with 61 additions and 12 deletions

View File

@ -56,6 +56,7 @@ if THIS_IS_FBANDROID:
# `initOnJSVMThread` to be called before the platform-specific hooks # `initOnJSVMThread` to be called before the platform-specific hooks
# have been properly initialised. Bad Times(TM). # have been properly initialised. Bad Times(TM).
# -- @ashokmenon (2017/01/03) # -- @ashokmenon (2017/01/03)
'//java/com/facebook/java2js:jni',
react_native_target('jni/xreact/jni:jni'), react_native_target('jni/xreact/jni:jni'),
react_native_xplat_target('cxxreact/...'), react_native_xplat_target('cxxreact/...'),
], ],
@ -158,7 +159,6 @@ react_library(
compiler_flags = [ compiler_flags = [
"-Wall", "-Wall",
"-fexceptions", "-fexceptions",
"-fvisibility=hidden",
"-frtti", "-frtti",
"-std=c++1y", "-std=c++1y",
] + REACT_LIBRARY_EXTRA_COMPILER_FLAGS, ] + REACT_LIBRARY_EXTRA_COMPILER_FLAGS,

View File

@ -192,6 +192,7 @@ class CxxMessageQueue::QueueRunner {
} }
void bindToThisThread() { void bindToThisThread() {
// TODO: handle nested runloops (either allow them or throw an exception).
if (tid_ != std::thread::id{}) { if (tid_ != std::thread::id{}) {
throw std::runtime_error("Message queue already bound to thread."); throw std::runtime_error("Message queue already bound to thread.");
} }
@ -290,9 +291,16 @@ MQRegistry& getMQRegistry() {
} }
} }
std::weak_ptr<CxxMessageQueue> CxxMessageQueue::current() { std::shared_ptr<CxxMessageQueue> CxxMessageQueue::current() {
auto tid = std::this_thread::get_id(); auto tid = std::this_thread::get_id();
return getMQRegistry().find(tid); return getMQRegistry().find(tid).lock();
}
std::function<void()> CxxMessageQueue::getUnregisteredRunLoop() {
return [capture=qr_] {
capture->bindToThisThread();
capture->run();
};
} }
std::function<void()> CxxMessageQueue::getRunLoop(std::shared_ptr<CxxMessageQueue> mq) { std::function<void()> CxxMessageQueue::getRunLoop(std::shared_ptr<CxxMessageQueue> mq) {
@ -300,7 +308,6 @@ std::function<void()> CxxMessageQueue::getRunLoop(std::shared_ptr<CxxMessageQueu
capture->bindToThisThread(); capture->bindToThisThread();
auto tid = std::this_thread::get_id(); auto tid = std::this_thread::get_id();
// TODO: handle nested runloops (either allow them or throw an exception).
getMQRegistry().registerQueue(tid, weakMq); getMQRegistry().registerQueue(tid, weakMq);
capture->run(); capture->run();
getMQRegistry().unregister(tid); getMQRegistry().unregister(tid);

View File

@ -62,6 +62,9 @@ class CxxMessageQueue : public MessageQueueThread {
bool isOnQueue(); bool isOnQueue();
// If this getRunLoop is used, current() will not work.
std::function<void()> getUnregisteredRunLoop();
// This returns a function that will actually run the runloop. // This returns a function that will actually run the runloop.
// This runloop will return some time after quitSynchronous (or after this is destroyed). // This runloop will return some time after quitSynchronous (or after this is destroyed).
// //
@ -71,7 +74,7 @@ class CxxMessageQueue : public MessageQueueThread {
// Only one thread should run the runloop. // Only one thread should run the runloop.
static std::function<void()> getRunLoop(std::shared_ptr<CxxMessageQueue> mq); static std::function<void()> getRunLoop(std::shared_ptr<CxxMessageQueue> mq);
static std::weak_ptr<CxxMessageQueue> current(); static std::shared_ptr<CxxMessageQueue> current();
private: private:
class QueueRunner; class QueueRunner;
std::shared_ptr<QueueRunner> qr_; std::shared_ptr<QueueRunner> qr_;

View File

@ -20,6 +20,7 @@ if THIS_IS_FBANDROID:
srcs = TEST_SRCS, srcs = TEST_SRCS,
compiler_flags = [ compiler_flags = [
'-fexceptions', '-fexceptions',
'-std=c++1y',
], ],
deps = [ deps = [
'//native/third-party/android-ndk:android', '//native/third-party/android-ndk:android',

View File

@ -1,3 +1,5 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <cxxreact/CxxMessageQueue.h> #include <cxxreact/CxxMessageQueue.h>
@ -29,6 +31,17 @@ std::shared_ptr<CxxMessageQueue> createAndStartQueue(EventFlag& finishedFlag) {
return q; return q;
} }
std::unique_ptr<CxxMessageQueue> createAndStartUnregisteredQueue(
EventFlag& finishedFlag) {
auto q = std::make_unique<CxxMessageQueue>();
std::thread t([loop=q->getUnregisteredRunLoop(), &finishedFlag] {
loop();
finishedFlag.set();
});
t.detach();
return q;
}
// This is just used to start up a queue for a test and make sure that it is // This is just used to start up a queue for a test and make sure that it is
// actually shut down after the test. // actually shut down after the test.
struct QueueWithThread { struct QueueWithThread {
@ -39,9 +52,7 @@ struct QueueWithThread {
~QueueWithThread() { ~QueueWithThread() {
queue->quitSynchronous(); queue->quitSynchronous();
queue.reset(); queue.reset();
if (!done.wait_until(now() + milliseconds(300))) { EXPECT_TRUE(done.wait_until(now() + milliseconds(300))) << "Queue did not exit";
ADD_FAILURE() << "Queue did not exit";
}
} }
EventFlag done; EventFlag done;
@ -53,9 +64,8 @@ TEST(CxxMessageQueue, TestQuit) {
EventFlag done; EventFlag done;
auto q = createAndStartQueue(done); auto q = createAndStartQueue(done);
q->quitSynchronous(); q->quitSynchronous();
if (!done.wait_until(now() + milliseconds(300))) { EXPECT_TRUE(done.wait_until(now() + milliseconds(300)))
FAIL() << "Queue did not exit runloop after quitSynchronous"; << "Queue did not exit runloop after quitSynchronous";
}
} }
TEST(CxxMessageQueue, TestPostTask) { TEST(CxxMessageQueue, TestPostTask) {
@ -69,6 +79,34 @@ TEST(CxxMessageQueue, TestPostTask) {
flag.wait(); flag.wait();
} }
TEST(CxxMessageQueue, TestPostUnregistered) {
EventFlag qdone;
auto q = createAndStartUnregisteredQueue(qdone);
EventFlag tflag;
q->runOnQueue([&] {
tflag.set();
});
tflag.wait();
q->quitSynchronous();
q.reset();
EXPECT_TRUE(qdone.wait_until(now() + milliseconds(300))) << "Queue did not exit";
}
TEST(CxxMessageQueue, TestPostCurrent) {
QueueWithThread qt;
auto q = qt.queue;
EventFlag flag;
q->runOnQueue([&] {
CxxMessageQueue::current()->runOnQueue([&] {
flag.set();
});
});
flag.wait();
}
TEST(CxxMessageQueue, TestPostTaskMultiple) { TEST(CxxMessageQueue, TestPostTaskMultiple) {
QueueWithThread qt; QueueWithThread qt;
auto q = qt.queue; auto q = qt.queue;

View File

@ -14,7 +14,7 @@ namespace {
int tempFileFromString(std::string contents) int tempFileFromString(std::string contents)
{ {
std::string tmp {getenv("TMPDIR")}; std::string tmp {getenv("TMPDIR")};
tmp += "/temp.XXXXX"; tmp += "/temp.XXXXXX";
std::vector<char> tmpBuf {tmp.begin(), tmp.end()}; std::vector<char> tmpBuf {tmp.begin(), tmp.end()};
tmpBuf.push_back('\0'); tmpBuf.push_back('\0');