From 920adde65fc3108a7b9aaea2cba8ddc6aa93de4b Mon Sep 17 00:00:00 2001 From: Vladimir Gorshenkov Date: Sat, 22 Jan 2022 14:55:28 +0300 Subject: [PATCH] [Network] and [Kernal] add cancel from thread (linux) --- .../FileTransporter/include/FileTransporter.h | 6 ++ .../FileTransporter/src/FileTransporter.cpp | 4 + .../src/FileTransporter_curl.cpp | 2 +- .../src/FileTransporter_private.h | 14 ++++ .../FileTransporter/src/transport_external.h | 75 ++++++++++++++----- DesktopEditor/graphics/BaseThread.cpp | 21 +++++- DesktopEditor/graphics/BaseThread.h | 3 + 7 files changed, 105 insertions(+), 20 deletions(-) diff --git a/Common/Network/FileTransporter/include/FileTransporter.h b/Common/Network/FileTransporter/include/FileTransporter.h index 3ed6ec61ca..caed9ac1cc 100644 --- a/Common/Network/FileTransporter/include/FileTransporter.h +++ b/Common/Network/FileTransporter/include/FileTransporter.h @@ -56,6 +56,8 @@ namespace NSNetwork virtual void Suspend() = 0; virtual void Resume() = 0; virtual void Stop() = 0; + virtual void StopNoJoin() = 0; + virtual void Cancel() = 0; virtual int IsRunned() = 0; //events @@ -92,6 +94,8 @@ namespace NSNetwork virtual void Suspend(); virtual void Resume(); virtual void Stop(); + virtual void StopNoJoin(); + virtual void Cancel(); virtual int IsRunned(); virtual void SetEvent_OnProgress(std::function); virtual void SetEvent_OnComplete(std::function); @@ -122,6 +126,8 @@ namespace NSNetwork virtual void Suspend(); virtual void Resume(); virtual void Stop(); + virtual void StopNoJoin(); + virtual void Cancel(); virtual int IsRunned(); virtual void SetEvent_OnProgress(std::function); virtual void SetEvent_OnComplete(std::function); diff --git a/Common/Network/FileTransporter/src/FileTransporter.cpp b/Common/Network/FileTransporter/src/FileTransporter.cpp index 86771a1022..ead40e574c 100644 --- a/Common/Network/FileTransporter/src/FileTransporter.cpp +++ b/Common/Network/FileTransporter/src/FileTransporter.cpp @@ -101,6 +101,8 @@ namespace NSNetwork void CFileDownloader::Suspend() { m_pInternal->Suspend(); } void CFileDownloader::Resume() { m_pInternal->Resume(); } void CFileDownloader::Stop() { m_pInternal->Stop(); } + void CFileDownloader::StopNoJoin() { m_pInternal->StopNoJoin(); } + void CFileDownloader::Cancel() { m_pInternal->Cancel(); } int CFileDownloader::IsRunned() { return m_pInternal->IsRunned(); } void CFileDownloader::SetEvent_OnProgress(std::function func) @@ -164,6 +166,8 @@ namespace NSNetwork void CFileUploader::Suspend() { m_pInternal->Suspend(); } void CFileUploader::Resume() { m_pInternal->Resume(); } void CFileUploader::Stop() { m_pInternal->Stop(); } + void CFileUploader::StopNoJoin() { m_pInternal->StopNoJoin(); } + void CFileUploader::Cancel() { m_pInternal->Cancel(); } int CFileUploader::IsRunned() { return m_pInternal->IsRunned(); } void CFileUploader::SetEvent_OnProgress(std::function func) diff --git a/Common/Network/FileTransporter/src/FileTransporter_curl.cpp b/Common/Network/FileTransporter/src/FileTransporter_curl.cpp index a64c8109c3..e9ca02c423 100644 --- a/Common/Network/FileTransporter/src/FileTransporter_curl.cpp +++ b/Common/Network/FileTransporter/src/FileTransporter_curl.cpp @@ -241,7 +241,7 @@ namespace NSNetwork if (NSFile::CFileBinary::Exists(m_sDownloadFilePath)) NSFile::CFileBinary::Remove(m_sDownloadFilePath); } - return download_external(m_sDownloadFileUrl, m_sDownloadFilePath, m_func_onProgress); + return download_external(m_sDownloadFileUrl, m_sDownloadFilePath, m_func_onProgress, m_bIsExit); } virtual int UploadData() override { diff --git a/Common/Network/FileTransporter/src/FileTransporter_private.h b/Common/Network/FileTransporter/src/FileTransporter_private.h index 32dc83fbbb..c70edba4b0 100644 --- a/Common/Network/FileTransporter/src/FileTransporter_private.h +++ b/Common/Network/FileTransporter/src/FileTransporter_private.h @@ -61,6 +61,8 @@ namespace NSNetwork m_func_onComplete = NULL; m_func_onProgress = NULL; + + m_bIsExit = nullptr; } CFileTransporterBase(const std::wstring &sUploadUrl, const unsigned char* cData, const int nSize) @@ -82,6 +84,8 @@ namespace NSNetwork m_func_onComplete = NULL; m_func_onProgress = NULL; + + m_bIsExit = nullptr; } CFileTransporterBase(const std::wstring &sUploadUrl, const std::wstring &sUploadFilePath) @@ -103,6 +107,8 @@ namespace NSNetwork m_func_onComplete = NULL; m_func_onProgress = NULL; + + m_bIsExit = nullptr; } virtual ~CFileTransporterBase () @@ -143,6 +149,8 @@ namespace NSNetwork std::function m_func_onComplete; std::function m_func_onProgress; + + std::atomic* m_bIsExit; // Для остановки и выхода потока }; class CFileTransporter_private : public NSThreads::CBaseThread @@ -234,6 +242,7 @@ namespace NSNetwork virtual DWORD ThreadProc () { m_pInternal->m_bComplete = false; + m_pInternal->m_bIsExit = NSThreads::CBaseThread::m_bIsExit; int hrResultAll = 0; if(m_pInternal->m_eLoadType == m_pInternal->DOWNLOADFILE) @@ -245,6 +254,11 @@ namespace NSNetwork if (0 == hrResultAll) m_pInternal->m_bComplete = true; + else + { + if (NSFile::CFileBinary::Exists(m_pInternal->m_sDownloadFilePath)) + NSFile::CFileBinary::Remove(m_pInternal->m_sDownloadFilePath); + } if (m_pInternal->m_func_onComplete) m_pInternal->m_func_onComplete(hrResultAll); diff --git a/Common/Network/FileTransporter/src/transport_external.h b/Common/Network/FileTransporter/src/transport_external.h index a3bf162134..6cbecd6172 100644 --- a/Common/Network/FileTransporter/src/transport_external.h +++ b/Common/Network/FileTransporter/src/transport_external.h @@ -41,11 +41,14 @@ #include #include #include +#include namespace NSNetwork { namespace NSFileTransport { + pid_t pid; + std::atomic* m_isExit; std::string wget_url_validate(const std::string& url) { std::string::size_type pos = 0; @@ -58,9 +61,10 @@ namespace NSNetwork return url.substr(pos); } - int download_external(const std::wstring& sUrl, const std::wstring& sOutput, std::function func_onProgress) + int download_external(const std::wstring& sUrl, const std::wstring& sOutput, std::function func_onProgress, std::atomic* isExit) { int nReturnCode = -1; + m_isExit = isExit; std::string sUrlA = U_TO_UTF8(sUrl); //sUrlA =("\"" + sUrlA + "\""); std::string sOutputA = U_TO_UTF8(sOutput); @@ -72,7 +76,7 @@ namespace NSNetwork if(func_onProgress) pipe(pipefd); - pid_t pid = fork(); // create child process + pid = fork(); // create child process int status; switch (pid) @@ -116,13 +120,27 @@ namespace NSNetwork default: // parent process, pid now contains the child pid if(func_onProgress) { + close(pipefd[1]); + // close the write end of the pipe in the parent size_t size = 81; char buffer[size]; std::string str; - close(pipefd[1]); // close the write end of the pipe in the parent ssize_t res = 1; + std::regex r(R"(\d+(?:\.\d+)?%)"); + std::smatch sm; + std::string percentFull; + std::string percent; + int percentInt; + while (1) { + if(m_isExit->load()) + { + kill(pid, SIGTERM); + //while (-1 == waitpid(pid, &status, 0)); // wait for child to complete + return nReturnCode; + } + str.clear(); res = read(pipefd[0], buffer, sizeof(buffer)); @@ -131,15 +149,11 @@ namespace NSNetwork str.append(buffer); - std::regex r(R"(\d+(?:\.\d+)?%)"); - std::smatch sm; - std::string percentFull; - std::string percent; if(regex_search(str, sm, r)) { percentFull = sm.str(); percent = percentFull.substr(0, percentFull.find(".")); - int percentInt = std::stoi(percent); + percentInt = std::stoi(percent); if(percentInt >= 0 && percentInt <= 100) func_onProgress(percentInt); @@ -147,14 +161,28 @@ namespace NSNetwork if(str.find("100.0%") != std::string::npos) break; + } } - while (-1 == waitpid(pid, &status, 0)); // wait for child to complete - if (WIFEXITED(status)) - { - nReturnCode = WEXITSTATUS(status); + else { + int waitres; + while (1) // wait for child to complete + { + if(m_isExit->load()) + { + kill(pid, SIGTERM); + return nReturnCode; + } + else if((waitres = waitpid(pid, &status, WNOHANG)) > 0) + { + if (WIFEXITED(status)) + { + nReturnCode = WEXITSTATUS(status); + } + break; + } + } } - break; } } @@ -162,7 +190,7 @@ namespace NSNetwork { std::string sUrlValidateA = wget_url_validate(sUrlA); - pid_t pid = fork(); // create child process + pid = fork(); // create child process int status; switch (pid) @@ -191,12 +219,23 @@ namespace NSNetwork break; } default: // parent process, pid now contains the child pid - while (-1 == waitpid(pid, &status, 0)); // wait for child to complete - if (WIFEXITED(status)) + int waitres; + while (1) // wait for child to complete { - nReturnCode = WEXITSTATUS(status); + if(m_isExit->load()) + { + kill(pid, SIGTERM); + return nReturnCode; + } + else if((waitres = waitpid(pid, &status, WNOHANG)) > 0) + { + if (WIFEXITED(status)) + { + nReturnCode = WEXITSTATUS(status); + } + break; + } } - break; } } diff --git a/DesktopEditor/graphics/BaseThread.cpp b/DesktopEditor/graphics/BaseThread.cpp index 4b4b817e7b..917b80a948 100644 --- a/DesktopEditor/graphics/BaseThread.cpp +++ b/DesktopEditor/graphics/BaseThread.cpp @@ -114,7 +114,7 @@ namespace NSThreads }; #else void* CBaseThread::__ThreadProc(void* pv) - { + { #ifndef NOT_USE_PTHREAD_CANCEL int old_thread_type; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_thread_type); @@ -155,6 +155,7 @@ namespace NSThreads m_lThreadPriority = 0; m_bIsNeedDestroy = false; + m_bIsExit = new std::atomic(false); } CBaseThread::~CBaseThread() { @@ -170,6 +171,8 @@ namespace NSThreads m_hThread = new __native_thread(); m_bRunThread = TRUE; + + m_bIsExit->exchange(false); #if defined(_WIN32) || defined(_WIN64) || defined(_WIN32_WCE) DWORD dwTemp; ((__native_thread*)m_hThread)->m_thread = CreateThread(NULL, 0, &__ThreadProc, (void*)this, 0, &dwTemp); @@ -228,6 +231,22 @@ namespace NSThreads WaitForSingleObject(((__native_thread*)m_hThread)->m_thread, INFINITE); #else pthread_join(((__native_thread*)m_hThread)->m_thread, 0); +#endif + } + + void CBaseThread::Cancel() + { + if (NULL == m_hThread) + return; + + m_bIsExit->exchange(true); + +#if defined(_WIN32) || defined(_WIN64) || defined(_WIN32_WCE) + //WaitForSingleObject(((__native_thread*)m_hThread)->m_thread, INFINITE); +#else + //pthread_cancel(((__native_thread*)m_hThread)->m_thread); + //pthread_kill(((__native_thread*)m_hThread)->m_thread, SIGUSR1); + pthread_join(((__native_thread*)m_hThread)->m_thread, 0); #endif } } diff --git a/DesktopEditor/graphics/BaseThread.h b/DesktopEditor/graphics/BaseThread.h index d733982278..cd1bfd98a1 100644 --- a/DesktopEditor/graphics/BaseThread.h +++ b/DesktopEditor/graphics/BaseThread.h @@ -33,6 +33,7 @@ #define _BUILD_BASETHREAD_H_ #include "../common/Types.h" +#include #if defined(_WIN32) || defined(_WIN64) || defined(_WIN32_WCE) #include @@ -66,6 +67,7 @@ namespace NSThreads int m_lThreadPriority; bool m_bIsNeedDestroy; + std::atomic* m_bIsExit; public: CBaseThread(); @@ -77,6 +79,7 @@ namespace NSThreads virtual void Stop(); virtual void StopNoJoin(); virtual void DestroyOnFinish(); + virtual void Cancel(); INT IsSuspended(); INT IsRunned();