CrossProcessSemaphore_mach.cpp (3011B)
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 <mach/mach_time.h> 11 12 static const uint64_t kNsPerUs = 1000; 13 static const uint64_t kNsPerSec = 1000000000; 14 15 namespace mozilla { 16 17 /* static */ 18 CrossProcessSemaphore* CrossProcessSemaphore::Create(const char*, 19 uint32_t aInitialValue) { 20 semaphore_t sem = SEMAPHORE_NULL; 21 if (semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, 22 aInitialValue) == KERN_SUCCESS && 23 sem != SEMAPHORE_NULL) { 24 return new CrossProcessSemaphore(CrossProcessSemaphoreHandle(sem)); 25 } 26 return nullptr; 27 } 28 29 /* static */ 30 CrossProcessSemaphore* CrossProcessSemaphore::Create( 31 CrossProcessSemaphoreHandle aHandle) { 32 if (!aHandle) { 33 return nullptr; 34 } 35 return new CrossProcessSemaphore(std::move(aHandle)); 36 } 37 38 CrossProcessSemaphore::CrossProcessSemaphore( 39 CrossProcessSemaphoreHandle aSemaphore) 40 : mSemaphore(std::move(aSemaphore)) { 41 MOZ_COUNT_CTOR(CrossProcessSemaphore); 42 } 43 44 CrossProcessSemaphore::~CrossProcessSemaphore() { 45 MOZ_ASSERT(mSemaphore, "Improper construction of semaphore or double free."); 46 MOZ_COUNT_DTOR(CrossProcessSemaphore); 47 } 48 49 bool CrossProcessSemaphore::Wait(const Maybe<TimeDuration>& aWaitTime) { 50 MOZ_ASSERT(mSemaphore, "Improper construction of semaphore."); 51 int kr = KERN_OPERATION_TIMED_OUT; 52 // semaphore_(timed)wait may be interrupted by KERN_ABORTED. Carefully restart 53 // the wait until it either succeeds or times out. 54 if (aWaitTime.isNothing()) { 55 do { 56 kr = semaphore_wait(mSemaphore.get()); 57 } while (kr == KERN_ABORTED); 58 } else { 59 mach_timebase_info_data_t tb; 60 if (mach_timebase_info(&tb) != KERN_SUCCESS) { 61 return false; 62 } 63 uint64_t now = (mach_absolute_time() * tb.numer) / tb.denom; 64 uint64_t deadline = now + uint64_t(kNsPerUs * aWaitTime->ToMicroseconds()); 65 while (now <= deadline) { 66 uint64_t ns = deadline - now; 67 mach_timespec_t ts; 68 ts.tv_sec = ns / kNsPerSec; 69 ts.tv_nsec = ns % kNsPerSec; 70 kr = semaphore_timedwait(mSemaphore.get(), ts); 71 if (kr != KERN_ABORTED) { 72 break; 73 } 74 now = (mach_absolute_time() * tb.numer) / tb.denom; 75 } 76 } 77 return kr == KERN_SUCCESS; 78 } 79 80 void CrossProcessSemaphore::Signal() { 81 MOZ_ASSERT(mSemaphore, "Improper construction of semaphore."); 82 semaphore_signal(mSemaphore.get()); 83 } 84 85 CrossProcessSemaphoreHandle CrossProcessSemaphore::CloneHandle() { 86 // Transfer the mach port backing the semaphore. 87 return mozilla::RetainMachSendRight(mSemaphore.get()); 88 } 89 90 void CrossProcessSemaphore::CloseHandle() {} 91 92 } // namespace mozilla