summaryrefslogtreecommitdiffstats
path: root/ipc/glue/CrossProcessMutex_posix.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/glue/CrossProcessMutex_posix.cpp')
-rw-r--r--ipc/glue/CrossProcessMutex_posix.cpp140
1 files changed, 140 insertions, 0 deletions
diff --git a/ipc/glue/CrossProcessMutex_posix.cpp b/ipc/glue/CrossProcessMutex_posix.cpp
new file mode 100644
index 0000000000..c37fcb797d
--- /dev/null
+++ b/ipc/glue/CrossProcessMutex_posix.cpp
@@ -0,0 +1,140 @@
+/* -*- 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/. */
+
+#include "CrossProcessMutex.h"
+#include "mozilla/Unused.h"
+#include "nsDebug.h"
+#include "nsISupportsImpl.h"
+
+namespace {
+
+struct MutexData {
+ pthread_mutex_t mMutex;
+ mozilla::Atomic<int32_t> mCount;
+};
+
+} // namespace
+
+namespace mozilla {
+
+static void InitMutex(pthread_mutex_t* mMutex) {
+ pthread_mutexattr_t mutexAttributes;
+ pthread_mutexattr_init(&mutexAttributes);
+ // Make the mutex reentrant so it behaves the same as a win32 mutex
+ if (pthread_mutexattr_settype(&mutexAttributes, PTHREAD_MUTEX_RECURSIVE)) {
+ MOZ_CRASH();
+ }
+ if (pthread_mutexattr_setpshared(&mutexAttributes, PTHREAD_PROCESS_SHARED)) {
+ MOZ_CRASH();
+ }
+
+ if (pthread_mutex_init(mMutex, &mutexAttributes)) {
+ MOZ_CRASH();
+ }
+}
+
+CrossProcessMutex::CrossProcessMutex(const char*)
+ : mMutex(nullptr), mCount(nullptr) {
+#if defined(MOZ_SANDBOX)
+ // POSIX mutexes in shared memory aren't guaranteed to be safe - and
+ // they specifically are not on Linux.
+ MOZ_RELEASE_ASSERT(false);
+#endif
+ mSharedBuffer = new ipc::SharedMemoryBasic;
+ if (!mSharedBuffer->Create(sizeof(MutexData))) {
+ MOZ_CRASH();
+ }
+
+ if (!mSharedBuffer->Map(sizeof(MutexData))) {
+ MOZ_CRASH();
+ }
+
+ MutexData* data = static_cast<MutexData*>(mSharedBuffer->memory());
+
+ if (!data) {
+ MOZ_CRASH();
+ }
+
+ mMutex = &(data->mMutex);
+ mCount = &(data->mCount);
+
+ *mCount = 1;
+ InitMutex(mMutex);
+
+ MOZ_COUNT_CTOR(CrossProcessMutex);
+}
+
+CrossProcessMutex::CrossProcessMutex(CrossProcessMutexHandle aHandle)
+ : mMutex(nullptr), mCount(nullptr) {
+ mSharedBuffer = new ipc::SharedMemoryBasic;
+
+ if (!mSharedBuffer->IsHandleValid(aHandle)) {
+ MOZ_CRASH();
+ }
+
+ if (!mSharedBuffer->SetHandle(std::move(aHandle),
+ ipc::SharedMemory::RightsReadWrite)) {
+ MOZ_CRASH();
+ }
+
+ if (!mSharedBuffer->Map(sizeof(MutexData))) {
+ MOZ_CRASH();
+ }
+
+ MutexData* data = static_cast<MutexData*>(mSharedBuffer->memory());
+
+ if (!data) {
+ MOZ_CRASH();
+ }
+
+ mMutex = &(data->mMutex);
+ mCount = &(data->mCount);
+ int32_t count = (*mCount)++;
+
+ if (count == 0) {
+ // The other side has already let go of their CrossProcessMutex, so now
+ // mMutex is garbage. We need to re-initialize it.
+ InitMutex(mMutex);
+ }
+
+ MOZ_COUNT_CTOR(CrossProcessMutex);
+}
+
+CrossProcessMutex::~CrossProcessMutex() {
+ int32_t count = --(*mCount);
+
+ if (count == 0) {
+ // Nothing can be done if the destroy fails so ignore return code.
+ Unused << pthread_mutex_destroy(mMutex);
+ }
+
+ MOZ_COUNT_DTOR(CrossProcessMutex);
+}
+
+void CrossProcessMutex::Lock() {
+ MOZ_ASSERT(*mCount > 0, "Attempting to lock mutex with zero ref count");
+ pthread_mutex_lock(mMutex);
+}
+
+void CrossProcessMutex::Unlock() {
+ MOZ_ASSERT(*mCount > 0, "Attempting to unlock mutex with zero ref count");
+ pthread_mutex_unlock(mMutex);
+}
+
+CrossProcessMutexHandle CrossProcessMutex::CloneHandle() {
+ CrossProcessMutexHandle result = ipc::SharedMemoryBasic::NULLHandle();
+
+ if (mSharedBuffer) {
+ result = mSharedBuffer->CloneHandle();
+ if (!result) {
+ MOZ_CRASH();
+ }
+ }
+
+ return result;
+}
+
+} // namespace mozilla