12bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian/*
22bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian * Copyright (C) 2007 The Android Open Source Project
32bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian *
42bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian * Licensed under the Apache License, Version 2.0 (the "License");
52bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian * you may not use this file except in compliance with the License.
62bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian * You may obtain a copy of the License at
72bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian *
82bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian *      http://www.apache.org/licenses/LICENSE-2.0
92bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian *
102bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian * Unless required by applicable law or agreed to in writing, software
112bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian * distributed under the License is distributed on an "AS IS" BASIS,
122bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian * See the License for the specific language governing permissions and
142bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian * limitations under the License.
152bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian */
162bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian
172bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#ifndef _LIBS_UTILS_CONDITION_H
182bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#define _LIBS_UTILS_CONDITION_H
192bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian
202bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#include <stdint.h>
212bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#include <sys/types.h>
222bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#include <time.h>
232bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian
242bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#if defined(HAVE_PTHREADS)
252bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian# include <pthread.h>
262bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#endif
272bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian
282bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#include <utils/Errors.h>
292bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#include <utils/Mutex.h>
302bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#include <utils/Timers.h>
312bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian
322bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian// ---------------------------------------------------------------------------
332bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopiannamespace android {
342bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian// ---------------------------------------------------------------------------
352bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian
362bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian/*
372bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian * Condition variable class.  The implementation is system-dependent.
382bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian *
392bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian * Condition variables are paired up with mutexes.  Lock the mutex,
402bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian * call wait(), then either re-wait() if things aren't quite what you want,
412bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian * or unlock the mutex and continue.  All threads calling wait() must
422bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian * use the same mutex for a given Condition.
432bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian */
442bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopianclass Condition {
452bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopianpublic:
462bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    enum {
472bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian        PRIVATE = 0,
482bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian        SHARED = 1
492bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    };
502bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian
5131ba37f1c80801ee128749d4772c47f23323a3beRomain Guy    enum WakeUpType {
5231ba37f1c80801ee128749d4772c47f23323a3beRomain Guy        WAKE_UP_ONE = 0,
5331ba37f1c80801ee128749d4772c47f23323a3beRomain Guy        WAKE_UP_ALL = 1
5431ba37f1c80801ee128749d4772c47f23323a3beRomain Guy    };
5531ba37f1c80801ee128749d4772c47f23323a3beRomain Guy
562bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    Condition();
572bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    Condition(int type);
582bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    ~Condition();
592bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    // Wait on the condition variable.  Lock the mutex before calling.
602bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    status_t wait(Mutex& mutex);
612bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    // same with relative timeout
622bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    status_t waitRelative(Mutex& mutex, nsecs_t reltime);
632bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    // Signal the condition variable, allowing one thread to continue.
642bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    void signal();
6531ba37f1c80801ee128749d4772c47f23323a3beRomain Guy    // Signal the condition variable, allowing one or all threads to continue.
6631ba37f1c80801ee128749d4772c47f23323a3beRomain Guy    void signal(WakeUpType type) {
6731ba37f1c80801ee128749d4772c47f23323a3beRomain Guy        if (type == WAKE_UP_ONE) {
6831ba37f1c80801ee128749d4772c47f23323a3beRomain Guy            signal();
6931ba37f1c80801ee128749d4772c47f23323a3beRomain Guy        } else {
7031ba37f1c80801ee128749d4772c47f23323a3beRomain Guy            broadcast();
7131ba37f1c80801ee128749d4772c47f23323a3beRomain Guy        }
7231ba37f1c80801ee128749d4772c47f23323a3beRomain Guy    }
732bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    // Signal the condition variable, allowing all threads to continue.
742bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    void broadcast();
752bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian
762bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopianprivate:
772bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#if defined(HAVE_PTHREADS)
782bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    pthread_cond_t mCond;
792bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#else
802bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    void*   mState;
812bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#endif
822bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian};
832bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian
842bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian// ---------------------------------------------------------------------------
852bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian
862bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#if defined(HAVE_PTHREADS)
872bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian
882bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopianinline Condition::Condition() {
892bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    pthread_cond_init(&mCond, NULL);
902bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian}
912bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopianinline Condition::Condition(int type) {
922bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    if (type == SHARED) {
932bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian        pthread_condattr_t attr;
942bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian        pthread_condattr_init(&attr);
952bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian        pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
962bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian        pthread_cond_init(&mCond, &attr);
972bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian        pthread_condattr_destroy(&attr);
982bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    } else {
992bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian        pthread_cond_init(&mCond, NULL);
1002bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    }
1012bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian}
1022bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopianinline Condition::~Condition() {
1032bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    pthread_cond_destroy(&mCond);
1042bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian}
1052bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopianinline status_t Condition::wait(Mutex& mutex) {
1062bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    return -pthread_cond_wait(&mCond, &mutex.mMutex);
1072bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian}
1082bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopianinline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
1092bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
1102bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    struct timespec ts;
1112bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    ts.tv_sec  = reltime/1000000000;
1122bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    ts.tv_nsec = reltime%1000000000;
1132bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts);
1142bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
1152bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    struct timespec ts;
1162bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#if defined(HAVE_POSIX_CLOCKS)
1172bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    clock_gettime(CLOCK_REALTIME, &ts);
1182bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#else // HAVE_POSIX_CLOCKS
1192bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    // we don't support the clocks here.
1202bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    struct timeval t;
1212bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    gettimeofday(&t, NULL);
1222bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    ts.tv_sec = t.tv_sec;
1232bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    ts.tv_nsec= t.tv_usec*1000;
1242bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#endif // HAVE_POSIX_CLOCKS
1252bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    ts.tv_sec += reltime/1000000000;
1262bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    ts.tv_nsec+= reltime%1000000000;
1272bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    if (ts.tv_nsec >= 1000000000) {
1282bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian        ts.tv_nsec -= 1000000000;
1292bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian        ts.tv_sec  += 1;
1302bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    }
1312bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
1322bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
1332bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian}
1342bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopianinline void Condition::signal() {
1352bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    pthread_cond_signal(&mCond);
1362bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian}
1372bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopianinline void Condition::broadcast() {
1382bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian    pthread_cond_broadcast(&mCond);
1392bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian}
1402bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian
1412bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#endif // HAVE_PTHREADS
1422bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian
1432bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian// ---------------------------------------------------------------------------
1442bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian}; // namespace android
1452bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian// ---------------------------------------------------------------------------
1462bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian
1472bd99599bb9eef197e6d1ccacb9f808ebfbcc598Mathias Agopian#endif // _LIBS_UTILS_CONDITON_H
148