UI/Qt: Implement register_process for Qt Windows event loop
Qt does not use IOCP's in their underlying Windows event loop implementation; however, QWinEventNotifier allows us to register a wait on a process handle that has SYNCHRONIZE access rights. This means an event will be signalled when that process terminates which emits the QWinEventNotifier::activated signal. Co-authored-by: Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
This commit is contained in:
parent
4cb7743915
commit
e3c2393d96
2 changed files with 67 additions and 0 deletions
|
|
@ -15,6 +15,7 @@
|
|||
#include <LibCore/System.h>
|
||||
#include <LibCore/ThreadEventQueue.h>
|
||||
#include <LibThreading/Mutex.h>
|
||||
#include <LibThreading/MutexProtected.h>
|
||||
#include <LibThreading/RWLock.h>
|
||||
#include <UI/Qt/EventLoopImplementationQt.h>
|
||||
#include <UI/Qt/EventLoopImplementationQtEventTarget.h>
|
||||
|
|
@ -25,6 +26,10 @@
|
|||
#include <QSocketNotifier>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#if defined(AK_OS_WINDOWS)
|
||||
# include <AK/Windows.h>
|
||||
# include <QWinEventNotifier>
|
||||
#endif
|
||||
|
||||
namespace Ladybird {
|
||||
|
||||
|
|
@ -33,6 +38,9 @@ static thread_local OwnPtr<ThreadData> s_this_thread_data;
|
|||
static HashMap<pthread_t, ThreadData*> s_thread_data;
|
||||
static Threading::RWLock s_thread_data_lock;
|
||||
static thread_local Optional<pthread_t> s_thread_id;
|
||||
#if defined(AK_OS_WINDOWS)
|
||||
static Threading::MutexProtected<HashMap<pid_t, QWinEventNotifier*>> s_processes;
|
||||
#endif
|
||||
|
||||
struct ThreadData {
|
||||
static ThreadData& the()
|
||||
|
|
@ -376,6 +384,60 @@ void EventLoopManagerQt::unregister_signal(int handler_id)
|
|||
info.signal_handlers.remove(remove_signal_number);
|
||||
}
|
||||
|
||||
#if defined(AK_OS_WINDOWS)
|
||||
|
||||
void EventLoopManagerQt::register_process(pid_t pid, ESCAPING Function<void(pid_t)> exit_handler)
|
||||
{
|
||||
s_processes.with_locked([&](auto& processes) {
|
||||
if (processes.contains(pid))
|
||||
return;
|
||||
|
||||
HANDLE process_handle = OpenProcess(SYNCHRONIZE, FALSE, pid);
|
||||
VERIFY(process_handle);
|
||||
|
||||
auto* process = new QWinEventNotifier(process_handle);
|
||||
QObject::connect(process, &QWinEventNotifier::activated, process, [process, process_id = pid, exit_handler = move(exit_handler), process_handle = process_handle](HANDLE terminated_process_handle) {
|
||||
if (process_handle != terminated_process_handle)
|
||||
return;
|
||||
|
||||
s_processes.with_locked([&](auto& processes) {
|
||||
auto maybe_process = processes.take(process_id);
|
||||
if (maybe_process.has_value())
|
||||
VERIFY(maybe_process.value() == process);
|
||||
});
|
||||
|
||||
CloseHandle(process_handle);
|
||||
process->deleteLater();
|
||||
exit_handler(process_id);
|
||||
});
|
||||
|
||||
processes.set(pid, process);
|
||||
});
|
||||
}
|
||||
|
||||
void EventLoopManagerQt::unregister_process(pid_t pid)
|
||||
{
|
||||
auto maybe_process = s_processes.with_locked([&](auto& processes) {
|
||||
return processes.take(pid);
|
||||
});
|
||||
if (!maybe_process.has_value())
|
||||
return;
|
||||
|
||||
auto* process = maybe_process.release_value();
|
||||
HANDLE process_handle = process->handle();
|
||||
if (QThread::currentThread() != process->thread()) {
|
||||
QMetaObject::invokeMethod(process, [process, process_handle] {
|
||||
CloseHandle(process_handle);
|
||||
delete process; }, Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
CloseHandle(process_handle);
|
||||
delete process;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void EventLoopManagerQt::did_post_event()
|
||||
{
|
||||
QCoreApplication::postEvent(m_main_thread_event_target.ptr(), new QtEventLoopManagerEvent(QtEventLoopManagerEvent::process_event_queue_event_type()));
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ public:
|
|||
virtual int register_signal(int, Function<void(int)>) override;
|
||||
virtual void unregister_signal(int) override;
|
||||
|
||||
#if defined(AK_OS_WINDOWS)
|
||||
virtual void register_process(pid_t, ESCAPING Function<void(pid_t)> exit_handler) override;
|
||||
virtual void unregister_process(pid_t pid) override;
|
||||
#endif
|
||||
|
||||
void set_main_loop_signal_notifiers(Badge<EventLoopImplementationQt>);
|
||||
|
||||
private:
|
||||
|
|
|
|||
Loading…
Reference in a new issue