diff options
author | 2020-07-20 17:46:29 +0800 | |
---|---|---|
committer | 2020-09-15 17:46:49 +0800 | |
commit | 3c2fdbd82090e0c1c3996c5f5091df309592699c (patch) | |
tree | 5fd389b7331f6eed014c0a03e6c1c2c620c34c3e | |
parent | a072152d2980a596580f8caea874be88098434fc (diff) |
Faster bugreports (3/n)
Post 'DumpHals', 'DumpBoard' and 'DumpIncidentReport' to the
thread pool. 30% is improved compared with single thread run.
Bug: 136262402
Test: atest dumpstate_test
Test: atest dumpstate_smoke_test
Test: atest BugreportManagerTestCases
Test: atest CtsBugreportTestCases
Test: Manual enable and disable parallel run
Test: Manual trigger report using hardware key and shortcut
Change-Id: Iea3a6e676f05149a3f2cfc1fcd475c70ea253d08
-rw-r--r-- | cmds/dumpstate/Android.bp | 3 | ||||
-rw-r--r-- | cmds/dumpstate/TaskQueue.cpp | 40 | ||||
-rw-r--r-- | cmds/dumpstate/TaskQueue.h | 76 | ||||
-rw-r--r-- | cmds/dumpstate/dumpstate.cpp | 132 | ||||
-rw-r--r-- | cmds/dumpstate/dumpstate.h | 28 | ||||
-rw-r--r-- | cmds/dumpstate/tests/dumpstate_test.cpp | 54 |
6 files changed, 301 insertions, 32 deletions
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp index 1f055f3be7..80d14ac3c4 100644 --- a/cmds/dumpstate/Android.bp +++ b/cmds/dumpstate/Android.bp @@ -106,6 +106,7 @@ cc_binary { defaults: ["dumpstate_defaults"], srcs: [ "DumpPool.cpp", + "TaskQueue.cpp", "dumpstate.cpp", "main.cpp", ], @@ -134,6 +135,7 @@ cc_test { defaults: ["dumpstate_defaults"], srcs: [ "DumpPool.cpp", + "TaskQueue.cpp", "dumpstate.cpp", "tests/dumpstate_test.cpp", ], @@ -151,6 +153,7 @@ cc_test { defaults: ["dumpstate_defaults"], srcs: [ "DumpPool.cpp", + "TaskQueue.cpp", "dumpstate.cpp", "tests/dumpstate_smoke_test.cpp", ], diff --git a/cmds/dumpstate/TaskQueue.cpp b/cmds/dumpstate/TaskQueue.cpp new file mode 100644 index 0000000000..8550aec4cc --- /dev/null +++ b/cmds/dumpstate/TaskQueue.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TaskQueue.h" + +namespace android { +namespace os { +namespace dumpstate { + +TaskQueue::~TaskQueue() { + run(/* do_cancel = */true); +} + +void TaskQueue::run(bool do_cancel) { + std::unique_lock lock(lock_); + while (!tasks_.empty()) { + auto task = tasks_.front(); + tasks_.pop(); + lock.unlock(); + std::invoke(task, do_cancel); + lock.lock(); + } +} + +} // namespace dumpstate +} // namespace os +} // namespace android diff --git a/cmds/dumpstate/TaskQueue.h b/cmds/dumpstate/TaskQueue.h new file mode 100644 index 0000000000..b7e72f1c26 --- /dev/null +++ b/cmds/dumpstate/TaskQueue.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FRAMEWORK_NATIVE_CMD_TASKQUEUE_H_ +#define FRAMEWORK_NATIVE_CMD_TASKQUEUE_H_ + +#include <mutex> +#include <queue> + +#include <android-base/macros.h> + +namespace android { +namespace os { +namespace dumpstate { + +/* + * A task queue for dumpstate to collect tasks such as adding file to the zip + * which are needed to run in a single thread. The task is a callable function + * included a cancel task boolean parameter. The TaskQueue could + * cancel the task in the destructor if the task has never been called. + */ +class TaskQueue { + public: + TaskQueue() = default; + ~TaskQueue(); + + /* + * Adds a task into the queue. + * + * |f| Callable function to execute the task. The function must include a + * boolean parameter for TaskQueue to notify whether the task is + * cancelled or not. + * |args| A list of arguments. + */ + template<class F, class... Args> void add(F&& f, Args&&... args) { + auto func = std::bind(std::forward<F>(f), std::forward<Args>(args)...); + std::unique_lock lock(lock_); + tasks_.emplace([=](bool cancelled) { + std::invoke(func, cancelled); + }); + } + + /* + * Invokes all tasks in the task queue. + * + * |do_cancel| true to cancel all tasks in the queue. + */ + void run(bool do_cancel); + + private: + using Task = std::function<void(bool)>; + + std::mutex lock_; + std::queue<Task> tasks_; + + DISALLOW_COPY_AND_ASSIGN(TaskQueue); +}; + +} // namespace dumpstate +} // namespace os +} // namespace android + +#endif //FRAMEWORK_NATIVE_CMD_TASKQUEUE_H_ diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 7d195b4fa1..e267ce336b 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -116,6 +116,7 @@ using android::os::dumpstate::CommandOptions; using android::os::dumpstate::DumpFileToFd; using android::os::dumpstate::DumpPool; using android::os::dumpstate::PropertiesHelper; +using android::os::dumpstate::TaskQueue; // Keep in sync with // frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java @@ -128,8 +129,8 @@ static const int32_t WEIGHT_FILE = 5; static Dumpstate& ds = Dumpstate::GetInstance(); static int RunCommand(const std::string& title, const std::vector<std::string>& full_command, const CommandOptions& options = CommandOptions::DEFAULT, - bool verbose_duration = false) { - return ds.RunCommand(title, full_command, options, verbose_duration); + bool verbose_duration = false, int out_fd = STDOUT_FILENO) { + return ds.RunCommand(title, full_command, options, verbose_duration, out_fd); } // Reasonable value for max stats. @@ -212,11 +213,19 @@ static const std::string ANR_FILE_PREFIX = "anr_"; RUN_SLOW_FUNCTION_AND_LOG(log_title, func_ptr, __VA_ARGS__); \ RETURN_IF_USER_DENIED_CONSENT(); +#define WAIT_TASK_WITH_CONSENT_CHECK(task_name, pool_ptr) \ + RETURN_IF_USER_DENIED_CONSENT(); \ + pool_ptr->waitForTask(task_name); \ + RETURN_IF_USER_DENIED_CONSENT(); + static const char* WAKE_LOCK_NAME = "dumpstate_wakelock"; // Names of parallel tasks, they are used for the DumpPool to identify the dump // task and the log title of the duration report. static const std::string DUMP_TRACES_TASK = "DUMP TRACES"; +static const std::string DUMP_INCIDENT_REPORT_TASK = "INCIDENT REPORT"; +static const std::string DUMP_HALS_TASK = "DUMP HALS"; +static const std::string DUMP_BOARD_TASK = "dumpstate_board()"; namespace android { namespace os { @@ -1014,7 +1023,6 @@ static void DumpIncidentReport() { MYLOGD("Not dumping incident report because it's not a zipped bugreport\n"); return; } - DurationReporter duration_reporter("INCIDENT REPORT"); const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report"; auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, @@ -1029,9 +1037,11 @@ static void DumpIncidentReport() { // Use a different name from "incident.proto" // /proto/incident.proto is reserved for incident service dump // i.e. metadata for debugging. - ds.AddZipEntry(kProtoPath + "incident_report" + kProtoExt, path); + ds.EnqueueAddZipEntryAndCleanupIfNeeded(kProtoPath + "incident_report" + kProtoExt, + path); + } else { + unlink(path.c_str()); } - unlink(path.c_str()); } static void DumpVisibleWindowViews() { @@ -1326,15 +1336,21 @@ static Dumpstate::RunStatus RunDumpsysNormal() { /* timeout= */ 90s, /* service_timeout= */ 10s); } -static void DumpHals() { +/* + * |out_fd| A fd to support the DumpPool to output results to a temporary file. + * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO + * if it's not running in the parallel task. + */ +static void DumpHals(int out_fd = STDOUT_FILENO) { if (!ds.IsZipping()) { RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all", "--debug"}, - CommandOptions::WithTimeout(10).AsRootIfAvailable().Build()); + CommandOptions::WithTimeout(10).AsRootIfAvailable().Build(), + false, out_fd); return; } - DurationReporter duration_reporter("DUMP HALS"); RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all"}, - CommandOptions::WithTimeout(10).AsRootIfAvailable().Build()); + CommandOptions::WithTimeout(10).AsRootIfAvailable().Build(), + false, out_fd); using android::hidl::manager::V1_0::IServiceManager; using android::hardware::defaultServiceManager; @@ -1356,6 +1372,7 @@ static void DumpHals() { }, '_'); const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName; + bool empty = false; { auto fd = android::base::unique_fd( TEMP_FAILURE_RETRY(open(path.c_str(), @@ -1370,13 +1387,14 @@ static void DumpHals() { {"lshal", "debug", "-E", interface}, CommandOptions::WithTimeout(2).AsRootIfAvailable().Build()); - bool empty = 0 == lseek(fd, 0, SEEK_END); - if (!empty) { - ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path); - } + empty = 0 == lseek(fd, 0, SEEK_END); + } + if (!empty) { + ds.EnqueueAddZipEntryAndCleanupIfNeeded("lshal-debug/" + cleanName + ".txt", + path); + } else { + unlink(path.c_str()); } - - unlink(path.c_str()); } }); @@ -1471,6 +1489,17 @@ static void DumpstateLimitedOnly() { static Dumpstate::RunStatus dumpstate() { DurationReporter duration_reporter("DUMPSTATE"); + // Enqueue slow functions into the thread pool, if the parallel run is enabled. + if (ds.dump_pool_) { + // Pool was shutdown in DumpstateDefaultAfterCritical method in order to + // drop root user. Restarts it with two threads for the parallel run. + ds.dump_pool_->start(/* thread_counts = */2); + + ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1); + ds.dump_pool_->enqueueTask(DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport); + ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1); + } + // Dump various things. Note that anything that takes "long" (i.e. several seconds) should // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK). @@ -1502,7 +1531,11 @@ static Dumpstate::RunStatus dumpstate() { RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"}, CommandOptions::AS_ROOT); - DumpHals(); + if (ds.dump_pool_) { + WAIT_TASK_WITH_CONSENT_CHECK(DUMP_HALS_TASK, ds.dump_pool_); + } else { + RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_HALS_TASK, DumpHals); + } RunCommand("PRINTENV", {"printenv"}); RunCommand("NETSTAT", {"netstat", "-nW"}); @@ -1583,7 +1616,11 @@ static Dumpstate::RunStatus dumpstate() { ds.AddDir(SNAPSHOTCTL_LOG_DIR, false); - RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard); + if (ds.dump_pool_) { + WAIT_TASK_WITH_CONSENT_CHECK(DUMP_BOARD_TASK, ds.dump_pool_); + } else { + RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard); + } /* Migrate the ril_dumpstate to a device specific dumpstate? */ int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0); @@ -1680,7 +1717,12 @@ static Dumpstate::RunStatus dumpstate() { // Add linker configuration directory ds.AddDir(LINKERCONFIG_DIR, true); - RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport); + if (ds.dump_pool_) { + WAIT_TASK_WITH_CONSENT_CHECK(DUMP_INCIDENT_REPORT_TASK, ds.dump_pool_); + } else { + RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_INCIDENT_REPORT_TASK, + DumpIncidentReport); + } return Dumpstate::RunStatus::OK; } @@ -1799,7 +1841,8 @@ static void DumpstateRadioCommon(bool include_sensitive_info = true) { // Too broad for connectivity problems. DoKmsg(); // Contains unrelated hardware info (camera, NFC, biometrics, ...). - DumpHals(); + // TODO(b/136262402) Using thread pool for DumpHals + RUN_SLOW_FUNCTION_AND_LOG(DUMP_HALS_TASK, DumpHals); } DumpPacketStats(); @@ -2029,11 +2072,10 @@ Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) { return RunStatus::OK; } -void Dumpstate::DumpstateBoard() { - DurationReporter duration_reporter("dumpstate_board()"); - printf("========================================================\n"); - printf("== Board\n"); - printf("========================================================\n"); +void Dumpstate::DumpstateBoard(int out_fd) { + dprintf(out_fd, "========================================================\n"); + dprintf(out_fd, "== Board\n"); + dprintf(out_fd, "========================================================\n"); if (!IsZipping()) { MYLOGD("Not dumping board info because it's not a zipped bugreport\n"); @@ -2159,8 +2201,9 @@ void Dumpstate::DumpstateBoard() { MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str()); continue; } - AddZipEntry(kDumpstateBoardFiles[i], paths[i]); - printf("*** See %s entry ***\n", kDumpstateBoardFiles[i].c_str()); + remover[i].Disable(); + EnqueueAddZipEntryAndCleanupIfNeeded(kDumpstateBoardFiles[i], paths[i]); + dprintf(out_fd, "*** See %s entry ***\n", kDumpstateBoardFiles[i].c_str()); } } @@ -2190,6 +2233,11 @@ static void register_sig_handler() { } bool Dumpstate::FinishZipFile() { + // Runs all enqueued adding zip entry and cleanup tasks before finishing the zip file. + if (zip_entry_tasks_) { + zip_entry_tasks_->run(/* do_cancel = */false); + } + std::string entry_name = base_name_ + "-" + name_ + ".txt"; MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(), tmp_path_.c_str()); @@ -2773,7 +2821,8 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package); MaybeCheckUserConsent(calling_uid, calling_package); DumpstateTelephonyOnly(calling_package); - DumpstateBoard(); + // TODO(b/136262402) Using thread pool for DumpstateBoard + RUN_SLOW_FUNCTION_AND_LOG(DUMP_BOARD_TASK, DumpstateBoard); } else if (options_->wifi_only) { MaybeTakeEarlyScreenshot(); onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package); @@ -2936,6 +2985,7 @@ void Dumpstate::EnableParallelRunIfNeeded() { return; } dump_pool_ = std::make_unique<DumpPool>(bugreport_internal_dir_); + zip_entry_tasks_ = std::make_unique<TaskQueue>(); } void Dumpstate::ShutdownDumpPool() { @@ -2943,6 +2993,27 @@ void Dumpstate::ShutdownDumpPool() { dump_pool_->shutdown(); dump_pool_ = nullptr; } + if (zip_entry_tasks_) { + zip_entry_tasks_->run(/* do_cancel = */true); + zip_entry_tasks_ = nullptr; + } +} + +void Dumpstate::EnqueueAddZipEntryAndCleanupIfNeeded(const std::string& entry_name, + const std::string& entry_path) { + auto func_add_zip_entry_and_cleanup = [=](bool task_cancelled) { + if (!task_cancelled) { + AddZipEntry(entry_name, entry_path); + } + android::os::UnlinkAndLogOnError(entry_path); + }; + if (zip_entry_tasks_) { + // Enqueues AddZipEntryAndCleanup function if the parallel run is enabled. + zip_entry_tasks_->add(func_add_zip_entry_and_cleanup, _1); + } else { + // Invokes AddZipEntryAndCleanup immediately + std::invoke(func_add_zip_entry_and_cleanup, /* task_cancelled = */false); + } } Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() { @@ -3666,10 +3737,11 @@ int dump_file_from_fd(const char *title, const char *path, int fd) { } int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command, - const CommandOptions& options, bool verbose_duration) { - DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration); + const CommandOptions& options, bool verbose_duration, int out_fd) { + DurationReporter duration_reporter(title, false /* logcat_only */, + verbose_duration, out_fd); - int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options); + int status = RunCommandToFd(out_fd, title, full_command, options); /* TODO: for now we're simplifying the progress calculation by using the * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys, diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index d400dc7127..0f0927cc29 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -36,6 +36,7 @@ #include "DumpstateUtil.h" #include "DumpPool.h" +#include "TaskQueue.h" // Workaround for const char *args[MAX_ARGS_ARRAY_SIZE] variables until they're converted to // std::vector<std::string> @@ -229,11 +230,13 @@ class Dumpstate { * |full_command| array containing the command (first entry) and its arguments. * Must contain at least one element. * |options| optional argument defining the command's behavior. + * |out_fd| A fd to support the DumpPool to output results to a temporary + * file. Using STDOUT_FILENO if it's not running in the parallel task. */ int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand, const android::os::dumpstate::CommandOptions& options = android::os::dumpstate::CommandOptions::DEFAULT, - bool verbose_duration = false); + bool verbose_duration = false, int out_fd = STDOUT_FILENO); /* * Runs `dumpsys` with the given arguments, automatically setting its timeout @@ -306,7 +309,12 @@ class Dumpstate { // Returns OK in all other cases. RunStatus DumpTraces(const char** path); - void DumpstateBoard(); + /* + * |out_fd| A fd to support the DumpPool to output results to a temporary file. + * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO + * if it's not running in the parallel task. + */ + void DumpstateBoard(int out_fd = STDOUT_FILENO); /* * Updates the overall progress of the bugreport generation by the given weight increment. @@ -363,6 +371,18 @@ class Dumpstate { bool CalledByApi() const; /* + * Enqueues a task to the dumpstate's TaskQueue if the parallel run is enabled, + * otherwise invokes it immediately. The task adds file at path entry_path + * as a zip file entry with name entry_name. Unlinks entry_path when done. + * + * All enqueued tasks will be executed in the dumpstate's FinishZipFile method + * before the zip file is finished. Tasks will be cancelled in dumpstate's + * ShutdownDumpPool method if they have never been called. + */ + void EnqueueAddZipEntryAndCleanupIfNeeded(const std::string& entry_name, + const std::string& entry_path); + + /* * Structure to hold options that determine the behavior of dumpstate. */ struct DumpOptions { @@ -495,6 +515,10 @@ class Dumpstate { // A thread pool to execute dump tasks simultaneously if the parallel run is enabled. std::unique_ptr<android::os::dumpstate::DumpPool> dump_pool_; + // A task queue to collect adding zip entry tasks inside dump tasks if the + // parallel run is enabled. + std::unique_ptr<android::os::dumpstate::TaskQueue> zip_entry_tasks_; + // A callback to IncidentCompanion service, which checks user consent for sharing the // bugreport with the calling app. If the user has not responded yet to the dialog it will // be neither confirmed nor denied. diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index b3cb4349f3..65d6b9bc72 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -1026,6 +1026,7 @@ TEST_F(DumpstateTest, DumpPool_withOutputToFileAndParallelRunEnabled_notNull) { SetParallelRun(true); EnableParallelRunIfNeeded(); EXPECT_TRUE(ds.options_->OutputToFile()); + EXPECT_TRUE(ds.zip_entry_tasks_); EXPECT_TRUE(ds.dump_pool_); } @@ -1033,12 +1034,14 @@ TEST_F(DumpstateTest, DumpPool_withNotOutputToFile_isNull) { ds.options_->use_socket = true; EnableParallelRunIfNeeded(); EXPECT_FALSE(ds.options_->OutputToFile()); + EXPECT_FALSE(ds.zip_entry_tasks_); EXPECT_FALSE(ds.dump_pool_); } TEST_F(DumpstateTest, DumpPool_withParallelRunDisabled_isNull) { SetParallelRun(false); EnableParallelRunIfNeeded(); + EXPECT_FALSE(ds.zip_entry_tasks_); EXPECT_FALSE(ds.dump_pool_); } @@ -1749,6 +1752,57 @@ TEST_F(DumpPoolTest, EnqueueTask_withDurationLog) { EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0)); } +class TaskQueueTest : public DumpstateBaseTest { +public: + void SetUp() { + DumpstateBaseTest::SetUp(); + } + + TaskQueue task_queue_; +}; + +TEST_F(TaskQueueTest, runTask) { + bool is_task1_run = false; + bool is_task2_run = false; + auto task_1 = [&](bool task_cancelled) { + if (task_cancelled) { + return; + } + is_task1_run = true; + }; + auto task_2 = [&](bool task_cancelled) { + if (task_cancelled) { + return; + } + is_task2_run = true; + }; + task_queue_.add(task_1, std::placeholders::_1); + task_queue_.add(task_2, std::placeholders::_1); + + task_queue_.run(/* do_cancel = */false); + + EXPECT_TRUE(is_task1_run); + EXPECT_TRUE(is_task2_run); +} + +TEST_F(TaskQueueTest, runTask_withCancelled) { + bool is_task1_cancelled = false; + bool is_task2_cancelled = false; + auto task_1 = [&](bool task_cancelled) { + is_task1_cancelled = task_cancelled; + }; + auto task_2 = [&](bool task_cancelled) { + is_task2_cancelled = task_cancelled; + }; + task_queue_.add(task_1, std::placeholders::_1); + task_queue_.add(task_2, std::placeholders::_1); + + task_queue_.run(/* do_cancel = */true); + + EXPECT_TRUE(is_task1_cancelled); + EXPECT_TRUE(is_task2_cancelled); +} + } // namespace dumpstate } // namespace os |