| Mathias Agopian | 2bd9959 | 2012-02-25 23:02:14 -0800 | [diff] [blame] | 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 <stdint.h> | 
|  | 21 | #include <sys/types.h> | 
|  | 22 | #include <time.h> | 
|  | 23 |  | 
| Yabin Cui | 4a6e5a3 | 2015-01-26 19:48:54 -0800 | [diff] [blame] | 24 | #if !defined(_WIN32) | 
| Mathias Agopian | 2bd9959 | 2012-02-25 23:02:14 -0800 | [diff] [blame] | 25 | # include <pthread.h> | 
|  | 26 | #endif | 
|  | 27 |  | 
|  | 28 | #include <utils/Errors.h> | 
|  | 29 | #include <utils/Mutex.h> | 
|  | 30 | #include <utils/Timers.h> | 
|  | 31 |  | 
|  | 32 | // --------------------------------------------------------------------------- | 
|  | 33 | namespace android { | 
|  | 34 | // --------------------------------------------------------------------------- | 
|  | 35 |  | 
|  | 36 | /* | 
|  | 37 | * Condition variable class.  The implementation is system-dependent. | 
|  | 38 | * | 
|  | 39 | * Condition variables are paired up with mutexes.  Lock the mutex, | 
|  | 40 | * call wait(), then either re-wait() if things aren't quite what you want, | 
|  | 41 | * or unlock the mutex and continue.  All threads calling wait() must | 
|  | 42 | * use the same mutex for a given Condition. | 
|  | 43 | */ | 
|  | 44 | class Condition { | 
|  | 45 | public: | 
|  | 46 | enum { | 
|  | 47 | PRIVATE = 0, | 
|  | 48 | SHARED = 1 | 
|  | 49 | }; | 
|  | 50 |  | 
| Romain Guy | 31ba37f | 2013-03-11 14:34:56 -0700 | [diff] [blame] | 51 | enum WakeUpType { | 
|  | 52 | WAKE_UP_ONE = 0, | 
|  | 53 | WAKE_UP_ALL = 1 | 
|  | 54 | }; | 
|  | 55 |  | 
| Mathias Agopian | 2bd9959 | 2012-02-25 23:02:14 -0800 | [diff] [blame] | 56 | Condition(); | 
|  | 57 | Condition(int type); | 
|  | 58 | ~Condition(); | 
|  | 59 | // Wait on the condition variable.  Lock the mutex before calling. | 
|  | 60 | status_t wait(Mutex& mutex); | 
|  | 61 | // same with relative timeout | 
|  | 62 | status_t waitRelative(Mutex& mutex, nsecs_t reltime); | 
| Igor Murashkin | db41938 | 2014-04-15 15:39:27 -0700 | [diff] [blame] | 63 | // Signal the condition variable, allowing exactly one thread to continue. | 
| Mathias Agopian | 2bd9959 | 2012-02-25 23:02:14 -0800 | [diff] [blame] | 64 | void signal(); | 
| Romain Guy | 31ba37f | 2013-03-11 14:34:56 -0700 | [diff] [blame] | 65 | // Signal the condition variable, allowing one or all threads to continue. | 
|  | 66 | void signal(WakeUpType type) { | 
|  | 67 | if (type == WAKE_UP_ONE) { | 
|  | 68 | signal(); | 
|  | 69 | } else { | 
|  | 70 | broadcast(); | 
|  | 71 | } | 
|  | 72 | } | 
| Mathias Agopian | 2bd9959 | 2012-02-25 23:02:14 -0800 | [diff] [blame] | 73 | // Signal the condition variable, allowing all threads to continue. | 
|  | 74 | void broadcast(); | 
|  | 75 |  | 
|  | 76 | private: | 
| Yabin Cui | 4a6e5a3 | 2015-01-26 19:48:54 -0800 | [diff] [blame] | 77 | #if !defined(_WIN32) | 
| Mathias Agopian | 2bd9959 | 2012-02-25 23:02:14 -0800 | [diff] [blame] | 78 | pthread_cond_t mCond; | 
|  | 79 | #else | 
|  | 80 | void*   mState; | 
|  | 81 | #endif | 
|  | 82 | }; | 
|  | 83 |  | 
|  | 84 | // --------------------------------------------------------------------------- | 
|  | 85 |  | 
| Yabin Cui | 4a6e5a3 | 2015-01-26 19:48:54 -0800 | [diff] [blame] | 86 | #if !defined(_WIN32) | 
| Mathias Agopian | 2bd9959 | 2012-02-25 23:02:14 -0800 | [diff] [blame] | 87 |  | 
|  | 88 | inline Condition::Condition() { | 
|  | 89 | pthread_cond_init(&mCond, NULL); | 
|  | 90 | } | 
|  | 91 | inline Condition::Condition(int type) { | 
|  | 92 | if (type == SHARED) { | 
|  | 93 | pthread_condattr_t attr; | 
|  | 94 | pthread_condattr_init(&attr); | 
|  | 95 | pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); | 
|  | 96 | pthread_cond_init(&mCond, &attr); | 
|  | 97 | pthread_condattr_destroy(&attr); | 
|  | 98 | } else { | 
|  | 99 | pthread_cond_init(&mCond, NULL); | 
|  | 100 | } | 
|  | 101 | } | 
|  | 102 | inline Condition::~Condition() { | 
|  | 103 | pthread_cond_destroy(&mCond); | 
|  | 104 | } | 
|  | 105 | inline status_t Condition::wait(Mutex& mutex) { | 
|  | 106 | return -pthread_cond_wait(&mCond, &mutex.mMutex); | 
|  | 107 | } | 
|  | 108 | inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) { | 
|  | 109 | #if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE) | 
|  | 110 | struct timespec ts; | 
|  | 111 | ts.tv_sec  = reltime/1000000000; | 
|  | 112 | ts.tv_nsec = reltime%1000000000; | 
|  | 113 | return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts); | 
|  | 114 | #else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE | 
|  | 115 | struct timespec ts; | 
| Elliott Hughes | 76f0a84 | 2015-01-09 16:16:53 -0800 | [diff] [blame] | 116 | #if defined(__linux__) | 
| Mathias Agopian | 2bd9959 | 2012-02-25 23:02:14 -0800 | [diff] [blame] | 117 | clock_gettime(CLOCK_REALTIME, &ts); | 
| Elliott Hughes | 76f0a84 | 2015-01-09 16:16:53 -0800 | [diff] [blame] | 118 | #else // __APPLE__ | 
| Mathias Agopian | 2bd9959 | 2012-02-25 23:02:14 -0800 | [diff] [blame] | 119 | // we don't support the clocks here. | 
|  | 120 | struct timeval t; | 
|  | 121 | gettimeofday(&t, NULL); | 
|  | 122 | ts.tv_sec = t.tv_sec; | 
|  | 123 | ts.tv_nsec= t.tv_usec*1000; | 
| Elliott Hughes | 76f0a84 | 2015-01-09 16:16:53 -0800 | [diff] [blame] | 124 | #endif | 
| Mathias Agopian | 2bd9959 | 2012-02-25 23:02:14 -0800 | [diff] [blame] | 125 | ts.tv_sec += reltime/1000000000; | 
|  | 126 | ts.tv_nsec+= reltime%1000000000; | 
|  | 127 | if (ts.tv_nsec >= 1000000000) { | 
|  | 128 | ts.tv_nsec -= 1000000000; | 
|  | 129 | ts.tv_sec  += 1; | 
|  | 130 | } | 
|  | 131 | return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts); | 
|  | 132 | #endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE | 
|  | 133 | } | 
|  | 134 | inline void Condition::signal() { | 
| Igor Murashkin | db41938 | 2014-04-15 15:39:27 -0700 | [diff] [blame] | 135 | /* | 
|  | 136 | * POSIX says pthread_cond_signal wakes up "one or more" waiting threads. | 
|  | 137 | * However bionic follows the glibc guarantee which wakes up "exactly one" | 
|  | 138 | * waiting thread. | 
|  | 139 | * | 
|  | 140 | * man 3 pthread_cond_signal | 
|  | 141 | *   pthread_cond_signal restarts one of the threads that are waiting on | 
|  | 142 | *   the condition variable cond. If no threads are waiting on cond, | 
|  | 143 | *   nothing happens. If several threads are waiting on cond, exactly one | 
|  | 144 | *   is restarted, but it is not specified which. | 
|  | 145 | */ | 
| Mathias Agopian | 2bd9959 | 2012-02-25 23:02:14 -0800 | [diff] [blame] | 146 | pthread_cond_signal(&mCond); | 
|  | 147 | } | 
|  | 148 | inline void Condition::broadcast() { | 
|  | 149 | pthread_cond_broadcast(&mCond); | 
|  | 150 | } | 
|  | 151 |  | 
| Yabin Cui | 4a6e5a3 | 2015-01-26 19:48:54 -0800 | [diff] [blame] | 152 | #endif // !defined(_WIN32) | 
| Mathias Agopian | 2bd9959 | 2012-02-25 23:02:14 -0800 | [diff] [blame] | 153 |  | 
|  | 154 | // --------------------------------------------------------------------------- | 
|  | 155 | }; // namespace android | 
|  | 156 | // --------------------------------------------------------------------------- | 
|  | 157 |  | 
|  | 158 | #endif // _LIBS_UTILS_CONDITON_H |