Coverage Report

Created: 2018-09-25 14:53

/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