media/omx-plugin/include/ics/utils/threads.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*
michael@0 2 * Copyright (C) 2007 The Android Open Source Project
michael@0 3 *
michael@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
michael@0 5 * you may not use this file except in compliance with the License.
michael@0 6 * You may obtain a copy of the License at
michael@0 7 *
michael@0 8 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 9 *
michael@0 10 * Unless required by applicable law or agreed to in writing, software
michael@0 11 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 13 * See the License for the specific language governing permissions and
michael@0 14 * limitations under the License.
michael@0 15 */
michael@0 16
michael@0 17 #ifndef _LIBS_UTILS_THREADS_H
michael@0 18 #define _LIBS_UTILS_THREADS_H
michael@0 19
michael@0 20 #include <stdint.h>
michael@0 21 #include <sys/types.h>
michael@0 22 #include <time.h>
michael@0 23 #include <system/graphics.h>
michael@0 24
michael@0 25 #if defined(HAVE_PTHREADS)
michael@0 26 # include <pthread.h>
michael@0 27 #endif
michael@0 28
michael@0 29 // ------------------------------------------------------------------
michael@0 30 // C API
michael@0 31
michael@0 32 #ifdef __cplusplus
michael@0 33 extern "C" {
michael@0 34 #endif
michael@0 35
michael@0 36 typedef void* android_thread_id_t;
michael@0 37
michael@0 38 typedef int (*android_thread_func_t)(void*);
michael@0 39
michael@0 40 enum {
michael@0 41 /*
michael@0 42 * ***********************************************
michael@0 43 * ** Keep in sync with android.os.Process.java **
michael@0 44 * ***********************************************
michael@0 45 *
michael@0 46 * This maps directly to the "nice" priorities we use in Android.
michael@0 47 * A thread priority should be chosen inverse-proportionally to
michael@0 48 * the amount of work the thread is expected to do. The more work
michael@0 49 * a thread will do, the less favorable priority it should get so that
michael@0 50 * it doesn't starve the system. Threads not behaving properly might
michael@0 51 * be "punished" by the kernel.
michael@0 52 * Use the levels below when appropriate. Intermediate values are
michael@0 53 * acceptable, preferably use the {MORE|LESS}_FAVORABLE constants below.
michael@0 54 */
michael@0 55 ANDROID_PRIORITY_LOWEST = 19,
michael@0 56
michael@0 57 /* use for background tasks */
michael@0 58 ANDROID_PRIORITY_BACKGROUND = 10,
michael@0 59
michael@0 60 /* most threads run at normal priority */
michael@0 61 ANDROID_PRIORITY_NORMAL = 0,
michael@0 62
michael@0 63 /* threads currently running a UI that the user is interacting with */
michael@0 64 ANDROID_PRIORITY_FOREGROUND = -2,
michael@0 65
michael@0 66 /* the main UI thread has a slightly more favorable priority */
michael@0 67 ANDROID_PRIORITY_DISPLAY = -4,
michael@0 68
michael@0 69 /* ui service treads might want to run at a urgent display (uncommon) */
michael@0 70 ANDROID_PRIORITY_URGENT_DISPLAY = HAL_PRIORITY_URGENT_DISPLAY,
michael@0 71
michael@0 72 /* all normal audio threads */
michael@0 73 ANDROID_PRIORITY_AUDIO = -16,
michael@0 74
michael@0 75 /* service audio threads (uncommon) */
michael@0 76 ANDROID_PRIORITY_URGENT_AUDIO = -19,
michael@0 77
michael@0 78 /* should never be used in practice. regular process might not
michael@0 79 * be allowed to use this level */
michael@0 80 ANDROID_PRIORITY_HIGHEST = -20,
michael@0 81
michael@0 82 ANDROID_PRIORITY_DEFAULT = ANDROID_PRIORITY_NORMAL,
michael@0 83 ANDROID_PRIORITY_MORE_FAVORABLE = -1,
michael@0 84 ANDROID_PRIORITY_LESS_FAVORABLE = +1,
michael@0 85 };
michael@0 86
michael@0 87 enum {
michael@0 88 ANDROID_TGROUP_DEFAULT = 0,
michael@0 89 ANDROID_TGROUP_BG_NONINTERACT = 1,
michael@0 90 ANDROID_TGROUP_FG_BOOST = 2,
michael@0 91 ANDROID_TGROUP_MAX = ANDROID_TGROUP_FG_BOOST,
michael@0 92 };
michael@0 93
michael@0 94 // Create and run a new thread.
michael@0 95 extern int androidCreateThread(android_thread_func_t, void *);
michael@0 96
michael@0 97 // Create thread with lots of parameters
michael@0 98 extern int androidCreateThreadEtc(android_thread_func_t entryFunction,
michael@0 99 void *userData,
michael@0 100 const char* threadName,
michael@0 101 int32_t threadPriority,
michael@0 102 size_t threadStackSize,
michael@0 103 android_thread_id_t *threadId);
michael@0 104
michael@0 105 // Get some sort of unique identifier for the current thread.
michael@0 106 extern android_thread_id_t androidGetThreadId();
michael@0 107
michael@0 108 // Low-level thread creation -- never creates threads that can
michael@0 109 // interact with the Java VM.
michael@0 110 extern int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
michael@0 111 void *userData,
michael@0 112 const char* threadName,
michael@0 113 int32_t threadPriority,
michael@0 114 size_t threadStackSize,
michael@0 115 android_thread_id_t *threadId);
michael@0 116
michael@0 117 // Used by the Java Runtime to control how threads are created, so that
michael@0 118 // they can be proper and lovely Java threads.
michael@0 119 typedef int (*android_create_thread_fn)(android_thread_func_t entryFunction,
michael@0 120 void *userData,
michael@0 121 const char* threadName,
michael@0 122 int32_t threadPriority,
michael@0 123 size_t threadStackSize,
michael@0 124 android_thread_id_t *threadId);
michael@0 125
michael@0 126 extern void androidSetCreateThreadFunc(android_create_thread_fn func);
michael@0 127
michael@0 128 // ------------------------------------------------------------------
michael@0 129 // Extra functions working with raw pids.
michael@0 130
michael@0 131 // Get pid for the current thread.
michael@0 132 extern pid_t androidGetTid();
michael@0 133
michael@0 134 // Change the scheduling group of a particular thread. The group
michael@0 135 // should be one of the ANDROID_TGROUP constants. Returns BAD_VALUE if
michael@0 136 // grp is out of range, else another non-zero value with errno set if
michael@0 137 // the operation failed. Thread ID zero means current thread.
michael@0 138 extern int androidSetThreadSchedulingGroup(pid_t tid, int grp);
michael@0 139
michael@0 140 // Change the priority AND scheduling group of a particular thread. The priority
michael@0 141 // should be one of the ANDROID_PRIORITY constants. Returns INVALID_OPERATION
michael@0 142 // if the priority set failed, else another value if just the group set failed;
michael@0 143 // in either case errno is set. Thread ID zero means current thread.
michael@0 144 extern int androidSetThreadPriority(pid_t tid, int prio);
michael@0 145
michael@0 146 // Get the current priority of a particular thread. Returns one of the
michael@0 147 // ANDROID_PRIORITY constants or a negative result in case of error.
michael@0 148 extern int androidGetThreadPriority(pid_t tid);
michael@0 149
michael@0 150 // Get the current scheduling group of a particular thread. Normally returns
michael@0 151 // one of the ANDROID_TGROUP constants other than ANDROID_TGROUP_DEFAULT.
michael@0 152 // Returns ANDROID_TGROUP_DEFAULT if no pthread support (e.g. on host) or if
michael@0 153 // scheduling groups are disabled. Returns INVALID_OPERATION if unexpected error.
michael@0 154 // Thread ID zero means current thread.
michael@0 155 extern int androidGetThreadSchedulingGroup(pid_t tid);
michael@0 156
michael@0 157 #ifdef __cplusplus
michael@0 158 }
michael@0 159 #endif
michael@0 160
michael@0 161 // ------------------------------------------------------------------
michael@0 162 // C++ API
michael@0 163
michael@0 164 #ifdef __cplusplus
michael@0 165
michael@0 166 #include <utils/Errors.h>
michael@0 167 #include <utils/RefBase.h>
michael@0 168 #include <utils/Timers.h>
michael@0 169
michael@0 170 namespace android {
michael@0 171
michael@0 172 typedef android_thread_id_t thread_id_t;
michael@0 173
michael@0 174 typedef android_thread_func_t thread_func_t;
michael@0 175
michael@0 176 enum {
michael@0 177 PRIORITY_LOWEST = ANDROID_PRIORITY_LOWEST,
michael@0 178 PRIORITY_BACKGROUND = ANDROID_PRIORITY_BACKGROUND,
michael@0 179 PRIORITY_NORMAL = ANDROID_PRIORITY_NORMAL,
michael@0 180 PRIORITY_FOREGROUND = ANDROID_PRIORITY_FOREGROUND,
michael@0 181 PRIORITY_DISPLAY = ANDROID_PRIORITY_DISPLAY,
michael@0 182 PRIORITY_URGENT_DISPLAY = ANDROID_PRIORITY_URGENT_DISPLAY,
michael@0 183 PRIORITY_AUDIO = ANDROID_PRIORITY_AUDIO,
michael@0 184 PRIORITY_URGENT_AUDIO = ANDROID_PRIORITY_URGENT_AUDIO,
michael@0 185 PRIORITY_HIGHEST = ANDROID_PRIORITY_HIGHEST,
michael@0 186 PRIORITY_DEFAULT = ANDROID_PRIORITY_DEFAULT,
michael@0 187 PRIORITY_MORE_FAVORABLE = ANDROID_PRIORITY_MORE_FAVORABLE,
michael@0 188 PRIORITY_LESS_FAVORABLE = ANDROID_PRIORITY_LESS_FAVORABLE,
michael@0 189 };
michael@0 190
michael@0 191 // Create and run a new thread.
michael@0 192 inline bool createThread(thread_func_t f, void *a) {
michael@0 193 return androidCreateThread(f, a) ? true : false;
michael@0 194 }
michael@0 195
michael@0 196 // Create thread with lots of parameters
michael@0 197 inline bool createThreadEtc(thread_func_t entryFunction,
michael@0 198 void *userData,
michael@0 199 const char* threadName = "android:unnamed_thread",
michael@0 200 int32_t threadPriority = PRIORITY_DEFAULT,
michael@0 201 size_t threadStackSize = 0,
michael@0 202 thread_id_t *threadId = 0)
michael@0 203 {
michael@0 204 return androidCreateThreadEtc(entryFunction, userData, threadName,
michael@0 205 threadPriority, threadStackSize, threadId) ? true : false;
michael@0 206 }
michael@0 207
michael@0 208 // Get some sort of unique identifier for the current thread.
michael@0 209 inline thread_id_t getThreadId() {
michael@0 210 return androidGetThreadId();
michael@0 211 }
michael@0 212
michael@0 213 /*****************************************************************************/
michael@0 214
michael@0 215 /*
michael@0 216 * Simple mutex class. The implementation is system-dependent.
michael@0 217 *
michael@0 218 * The mutex must be unlocked by the thread that locked it. They are not
michael@0 219 * recursive, i.e. the same thread can't lock it multiple times.
michael@0 220 */
michael@0 221 class Mutex {
michael@0 222 public:
michael@0 223 enum {
michael@0 224 PRIVATE = 0,
michael@0 225 SHARED = 1
michael@0 226 };
michael@0 227
michael@0 228 Mutex();
michael@0 229 Mutex(const char* name);
michael@0 230 Mutex(int type, const char* name = NULL);
michael@0 231 ~Mutex();
michael@0 232
michael@0 233 // lock or unlock the mutex
michael@0 234 status_t lock();
michael@0 235 void unlock();
michael@0 236
michael@0 237 // lock if possible; returns 0 on success, error otherwise
michael@0 238 status_t tryLock();
michael@0 239
michael@0 240 // Manages the mutex automatically. It'll be locked when Autolock is
michael@0 241 // constructed and released when Autolock goes out of scope.
michael@0 242 class Autolock {
michael@0 243 public:
michael@0 244 inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
michael@0 245 inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
michael@0 246 inline ~Autolock() { mLock.unlock(); }
michael@0 247 private:
michael@0 248 Mutex& mLock;
michael@0 249 };
michael@0 250
michael@0 251 private:
michael@0 252 friend class Condition;
michael@0 253
michael@0 254 // A mutex cannot be copied
michael@0 255 Mutex(const Mutex&);
michael@0 256 Mutex& operator = (const Mutex&);
michael@0 257
michael@0 258 #if defined(HAVE_PTHREADS)
michael@0 259 pthread_mutex_t mMutex;
michael@0 260 #else
michael@0 261 void _init();
michael@0 262 void* mState;
michael@0 263 #endif
michael@0 264 };
michael@0 265
michael@0 266 #if defined(HAVE_PTHREADS)
michael@0 267
michael@0 268 inline Mutex::Mutex() {
michael@0 269 pthread_mutex_init(&mMutex, NULL);
michael@0 270 }
michael@0 271 inline Mutex::Mutex(const char* name) {
michael@0 272 pthread_mutex_init(&mMutex, NULL);
michael@0 273 }
michael@0 274 inline Mutex::Mutex(int type, const char* name) {
michael@0 275 if (type == SHARED) {
michael@0 276 pthread_mutexattr_t attr;
michael@0 277 pthread_mutexattr_init(&attr);
michael@0 278 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
michael@0 279 pthread_mutex_init(&mMutex, &attr);
michael@0 280 pthread_mutexattr_destroy(&attr);
michael@0 281 } else {
michael@0 282 pthread_mutex_init(&mMutex, NULL);
michael@0 283 }
michael@0 284 }
michael@0 285 inline Mutex::~Mutex() {
michael@0 286 pthread_mutex_destroy(&mMutex);
michael@0 287 }
michael@0 288 inline status_t Mutex::lock() {
michael@0 289 return -pthread_mutex_lock(&mMutex);
michael@0 290 }
michael@0 291 inline void Mutex::unlock() {
michael@0 292 pthread_mutex_unlock(&mMutex);
michael@0 293 }
michael@0 294 inline status_t Mutex::tryLock() {
michael@0 295 return -pthread_mutex_trylock(&mMutex);
michael@0 296 }
michael@0 297
michael@0 298 #endif // HAVE_PTHREADS
michael@0 299
michael@0 300 /*
michael@0 301 * Automatic mutex. Declare one of these at the top of a function.
michael@0 302 * When the function returns, it will go out of scope, and release the
michael@0 303 * mutex.
michael@0 304 */
michael@0 305
michael@0 306 typedef Mutex::Autolock AutoMutex;
michael@0 307
michael@0 308 /*****************************************************************************/
michael@0 309
michael@0 310 #if defined(HAVE_PTHREADS)
michael@0 311
michael@0 312 /*
michael@0 313 * Simple mutex class. The implementation is system-dependent.
michael@0 314 *
michael@0 315 * The mutex must be unlocked by the thread that locked it. They are not
michael@0 316 * recursive, i.e. the same thread can't lock it multiple times.
michael@0 317 */
michael@0 318 class RWLock {
michael@0 319 public:
michael@0 320 enum {
michael@0 321 PRIVATE = 0,
michael@0 322 SHARED = 1
michael@0 323 };
michael@0 324
michael@0 325 RWLock();
michael@0 326 RWLock(const char* name);
michael@0 327 RWLock(int type, const char* name = NULL);
michael@0 328 ~RWLock();
michael@0 329
michael@0 330 status_t readLock();
michael@0 331 status_t tryReadLock();
michael@0 332 status_t writeLock();
michael@0 333 status_t tryWriteLock();
michael@0 334 void unlock();
michael@0 335
michael@0 336 class AutoRLock {
michael@0 337 public:
michael@0 338 inline AutoRLock(RWLock& rwlock) : mLock(rwlock) { mLock.readLock(); }
michael@0 339 inline ~AutoRLock() { mLock.unlock(); }
michael@0 340 private:
michael@0 341 RWLock& mLock;
michael@0 342 };
michael@0 343
michael@0 344 class AutoWLock {
michael@0 345 public:
michael@0 346 inline AutoWLock(RWLock& rwlock) : mLock(rwlock) { mLock.writeLock(); }
michael@0 347 inline ~AutoWLock() { mLock.unlock(); }
michael@0 348 private:
michael@0 349 RWLock& mLock;
michael@0 350 };
michael@0 351
michael@0 352 private:
michael@0 353 // A RWLock cannot be copied
michael@0 354 RWLock(const RWLock&);
michael@0 355 RWLock& operator = (const RWLock&);
michael@0 356
michael@0 357 pthread_rwlock_t mRWLock;
michael@0 358 };
michael@0 359
michael@0 360 inline RWLock::RWLock() {
michael@0 361 pthread_rwlock_init(&mRWLock, NULL);
michael@0 362 }
michael@0 363 inline RWLock::RWLock(const char* name) {
michael@0 364 pthread_rwlock_init(&mRWLock, NULL);
michael@0 365 }
michael@0 366 inline RWLock::RWLock(int type, const char* name) {
michael@0 367 if (type == SHARED) {
michael@0 368 pthread_rwlockattr_t attr;
michael@0 369 pthread_rwlockattr_init(&attr);
michael@0 370 pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
michael@0 371 pthread_rwlock_init(&mRWLock, &attr);
michael@0 372 pthread_rwlockattr_destroy(&attr);
michael@0 373 } else {
michael@0 374 pthread_rwlock_init(&mRWLock, NULL);
michael@0 375 }
michael@0 376 }
michael@0 377 inline RWLock::~RWLock() {
michael@0 378 pthread_rwlock_destroy(&mRWLock);
michael@0 379 }
michael@0 380 inline status_t RWLock::readLock() {
michael@0 381 return -pthread_rwlock_rdlock(&mRWLock);
michael@0 382 }
michael@0 383 inline status_t RWLock::tryReadLock() {
michael@0 384 return -pthread_rwlock_tryrdlock(&mRWLock);
michael@0 385 }
michael@0 386 inline status_t RWLock::writeLock() {
michael@0 387 return -pthread_rwlock_wrlock(&mRWLock);
michael@0 388 }
michael@0 389 inline status_t RWLock::tryWriteLock() {
michael@0 390 return -pthread_rwlock_trywrlock(&mRWLock);
michael@0 391 }
michael@0 392 inline void RWLock::unlock() {
michael@0 393 pthread_rwlock_unlock(&mRWLock);
michael@0 394 }
michael@0 395
michael@0 396 #endif // HAVE_PTHREADS
michael@0 397
michael@0 398 /*****************************************************************************/
michael@0 399
michael@0 400 /*
michael@0 401 * Condition variable class. The implementation is system-dependent.
michael@0 402 *
michael@0 403 * Condition variables are paired up with mutexes. Lock the mutex,
michael@0 404 * call wait(), then either re-wait() if things aren't quite what you want,
michael@0 405 * or unlock the mutex and continue. All threads calling wait() must
michael@0 406 * use the same mutex for a given Condition.
michael@0 407 */
michael@0 408 class Condition {
michael@0 409 public:
michael@0 410 enum {
michael@0 411 PRIVATE = 0,
michael@0 412 SHARED = 1
michael@0 413 };
michael@0 414
michael@0 415 Condition();
michael@0 416 Condition(int type);
michael@0 417 ~Condition();
michael@0 418 // Wait on the condition variable. Lock the mutex before calling.
michael@0 419 status_t wait(Mutex& mutex);
michael@0 420 // same with relative timeout
michael@0 421 status_t waitRelative(Mutex& mutex, nsecs_t reltime);
michael@0 422 // Signal the condition variable, allowing one thread to continue.
michael@0 423 void signal();
michael@0 424 // Signal the condition variable, allowing all threads to continue.
michael@0 425 void broadcast();
michael@0 426
michael@0 427 private:
michael@0 428 #if defined(HAVE_PTHREADS)
michael@0 429 pthread_cond_t mCond;
michael@0 430 #else
michael@0 431 void* mState;
michael@0 432 #endif
michael@0 433 };
michael@0 434
michael@0 435 #if defined(HAVE_PTHREADS)
michael@0 436
michael@0 437 inline Condition::Condition() {
michael@0 438 pthread_cond_init(&mCond, NULL);
michael@0 439 }
michael@0 440 inline Condition::Condition(int type) {
michael@0 441 if (type == SHARED) {
michael@0 442 pthread_condattr_t attr;
michael@0 443 pthread_condattr_init(&attr);
michael@0 444 pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
michael@0 445 pthread_cond_init(&mCond, &attr);
michael@0 446 pthread_condattr_destroy(&attr);
michael@0 447 } else {
michael@0 448 pthread_cond_init(&mCond, NULL);
michael@0 449 }
michael@0 450 }
michael@0 451 inline Condition::~Condition() {
michael@0 452 pthread_cond_destroy(&mCond);
michael@0 453 }
michael@0 454 inline status_t Condition::wait(Mutex& mutex) {
michael@0 455 return -pthread_cond_wait(&mCond, &mutex.mMutex);
michael@0 456 }
michael@0 457 inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
michael@0 458 #if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
michael@0 459 struct timespec ts;
michael@0 460 ts.tv_sec = reltime/1000000000;
michael@0 461 ts.tv_nsec = reltime%1000000000;
michael@0 462 return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts);
michael@0 463 #else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
michael@0 464 struct timespec ts;
michael@0 465 #if defined(HAVE_POSIX_CLOCKS)
michael@0 466 clock_gettime(CLOCK_REALTIME, &ts);
michael@0 467 #else // HAVE_POSIX_CLOCKS
michael@0 468 // we don't support the clocks here.
michael@0 469 struct timeval t;
michael@0 470 gettimeofday(&t, NULL);
michael@0 471 ts.tv_sec = t.tv_sec;
michael@0 472 ts.tv_nsec= t.tv_usec*1000;
michael@0 473 #endif // HAVE_POSIX_CLOCKS
michael@0 474 ts.tv_sec += reltime/1000000000;
michael@0 475 ts.tv_nsec+= reltime%1000000000;
michael@0 476 if (ts.tv_nsec >= 1000000000) {
michael@0 477 ts.tv_nsec -= 1000000000;
michael@0 478 ts.tv_sec += 1;
michael@0 479 }
michael@0 480 return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
michael@0 481 #endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
michael@0 482 }
michael@0 483 inline void Condition::signal() {
michael@0 484 pthread_cond_signal(&mCond);
michael@0 485 }
michael@0 486 inline void Condition::broadcast() {
michael@0 487 pthread_cond_broadcast(&mCond);
michael@0 488 }
michael@0 489
michael@0 490 #endif // HAVE_PTHREADS
michael@0 491
michael@0 492 /*****************************************************************************/
michael@0 493
michael@0 494 /*
michael@0 495 * This is our spiffy thread object!
michael@0 496 */
michael@0 497
michael@0 498 class Thread : virtual public RefBase
michael@0 499 {
michael@0 500 public:
michael@0 501 // Create a Thread object, but doesn't create or start the associated
michael@0 502 // thread. See the run() method.
michael@0 503 Thread(bool canCallJava = true);
michael@0 504 virtual ~Thread();
michael@0 505
michael@0 506 // Start the thread in threadLoop() which needs to be implemented.
michael@0 507 virtual status_t run( const char* name = 0,
michael@0 508 int32_t priority = PRIORITY_DEFAULT,
michael@0 509 size_t stack = 0);
michael@0 510
michael@0 511 // Ask this object's thread to exit. This function is asynchronous, when the
michael@0 512 // function returns the thread might still be running. Of course, this
michael@0 513 // function can be called from a different thread.
michael@0 514 virtual void requestExit();
michael@0 515
michael@0 516 // Good place to do one-time initializations
michael@0 517 virtual status_t readyToRun();
michael@0 518
michael@0 519 // Call requestExit() and wait until this object's thread exits.
michael@0 520 // BE VERY CAREFUL of deadlocks. In particular, it would be silly to call
michael@0 521 // this function from this object's thread. Will return WOULD_BLOCK in
michael@0 522 // that case.
michael@0 523 status_t requestExitAndWait();
michael@0 524
michael@0 525 // Wait until this object's thread exits. Returns immediately if not yet running.
michael@0 526 // Do not call from this object's thread; will return WOULD_BLOCK in that case.
michael@0 527 status_t join();
michael@0 528
michael@0 529 protected:
michael@0 530 // exitPending() returns true if requestExit() has been called.
michael@0 531 bool exitPending() const;
michael@0 532
michael@0 533 private:
michael@0 534 // Derived class must implement threadLoop(). The thread starts its life
michael@0 535 // here. There are two ways of using the Thread object:
michael@0 536 // 1) loop: if threadLoop() returns true, it will be called again if
michael@0 537 // requestExit() wasn't called.
michael@0 538 // 2) once: if threadLoop() returns false, the thread will exit upon return.
michael@0 539 virtual bool threadLoop() = 0;
michael@0 540
michael@0 541 private:
michael@0 542 Thread& operator=(const Thread&);
michael@0 543 static int _threadLoop(void* user);
michael@0 544 const bool mCanCallJava;
michael@0 545 // always hold mLock when reading or writing
michael@0 546 thread_id_t mThread;
michael@0 547 mutable Mutex mLock;
michael@0 548 Condition mThreadExitedCondition;
michael@0 549 status_t mStatus;
michael@0 550 // note that all accesses of mExitPending and mRunning need to hold mLock
michael@0 551 volatile bool mExitPending;
michael@0 552 volatile bool mRunning;
michael@0 553 sp<Thread> mHoldSelf;
michael@0 554 #if HAVE_ANDROID_OS
michael@0 555 int mTid;
michael@0 556 #endif
michael@0 557 };
michael@0 558
michael@0 559
michael@0 560 }; // namespace android
michael@0 561
michael@0 562 #endif // __cplusplus
michael@0 563
michael@0 564 #endif // _LIBS_UTILS_THREADS_H

mercurial