summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/defaultagent/WindowsMutex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/defaultagent/WindowsMutex.cpp')
-rw-r--r--toolkit/mozapps/defaultagent/WindowsMutex.cpp103
1 files changed, 103 insertions, 0 deletions
diff --git a/toolkit/mozapps/defaultagent/WindowsMutex.cpp b/toolkit/mozapps/defaultagent/WindowsMutex.cpp
new file mode 100644
index 0000000000..804c3e6d75
--- /dev/null
+++ b/toolkit/mozapps/defaultagent/WindowsMutex.cpp
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+#include "mozilla/Logging.h"
+
+#include "WindowsMutex.h"
+
+namespace mozilla::default_agent {
+
+using mozilla::LogLevel;
+
+static LazyLogModule gWindowsMutexLog("WindowsMutex");
+
+NS_IMPL_ISUPPORTS(WindowsMutexFactory, nsIWindowsMutexFactory)
+
+NS_IMETHODIMP
+WindowsMutexFactory::CreateMutex(const nsAString& aName,
+ nsIWindowsMutex** aWindowsMutex) {
+ nsAutoHandle mutex;
+ auto name = PromiseFlatString(aName);
+
+ mutex.own(CreateMutexW(nullptr, FALSE, name.get()));
+ if (mutex.get() == nullptr) {
+ MOZ_LOG(gWindowsMutexLog, LogLevel::Error,
+ ("Couldn't open mutex \"%s\": %#lX",
+ NS_ConvertUTF16toUTF8(name).get(), GetLastError()));
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ RefPtr<WindowsMutex> nsMutex = new WindowsMutex(name, mutex);
+ nsMutex.forget(aWindowsMutex);
+ return NS_OK;
+}
+
+WindowsMutex::WindowsMutex(const nsString& aName, nsAutoHandle& aMutex)
+ : mName(NS_ConvertUTF16toUTF8(aName)), mLocked(false) {
+ mMutex.steal(aMutex);
+}
+
+WindowsMutex::~WindowsMutex() {
+ Unlock();
+ // nsAutoHandle will take care of closing the mutex's handle.
+}
+
+NS_IMPL_ISUPPORTS(WindowsMutex, nsIWindowsMutex)
+
+NS_IMETHODIMP
+WindowsMutex::TryLock() {
+ // This object may be used on the main thread, so don't wait if it's
+ // not signaled.
+ DWORD mutexStatus = WaitForSingleObject(mMutex.get(), 0);
+ if (mutexStatus == WAIT_OBJECT_0) {
+ mLocked = true;
+ } else if (mutexStatus == WAIT_TIMEOUT) {
+ MOZ_LOG(gWindowsMutexLog, LogLevel::Warning,
+ ("Timed out waiting for mutex \"%s\"", mName.get()));
+ } else if (mutexStatus == WAIT_ABANDONED) {
+ // This status code means that we are supposed to check our data for
+ // consistency as the last locking process didn't signal intentional
+ // unlocking which might indicate it crashed mid-operation. Current uses of
+ // this `WindowsMutex` don't need to worry about corruption of the locked
+ // object, if needed the `nsIWindowsMutex` interface should be extended.
+ MOZ_LOG(gWindowsMutexLog, LogLevel::Warning,
+ ("Found abandoned mutex \"%s\". Continuing...", mName.get()));
+ mLocked = true;
+ } else {
+ // The only other documented status code is WAIT_FAILED. In the case that
+ // we somehow get some other code, that is also an error.
+ MOZ_LOG(gWindowsMutexLog, LogLevel::Error,
+ ("Failed to wait on mutex: mName: %s, error %#lX", mName.get(),
+ GetLastError()));
+ }
+ return mLocked ? NS_OK : NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+WindowsMutex::IsLocked(bool* aLocked) {
+ *aLocked = mLocked;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WindowsMutex::Unlock() {
+ nsresult rv = NS_OK;
+
+ if (mLocked) {
+ BOOL success = ReleaseMutex(mMutex.get());
+ if (!success) {
+ MOZ_LOG(gWindowsMutexLog, LogLevel::Error,
+ ("Failed to release mutex \"%s\"", mName.get()));
+ rv = NS_ERROR_UNEXPECTED;
+ }
+
+ mLocked = false;
+ }
+
+ return rv;
+}
+
+} // namespace mozilla::default_agent