Skip to content

Commit 5cd1eb2

Browse files
committed
LibWebView: 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.
1 parent 465dfce commit 5cd1eb2

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

UI/Qt/EventLoopImplementationQt.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
#include <QSocketNotifier>
2626
#include <QThread>
2727
#include <QTimer>
28+
#if defined(AK_OS_WINDOWS)
29+
# include <AK/Windows.h>
30+
# include <QWinEventNotifier>
31+
#endif
2832

2933
namespace Ladybird {
3034

@@ -61,6 +65,9 @@ struct ThreadData {
6165

6266
Threading::Mutex mutex;
6367
HashMap<Core::Notifier*, NonnullOwnPtr<QSocketNotifier>> notifiers;
68+
#if defined(AK_OS_WINDOWS)
69+
HashMap<pid_t, QWinEventNotifier*> processes;
70+
#endif
6471
};
6572

6673
class QtEventLoopManagerEvent final : public QEvent {
@@ -376,6 +383,44 @@ void EventLoopManagerQt::unregister_signal(int handler_id)
376383
info.signal_handlers.remove(remove_signal_number);
377384
}
378385

386+
#if defined(AK_OS_WINDOWS)
387+
388+
void EventLoopManagerQt::register_process(pid_t pid, ESCAPING Function<void(pid_t)> exit_handler)
389+
{
390+
HANDLE process_handle = OpenProcess(SYNCHRONIZE, FALSE, pid);
391+
VERIFY(process_handle);
392+
393+
auto* process = new QWinEventNotifier(process_handle);
394+
QObject::connect(process, &QWinEventNotifier::activated, [process_id = pid, exit_handler = move(exit_handler), process_handle = process_handle](HANDLE terminated_process_handle) {
395+
if (process_handle == terminated_process_handle) {
396+
exit_handler(process_id);
397+
}
398+
});
399+
400+
{
401+
auto& thread_data = ThreadData::the();
402+
Threading::MutexLocker locker(thread_data.mutex);
403+
thread_data.processes.set(pid, process);
404+
}
405+
}
406+
407+
void EventLoopManagerQt::unregister_process(pid_t pid)
408+
{
409+
{
410+
auto& thread_data = ThreadData::the();
411+
Threading::MutexLocker locker(thread_data.mutex);
412+
auto maybe_process = thread_data.processes.take(pid);
413+
if (!maybe_process.has_value())
414+
return;
415+
if (auto* process = maybe_process.release_value()) {
416+
CloseHandle(process->handle());
417+
delete process;
418+
}
419+
}
420+
}
421+
422+
#endif
423+
379424
void EventLoopManagerQt::did_post_event()
380425
{
381426
QCoreApplication::postEvent(m_main_thread_event_target.ptr(), new QtEventLoopManagerEvent(QtEventLoopManagerEvent::process_event_queue_event_type()));

UI/Qt/EventLoopImplementationQt.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ class EventLoopManagerQt final : public Core::EventLoopManager {
3737
virtual int register_signal(int, Function<void(int)>) override;
3838
virtual void unregister_signal(int) override;
3939

40+
#if defined(AK_OS_WINDOWS)
41+
virtual void register_process(pid_t, ESCAPING Function<void(pid_t)> exit_handler) override;
42+
virtual void unregister_process(pid_t pid) override;
43+
#endif
44+
4045
void set_main_loop_signal_notifiers(Badge<EventLoopImplementationQt>);
4146

4247
private:

0 commit comments

Comments
 (0)