Home | History | Annotate | Download | only in utils
      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 // ---------------------------------------------------------------------------
     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 
     51     enum WakeUpType {
     52         WAKE_UP_ONE = 0,
     53         WAKE_UP_ALL = 1
     54     };
     55 
     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);
     63     // Signal the condition variable, allowing exactly one thread to continue.
     64     void signal();
     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     }
     73     // Signal the condition variable, allowing all threads to continue.
     74     void broadcast();
     75 
     76 private:
     77 #if defined(HAVE_PTHREADS)
     78     pthread_cond_t mCond;
     79 #else
     80     void*   mState;
     81 #endif
     82 };
     83 
     84 // ---------------------------------------------------------------------------
     85 
     86 #if defined(HAVE_PTHREADS)
     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;
    116 #if defined(HAVE_POSIX_CLOCKS)
    117     clock_gettime(CLOCK_REALTIME, &ts);
    118 #else // HAVE_POSIX_CLOCKS
    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;
    124 #endif // HAVE_POSIX_CLOCKS
    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() {
    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      */
    146     pthread_cond_signal(&mCond);
    147 }
    148 inline void Condition::broadcast() {
    149     pthread_cond_broadcast(&mCond);
    150 }
    151 
    152 #endif // HAVE_PTHREADS
    153 
    154 // ---------------------------------------------------------------------------
    155 }; // namespace android
    156 // ---------------------------------------------------------------------------
    157 
    158 #endif // _LIBS_UTILS_CONDITON_H
    159