/src/mozilla-central/ipc/glue/CrossProcessSemaphore_posix.cpp
Line | Count | Source (jump to first uncovered line) |
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 "CrossProcessSemaphore.h" |
8 | | #include "mozilla/Unused.h" |
9 | | #include "nsDebug.h" |
10 | | #include "nsISupportsImpl.h" |
11 | | #include <errno.h> |
12 | | |
13 | | static const uint64_t kNsPerMs = 1000000; |
14 | | static const uint64_t kNsPerSec = 1000000000; |
15 | | |
16 | | namespace { |
17 | | |
18 | | |
19 | | struct SemaphoreData { |
20 | | sem_t mSemaphore; |
21 | | mozilla::Atomic<int32_t> mRefCount; |
22 | | uint32_t mInitialValue; |
23 | | }; |
24 | | |
25 | | } // namespace |
26 | | |
27 | | namespace mozilla { |
28 | | |
29 | | /* static */ CrossProcessSemaphore* |
30 | | CrossProcessSemaphore::Create(const char*, uint32_t aInitialValue) |
31 | 0 | { |
32 | 0 | RefPtr<ipc::SharedMemoryBasic> sharedBuffer = new ipc::SharedMemoryBasic; |
33 | 0 | if (!sharedBuffer->Create(sizeof(SemaphoreData))) { |
34 | 0 | return nullptr; |
35 | 0 | } |
36 | 0 | |
37 | 0 | if (!sharedBuffer->Map(sizeof(SemaphoreData))) { |
38 | 0 | return nullptr; |
39 | 0 | } |
40 | 0 | |
41 | 0 | SemaphoreData* data = static_cast<SemaphoreData*>(sharedBuffer->memory()); |
42 | 0 |
|
43 | 0 | if (!data) { |
44 | 0 | return nullptr; |
45 | 0 | } |
46 | 0 | |
47 | 0 | if (sem_init(&data->mSemaphore, 1, aInitialValue)) { |
48 | 0 | return nullptr; |
49 | 0 | } |
50 | 0 | |
51 | 0 | CrossProcessSemaphore* sem = new CrossProcessSemaphore; |
52 | 0 | sem->mSharedBuffer = sharedBuffer; |
53 | 0 | sem->mSemaphore = &data->mSemaphore; |
54 | 0 | sem->mRefCount = &data->mRefCount; |
55 | 0 | *sem->mRefCount = 1; |
56 | 0 |
|
57 | 0 | data->mInitialValue = aInitialValue; |
58 | 0 |
|
59 | 0 | return sem; |
60 | 0 | } |
61 | | |
62 | | /* static */ CrossProcessSemaphore* |
63 | | CrossProcessSemaphore::Create(CrossProcessSemaphoreHandle aHandle) |
64 | 0 | { |
65 | 0 | RefPtr<ipc::SharedMemoryBasic> sharedBuffer = new ipc::SharedMemoryBasic; |
66 | 0 |
|
67 | 0 | if (!sharedBuffer->IsHandleValid(aHandle)) { |
68 | 0 | return nullptr; |
69 | 0 | } |
70 | 0 | |
71 | 0 | if (!sharedBuffer->SetHandle(aHandle, ipc::SharedMemory::RightsReadWrite)) { |
72 | 0 | return nullptr; |
73 | 0 | } |
74 | 0 | |
75 | 0 | if (!sharedBuffer->Map(sizeof(SemaphoreData))) { |
76 | 0 | return nullptr; |
77 | 0 | } |
78 | 0 | |
79 | 0 | sharedBuffer->CloseHandle(); |
80 | 0 |
|
81 | 0 | SemaphoreData* data = static_cast<SemaphoreData*>(sharedBuffer->memory()); |
82 | 0 |
|
83 | 0 | if (!data) { |
84 | 0 | return nullptr; |
85 | 0 | } |
86 | 0 | |
87 | 0 | int32_t oldCount = data->mRefCount++; |
88 | 0 | if (oldCount == 0) { |
89 | 0 | // The other side has already let go of their CrossProcessSemaphore, so now |
90 | 0 | // mSemaphore is garbage. We need to re-initialize it. |
91 | 0 | if (sem_init(&data->mSemaphore, 1, data->mInitialValue)) { |
92 | 0 | data->mRefCount--; |
93 | 0 | return nullptr; |
94 | 0 | } |
95 | 0 | } |
96 | 0 | |
97 | 0 | CrossProcessSemaphore* sem = new CrossProcessSemaphore; |
98 | 0 | sem->mSharedBuffer = sharedBuffer; |
99 | 0 | sem->mSemaphore = &data->mSemaphore; |
100 | 0 | sem->mRefCount = &data->mRefCount; |
101 | 0 | return sem; |
102 | 0 | } |
103 | | |
104 | | |
105 | | CrossProcessSemaphore::CrossProcessSemaphore() |
106 | | : mSemaphore(nullptr) |
107 | | , mRefCount(nullptr) |
108 | 0 | { |
109 | 0 | MOZ_COUNT_CTOR(CrossProcessSemaphore); |
110 | 0 | } |
111 | | |
112 | | CrossProcessSemaphore::~CrossProcessSemaphore() |
113 | 0 | { |
114 | 0 | int32_t oldCount = --(*mRefCount); |
115 | 0 |
|
116 | 0 | if (oldCount == 0) { |
117 | 0 | // Nothing can be done if the destroy fails so ignore return code. |
118 | 0 | Unused << sem_destroy(mSemaphore); |
119 | 0 | } |
120 | 0 |
|
121 | 0 | MOZ_COUNT_DTOR(CrossProcessSemaphore); |
122 | 0 | } |
123 | | |
124 | | bool |
125 | | CrossProcessSemaphore::Wait(const Maybe<TimeDuration>& aWaitTime) |
126 | 0 | { |
127 | 0 | MOZ_ASSERT(*mRefCount > 0, "Attempting to wait on a semaphore with zero ref count"); |
128 | 0 | int ret; |
129 | 0 | if (aWaitTime.isSome()) { |
130 | 0 | struct timespec ts; |
131 | 0 | if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { |
132 | 0 | return false; |
133 | 0 | } |
134 | 0 | |
135 | 0 | ts.tv_nsec += (kNsPerMs * aWaitTime->ToMilliseconds()); |
136 | 0 | ts.tv_sec += ts.tv_nsec / kNsPerSec; |
137 | 0 | ts.tv_nsec %= kNsPerSec; |
138 | 0 |
|
139 | 0 | while ((ret = sem_timedwait(mSemaphore, &ts)) == -1 && errno == EINTR) { |
140 | 0 | } |
141 | 0 | } else { |
142 | 0 | while ((ret = sem_wait(mSemaphore)) == -1 && errno == EINTR) { |
143 | 0 | } |
144 | 0 | } |
145 | 0 | return ret == 0; |
146 | 0 | } |
147 | | |
148 | | void |
149 | | CrossProcessSemaphore::Signal() |
150 | 0 | { |
151 | 0 | MOZ_ASSERT(*mRefCount > 0, "Attempting to signal a semaphore with zero ref count"); |
152 | 0 | sem_post(mSemaphore); |
153 | 0 | } |
154 | | |
155 | | CrossProcessSemaphoreHandle |
156 | | CrossProcessSemaphore::ShareToProcess(base::ProcessId aTargetPid) |
157 | 0 | { |
158 | 0 | CrossProcessSemaphoreHandle result = ipc::SharedMemoryBasic::NULLHandle(); |
159 | 0 |
|
160 | 0 | if (mSharedBuffer && !mSharedBuffer->ShareToProcess(aTargetPid, &result)) { |
161 | 0 | MOZ_CRASH(); |
162 | 0 | } |
163 | 0 |
|
164 | 0 | return result; |
165 | 0 | } |
166 | | |
167 | | void |
168 | | CrossProcessSemaphore::CloseHandle() |
169 | 0 | { |
170 | 0 | mSharedBuffer->CloseHandle(); |
171 | 0 | } |
172 | | |
173 | | } // namespace mozilla |