Line data Source code
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/Unused.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
24 1 : InitMutex(pthread_mutex_t* mMutex)
25 : {
26 : pthread_mutexattr_t mutexAttributes;
27 1 : pthread_mutexattr_init(&mutexAttributes);
28 : // Make the mutex reentrant so it behaves the same as a win32 mutex
29 1 : if (pthread_mutexattr_settype(&mutexAttributes, PTHREAD_MUTEX_RECURSIVE)) {
30 0 : MOZ_CRASH();
31 : }
32 1 : if (pthread_mutexattr_setpshared(&mutexAttributes, PTHREAD_PROCESS_SHARED)) {
33 0 : MOZ_CRASH();
34 : }
35 :
36 1 : if (pthread_mutex_init(mMutex, &mutexAttributes)) {
37 0 : MOZ_CRASH();
38 : }
39 1 : }
40 :
41 1 : CrossProcessMutex::CrossProcessMutex(const char*)
42 : : mMutex(nullptr)
43 1 : , mCount(nullptr)
44 : {
45 1 : mSharedBuffer = new ipc::SharedMemoryBasic;
46 1 : if (!mSharedBuffer->Create(sizeof(MutexData))) {
47 0 : MOZ_CRASH();
48 : }
49 :
50 1 : if (!mSharedBuffer->Map(sizeof(MutexData))) {
51 0 : MOZ_CRASH();
52 : }
53 :
54 1 : MutexData* data = static_cast<MutexData*>(mSharedBuffer->memory());
55 :
56 1 : if (!data) {
57 0 : MOZ_CRASH();
58 : }
59 :
60 1 : mMutex = &(data->mMutex);
61 1 : mCount = &(data->mCount);
62 :
63 1 : *mCount = 1;
64 1 : InitMutex(mMutex);
65 :
66 1 : MOZ_COUNT_CTOR(CrossProcessMutex);
67 1 : }
68 :
69 2 : CrossProcessMutex::CrossProcessMutex(CrossProcessMutexHandle aHandle)
70 : : mMutex(nullptr)
71 2 : , mCount(nullptr)
72 : {
73 2 : mSharedBuffer = new ipc::SharedMemoryBasic;
74 :
75 2 : if (!mSharedBuffer->IsHandleValid(aHandle)) {
76 0 : MOZ_CRASH();
77 : }
78 :
79 2 : if (!mSharedBuffer->SetHandle(aHandle, ipc::SharedMemory::RightsReadWrite)) {
80 0 : MOZ_CRASH();
81 : }
82 :
83 2 : if (!mSharedBuffer->Map(sizeof(MutexData))) {
84 0 : MOZ_CRASH();
85 : }
86 :
87 2 : MutexData* data = static_cast<MutexData*>(mSharedBuffer->memory());
88 :
89 2 : if (!data) {
90 0 : MOZ_CRASH();
91 : }
92 :
93 2 : mMutex = &(data->mMutex);
94 2 : mCount = &(data->mCount);
95 2 : int32_t count = (*mCount)++;
96 :
97 2 : if (count == 0) {
98 : // The other side has already let go of their CrossProcessMutex, so now
99 : // mMutex is garbage. We need to re-initialize it.
100 0 : InitMutex(mMutex);
101 : }
102 :
103 2 : MOZ_COUNT_CTOR(CrossProcessMutex);
104 2 : }
105 :
106 0 : CrossProcessMutex::~CrossProcessMutex()
107 : {
108 0 : int32_t count = --(*mCount);
109 :
110 0 : if (count == 0) {
111 : // Nothing can be done if the destroy fails so ignore return code.
112 0 : Unused << pthread_mutex_destroy(mMutex);
113 : }
114 :
115 0 : MOZ_COUNT_DTOR(CrossProcessMutex);
116 0 : }
117 :
118 : void
119 3 : CrossProcessMutex::Lock()
120 : {
121 3 : MOZ_ASSERT(*mCount > 0, "Attempting to lock mutex with zero ref count");
122 3 : pthread_mutex_lock(mMutex);
123 3 : }
124 :
125 : void
126 0 : CrossProcessMutex::Unlock()
127 : {
128 0 : MOZ_ASSERT(*mCount > 0, "Attempting to unlock mutex with zero ref count");
129 0 : pthread_mutex_unlock(mMutex);
130 0 : }
131 :
132 : CrossProcessMutexHandle
133 2 : CrossProcessMutex::ShareToProcess(base::ProcessId aTargetPid)
134 : {
135 2 : CrossProcessMutexHandle result = ipc::SharedMemoryBasic::NULLHandle();
136 :
137 2 : if (mSharedBuffer && !mSharedBuffer->ShareToProcess(aTargetPid, &result)) {
138 0 : MOZ_CRASH();
139 : }
140 :
141 2 : return result;
142 : }
143 :
144 : } // namespace mozilla
|