1 // Copyright 2023 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // This file is a clone of "v8/src/base/platform/semaphore.cc" in v8. 6 // Keep in sync, especially when fixing bugs. 7 8 // Copyright 2013 the V8 project authors. All rights reserved. 9 // Use of this source code is governed by a BSD-style license that can be 10 // found in the LICENSE file. 11 12 #include "base/task/thread_pool/semaphore.h" 13 14 #include <errno.h> 15 #include <semaphore.h> 16 17 #include "base/check.h" 18 #include "base/logging.h" 19 #include "base/notreached.h" 20 #include "base/posix/eintr_wrapper.h" 21 #include "base/time/time.h" 22 23 namespace base { 24 namespace internal { 25 26 namespace { 27 // Translates a base::TimeDelta (relative to now) to struct timedelta containing 28 // that position in time relative to unix epoch TimeDeltaToAbsTimeSpec(base::TimeDelta time_delta)29struct timespec TimeDeltaToAbsTimeSpec(base::TimeDelta time_delta) { 30 struct timespec now; 31 clock_gettime(CLOCK_REALTIME, &now); 32 struct timespec offset = time_delta.ToTimeSpec(); 33 now.tv_sec += offset.tv_sec; 34 now.tv_nsec += offset.tv_nsec; 35 if (now.tv_nsec >= Time::kNanosecondsPerSecond) { 36 now.tv_sec++; 37 now.tv_nsec -= Time::kNanosecondsPerSecond; 38 } 39 return now; 40 } 41 } // namespace 42 Semaphore(int count)43Semaphore::Semaphore(int count) { 44 CHECK_GE(count, 0); 45 int result = sem_init(&native_handle_, 0, static_cast<unsigned int>(count)); 46 CHECK_EQ(result, 0); 47 } 48 ~Semaphore()49Semaphore::~Semaphore() { 50 int result = sem_destroy(&native_handle_); 51 CHECK_EQ(result, 0); 52 } 53 Signal()54void Semaphore::Signal() { 55 int result = sem_post(&native_handle_); 56 CHECK_EQ(result, 0); 57 } 58 Wait()59void Semaphore::Wait() { 60 int result = HANDLE_EINTR(sem_wait(&native_handle_)); 61 if (result == 0) { 62 return; // Semaphore was signalled. 63 } 64 PCHECK(false); 65 } 66 TimedWait(TimeDelta timeout)67bool Semaphore::TimedWait(TimeDelta timeout) { 68 // Compute the time for end of timeout. 69 const struct timespec ts = TimeDeltaToAbsTimeSpec(timeout); 70 71 // Wait for semaphore signalled or timeout. 72 int result = HANDLE_EINTR(sem_timedwait(&native_handle_, &ts)); 73 if (result == 0) { 74 return true; // Semaphore was signalled. 75 } 76 if (result == -1 && errno == ETIMEDOUT) { 77 // Timed out while waiting for semaphore. 78 return false; 79 } 80 PCHECK(false); 81 return false; 82 } 83 84 } // namespace internal 85 } // namespace base 86