SmpError SThread::run(const char* name, int priority, int stack) { SMutex::Autolock _l(mLock); if (mRunning) { // thread already started return SMP_INVALID_REQ; } // reset status and exitPending to their default value, so we can // try again after an error happened (either below, or in readyToRun()) mStatus = SMP_OK; mExitPending = false; mThread = thread_id_t(-1); mRunning = true; bool res; res = createRawThreadEtc(_threadLoop, this, name, priority, stack, &mThread); if (res == false) { mStatus = SMP_UNKNOWN; // something happened! mRunning = false; mThread = thread_id_t(-1); return SMP_UNKNOWN; } // Do not refer to mStatus here: The thread is already running (may, in fact // already have exited with a valid mStatus result). The SMP_OK indication // here merely indicates successfully starting the thread and does not // imply successful termination/execution. return SMP_OK; // Exiting scope of mLock is a memory barrier and allows new thread to run }
SThread::SThread() :mThread(thread_id_t(-1)), mStatus(SMP_OK), mExitPending(false), mRunning(false) { }
status_t Thread::run(const char* name, int32_t priority, size_t stack) { Mutex::Autolock _l(mLock); if (mRunning) { // thread already started return INVALID_OPERATION; } // reset status and exitPending to their default value, so we can // try again after an error happened (either below, or in readyToRun()) mStatus = NO_ERROR; mExitPending = false; mThread = thread_id_t(-1); // hold a strong reference on ourself mHoldSelf = this; mRunning = true; bool res; if (mCanCallJava) { res = createThreadEtc(_threadLoop, this, name, priority, stack, &mThread); } else { res = androidCreateRawThreadEtc(_threadLoop, this, name, priority, stack, &mThread); } if (res == false) { mStatus = UNKNOWN_ERROR; // something happened! mRunning = false; mThread = thread_id_t(-1); mHoldSelf.clear(); // "this" may have gone away after this. return UNKNOWN_ERROR; } // Do not refer to mStatus here: The thread is already running (may, in fact // already have exited with a valid mStatus result). The NO_ERROR indication // here merely indicates successfully starting the thread and does not // imply successful termination/execution. return NO_ERROR; // Exiting scope of mLock is a memory barrier and allows new thread to run }
Thread::Thread(bool canCallJava) : mCanCallJava(canCallJava), mThread(thread_id_t(-1)), mLock("Thread::mLock"), mStatus(NO_ERROR), mExitPending(false), mRunning(false) { }
int Thread::_threadLoop(void* user) { Thread* const self = static_cast<Thread*>(user); sp<Thread> strong(self->mHoldSelf); wp<Thread> weak(strong); self->mHoldSelf.clear(); #if HAVE_ANDROID_OS // this is very useful for debugging with gdb self->mTid = gettid(); #endif bool first = true; do { bool result; if (first) { first = false; self->mStatus = self->readyToRun(); result = (self->mStatus == NO_ERROR); if (result && !self->mExitPending) { // Binder threads (and maybe others) rely on threadLoop // running at least once after a successful ::readyToRun() // (unless, of course, the thread has already been asked to exit // at that point). // This is because threads are essentially used like this: // (new ThreadSubclass())->run(); // The caller therefore does not retain a strong reference to // the thread and the thread would simply disappear after the // successful ::readyToRun() call instead of entering the // threadLoop at least once. result = self->threadLoop(); } } else { result = self->threadLoop(); } if (result == false || self->mExitPending) { self->mExitPending = true; self->mLock.lock(); self->mRunning = false; self->mThreadExitedCondition.broadcast(); self->mThread = thread_id_t(-1); // thread id could be reused self->mLock.unlock(); break; } // Release our strong reference, to let a chance to the thread // to die a peaceful death. strong.clear(); // And immediately, re-acquire a strong reference for the next loop strong = weak.promote(); } while(strong != 0); return 0; }
Thread::Thread(bool canCallJava) : mCanCallJava(canCallJava), mThread(thread_id_t(-1)), mLock("Thread::mLock"), mStatus(NO_ERROR), mExitPending(false), mRunning(false) #ifdef HAVE_ANDROID_OS , mTid(-1) #endif { }
int SThread::_threadLoop(void* user) { SThread* const self = static_cast<SThread*>(user); bool first = true; bool result; do { if (first) { first = false; self->mStatus = self->readyToRun(); result = self->mStatus == SMP_OK; if (result && !self->exitPending()) { // Binder threads (and maybe others) rely on threadLoop // running at least once after a successful ::readyToRun() // (unless, of course, the thread has already been asked to exit // at that point). // This is because threads are essentially used like this: // (new ThreadSubclass())->run(); // The caller therefore does not retain a strong reference to // the thread and the thread would simply disappear after the // successful ::readyToRun() call instead of entering the // threadLoop at least once. result = self->threadLoop(); } } else { result = self->threadLoop(); } // establish a scope for mLock { SMutex::Autolock _l(self->mLock); if (result == false || self->mExitPending) { self->mExitPending = true; self->mRunning = false; // clear thread ID so that requestExitAndWait() does not exit if // called by a new thread using the same thread ID as this one. self->mThread = thread_id_t(-1); // note that interested observers blocked in requestExitAndWait are // awoken by broadcast, but blocked on mLock until break exits scope self->mThreadExitedCondition.broadcast(); break; } } } while (true); return 0; }