CrossProcessMutex_posix.cpp (3081B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "CrossProcessMutex.h" 8 #include "mozilla/ipc/SharedMemoryHandle.h" 9 #include "nsDebug.h" 10 #include "nsISupportsImpl.h" 11 12 namespace { 13 14 struct MutexData { 15 pthread_mutex_t mMutex; 16 mozilla::Atomic<int32_t> mCount; 17 }; 18 19 } // namespace 20 21 namespace mozilla { 22 23 static void InitMutex(pthread_mutex_t* mMutex) { 24 pthread_mutexattr_t mutexAttributes; 25 pthread_mutexattr_init(&mutexAttributes); 26 // Make the mutex reentrant so it behaves the same as a win32 mutex 27 if (pthread_mutexattr_settype(&mutexAttributes, PTHREAD_MUTEX_RECURSIVE)) { 28 MOZ_CRASH(); 29 } 30 if (pthread_mutexattr_setpshared(&mutexAttributes, PTHREAD_PROCESS_SHARED)) { 31 MOZ_CRASH(); 32 } 33 34 if (pthread_mutex_init(mMutex, &mutexAttributes)) { 35 MOZ_CRASH(); 36 } 37 } 38 39 CrossProcessMutex::CrossProcessMutex(const char*) 40 : mMutex(nullptr), mCount(nullptr) { 41 #if defined(MOZ_SANDBOX) 42 // POSIX mutexes in shared memory aren't guaranteed to be safe - and 43 // they specifically are not on Linux. 44 MOZ_RELEASE_ASSERT(false); 45 #endif 46 mSharedBuffer = ipc::shared_memory::Create(sizeof(MutexData)).MapWithHandle(); 47 if (!mSharedBuffer) { 48 MOZ_CRASH(); 49 } 50 51 MutexData* data = mSharedBuffer.DataAs<MutexData>(); 52 53 if (!data) { 54 MOZ_CRASH(); 55 } 56 57 mMutex = &(data->mMutex); 58 mCount = &(data->mCount); 59 60 *mCount = 1; 61 InitMutex(mMutex); 62 63 MOZ_COUNT_CTOR(CrossProcessMutex); 64 } 65 66 CrossProcessMutex::CrossProcessMutex(CrossProcessMutexHandle aHandle) 67 : mMutex(nullptr), mCount(nullptr) { 68 mSharedBuffer = std::move(aHandle).MapWithHandle(); 69 if (!mSharedBuffer) { 70 MOZ_CRASH(); 71 } 72 73 MutexData* data = mSharedBuffer.DataAs<MutexData>(); 74 75 if (!data) { 76 MOZ_CRASH(); 77 } 78 79 mMutex = &(data->mMutex); 80 mCount = &(data->mCount); 81 int32_t count = (*mCount)++; 82 83 if (count == 0) { 84 // The other side has already let go of their CrossProcessMutex, so now 85 // mMutex is garbage. We need to re-initialize it. 86 InitMutex(mMutex); 87 } 88 89 MOZ_COUNT_CTOR(CrossProcessMutex); 90 } 91 92 CrossProcessMutex::~CrossProcessMutex() { 93 int32_t count = --(*mCount); 94 95 if (count == 0) { 96 // Nothing can be done if the destroy fails so ignore return code. 97 (void)pthread_mutex_destroy(mMutex); 98 } 99 100 MOZ_COUNT_DTOR(CrossProcessMutex); 101 } 102 103 void CrossProcessMutex::Lock() { 104 MOZ_ASSERT(*mCount > 0, "Attempting to lock mutex with zero ref count"); 105 pthread_mutex_lock(mMutex); 106 } 107 108 void CrossProcessMutex::Unlock() { 109 MOZ_ASSERT(*mCount > 0, "Attempting to unlock mutex with zero ref count"); 110 pthread_mutex_unlock(mMutex); 111 } 112 113 CrossProcessMutexHandle CrossProcessMutex::CloneHandle() { 114 if (mSharedBuffer) { 115 auto handle = mSharedBuffer.Handle().Clone(); 116 if (!handle) { 117 MOZ_CRASH(); 118 } 119 return handle; 120 } 121 return nullptr; 122 } 123 124 } // namespace mozilla