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/. */
7 #include "CrossProcessSemaphore.h"
8 #include "mozilla/Unused.h"
10 #include "nsISupportsImpl.h"
13 static const uint64_t kNsPerMs
= 1000000;
14 static const uint64_t kNsPerSec
= 1000000000;
18 struct SemaphoreData
{
20 mozilla::Atomic
<int32_t> mRefCount
;
21 uint32_t mInitialValue
;
29 CrossProcessSemaphore
* CrossProcessSemaphore::Create(const char*,
30 uint32_t aInitialValue
) {
31 RefPtr
<ipc::SharedMemoryBasic
> sharedBuffer
= new ipc::SharedMemoryBasic
;
32 if (!sharedBuffer
->Create(sizeof(SemaphoreData
))) {
36 if (!sharedBuffer
->Map(sizeof(SemaphoreData
))) {
40 SemaphoreData
* data
= static_cast<SemaphoreData
*>(sharedBuffer
->memory());
46 if (sem_init(&data
->mSemaphore
, 1, aInitialValue
)) {
50 CrossProcessSemaphore
* sem
= new CrossProcessSemaphore
;
51 sem
->mSharedBuffer
= sharedBuffer
;
52 sem
->mSemaphore
= &data
->mSemaphore
;
53 sem
->mRefCount
= &data
->mRefCount
;
56 data
->mInitialValue
= aInitialValue
;
62 CrossProcessSemaphore
* CrossProcessSemaphore::Create(
63 CrossProcessSemaphoreHandle aHandle
) {
64 RefPtr
<ipc::SharedMemoryBasic
> sharedBuffer
= new ipc::SharedMemoryBasic
;
66 if (!sharedBuffer
->IsHandleValid(aHandle
)) {
70 if (!sharedBuffer
->SetHandle(std::move(aHandle
),
71 ipc::SharedMemory::RightsReadWrite
)) {
75 if (!sharedBuffer
->Map(sizeof(SemaphoreData
))) {
79 sharedBuffer
->CloseHandle();
81 SemaphoreData
* data
= static_cast<SemaphoreData
*>(sharedBuffer
->memory());
87 int32_t oldCount
= data
->mRefCount
++;
89 // The other side has already let go of their CrossProcessSemaphore, so now
90 // mSemaphore is garbage. We need to re-initialize it.
91 if (sem_init(&data
->mSemaphore
, 1, data
->mInitialValue
)) {
97 CrossProcessSemaphore
* sem
= new CrossProcessSemaphore
;
98 sem
->mSharedBuffer
= sharedBuffer
;
99 sem
->mSemaphore
= &data
->mSemaphore
;
100 sem
->mRefCount
= &data
->mRefCount
;
104 CrossProcessSemaphore::CrossProcessSemaphore()
105 : mSemaphore(nullptr), mRefCount(nullptr) {
106 MOZ_COUNT_CTOR(CrossProcessSemaphore
);
109 CrossProcessSemaphore::~CrossProcessSemaphore() {
110 int32_t oldCount
= --(*mRefCount
);
113 // Nothing can be done if the destroy fails so ignore return code.
114 Unused
<< sem_destroy(mSemaphore
);
117 MOZ_COUNT_DTOR(CrossProcessSemaphore
);
120 bool CrossProcessSemaphore::Wait(const Maybe
<TimeDuration
>& aWaitTime
) {
121 MOZ_ASSERT(*mRefCount
> 0,
122 "Attempting to wait on a semaphore with zero ref count");
124 if (aWaitTime
.isSome()) {
126 if (clock_gettime(CLOCK_REALTIME
, &ts
) == -1) {
130 ts
.tv_nsec
+= (kNsPerMs
* aWaitTime
->ToMilliseconds());
131 ts
.tv_sec
+= ts
.tv_nsec
/ kNsPerSec
;
132 ts
.tv_nsec
%= kNsPerSec
;
134 while ((ret
= sem_timedwait(mSemaphore
, &ts
)) == -1 && errno
== EINTR
) {
137 while ((ret
= sem_wait(mSemaphore
)) == -1 && errno
== EINTR
) {
143 void CrossProcessSemaphore::Signal() {
144 MOZ_ASSERT(*mRefCount
> 0,
145 "Attempting to signal a semaphore with zero ref count");
146 sem_post(mSemaphore
);
149 CrossProcessSemaphoreHandle
CrossProcessSemaphore::CloneHandle() {
150 CrossProcessSemaphoreHandle result
= ipc::SharedMemoryBasic::NULLHandle();
153 result
= mSharedBuffer
->CloneHandle();
162 void CrossProcessSemaphore::CloseHandle() { mSharedBuffer
->CloseHandle(); }
164 } // namespace mozilla