RCTMessageThread.mm 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #include "RCTMessageThread.h"
  8. #include <condition_variable>
  9. #include <mutex>
  10. #import <React/RCTCxxUtils.h>
  11. #import <React/RCTUtils.h>
  12. // A note about the implementation: This class is not used
  13. // generically. It's a thin wrapper around a run loop which
  14. // implements a C++ interface, for use by the C++ xplat bridge code.
  15. // This means it can make certain non-generic assumptions. In
  16. // particular, the sync functions are only used for bridge setup and
  17. // teardown, and quitSynchronous is guaranteed to be called.
  18. namespace facebook {
  19. namespace react {
  20. RCTMessageThread::RCTMessageThread(NSRunLoop *runLoop, RCTJavaScriptCompleteBlock errorBlock)
  21. : m_cfRunLoop([runLoop getCFRunLoop]), m_errorBlock(errorBlock), m_shutdown(false)
  22. {
  23. CFRetain(m_cfRunLoop);
  24. }
  25. RCTMessageThread::~RCTMessageThread()
  26. {
  27. CFRelease(m_cfRunLoop);
  28. }
  29. // This is analogous to dispatch_async
  30. void RCTMessageThread::runAsync(std::function<void()> func)
  31. {
  32. CFRunLoopPerformBlock(m_cfRunLoop, kCFRunLoopCommonModes, ^{
  33. // Create an autorelease pool each run loop to prevent memory footprint from growing too large, which can lead to
  34. // performance problems.
  35. @autoreleasepool {
  36. func();
  37. }
  38. });
  39. CFRunLoopWakeUp(m_cfRunLoop);
  40. }
  41. // This is analogous to dispatch_sync
  42. void RCTMessageThread::runSync(std::function<void()> func)
  43. {
  44. if (m_cfRunLoop == CFRunLoopGetCurrent()) {
  45. func();
  46. return;
  47. }
  48. dispatch_semaphore_t sema = dispatch_semaphore_create(0);
  49. runAsync([func = std::make_shared<std::function<void()>>(std::move(func)), &sema] {
  50. (*func)();
  51. dispatch_semaphore_signal(sema);
  52. });
  53. dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
  54. }
  55. void RCTMessageThread::tryFunc(const std::function<void()> &func)
  56. {
  57. NSError *error = tryAndReturnError(func);
  58. if (error) {
  59. m_errorBlock(error);
  60. }
  61. }
  62. void RCTMessageThread::runOnQueue(std::function<void()> &&func)
  63. {
  64. if (m_shutdown) {
  65. return;
  66. }
  67. runAsync([this, func = std::make_shared<std::function<void()>>(std::move(func))] {
  68. if (!m_shutdown) {
  69. tryFunc(*func);
  70. }
  71. });
  72. }
  73. void RCTMessageThread::runOnQueueSync(std::function<void()> &&func)
  74. {
  75. if (m_shutdown) {
  76. return;
  77. }
  78. runSync([this, func = std::move(func)] {
  79. if (!m_shutdown) {
  80. tryFunc(func);
  81. }
  82. });
  83. }
  84. void RCTMessageThread::quitSynchronous()
  85. {
  86. m_shutdown = true;
  87. runSync([] {});
  88. CFRunLoopStop(m_cfRunLoop);
  89. }
  90. void RCTMessageThread::setRunLoop(NSRunLoop *runLoop)
  91. {
  92. CFRelease(m_cfRunLoop);
  93. m_cfRunLoop = [runLoop getCFRunLoop];
  94. CFRetain(m_cfRunLoop);
  95. }
  96. }
  97. }