| /* | 
 |  * Copyright (C) 2007 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #ifndef _LIBS_UTILS_THREADS_H | 
 | #define _LIBS_UTILS_THREADS_H | 
 |  | 
 | #include <stdint.h> | 
 | #include <sys/types.h> | 
 | #include <time.h> | 
 |  | 
 | #if defined(HAVE_PTHREADS) | 
 | # include <pthread.h> | 
 | #endif | 
 |  | 
 | // ------------------------------------------------------------------ | 
 | // C API | 
 |  | 
 | #ifdef __cplusplus | 
 | extern "C" { | 
 | #endif | 
 |  | 
 | typedef void* android_thread_id_t; | 
 |  | 
 | typedef int (*android_thread_func_t)(void*); | 
 |  | 
 | enum { | 
 |     /* | 
 |      * *********************************************** | 
 |      * ** Keep in sync with android.os.Process.java ** | 
 |      * *********************************************** | 
 |      *  | 
 |      * This maps directly to the "nice" priorites we use in Android. | 
 |      * A thread priority should be chosen inverse-proportinally to | 
 |      * the amount of work the thread is expected to do. The more work | 
 |      * a thread will do, the less favorable priority it should get so that  | 
 |      * it doesn't starve the system. Threads not behaving properly might | 
 |      * be "punished" by the kernel. | 
 |      * Use the levels below when appropriate. Intermediate values are | 
 |      * acceptable, preferably use the {MORE|LESS}_FAVORABLE constants below. | 
 |      */ | 
 |     ANDROID_PRIORITY_LOWEST         =  19, | 
 |  | 
 |     /* use for background tasks */ | 
 |     ANDROID_PRIORITY_BACKGROUND     =  10, | 
 |      | 
 |     /* most threads run at normal priority */ | 
 |     ANDROID_PRIORITY_NORMAL         =   0, | 
 |      | 
 |     /* threads currently running a UI that the user is interacting with */ | 
 |     ANDROID_PRIORITY_FOREGROUND     =  -2, | 
 |  | 
 |     /* the main UI thread has a slightly more favorable priority */ | 
 |     ANDROID_PRIORITY_DISPLAY        =  -4, | 
 |      | 
 |     /* ui service treads might want to run at a urgent display (uncommon) */ | 
 |     ANDROID_PRIORITY_URGENT_DISPLAY =  -8, | 
 |      | 
 |     /* all normal audio threads */ | 
 |     ANDROID_PRIORITY_AUDIO          = -16, | 
 |      | 
 |     /* service audio threads (uncommon) */ | 
 |     ANDROID_PRIORITY_URGENT_AUDIO   = -19, | 
 |  | 
 |     /* should never be used in practice. regular process might not  | 
 |      * be allowed to use this level */ | 
 |     ANDROID_PRIORITY_HIGHEST        = -20, | 
 |  | 
 |     ANDROID_PRIORITY_DEFAULT        = ANDROID_PRIORITY_NORMAL, | 
 |     ANDROID_PRIORITY_MORE_FAVORABLE = -1, | 
 |     ANDROID_PRIORITY_LESS_FAVORABLE = +1, | 
 | }; | 
 |  | 
 | enum { | 
 |     ANDROID_TGROUP_DEFAULT          = 0, | 
 |     ANDROID_TGROUP_BG_NONINTERACT   = 1, | 
 |     ANDROID_TGROUP_FG_BOOST         = 2, | 
 |     ANDROID_TGROUP_MAX              = ANDROID_TGROUP_FG_BOOST, | 
 | }; | 
 |  | 
 | // Create and run a new thread. | 
 | extern int androidCreateThread(android_thread_func_t, void *); | 
 |  | 
 | // Create thread with lots of parameters | 
 | extern int androidCreateThreadEtc(android_thread_func_t entryFunction, | 
 |                                   void *userData, | 
 |                                   const char* threadName, | 
 |                                   int32_t threadPriority, | 
 |                                   size_t threadStackSize, | 
 |                                   android_thread_id_t *threadId); | 
 |  | 
 | // Get some sort of unique identifier for the current thread. | 
 | extern android_thread_id_t androidGetThreadId(); | 
 |  | 
 | // Low-level thread creation -- never creates threads that can | 
 | // interact with the Java VM. | 
 | extern int androidCreateRawThreadEtc(android_thread_func_t entryFunction, | 
 |                                      void *userData, | 
 |                                      const char* threadName, | 
 |                                      int32_t threadPriority, | 
 |                                      size_t threadStackSize, | 
 |                                      android_thread_id_t *threadId); | 
 |  | 
 | // Used by the Java Runtime to control how threads are created, so that | 
 | // they can be proper and lovely Java threads. | 
 | typedef int (*android_create_thread_fn)(android_thread_func_t entryFunction, | 
 |                                         void *userData, | 
 |                                         const char* threadName, | 
 |                                         int32_t threadPriority, | 
 |                                         size_t threadStackSize, | 
 |                                         android_thread_id_t *threadId); | 
 |  | 
 | extern void androidSetCreateThreadFunc(android_create_thread_fn func); | 
 |  | 
 | #ifdef __cplusplus | 
 | } | 
 | #endif | 
 |  | 
 | // ------------------------------------------------------------------ | 
 | // C++ API | 
 |  | 
 | #ifdef __cplusplus | 
 |  | 
 | #include <utils/Errors.h> | 
 | #include <utils/RefBase.h> | 
 | #include <utils/Timers.h> | 
 |  | 
 | namespace android { | 
 |  | 
 | typedef android_thread_id_t thread_id_t; | 
 |  | 
 | typedef android_thread_func_t thread_func_t; | 
 |  | 
 | enum { | 
 |     PRIORITY_LOWEST         = ANDROID_PRIORITY_LOWEST, | 
 |     PRIORITY_BACKGROUND     = ANDROID_PRIORITY_BACKGROUND, | 
 |     PRIORITY_NORMAL         = ANDROID_PRIORITY_NORMAL, | 
 |     PRIORITY_FOREGROUND     = ANDROID_PRIORITY_FOREGROUND, | 
 |     PRIORITY_DISPLAY        = ANDROID_PRIORITY_DISPLAY, | 
 |     PRIORITY_URGENT_DISPLAY = ANDROID_PRIORITY_URGENT_DISPLAY, | 
 |     PRIORITY_AUDIO          = ANDROID_PRIORITY_AUDIO, | 
 |     PRIORITY_URGENT_AUDIO   = ANDROID_PRIORITY_URGENT_AUDIO, | 
 |     PRIORITY_HIGHEST        = ANDROID_PRIORITY_HIGHEST, | 
 |     PRIORITY_DEFAULT        = ANDROID_PRIORITY_DEFAULT, | 
 |     PRIORITY_MORE_FAVORABLE = ANDROID_PRIORITY_MORE_FAVORABLE, | 
 |     PRIORITY_LESS_FAVORABLE = ANDROID_PRIORITY_LESS_FAVORABLE, | 
 | }; | 
 |  | 
 | // Create and run a new thread. | 
 | inline bool createThread(thread_func_t f, void *a) { | 
 |     return androidCreateThread(f, a) ? true : false; | 
 | } | 
 |  | 
 | // Create thread with lots of parameters | 
 | inline bool createThreadEtc(thread_func_t entryFunction, | 
 |                             void *userData, | 
 |                             const char* threadName = "android:unnamed_thread", | 
 |                             int32_t threadPriority = PRIORITY_DEFAULT, | 
 |                             size_t threadStackSize = 0, | 
 |                             thread_id_t *threadId = 0) | 
 | { | 
 |     return androidCreateThreadEtc(entryFunction, userData, threadName, | 
 |         threadPriority, threadStackSize, threadId) ? true : false; | 
 | } | 
 |  | 
 | // Get some sort of unique identifier for the current thread. | 
 | inline thread_id_t getThreadId() { | 
 |     return androidGetThreadId(); | 
 | } | 
 |  | 
 | /*****************************************************************************/ | 
 |  | 
 | /* | 
 |  * Simple mutex class.  The implementation is system-dependent. | 
 |  * | 
 |  * The mutex must be unlocked by the thread that locked it.  They are not | 
 |  * recursive, i.e. the same thread can't lock it multiple times. | 
 |  */ | 
 | class Mutex { | 
 | public: | 
 |     enum { | 
 |         NORMAL = 0, | 
 |         SHARED = 1 | 
 |     }; | 
 |      | 
 |                 Mutex(); | 
 |                 Mutex(const char* name); | 
 |                 Mutex(int type, const char* name = NULL); | 
 |                 ~Mutex(); | 
 |  | 
 |     // lock or unlock the mutex | 
 |     status_t    lock(); | 
 |     void        unlock(); | 
 |  | 
 |     // lock if possible; returns 0 on success, error otherwise | 
 |     status_t    tryLock(); | 
 |  | 
 |     // Manages the mutex automatically. It'll be locked when Autolock is | 
 |     // constructed and released when Autolock goes out of scope. | 
 |     class Autolock { | 
 |     public: | 
 |         inline Autolock(Mutex& mutex) : mLock(mutex)  { mLock.lock(); } | 
 |         inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); } | 
 |         inline ~Autolock() { mLock.unlock(); } | 
 |     private: | 
 |         Mutex& mLock; | 
 |     }; | 
 |  | 
 | private: | 
 |     friend class Condition; | 
 |      | 
 |     // A mutex cannot be copied | 
 |                 Mutex(const Mutex&); | 
 |     Mutex&      operator = (const Mutex&); | 
 |      | 
 | #if defined(HAVE_PTHREADS) | 
 |     pthread_mutex_t mMutex; | 
 | #else | 
 |     void    _init(); | 
 |     void*   mState; | 
 | #endif | 
 | }; | 
 |  | 
 | #if defined(HAVE_PTHREADS) | 
 |  | 
 | inline Mutex::Mutex() { | 
 |     pthread_mutex_init(&mMutex, NULL); | 
 | } | 
 | inline Mutex::Mutex(const char* name) { | 
 |     pthread_mutex_init(&mMutex, NULL); | 
 | } | 
 | inline Mutex::Mutex(int type, const char* name) { | 
 |     if (type == SHARED) { | 
 |         pthread_mutexattr_t attr; | 
 |         pthread_mutexattr_init(&attr); | 
 |         pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); | 
 |         pthread_mutex_init(&mMutex, &attr); | 
 |         pthread_mutexattr_destroy(&attr); | 
 |     } else { | 
 |         pthread_mutex_init(&mMutex, NULL); | 
 |     } | 
 | } | 
 | inline Mutex::~Mutex() { | 
 |     pthread_mutex_destroy(&mMutex); | 
 | } | 
 | inline status_t Mutex::lock() { | 
 |     return -pthread_mutex_lock(&mMutex); | 
 | } | 
 | inline void Mutex::unlock() { | 
 |     pthread_mutex_unlock(&mMutex); | 
 | } | 
 | inline status_t Mutex::tryLock() { | 
 |     return -pthread_mutex_trylock(&mMutex); | 
 | } | 
 |  | 
 | #endif // HAVE_PTHREADS | 
 |  | 
 | /* | 
 |  * Automatic mutex.  Declare one of these at the top of a function. | 
 |  * When the function returns, it will go out of scope, and release the | 
 |  * mutex. | 
 |  */ | 
 |   | 
 | typedef Mutex::Autolock AutoMutex; | 
 |  | 
 | /*****************************************************************************/ | 
 |  | 
 | /* | 
 |  * Condition variable class.  The implementation is system-dependent. | 
 |  * | 
 |  * Condition variables are paired up with mutexes.  Lock the mutex, | 
 |  * call wait(), then either re-wait() if things aren't quite what you want, | 
 |  * or unlock the mutex and continue.  All threads calling wait() must | 
 |  * use the same mutex for a given Condition. | 
 |  */ | 
 | class Condition { | 
 | public: | 
 |     Condition(); | 
 |     ~Condition(); | 
 |     // Wait on the condition variable.  Lock the mutex before calling. | 
 |     status_t wait(Mutex& mutex); | 
 |     // same with relative timeout | 
 |     status_t waitRelative(Mutex& mutex, nsecs_t reltime); | 
 |     // Signal the condition variable, allowing one thread to continue. | 
 |     void signal(); | 
 |     // Signal the condition variable, allowing all threads to continue. | 
 |     void broadcast(); | 
 |  | 
 | private: | 
 | #if defined(HAVE_PTHREADS) | 
 |     pthread_cond_t mCond; | 
 | #else | 
 |     void*   mState; | 
 | #endif | 
 | }; | 
 |  | 
 | #if defined(HAVE_PTHREADS) | 
 |  | 
 | inline Condition::Condition() { | 
 |     pthread_cond_init(&mCond, NULL); | 
 | } | 
 | inline Condition::~Condition() { | 
 |     pthread_cond_destroy(&mCond); | 
 | } | 
 | inline status_t Condition::wait(Mutex& mutex) { | 
 |     return -pthread_cond_wait(&mCond, &mutex.mMutex); | 
 | } | 
 | inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) { | 
 | #if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE) | 
 |     struct timespec ts; | 
 |     ts.tv_sec  = reltime/1000000000; | 
 |     ts.tv_nsec = reltime%1000000000; | 
 |     return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts); | 
 | #else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE | 
 |     struct timespec ts; | 
 | #if defined(HAVE_POSIX_CLOCKS) | 
 |     clock_gettime(CLOCK_REALTIME, &ts); | 
 | #else // HAVE_POSIX_CLOCKS | 
 |     // we don't support the clocks here. | 
 |     struct timeval t; | 
 |     gettimeofday(&t, NULL); | 
 |     ts.tv_sec = t.tv_sec; | 
 |     ts.tv_nsec= t.tv_usec*1000; | 
 | #endif // HAVE_POSIX_CLOCKS | 
 |     ts.tv_sec += reltime/1000000000; | 
 |     ts.tv_nsec+= reltime%1000000000; | 
 |     if (ts.tv_nsec >= 1000000000) { | 
 |         ts.tv_nsec -= 1000000000; | 
 |         ts.tv_sec  += 1; | 
 |     } | 
 |     return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts); | 
 | #endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE | 
 | } | 
 | inline void Condition::signal() { | 
 |     pthread_cond_signal(&mCond); | 
 | } | 
 | inline void Condition::broadcast() { | 
 |     pthread_cond_broadcast(&mCond); | 
 | } | 
 |  | 
 | #endif // HAVE_PTHREADS | 
 |  | 
 | /*****************************************************************************/ | 
 |  | 
 | /* | 
 |  * This is our spiffy thread object! | 
 |  */ | 
 |  | 
 | class Thread : virtual public RefBase | 
 | { | 
 | public: | 
 |     // Create a Thread object, but doesn't create or start the associated | 
 |     // thread. See the run() method. | 
 |                         Thread(bool canCallJava = true); | 
 |     virtual             ~Thread(); | 
 |  | 
 |     // Start the thread in threadLoop() which needs to be implemented. | 
 |     virtual status_t    run(    const char* name = 0, | 
 |                                 int32_t priority = PRIORITY_DEFAULT, | 
 |                                 size_t stack = 0); | 
 |      | 
 |     // Ask this object's thread to exit. This function is asynchronous, when the | 
 |     // function returns the thread might still be running. Of course, this | 
 |     // function can be called from a different thread. | 
 |     virtual void        requestExit(); | 
 |  | 
 |     // Good place to do one-time initializations | 
 |     virtual status_t    readyToRun(); | 
 |      | 
 |     // Call requestExit() and wait until this object's thread exits. | 
 |     // BE VERY CAREFUL of deadlocks. In particular, it would be silly to call | 
 |     // this function from this object's thread. Will return WOULD_BLOCK in | 
 |     // that case. | 
 |             status_t    requestExitAndWait(); | 
 |  | 
 | protected: | 
 |     // exitPending() returns true if requestExit() has been called. | 
 |             bool        exitPending() const; | 
 |      | 
 | private: | 
 |     // Derived class must implement threadLoop(). The thread starts its life | 
 |     // here. There are two ways of using the Thread object: | 
 |     // 1) loop: if threadLoop() returns true, it will be called again if | 
 |     //          requestExit() wasn't called. | 
 |     // 2) once: if threadLoop() returns false, the thread will exit upon return. | 
 |     virtual bool        threadLoop() = 0; | 
 |  | 
 | private: | 
 |     Thread& operator=(const Thread&); | 
 |     static  int             _threadLoop(void* user); | 
 |     const   bool            mCanCallJava; | 
 |             thread_id_t     mThread; | 
 |             Mutex           mLock; | 
 |             Condition       mThreadExitedCondition; | 
 |             status_t        mStatus; | 
 |     volatile bool           mExitPending; | 
 |     volatile bool           mRunning; | 
 |             sp<Thread>      mHoldSelf; | 
 | }; | 
 |  | 
 |  | 
 | }; // namespace android | 
 |  | 
 | #endif  // __cplusplus | 
 |  | 
 | #endif // _LIBS_UTILS_THREADS_H |