diff options
Diffstat (limited to 'toolkit/mozapps/defaultagent/WindowsMutex.cpp')
-rw-r--r-- | toolkit/mozapps/defaultagent/WindowsMutex.cpp | 103 |
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 |