xref: /aosp_15_r20/external/cronet/base/task/thread_pool/semaphore/semaphore_posix.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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)29 struct 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)43 Semaphore::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()49 Semaphore::~Semaphore() {
50   int result = sem_destroy(&native_handle_);
51   CHECK_EQ(result, 0);
52 }
53 
Signal()54 void Semaphore::Signal() {
55   int result = sem_post(&native_handle_);
56   CHECK_EQ(result, 0);
57 }
58 
Wait()59 void 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)67 bool 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