Selaa lähdekoodia

双线程运行重定向,只能有一个线程调用EndSubprocessStdOut();

scbc.sat2 5 vuotta sitten
vanhempi
commit
7ce10195cf
2 muutettua tiedostoa jossa 53 lisäystä ja 199 poistoa
  1. 49 181
      SATService/SATService/PythonExecutor.cpp
  2. 4 18
      SATService/SATService/PythonExecutor.h

+ 49 - 181
SATService/SATService/PythonExecutor.cpp

@@ -11,18 +11,12 @@
 #include <Userenv.h>
 #pragma comment(lib,"userenv.lib")
 
-/*
-typedef struct _TOKEN_LINKED_TOKEN {
-HANDLE LinkedToken;
-} TOKEN_LINKED_TOKEN, *PTOKEN_LINKED_TOKEN;
-SERVICE_STATUS_HANDLE hServiceStatus;
-*/
 
 CPythonExecutor::CPythonExecutor(void)
 {
 	m_hWorkThread = NULL;
 	m_hStdoutLogThread = NULL;
-	m_bStatus = FALSE;
+	m_hStderrLogThread = NULL;
 
 	m_hStdOutRead = NULL;
 	m_hStdOutWrite = NULL;
@@ -37,10 +31,7 @@ CPythonExecutor::CPythonExecutor(void)
 	memset(&m_pi, 0, sizeof(m_pi));
 	m_si.cb = sizeof(m_si);
 
-	m_bKillProcess = FALSE;
 	m_bStopLogExport = FALSE;
-	m_dwThreadId = 0;
-	m_dwSubprocessId = 0;
 
 	m_pCaseObj = NULL;
 	m_ulStartTickCount = 0;
@@ -78,11 +69,6 @@ DWORD CPythonExecutor::_WorkerThread(LPVOID lpParam)
 DWORD CPythonExecutor::_StdoutLogExportThread(LPVOID lpParam)
 {
 	CPythonExecutor* that = (CPythonExecutor*)lpParam;
-	if (!that) {
-		printf("Error:参数失效\n");
-		return -1;
-	}
-
 
 	DWORD dwRead;
 	CHAR chBuf[BUFSIZE] = {0};
@@ -102,11 +88,7 @@ DWORD CPythonExecutor::_StdoutLogExportThread(LPVOID lpParam)
 		memset(chBuf, 0, BUFSIZE);
 	} while (!that->m_bStopLogExport);
 
-
-
-	// 结束重定向;
-	that->EndSubprocessStdOut();
-	GLOBAL::WriteTextLog(_T("脚本日志线程结束,用例名=%s"), that->m_pCaseObj->strCaseName.c_str());
+	GLOBAL::WriteTextLog(_T("脚本标准输出日志线程结束,用例名=%s"), that->m_pCaseObj->strCaseName.c_str());
 
 	return 0;
 }
@@ -114,11 +96,6 @@ DWORD CPythonExecutor::_StdoutLogExportThread(LPVOID lpParam)
 DWORD CPythonExecutor::_StderrLogExportThread(LPVOID lpParam)
 {
 	CPythonExecutor* that = (CPythonExecutor*)lpParam;
-	if (!that) {
-		printf("Error:参数失效\n");
-		return -1;
-	}
-
 
 	DWORD dwRead;
 	CHAR chBuf[BUFSIZE] = {0};
@@ -126,21 +103,18 @@ DWORD CPythonExecutor::_StderrLogExportThread(LPVOID lpParam)
 
 	do
 	{
-		bSuccess = ReadFile(that->m_hStdOutRead, chBuf, BUFSIZE, &dwRead, NULL);
+		bSuccess = ReadFile(that->m_hStdErrorRead, chBuf, BUFSIZE, &dwRead, NULL);
 		if (!bSuccess || dwRead == 0 || !_tcslen(chBuf)) 
 			continue;
 
-		that->m_ulStartTickCount = GetTickCount64();
 		GLOBAL::WritePythonLog(that->m_szLogPath, chBuf);
-		// 更新日志时间;
-		if ( that->m_pCaseObj )
-			that->m_pCaseObj->_ulStartTickCount = GetTickCount64();
+		that->m_pCaseObj->_nExecutionState = 4;
 		memset(chBuf, 0, BUFSIZE);
-	} while (!that->m_bStopLogExport);
-
+	} while (!that->m_bStopLogExport); 
+	
 	// 结束重定向;
 	that->EndSubprocessStdOut();
-	GLOBAL::WriteTextLog(_T("脚本日志线程结束,用例名=%s"), that->m_pCaseObj->strCaseName.c_str());
+	GLOBAL::WriteTextLog(_T("脚本标准错误日志线程结束,用例名=%s"), that->m_pCaseObj->strCaseName.c_str());
 
 	return 0;
 }
@@ -184,8 +158,7 @@ int CPythonExecutor::RedirectSubprocessStdout(LPSTARTUPINFO si /*=NULL*/)
 
 int CPythonExecutor::RunScriptProcess()
 {
-	if (!PathFileExists(m_szScriptPath))
-	{
+	if (!PathFileExists(m_szScriptPath)) {
 		printf("Error:脚本路径无效\n");
 		return -1;
 	}
@@ -207,6 +180,7 @@ int CPythonExecutor::RunScriptProcess()
 	RedirectSubprocessStdout(&m_si);
 	// 恢复日志线程;
 	ResumeThread(m_hStdoutLogThread);
+	ResumeThread(m_hStderrLogThread);
 
 	// 启动子进程;
 	if (!CreateProcess(
@@ -226,7 +200,6 @@ int CPythonExecutor::RunScriptProcess()
 		return -3;
 	}
 
-	m_dwSubprocessId = m_pi.dwProcessId;
 	// 等待进程完成退出.
 	WaitForSingleObject(m_pi.hProcess, INFINITE);
 
@@ -345,6 +318,7 @@ int CPythonExecutor::ServiceRunScriptProcess()
 	RedirectSubprocessStdout(&m_si);
 	// 恢复日志线程;
 	ResumeThread(m_hStdoutLogThread);
+	ResumeThread(m_hStderrLogThread);
 
 	// 强制stdion, stdout和stderr完全无缓冲:python -u
 	TCHAR szCommandLine[MAX_PATH] = { 0 };
@@ -369,8 +343,6 @@ int CPythonExecutor::ServiceRunScriptProcess()
 	if ( !bResult )
 		return -1;
 
-	m_dwSubprocessId = m_pi.dwProcessId;
-
 	// 等待进程完成退出.
 	WaitForSingleObject(m_pi.hProcess, INFINITE);
 
@@ -406,20 +378,27 @@ int CPythonExecutor::ServiceRunScriptProcess()
 
 bool CPythonExecutor::StartThread()
 {
-	// 创建线程;
-	m_hWorkThread = CreateThread(NULL, 0, _WorkerThread, this, 0, &m_dwThreadId);
+	// 脚本进程运行线程;
+	m_hWorkThread = CreateThread(NULL, 0, _WorkerThread, this, 0, NULL);
 	if (!m_hWorkThread) {
 		printf("Error:创建执行线程失败\n");
 		return false;
 	}
 
-	// 创建线程;
+	// 标准输出重定向线程;
 	m_hStdoutLogThread = CreateThread(NULL, 0, _StdoutLogExportThread, this, CREATE_SUSPENDED, NULL);
 	if (!m_hStdoutLogThread) {
 		printf("Error:创建日志线程失败\n");
 		return false;
 	}
 
+	// 标准错误重定向线程;
+	m_hStderrLogThread = CreateThread(NULL, 0, _StderrLogExportThread, this, CREATE_SUSPENDED, NULL);
+	if (!m_hStderrLogThread) {
+		printf("Error:创建日志线程失败\n");
+		return false;
+	}
+
 	return true;
 }
 
@@ -451,13 +430,13 @@ void CPythonExecutor::EndWorkThread()
 
 void CPythonExecutor::EndLogThread()
 {
+	// 标记结束;
 	m_bStopLogExport = TRUE;
 	// 等待3秒,是否能自主结束线程;
 	if ( m_hStdoutLogThread ) {
 		if ( WaitForSingleObject(m_hStdoutLogThread, 3000) == WAIT_OBJECT_0 ) {
 			CloseHandle(m_hStdoutLogThread);
 			m_hStdoutLogThread = NULL;
-			return;
 		}	
 	}
 
@@ -472,6 +451,26 @@ void CPythonExecutor::EndLogThread()
 		CloseHandle(m_hStdoutLogThread);
 		m_hStdoutLogThread = NULL;
 	}
+
+	//////////////////////////////////////////////////////////////////////////
+	if ( m_hStderrLogThread ) {
+		if ( WaitForSingleObject(m_hStderrLogThread, 3000) == WAIT_OBJECT_0 ) {
+			CloseHandle(m_hStderrLogThread);
+			m_hStderrLogThread = NULL;
+		}	
+	}
+
+	// 手动结束线程;
+	if (m_hStderrLogThread) {
+		// 尝试5次结束行为;
+		for (int i = 0; i < 5; i++) {
+			if (TerminateThread(m_hStderrLogThread, 0))
+				break;
+		}
+
+		CloseHandle(m_hStderrLogThread);
+		m_hStderrLogThread = NULL;
+	}
 }
 
 void CPythonExecutor::EndThread()
@@ -496,8 +495,12 @@ BOOL CPythonExecutor::EndSubprocess()
 
 void CPythonExecutor::EndSubprocessStdOut()
 {
-	OutputDebugString("--------------EndSubprocessStdOut----------------\n");
+	OutputDebugString("关闭重定向子进程标准输出管道句柄\n");
 	// 关闭重定向句柄;
+	if (m_hStdErrorRead)
+		CloseHandle(m_hStdErrorRead);
+	m_hStdErrorRead = NULL;
+
 	if (m_hStdErrorWrite)
 		CloseHandle(m_hStdErrorWrite);
 	m_hStdErrorWrite = NULL;
@@ -533,139 +536,6 @@ DWORD CPythonExecutor::GetActiveSessionID()
 	return dwSessionId;
 }
 
-BOOL CPythonExecutor::ServiceExecute(std::wstring wstrCmdLine, INT32& n32ExitResult)
-{
-	ofstream ofile("C:\\logEvent.txt");
-	ofile<<"start excute"<<std::endl;
-	DWORD dwProcesses = 0;
-	BOOL bResult = FALSE;
-
-	DWORD dwSid = GetActiveSessionID();
-
-	DWORD dwRet = 0;
-	PROCESS_INFORMATION pi;
-	STARTUPINFO si;
-	HANDLE hProcess = NULL, hPToken = NULL, hUserTokenDup = NULL;
-	if (!WTSQueryUserToken(dwSid, &hPToken)) {
-		PROCESSENTRY32 procEntry;
-		DWORD dwPid = 0;
-		HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
-		if (hSnap == INVALID_HANDLE_VALUE) {
-			return FALSE;
-		}
-
-		procEntry.dwSize = sizeof(PROCESSENTRY32);
-		if (Process32First(hSnap, &procEntry)) {
-			do {
-				if (_tcsicmp(procEntry.szExeFile, _T("explorer.exe")) == 0) {
-					DWORD exeSessionId = 0;
-					if (ProcessIdToSessionId(procEntry.th32ProcessID, &exeSessionId) && exeSessionId == dwSid) {
-						dwPid = procEntry.th32ProcessID;
-						break;
-					}
-				}
-
-			} while (Process32Next(hSnap, &procEntry));
-		}
-		CloseHandle(hSnap);
-
-		// explorer进程不存在
-		if (dwPid == 0)
-		{
-			return FALSE;
-		}
-
-		hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid);
-		if (hProcess == NULL) {
-			return FALSE;
-		}
-
-		if(!::OpenProcessToken(hProcess, TOKEN_ALL_ACCESS_P,&hPToken)) {
-			CloseHandle(hProcess);
-			return FALSE;
-		}
-	}
-
-	if (hPToken == NULL)
-		return FALSE;
-
-	TOKEN_LINKED_TOKEN admin;
-	bResult = GetTokenInformation(hPToken, (TOKEN_INFORMATION_CLASS)19, &admin, sizeof(TOKEN_LINKED_TOKEN), &dwRet);
-
-	if (!bResult)  {// vista 以前版本不支持TokenLinkedToken
-		TOKEN_PRIVILEGES tp;
-		LUID luid;
-		if (LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid)) {
-			tp.PrivilegeCount =1;
-			tp.Privileges[0].Luid =luid;
-			tp.Privileges[0].Attributes =SE_PRIVILEGE_ENABLED;
-		}
-		DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);
-	} else {
-		hUserTokenDup = admin.LinkedToken;
-		ofile<<"token: "<<hUserTokenDup<<std::endl;
-	}
-
-	LPVOID pEnv =NULL;
-	DWORD dwCreationFlags = CREATE_PRESERVE_CODE_AUTHZ_LEVEL;
-
-	if(CreateEnvironmentBlock(&pEnv,hUserTokenDup,TRUE)) {
-		dwCreationFlags|=CREATE_UNICODE_ENVIRONMENT;
-	} else {
-		pEnv = NULL;
-	}
-
-	ZeroMemory( &si, sizeof(si) );
-	si.cb = sizeof(si);
-	si.dwFlags = STARTF_USESHOWWINDOW;
-	si.wShowWindow = SW_SHOWNORMAL;
-	ZeroMemory( &pi, sizeof(pi) );
-
-	bResult = CreateProcessAsUser(
-		hUserTokenDup,                     // client's access token
-		NULL,							// file to execute
-		(LPTSTR) wstrCmdLine.c_str(),                 // command line
-		NULL,							// pointer to process SECURITY_ATTRIBUTES
-		NULL,							// pointer to thread SECURITY_ATTRIBUTES
-		FALSE,							// handles are not inheritable
-		dwCreationFlags,				// creation flags
-		pEnv,							// pointer to new environment block
-		NULL,							// name of current directory
-		&si,							// pointer to STARTUPINFO structure
-		&pi								// receives information about new process
-		);	
-
-	if(pi.hProcess) {
-		if(WAIT_OBJECT_0 == WaitForSingleObject(pi.hProcess, 180000)) {
-			DWORD dwResult = 0;
-			if(GetExitCodeProcess(pi.hProcess,  &dwResult)) {
-				n32ExitResult = dwResult;
-			} else {
-				n32ExitResult = -1;
-			}
-
-			CloseHandle(pi.hThread);
-			CloseHandle(pi.hProcess);
-		} else {
-			CloseHandle(pi.hThread);
-			CloseHandle(pi.hProcess);
-			n32ExitResult = -1;
-		}
-	}
-
-	if (hUserTokenDup != NULL)
-		CloseHandle(hUserTokenDup);
-	if (hProcess != NULL)
-		CloseHandle(hProcess);
-	if (hPToken != NULL)
-		CloseHandle(hPToken);
-	if (pEnv != NULL)
-		DestroyEnvironmentBlock(pEnv);
-
-	return TRUE;
-
-}
-
 bool CPythonExecutor::InitScript(std::string strScript, std::string strLogPath, std::string strScriptCmd)
 {
 	// 判断脚本是否存在;
@@ -692,7 +562,6 @@ bool CPythonExecutor::InitScript(std::string strScript, std::string strLogPath,
 	}
 
 	// 赋值参数;
-	m_dwThreadId = m_dwSubprocessId = 0;
 	_tcscpy_s(m_szScriptPath, strScript.c_str());
 	_tcscpy_s(m_szLogPath, strLogPath.c_str());
 	_tcscpy_s(m_szExtraSentence, strScriptCmd.c_str());
@@ -707,9 +576,6 @@ bool CPythonExecutor::StartScript()
 		return true;
 	}
 
-	// 异常类型;
-	printf("Error:异常类型脚本\n");
-
 	return false;
 }
 
@@ -723,7 +589,9 @@ void CPythonExecutor::StopScript()
 
 bool CPythonExecutor::IsScriptOver()
 {
-	if ( WaitForSingleObject(m_hStdoutLogThread, 0) == WAIT_OBJECT_0  && WaitForSingleObject(m_hWorkThread, 0) == WAIT_OBJECT_0)
+	if ( WaitForSingleObject(m_hStdoutLogThread, 0) == WAIT_OBJECT_0  && 
+		 WaitForSingleObject(m_hStderrLogThread, 0) == WAIT_OBJECT_0 && 
+		 WaitForSingleObject(m_hWorkThread, 0) == WAIT_OBJECT_0)
 	{
 		GLOBAL::WriteTextLog(_T("====>脚本(%s)已完成"), m_pCaseObj->strCaseName.c_str());
 		return true;

+ 4 - 18
SATService/SATService/PythonExecutor.h

@@ -13,9 +13,9 @@ public:
 
 protected:
 	SATHTTP::STCase *m_pCaseObj;						// 用例对象;
-	HANDLE			m_hWorkThread;						// 事件句柄;
-	HANDLE			m_hStdoutLogThread;					// 事件句柄;
-	BOOL			m_bStatus;							// 线程状态;
+	HANDLE			m_hWorkThread;						// 线程句柄;
+	HANDLE			m_hStdoutLogThread;					// 线程句柄;
+	HANDLE			m_hStderrLogThread;					// 线程句柄;
 	TCHAR			m_szScriptPath[MAX_PATH];			// 脚本路径;
 	TCHAR			m_szLogPath[MAX_PATH];				// 日志路径;	
 	TCHAR			m_szExtraSentence[MAX_PATH];		// 脚本命令行参数或额外要执行的语句;
@@ -27,19 +27,11 @@ protected:
 	// 子进程信息;
 	STARTUPINFO			m_si;
 	PROCESS_INFORMATION	m_pi;
-	// 进程结束标志;
-	BOOL			m_bKillProcess;
+
 	// 停止日志导出线程;
 	BOOL			m_bStopLogExport;
 	// 执行器执行时间;
-	CTime			m_tStartTime;
 	ULONGLONG		m_ulStartTickCount;
-	// 执行器结束时间;
-	CTime			m_tEndTime;
-	// 子进程ID;
-	DWORD			m_dwSubprocessId;
-	// 线程ID;
-	DWORD			m_dwThreadId;
 protected:
 	// 工作者线程函数;
 	static DWORD WINAPI _WorkerThread(LPVOID lpParam);
@@ -66,8 +58,6 @@ protected:
 	void EndSubprocessStdOut();
 	// 获取当前活动的会话ID;
 	DWORD GetActiveSessionID();
-	// 在服务进程下创建子进程;
-	BOOL ServiceExecute(std::wstring wstrCmdLine, INT32& n32ExitResult);
 public:
 	// 初始脚本运行参数;
 	bool InitScript(
@@ -80,10 +70,6 @@ public:
 	void StopScript();
 	// 脚本是否结束;
 	bool IsScriptOver();
-	// 获取脚本Id;
-	DWORD GetScriptId() const {
-		return m_dwSubprocessId;
-	}
 	// 设置用例对象;
 	void SetCaseObje(SATHTTP::STCase *pObj){ m_pCaseObj = pObj;}
 	// 结束子进程;