xref: /aosp_15_r20/system/core/libutils/include/utils/Condition.h (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1  /*
2   * Copyright (C) 2007 The Android Open Source Project
3   *
4   * Licensed under the Apache License, Version 2.0 (the "License");
5   * you may not use this file except in compliance with the License.
6   * You may obtain a copy of the License at
7   *
8   *      http://www.apache.org/licenses/LICENSE-2.0
9   *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  #ifndef _LIBS_UTILS_CONDITION_H
18  #define _LIBS_UTILS_CONDITION_H
19  
20  #include <limits.h>
21  #include <stdint.h>
22  #include <sys/types.h>
23  #include <time.h>
24  
25  #if !defined(_WIN32)
26  # include <pthread.h>
27  #endif
28  
29  #include <utils/Errors.h>
30  #include <utils/Mutex.h>
31  #include <utils/Timers.h>
32  
33  // ---------------------------------------------------------------------------
34  namespace android {
35  // ---------------------------------------------------------------------------
36  
37  // DO NOT USE: please use std::condition_variable instead.
38  
39  /*
40   * Condition variable class.  The implementation is system-dependent.
41   *
42   * Condition variables are paired up with mutexes.  Lock the mutex,
43   * call wait(), then either re-wait() if things aren't quite what you want,
44   * or unlock the mutex and continue.  All threads calling wait() must
45   * use the same mutex for a given Condition.
46   *
47   * On Android and Apple platforms, these are implemented as a simple wrapper
48   * around pthread condition variables.  Care must be taken to abide by
49   * the pthreads semantics, in particular, a boolean predicate must
50   * be re-evaluated after a wake-up, as spurious wake-ups may happen.
51   */
52  class Condition {
53  public:
54      enum {
55          PRIVATE = 0,
56          SHARED = 1
57      };
58  
59      enum WakeUpType {
60          WAKE_UP_ONE = 0,
61          WAKE_UP_ALL = 1
62      };
63  
64      Condition();
65      explicit Condition(int type);
66      ~Condition();
67      // Wait on the condition variable.  Lock the mutex before calling.
68      // Note that spurious wake-ups may happen.
69      status_t wait(Mutex& mutex);
70      // same with relative timeout
71      status_t waitRelative(Mutex& mutex, nsecs_t reltime);
72      // Signal the condition variable, allowing one thread to continue.
73      void signal();
74      // Signal the condition variable, allowing one or all threads to continue.
signal(WakeUpType type)75      void signal(WakeUpType type) {
76          if (type == WAKE_UP_ONE) {
77              signal();
78          } else {
79              broadcast();
80          }
81      }
82      // Signal the condition variable, allowing all threads to continue.
83      void broadcast();
84  
85  private:
86  #if !defined(_WIN32)
87      pthread_cond_t mCond;
88  #else
89      void*   mState;
90  #endif
91  };
92  
93  // ---------------------------------------------------------------------------
94  
95  #if !defined(_WIN32)
96  
Condition()97  inline Condition::Condition() : Condition(PRIVATE) {
98  }
Condition(int type)99  inline Condition::Condition(int type) {
100      pthread_condattr_t attr;
101      pthread_condattr_init(&attr);
102  #if defined(__linux__)
103      pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
104  #endif
105  
106      if (type == SHARED) {
107          pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
108      }
109  
110      pthread_cond_init(&mCond, &attr);
111      pthread_condattr_destroy(&attr);
112  
113  }
~Condition()114  inline Condition::~Condition() {
115      pthread_cond_destroy(&mCond);
116  }
wait(Mutex & mutex)117  inline status_t Condition::wait(Mutex& mutex) {
118      return -pthread_cond_wait(&mCond, &mutex.mMutex);
119  }
waitRelative(Mutex & mutex,nsecs_t reltime)120  inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
121      struct timespec ts;
122  #if defined(__linux__)
123      clock_gettime(CLOCK_MONOTONIC, &ts);
124  #else // __APPLE__
125      // Apple doesn't support POSIX clocks.
126      struct timeval t;
127      gettimeofday(&t, nullptr);
128      ts.tv_sec = t.tv_sec;
129      ts.tv_nsec = t.tv_usec*1000;
130  #endif
131  
132      // On 32-bit devices, tv_sec is 32-bit, but `reltime` is 64-bit.
133      int64_t reltime_sec = reltime/1000000000;
134  
135      ts.tv_nsec += static_cast<long>(reltime%1000000000);
136      if (reltime_sec < INT64_MAX && ts.tv_nsec >= 1000000000) {
137          ts.tv_nsec -= 1000000000;
138          ++reltime_sec;
139      }
140  
141      int64_t time_sec = ts.tv_sec;
142      if (time_sec > INT64_MAX - reltime_sec) {
143          time_sec = INT64_MAX;
144      } else {
145          time_sec += reltime_sec;
146      }
147  
148      ts.tv_sec = (time_sec > LONG_MAX) ? LONG_MAX : static_cast<long>(time_sec);
149  
150      return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
151  }
signal()152  inline void Condition::signal() {
153      pthread_cond_signal(&mCond);
154  }
broadcast()155  inline void Condition::broadcast() {
156      pthread_cond_broadcast(&mCond);
157  }
158  
159  #endif // !defined(_WIN32)
160  
161  // ---------------------------------------------------------------------------
162  }  // namespace android
163  // ---------------------------------------------------------------------------
164  
165  #endif // _LIBS_UTILS_CONDITON_H
166