From 73a5295f6934065cd43e37e298609ad03f14b878 Mon Sep 17 00:00:00 2001 From: that Date: Wed, 28 Jan 2015 23:07:34 +0100 Subject: gui: run cancel action in another thread Some actions did not have an operation_end where needed especially when dealing with cancel actions. Cancel actions now do not run operation_start or operation_end and let the original action handle the operation_end so that the GUI waits until the original action acutally cancels. Change-Id: I28e6260abb058acb982cecd108c09fc89e0ffeed --- gui/action.cpp | 108 +++++++++++++++++++++++++++++++++++++++----------------- gui/objects.hpp | 23 ++---------- 2 files changed, 79 insertions(+), 52 deletions(-) diff --git a/gui/action.cpp b/gui/action.cpp index f030635d7..2aa03a637 100644 --- a/gui/action.cpp +++ b/gui/action.cpp @@ -67,11 +67,36 @@ static int zip_queue_index; static pthread_t terminal_command; pid_t sideload_child_pid; -static ActionThread action_thread; +static void *ActionThread_work_wrapper(void *data); + +class ActionThread +{ +public: + ActionThread(); + ~ActionThread(); + + void threadActions(GUIAction *act); + void run(void *data); +private: + friend void *ActionThread_work_wrapper(void*); + struct ThreadData + { + ActionThread *this_; + GUIAction *act; + ThreadData(ActionThread *this_, GUIAction *act) : this_(this_), act(act) {} + }; + + pthread_t m_thread; + bool m_thread_running; + pthread_mutex_t m_act_lock; +}; + +static ActionThread action_thread; // for all kinds of longer running actions +static ActionThread cancel_thread; // for longer running "cancel" actions static void *ActionThread_work_wrapper(void *data) { - action_thread.run(data); + static_cast(data)->this_->run(data); return NULL; } @@ -103,9 +128,7 @@ void ActionThread::threadActions(GUIAction *act) } else { m_thread_running = true; pthread_mutex_unlock(&m_act_lock); - ThreadData *d = new ThreadData; - d->act = act; - + ThreadData *d = new ThreadData(this, act); pthread_create(&m_thread, NULL, &ActionThread_work_wrapper, d); } } @@ -370,9 +393,17 @@ int GUIAction::flash_zip(std::string filename, int* wipe_cache) return ret_val; } -bool GUIAction::needsToRunInSeparateThread(const GUIAction::Action& action) +GUIAction::ThreadType GUIAction::getThreadType(const GUIAction::Action& action) { - return setActionsRunningInCallerThread.find(gui_parse_text(action.mFunction)) == setActionsRunningInCallerThread.end(); + string func = gui_parse_text(action.mFunction); + bool needsThread = setActionsRunningInCallerThread.find(func) == setActionsRunningInCallerThread.end(); + if (needsThread) { + if (func == "cancelbackup") + return THREAD_CANCEL; + else + return THREAD_ACTION; + } + return THREAD_NONE; } int GUIAction::doActions() @@ -380,25 +411,40 @@ int GUIAction::doActions() if (mActions.size() < 1) return -1; - bool needThread = false; + // Determine in which thread to run the actions. + // Do it for all actions at once before starting, so that we can cancel the whole batch if the thread is already busy. + ThreadType threadType = THREAD_NONE; std::vector::iterator it; - for (it = mActions.begin(); it != mActions.end(); ++it) - { - if (needsToRunInSeparateThread(*it)) - { - needThread = true; + for (it = mActions.begin(); it != mActions.end(); ++it) { + ThreadType tt = getThreadType(*it); + if (tt == THREAD_NONE) + continue; + if (threadType == THREAD_NONE) + threadType = tt; + else if (threadType != tt) { + LOGERR("Can't mix normal and cancel actions in the same list.\n" + "Running the whole batch in the cancel thread.\n"); + threadType = THREAD_CANCEL; break; } } - if (needThread) - { - action_thread.threadActions(this); - } - else - { - const size_t cnt = mActions.size(); - for (size_t i = 0; i < cnt; ++i) - doAction(mActions[i]); + + // Now run the actions in the desired thread. + switch (threadType) { + case THREAD_ACTION: + action_thread.threadActions(this); + break; + + case THREAD_CANCEL: + cancel_thread.threadActions(this); + break; + + default: { + // no iterators here because theme reloading might kill our object + const size_t cnt = mActions.size(); + for (size_t i = 0; i < cnt; ++i) + doAction(mActions[i]); + } } return 0; @@ -920,7 +966,6 @@ int GUIAction::fileexists(std::string arg) void GUIAction::reinject_after_flash() { if (DataManager::GetIntValue(TW_HAS_INJECTTWRP) == 1 && DataManager::GetIntValue(TW_INJECT_AFTER_ZIP) == 1) { - operation_start("ReinjectTWRP"); gui_print("Injecting TWRP into boot image...\n"); if (simulate) { simulate_progress_bar(); @@ -1060,7 +1105,7 @@ int GUIAction::wipe(std::string arg) } } else ret_val = PartitionManager.Wipe_By_Path(arg); -#ifdef TW_OEM_BUILD +#ifndef TW_OEM_BUILD if (arg == DataManager::GetSettingsStoragePath()) { // If we wiped the settings storage path, recreate the TWRP folder and dump the settings string Storage_Path = DataManager::GetSettingsStoragePath(); @@ -1099,8 +1144,10 @@ int GUIAction::refreshsizes(std::string arg) int GUIAction::nandroid(std::string arg) { if (simulate) { + PartitionManager.stop_backup.set_value(0); DataManager::SetValue("tw_partition", "Simulation"); simulate_progress_bar(); + operation_end(0); } else { operation_start("Nandroid"); int ret = 0; @@ -1131,13 +1178,13 @@ int GUIAction::nandroid(std::string arg) else ret = 0; // 0 for success DataManager::SetValue("tw_cancel_backup", 0); - operation_end(ret); } else { DataManager::SetValue("tw_cancel_backup", 1); gui_print("Backup Canceled.\n"); ret = 0; } + operation_end(ret); return ret; } return 0; @@ -1145,16 +1192,12 @@ int GUIAction::nandroid(std::string arg) int GUIAction::cancelbackup(std::string arg) { if (simulate) { - simulate_progress_bar(); PartitionManager.stop_backup.set_value(1); - operation_end(0); } else { - operation_start("Cancel Backup"); int op_status = PartitionManager.Cancel_Backup(); if (op_status != 0) op_status = 1; // failure - operation_end(op_status); } return 0; @@ -1162,16 +1205,18 @@ int GUIAction::cancelbackup(std::string arg) { int GUIAction::fixpermissions(std::string arg) { + int op_status = 0; + operation_start("Fix Permissions"); LOGINFO("fix permissions started!\n"); if (simulate) { simulate_progress_bar(); } else { - int op_status = PartitionManager.Fix_Permissions(); + op_status = PartitionManager.Fix_Permissions(); if (op_status != 0) op_status = 1; // failure - operation_end(op_status); } + operation_end(op_status); return 0; } @@ -1481,7 +1526,6 @@ int GUIAction::adbsideloadcancel(std::string arg) LOGINFO("Waiting for child sideload process to exit.\n"); waitpid(sideload_child_pid, &status, 0); sideload_child_pid = 0; - operation_end(1); DataManager::SetValue("tw_page_done", "1"); // For OpenRecoveryScript support return 0; } diff --git a/gui/objects.hpp b/gui/objects.hpp index bdccc6e42..c95a9356e 100644 --- a/gui/objects.hpp +++ b/gui/objects.hpp @@ -288,9 +288,11 @@ protected: std::map mKeys; protected: + enum ThreadType { THREAD_NONE, THREAD_ACTION, THREAD_CANCEL }; + int getKeyByName(std::string key); int doAction(Action action); - bool needsToRunInSeparateThread(const Action& action); + ThreadType getThreadType(const Action& action); void simulate_progress_bar(void); int flash_zip(std::string filename, int* wipe_cache); void reinject_after_flash(); @@ -365,25 +367,6 @@ protected: int simulate; }; -class ActionThread -{ -public: - ActionThread(); - ~ActionThread(); - - void threadActions(GUIAction *act); - void run(void *data); -private: - struct ThreadData - { - GUIAction *act; - }; - - pthread_t m_thread; - bool m_thread_running; - pthread_mutex_t m_act_lock; -}; - class GUIConsole : public GUIObject, public RenderObject, public ActionObject { public: -- cgit v1.2.3