Repository: flutter/flutter
File: engine/src/flutter/shell/platform/embedder/tests/embedder_unittests_util.h (C/C++)

Code before:
                                                     uint64_t target_time_nanos,
                                                     void* user_data) -> void {
      auto thiz = reinterpret_cast<EmbedderTestTaskRunner*>(user_data);

      auto target_time = fml::TimePoint::FromEpochDelta(
          fml::TimeDelta::FromNanoseconds(target_time_nanos));
      auto on_task_expired = thiz->on_task_expired_;
      auto invoke_task = [task, on_task_expired]() { on_task_expired(task); };
      auto real_task_runner = thiz->real_task_runner_;

      real_task_runner->PostTaskForTime(invoke_task, target_time);
    };
    task_runner_description_.destruction_callback = [](void* user_data) {
      auto thiz = reinterpret_cast<EmbedderTestTaskRunner*>(user_data);
      if (thiz->destruction_callback_) {
        thiz->destruction_callback_();
      }
    };
    task_runner_description_.identifier = identifier_;
  }

  void SetDestructionCallback(std::function<void()> callback) {
    destruction_callback_ = std::move(callback);
  }

  const FlutterTaskRunnerDescription& GetFlutterTaskRunnerDescription() {
    return task_runner_description_;
  }

 private:
  static std::atomic_size_t sEmbedderTaskRunnerIdentifiers;
  const size_t identifier_;
  fml::RefPtr<fml::TaskRunner> real_task_runner_;
  TaskExpiryCallback on_task_expired_;
  FlutterTaskRunnerDescription task_runner_description_ = {};
  std::function<void()> destruction_callback_;

  FML_DISALLOW_COPY_AND_ASSIGN(EmbedderTestTaskRunner);
};

}  // namespace testing
}  // namespace flutter

#endif  // FLUTTER_SHELL_PLATFORM_EMBEDDER_TESTS_EMBEDDER_UNITTESTS_UTIL_H_


Review comment (bug):
Is this executing on a different thread than SetDestructionCallback?  If so there is a race condition and we'll need a mutex.

Code after:
    FML_CHECK(on_task_expired_);

    task_runner_description_.struct_size = sizeof(FlutterTaskRunnerDescription);
    task_runner_description_.user_data = this;
    task_runner_description_.runs_task_on_current_thread_callback =
        [](void* user_data) -> bool {
      return reinterpret_cast<EmbedderTestTaskRunner*>(user_data)
          ->real_task_runner_->RunsTasksOnCurrentThread();
    };
    task_runner_description_.post_task_callback = [](FlutterTask task,
                                                     uint64_t target_time_nanos,
                                                     void* user_data) -> void {
      auto thiz = reinterpret_cast<EmbedderTestTaskRunner*>(user_data);

      auto target_time = fml::TimePoint::FromEpochDelta(
          fml::TimeDelta::FromNanoseconds(target_time_nanos));
      auto on_task_expired = thiz->on_task_expired_;
      auto invoke_task = [task, on_task_expired]() { on_task_expired(task); };
      auto real_task_runner = thiz->real_task_runner_;

      real_task_runner->PostTaskForTime(invoke_task, target_time);
    };
    if (destruction_callback_) {
      task_runner_description_.destruction_callback = [](void* user_data) {
        auto thiz = reinterpret_cast<EmbedderTestTaskRunner*>(user_data);
        thiz->destruction_callback_();
      };
    } else {
      task_runner_description_.destruction_callback = [](void* user_data) {};
    }
    task_runner_description_.identifier = identifier_;
  }

  const FlutterTaskRunnerDescription& GetFlutterTaskRunnerDescription() {
    return task_runner_description_;
  }

 private:
  static std::atomic_size_t sEmbedderTaskRunnerIdentifiers;
  const size_t identifier_;
  const fml::RefPtr<fml::TaskRunner> real_task_runner_;
  const TaskExpiryCallback on_task_expired_;
  const DestructionCallback destruction_callback_;
  FlutterTaskRunnerDescription task_runner_description_ = {};

  FML_DISALLOW_COPY_AND_ASSIGN(EmbedderTestTaskRunner);
};

class EmbedderTestTaskRunnerBuilder {
 public:
  EmbedderTestTaskRunnerBuilder& SetRealTaskRunner(