// Copyright 2024 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/synchronization/cancelable_event.h" #include #include #include #include "base/check.h" #include "base/dcheck_is_on.h" #include "base/logging.h" #include "base/notreached.h" #include "base/posix/eintr_wrapper.h" #include "base/time/time.h" namespace base { namespace { // Translates a base::TimeDelta (relative to now) to timespec containing // that position in time relative to unix epoch struct timespec TimeDeltaToAbsTimeSpec(base::TimeDelta time_delta) { struct timespec now; clock_gettime(CLOCK_REALTIME, &now); struct timespec offset = time_delta.ToTimeSpec(); now.tv_sec += offset.tv_sec; now.tv_nsec += offset.tv_nsec; if (now.tv_nsec >= Time::kNanosecondsPerSecond) { now.tv_sec++; now.tv_nsec -= Time::kNanosecondsPerSecond; } return now; } } // namespace CancelableEvent::CancelableEvent() { int result = sem_init(&native_handle_, 0, 0U); CHECK_EQ(result, 0); } CancelableEvent::~CancelableEvent() { int result = sem_destroy(&native_handle_); CHECK_EQ(result, 0); } void CancelableEvent::SignalImpl() { int result; #if DCHECK_IS_ON() int sem_value = 0; result = sem_getvalue(&native_handle_, &sem_value); CHECK_EQ(result, 0); DCHECK_EQ(sem_value, 0); #endif result = sem_post(&native_handle_); CHECK_EQ(result, 0); } bool CancelableEvent::CancelImpl() { int result = sem_trywait(&native_handle_); if (result == -1 && errno == EAGAIN) { return false; } if (result == 0) { return true; } PCHECK(false); } bool CancelableEvent::TimedWaitImpl(TimeDelta timeout) { int result; if (timeout.is_max()) { result = HANDLE_EINTR(sem_wait(&native_handle_)); } else { // Compute the time for the end of the timeout. const struct timespec ts = TimeDeltaToAbsTimeSpec(timeout); // Wait for semaphore to be signalled or to timeout. result = HANDLE_EINTR(sem_timedwait(&native_handle_, &ts)); } if (result == 0) { return true; // The semaphore was signalled. } if (result == -1 && errno == ETIMEDOUT) { // Timed out while waiting for semaphore. return false; } PCHECK(false); } } // namespace base