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
24#if defined(HAVE_PTHREADS)
25# include <pthread.h>
26#endif
27
28#include <utils/Errors.h>
29#include <utils/Mutex.h>
30#include <utils/Timers.h>
31
32// ---------------------------------------------------------------------------
33namespace 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 */
44class Condition {
45public:
46    enum {
47        PRIVATE = 0,
48        SHARED = 1
49    };
50
51    Condition();
52    Condition(int type);
53    ~Condition();
54    // Wait on the condition variable.  Lock the mutex before calling.
55    status_t wait(Mutex& mutex);
56    // same with relative timeout
57    status_t waitRelative(Mutex& mutex, nsecs_t reltime);
58    // Signal the condition variable, allowing one thread to continue.
59    void signal();
60    // Signal the condition variable, allowing all threads to continue.
61    void broadcast();
62
63private:
64#if defined(HAVE_PTHREADS)
65    pthread_cond_t mCond;
66#else
67    void*   mState;
68#endif
69};
70
71// ---------------------------------------------------------------------------
72
73#if defined(HAVE_PTHREADS)
74
75inline Condition::Condition() {
76    pthread_cond_init(&mCond, NULL);
77}
78inline Condition::Condition(int type) {
79    if (type == SHARED) {
80        pthread_condattr_t attr;
81        pthread_condattr_init(&attr);
82        pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
83        pthread_cond_init(&mCond, &attr);
84        pthread_condattr_destroy(&attr);
85    } else {
86        pthread_cond_init(&mCond, NULL);
87    }
88}
89inline Condition::~Condition() {
90    pthread_cond_destroy(&mCond);
91}
92inline status_t Condition::wait(Mutex& mutex) {
93    return -pthread_cond_wait(&mCond, &mutex.mMutex);
94}
95inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
96#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
97    struct timespec ts;
98    ts.tv_sec  = reltime/1000000000;
99    ts.tv_nsec = reltime%1000000000;
100    return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts);
101#else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
102    struct timespec ts;
103#if defined(HAVE_POSIX_CLOCKS)
104    clock_gettime(CLOCK_REALTIME, &ts);
105#else // HAVE_POSIX_CLOCKS
106    // we don't support the clocks here.
107    struct timeval t;
108    gettimeofday(&t, NULL);
109    ts.tv_sec = t.tv_sec;
110    ts.tv_nsec= t.tv_usec*1000;
111#endif // HAVE_POSIX_CLOCKS
112    ts.tv_sec += reltime/1000000000;
113    ts.tv_nsec+= reltime%1000000000;
114    if (ts.tv_nsec >= 1000000000) {
115        ts.tv_nsec -= 1000000000;
116        ts.tv_sec  += 1;
117    }
118    return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
119#endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
120}
121inline void Condition::signal() {
122    pthread_cond_signal(&mCond);
123}
124inline void Condition::broadcast() {
125    pthread_cond_broadcast(&mCond);
126}
127
128#endif // HAVE_PTHREADS
129
130// ---------------------------------------------------------------------------
131}; // namespace android
132// ---------------------------------------------------------------------------
133
134#endif // _LIBS_UTILS_CONDITON_H
135