Terminal: Use QWinEventNotifier for shell process termination

Change-Id: I59ddcaa76714a0b15987b9e0912f4701a2951648
Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
Cristian Adam
2023-02-22 15:12:48 +01:00
committed by Marcus Tillmanns
parent 3287e14dd1
commit 007c47a2d4
4 changed files with 44 additions and 36 deletions

View File

@@ -6,6 +6,7 @@
#include <QTimer> #include <QTimer>
#include <QMutexLocker> #include <QMutexLocker>
#include <QCoreApplication> #include <QCoreApplication>
#include <QWinEventNotifier>
#include <qt_windows.h> #include <qt_windows.h>
@@ -179,21 +180,19 @@ bool ConPtyProcess::startProcess(const QString &executable,
m_pid = m_shellProcessInformation.dwProcessId; m_pid = m_shellProcessInformation.dwProcessId;
// Notify when the shell process has been terminated // Notify when the shell process has been terminated
RegisterWaitForSingleObject( m_shellCloseWaitNotifier = new QWinEventNotifier(m_shellProcessInformation.hProcess, notifier());
&m_shellCloseWaitHandle, QObject::connect(m_shellCloseWaitNotifier,
m_shellProcessInformation.hProcess, &QWinEventNotifier::activated,
[](PVOID data, BOOLEAN) { notifier(),
auto self = static_cast<ConPtyProcess *>(data); [this](HANDLE hEvent) {
DWORD exitCode = 0; DWORD exitCode = 0;
GetExitCodeProcess(self->m_shellProcessInformation.hProcess, &exitCode); GetExitCodeProcess(hEvent, &exitCode);
self->m_exitCode = exitCode; m_exitCode = exitCode;
// Do not respawn if the object is about to be destructed // Do not respawn if the object is about to be destructed
if (!self->m_aboutToDestruct) if (!m_aboutToDestruct)
emit self->notifier()->aboutToClose(); emit notifier()->aboutToClose();
}, m_shellCloseWaitNotifier->setEnabled(false);
this, });
INFINITE,
WT_EXECUTEONLYONCE);
//this code runned in separate thread //this code runned in separate thread
m_readThread = QThread::create([this]() m_readThread = QThread::create([this]()
@@ -220,6 +219,8 @@ bool ConPtyProcess::startProcess(const QString &executable,
if (QThread::currentThread()->isInterruptionRequested() || brokenPipe) if (QThread::currentThread()->isInterruptionRequested() || brokenPipe)
break; break;
} }
CancelIoEx(m_hPipeIn, nullptr);
}); });
//start read thread //start read thread
@@ -269,6 +270,9 @@ bool ConPtyProcess::kill()
m_readThread->deleteLater(); m_readThread->deleteLater();
m_readThread = nullptr; m_readThread = nullptr;
delete m_shellCloseWaitNotifier;
m_shellCloseWaitNotifier = nullptr;
m_pid = 0; m_pid = 0;
m_ptyHandler = INVALID_HANDLE_VALUE; m_ptyHandler = INVALID_HANDLE_VALUE;
m_hPipeIn = INVALID_HANDLE_VALUE; m_hPipeIn = INVALID_HANDLE_VALUE;
@@ -276,7 +280,6 @@ bool ConPtyProcess::kill()
CloseHandle(m_shellProcessInformation.hThread); CloseHandle(m_shellProcessInformation.hThread);
CloseHandle(m_shellProcessInformation.hProcess); CloseHandle(m_shellProcessInformation.hProcess);
UnregisterWait(m_shellCloseWaitHandle);
// Cleanup attribute list // Cleanup attribute list
if (m_shellStartupInfo.lpAttributeList) { if (m_shellStartupInfo.lpAttributeList) {

View File

@@ -23,6 +23,8 @@ typedef VOID* HPCON;
#define TOO_OLD_WINSDK #define TOO_OLD_WINSDK
#endif #endif
class QWinEventNotifier;
template <typename T> template <typename T>
std::vector<T> vectorFromString(const std::basic_string<T> &str) std::vector<T> vectorFromString(const std::basic_string<T> &str)
{ {
@@ -160,7 +162,7 @@ private:
PtyBuffer m_buffer; PtyBuffer m_buffer;
bool m_aboutToDestruct{false}; bool m_aboutToDestruct{false};
PROCESS_INFORMATION m_shellProcessInformation{}; PROCESS_INFORMATION m_shellProcessInformation{};
HANDLE m_shellCloseWaitHandle{INVALID_HANDLE_VALUE}; QWinEventNotifier* m_shellCloseWaitNotifier;
STARTUPINFOEX m_shellStartupInfo{}; STARTUPINFOEX m_shellStartupInfo{};
}; };

View File

@@ -3,6 +3,8 @@
#include <QFileInfo> #include <QFileInfo>
#include <sstream> #include <sstream>
#include <QCoreApplication> #include <QCoreApplication>
#include <QLocalSocket>
#include <QWinEventNotifier>
#define DEBUG_VAR_LEGACY "WINPTYDBG" #define DEBUG_VAR_LEGACY "WINPTYDBG"
#define DEBUG_VAR_ACTUAL "WINPTY_DEBUG" #define DEBUG_VAR_ACTUAL "WINPTY_DEBUG"
@@ -132,22 +134,22 @@ bool WinPtyProcess::startProcess(const QString &executable,
m_pid = (int)GetProcessId(m_innerHandle); m_pid = (int)GetProcessId(m_innerHandle);
m_outSocket = new QLocalSocket();
// Notify when the shell process has been terminated // Notify when the shell process has been terminated
RegisterWaitForSingleObject( m_shellCloseWaitNotifier = new QWinEventNotifier(m_innerHandle, notifier());
&m_shellCloseWaitHandle, QObject::connect(m_shellCloseWaitNotifier,
m_innerHandle, &QWinEventNotifier::activated,
[](PVOID data, BOOLEAN) { notifier(),
auto self = static_cast<WinPtyProcess *>(data); [this](HANDLE hEvent) {
// Do not respawn if the object is about to be destructed
DWORD exitCode = 0; DWORD exitCode = 0;
GetExitCodeProcess(self->m_innerHandle, &exitCode); GetExitCodeProcess(hEvent, &exitCode);
self->m_exitCode = exitCode; m_exitCode = exitCode;
if (!self->m_aboutToDestruct) // Do not respawn if the object is about to be destructed
emit self->notifier()->aboutToClose(); if (!m_aboutToDestruct)
}, emit notifier()->aboutToClose();
this, m_shellCloseWaitNotifier->setEnabled(false);
INFINITE, });
WT_EXECUTEONLYONCE);
//get pipe names //get pipe names
LPCWSTR conInPipeName = winpty_conin_name(m_ptyHandler); LPCWSTR conInPipeName = winpty_conin_name(m_ptyHandler);
@@ -158,7 +160,6 @@ bool WinPtyProcess::startProcess(const QString &executable,
LPCWSTR conOutPipeName = winpty_conout_name(m_ptyHandler); LPCWSTR conOutPipeName = winpty_conout_name(m_ptyHandler);
m_conOutName = QString::fromStdWString(std::wstring(conOutPipeName)); m_conOutName = QString::fromStdWString(std::wstring(conOutPipeName));
m_outSocket = new QLocalSocket();
m_outSocket->connectToServer(m_conOutName, QIODevice::ReadOnly); m_outSocket->connectToServer(m_conOutName, QIODevice::ReadOnly);
m_outSocket->waitForConnected(); m_outSocket->waitForConnected();
@@ -214,7 +215,8 @@ bool WinPtyProcess::kill()
winpty_free(m_ptyHandler); winpty_free(m_ptyHandler);
exitCode = CloseHandle(m_innerHandle); exitCode = CloseHandle(m_innerHandle);
UnregisterWait(m_shellCloseWaitHandle); delete m_shellCloseWaitNotifier;
m_shellCloseWaitNotifier = nullptr;
m_ptyHandler = nullptr; m_ptyHandler = nullptr;
m_innerHandle = nullptr; m_innerHandle = nullptr;

View File

@@ -4,7 +4,8 @@
#include "iptyprocess.h" #include "iptyprocess.h"
#include "winpty.h" #include "winpty.h"
#include <QLocalSocket> class QLocalSocket;
class QWinEventNotifier;
class WinPtyProcess : public IPtyProcess class WinPtyProcess : public IPtyProcess
{ {
@@ -36,7 +37,7 @@ private:
QLocalSocket *m_inSocket; QLocalSocket *m_inSocket;
QLocalSocket *m_outSocket; QLocalSocket *m_outSocket;
bool m_aboutToDestruct{false}; bool m_aboutToDestruct{false};
HANDLE m_shellCloseWaitHandle{INVALID_HANDLE_VALUE}; QWinEventNotifier* m_shellCloseWaitNotifier;
}; };
#endif // WINPTYPROCESS_H #endif // WINPTYPROCESS_H