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

View File

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

View File

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

View File

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