tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CrossProcessSemaphore_posix.cpp (3847B)


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