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 if (timeout.is_max()) { 69 Wait(); 70 return true; 71 } 72 73 // Compute the time for end of timeout. 74 const struct timespec ts = TimeDeltaToAbsTimeSpec(timeout); 75 76 // Wait for semaphore signalled or timeout. 77 int result = HANDLE_EINTR(sem_timedwait(&native_handle_, &ts)); 78 if (result == 0) { 79 return true; // Semaphore was signalled. 80 } 81 if (result == -1 && errno == ETIMEDOUT) { 82 // Timed out while waiting for semaphore. 83 return false; 84 } 85 PCHECK(false); 86 return false; 87 } 88 89 } // namespace internal 90 } // namespace base 91