• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 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 #include "base/synchronization/cancelable_event.h"
6 
7 #include <errno.h>
8 #include <semaphore.h>
9 
10 #include <tuple>
11 
12 #include "base/check.h"
13 #include "base/dcheck_is_on.h"
14 #include "base/logging.h"
15 #include "base/notreached.h"
16 #include "base/posix/eintr_wrapper.h"
17 #include "base/time/time.h"
18 
19 namespace base {
20 
21 namespace {
22 // Translates a base::TimeDelta (relative to now) to timespec containing
23 // that position in time relative to unix epoch
TimeDeltaToAbsTimeSpec(base::TimeDelta time_delta)24 struct timespec TimeDeltaToAbsTimeSpec(base::TimeDelta time_delta) {
25   struct timespec now;
26   clock_gettime(CLOCK_REALTIME, &now);
27   struct timespec offset = time_delta.ToTimeSpec();
28   now.tv_sec += offset.tv_sec;
29   now.tv_nsec += offset.tv_nsec;
30   if (now.tv_nsec >= Time::kNanosecondsPerSecond) {
31     now.tv_sec++;
32     now.tv_nsec -= Time::kNanosecondsPerSecond;
33   }
34   return now;
35 }
36 }  // namespace
37 
CancelableEvent()38 CancelableEvent::CancelableEvent() {
39   int result = sem_init(&native_handle_, 0, 0U);
40   CHECK_EQ(result, 0);
41 }
42 
~CancelableEvent()43 CancelableEvent::~CancelableEvent() {
44   int result = sem_destroy(&native_handle_);
45   CHECK_EQ(result, 0);
46 }
47 
SignalImpl()48 void CancelableEvent::SignalImpl() {
49   int result;
50 #if DCHECK_IS_ON()
51   int sem_value = 0;
52   result = sem_getvalue(&native_handle_, &sem_value);
53   CHECK_EQ(result, 0);
54   DCHECK_EQ(sem_value, 0);
55 #endif
56   result = sem_post(&native_handle_);
57   CHECK_EQ(result, 0);
58 }
59 
CancelImpl()60 bool CancelableEvent::CancelImpl() {
61   int result = sem_trywait(&native_handle_);
62   if (result == -1 && errno == EAGAIN) {
63     return false;
64   }
65   if (result == 0) {
66     return true;
67   }
68 
69   PCHECK(false);
70 }
71 
TimedWaitImpl(TimeDelta timeout)72 bool CancelableEvent::TimedWaitImpl(TimeDelta timeout) {
73   int result;
74   if (timeout.is_max()) {
75     result = HANDLE_EINTR(sem_wait(&native_handle_));
76   } else {
77     // Compute the time for the end of the timeout.
78     const struct timespec ts = TimeDeltaToAbsTimeSpec(timeout);
79 
80     // Wait for semaphore to be signalled or to timeout.
81     result = HANDLE_EINTR(sem_timedwait(&native_handle_, &ts));
82   }
83   if (result == 0) {
84     return true;  // The semaphore was signalled.
85   }
86   if (result == -1 && errno == ETIMEDOUT) {
87     // Timed out while waiting for semaphore.
88     return false;
89   }
90   PCHECK(false);
91 }
92 
93 }  // namespace base
94