summaryrefslogtreecommitdiffstats
path: root/xpcom/threads/WinHandleWatcher.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /xpcom/threads/WinHandleWatcher.h
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xpcom/threads/WinHandleWatcher.h')
-rw-r--r--xpcom/threads/WinHandleWatcher.h117
1 files changed, 117 insertions, 0 deletions
diff --git a/xpcom/threads/WinHandleWatcher.h b/xpcom/threads/WinHandleWatcher.h
new file mode 100644
index 0000000000..eb1e1c0245
--- /dev/null
+++ b/xpcom/threads/WinHandleWatcher.h
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef WinHandleWatcher_h__
+#define WinHandleWatcher_h__
+
+#include <minwindef.h>
+
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
+
+#include "nsIEventTarget.h"
+#include "nsIRunnable.h"
+#include "nsIThread.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+///////////////////////////////////////////////////////////////////////
+// HandleWatcher
+//
+// Enqueues a task onto an event target when a watched Win32 synchronization
+// object [1] enters the signaled state.
+//
+// The HandleWatcher must be stopped before either it or the synchronization
+// object is destroyed.
+//
+//////
+//
+// Example of use:
+//
+// ```
+// class MyClass {
+// /* ... */
+//
+// HANDLE CreateThing();
+// void OnComplete();
+// public:
+// void Fire() {
+// mHandle.set(CreateThing());
+// mWatcher.Watch(
+// mHandle.get(), NS_GetCurrentThread(), // (or any other thread)
+// NS_NewRunnableFunction("OnComplete", [this] { OnComplete(); }));
+// }
+//
+// ~MyClass() { mWatcher.Stop(); }
+//
+// HandleWatcher mWatcher;
+// HandlePtr mHandle; // calls ::CloseHandle() on destruction
+// };
+// ```
+//
+// Note: this example demonstrates why an explicit `Stop()` is necessary in
+// MyClass's destructor. Without it, the `HandlePtr` would destroy the HANDLE --
+// and possibly whatever other data `OnComplete()` depends on -- before the
+// watch was stopped!
+//
+// Rather than make code correctness silently dependent on member object order,
+// we require that HandleWatcher already be stopped at its destruction time.
+// (This does not guarantee correctness, as the task may still reference a
+// partially-destroyed transitive owner; but, short of RIIR, a guarantee of
+// correctness is probably not possible here.)
+//
+//////
+//
+// [1]https://learn.microsoft.com/en-us/windows/win32/sync/synchronization-objects
+class HandleWatcher {
+ public:
+ class Impl;
+
+ HandleWatcher();
+ ~HandleWatcher();
+
+ HandleWatcher(HandleWatcher const&) = delete;
+ HandleWatcher& operator=(HandleWatcher const&) = delete;
+
+ HandleWatcher(HandleWatcher&&) noexcept;
+ HandleWatcher& operator=(HandleWatcher&&) noexcept;
+
+ // Watches the given Win32 HANDLE, which must be a synchronization object. As
+ // soon as the HANDLE is signaled, posts `aRunnable` to `aTarget`.
+ //
+ // `aHandle` is merely borrowed for the duration of the watch: the
+ // HandleWatcher does not attempt to close it, and its lifetime must exceed
+ // that of the watch.
+ //
+ // If the watch is stopped for any reason other than completion, `aRunnable`
+ // is released immediately, on the same thread from which the Watch was
+ // stopped.
+ //
+ // The watch is stopped when any of the following occurs:
+ // * `Stop()` is called.
+ // * `Watch()` is called again, even without an intervening `Stop()`.
+ // * This object is destroyed.
+ // * `aTarget` shuts down.
+ // * `aHandle` becomes signaled.
+ //
+ void Watch(HANDLE aHandle, nsIEventTarget* aTarget,
+ already_AddRefed<nsIRunnable> aRunnable);
+
+ // Cancels the current watch, if any.
+ //
+ // Idempotent. Thread-safe with respect to other calls of `Stop()`.
+ void Stop();
+
+ // Potentially racy. Only intended for tests.
+ bool IsStopped();
+
+ private:
+ RefPtr<Impl> mImpl;
+};
+} // namespace mozilla
+
+#endif // WinHandleWatcher_h__