diff --git a/include/utils/threads.h b/include/utils/threads.h index e0cb66423..5c0396596 100644 --- a/include/utils/threads.h +++ b/include/utils/threads.h @@ -21,6 +21,10 @@ #include #include +#if defined(HAVE_PTHREADS) +# include +#endif + // ------------------------------------------------------------------ // C API @@ -176,6 +180,8 @@ inline thread_id_t getThreadId() { return androidGetThreadId(); } +/*****************************************************************************/ + /* * Simple mutex class. The implementation is system-dependent. * @@ -212,11 +218,38 @@ private: // A mutex cannot be copied Mutex(const Mutex&); Mutex& operator = (const Mutex&); - void _init(); +#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() { + 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 @@ -225,6 +258,7 @@ private: typedef Mutex::Autolock AutoMutex; +/*****************************************************************************/ /* * Condition variable class. The implementation is system-dependent. @@ -240,9 +274,6 @@ public: ~Condition(); // Wait on the condition variable. Lock the mutex before calling. status_t wait(Mutex& mutex); - // Wait on the condition variable until the given time. Lock the mutex - // before calling. - status_t wait(Mutex& mutex, nsecs_t abstime); // same with relative timeout status_t waitRelative(Mutex& mutex, nsecs_t reltime); // Signal the condition variable, allowing one thread to continue. @@ -251,9 +282,60 @@ public: 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! diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk index 3f5cb85ac..59409a2bf 100644 --- a/libs/utils/Android.mk +++ b/libs/utils/Android.mk @@ -51,13 +51,6 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= $(commonSources) -ifeq ($(HOST_OS),linux) -# Use the futex based mutex and condition variable -# implementation from android-arm because it's shared mem safe - LOCAL_SRC_FILES += \ - futex_synchro.c -endif - LOCAL_MODULE:= libutils LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) @@ -87,15 +80,13 @@ LOCAL_SRC_FILES:= \ BackupHelpers.cpp ifeq ($(TARGET_OS),linux) -# Use the futex based mutex and condition variable -# implementation from android-arm because it's shared mem safe -LOCAL_SRC_FILES += futex_synchro.c LOCAL_LDLIBS += -lrt -ldl endif LOCAL_C_INCLUDES += \ external/zlib \ external/icu4c/common + LOCAL_LDLIBS += -lpthread LOCAL_SHARED_LIBRARIES := \ @@ -106,8 +97,7 @@ LOCAL_SHARED_LIBRARIES := \ ifneq ($(TARGET_SIMULATOR),true) ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86) # This is needed on x86 to bring in dl_iterate_phdr for CallStack.cpp -LOCAL_SHARED_LIBRARIES += \ - libdl +LOCAL_SHARED_LIBRARIES += libdl endif # linux-x86 endif # sim diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp index 9287c0bba..4036c497a 100644 --- a/libs/utils/Threads.cpp +++ b/libs/utils/Threads.cpp @@ -38,10 +38,6 @@ # define HAVE_CREATETHREAD // Cygwin, vs. HAVE__BEGINTHREADEX for MinGW #endif -#if defined(HAVE_FUTEX) -#include -#endif - #if defined(HAVE_PRCTL) #include #endif @@ -56,10 +52,6 @@ using namespace android; // ---------------------------------------------------------------------------- #if defined(HAVE_PTHREADS) -#if 0 -#pragma mark - -#pragma mark PTHREAD -#endif // ---------------------------------------------------------------------------- /* @@ -163,10 +155,6 @@ android_thread_id_t androidGetThreadId() // ---------------------------------------------------------------------------- #elif defined(HAVE_WIN32_THREADS) -#if 0 -#pragma mark - -#pragma mark WIN32_THREADS -#endif // ---------------------------------------------------------------------------- /* @@ -252,11 +240,6 @@ android_thread_id_t androidGetThreadId() // ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark Common Thread functions -#endif - int androidCreateThread(android_thread_func_t fn, void* arg) { return createThreadEtc(fn, arg); @@ -294,109 +277,9 @@ namespace android { * =========================================================================== */ -#if 0 -#pragma mark - -#pragma mark Mutex -#endif - -#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX) -/* - * Simple pthread wrapper. - */ - -Mutex::Mutex() -{ - _init(); -} - -Mutex::Mutex(const char* name) -{ - // XXX: name not used for now - _init(); -} - -void Mutex::_init() -{ - pthread_mutex_t* pMutex = new pthread_mutex_t; - pthread_mutex_init(pMutex, NULL); - mState = pMutex; -} - -Mutex::~Mutex() -{ - delete (pthread_mutex_t*) mState; -} - -status_t Mutex::lock() -{ - int res; - while ((res=pthread_mutex_lock((pthread_mutex_t*) mState)) == EINTR) ; - return -res; -} - -void Mutex::unlock() -{ - pthread_mutex_unlock((pthread_mutex_t*) mState); -} - -status_t Mutex::tryLock() -{ - int res; - while ((res=pthread_mutex_trylock((pthread_mutex_t*) mState)) == EINTR) ; - return -res; -} - -#elif defined(HAVE_FUTEX) -#if 0 -#pragma mark - -#endif - -#define STATE ((futex_mutex_t*) (&mState)) - -Mutex::Mutex() -{ - _init(); -} - -Mutex::Mutex(const char* name) -{ - _init(); -} - -void -Mutex::_init() -{ - futex_mutex_init(STATE); -} - -Mutex::~Mutex() -{ -} - -status_t Mutex::lock() -{ - int res; - while ((res=futex_mutex_lock(STATE, FUTEX_WAIT_INFINITE)) == EINTR) ; - return -res; -} - -void Mutex::unlock() -{ - futex_mutex_unlock(STATE); -} - -status_t Mutex::tryLock() -{ - int res; - while ((res=futex_mutex_trylock(STATE)) == EINTR) ; - return -res; -} -#undef STATE - +#if defined(HAVE_PTHREADS) +// implemented as inlines in threads.h #elif defined(HAVE_WIN32_THREADS) -#if 0 -#pragma mark - -#endif Mutex::Mutex() { @@ -456,161 +339,9 @@ status_t Mutex::tryLock() * =========================================================================== */ -#if 0 -#pragma mark - -#pragma mark Condition -#endif - -#if defined(HAVE_PTHREADS) && !defined(HAVE_FUTEX) - -/* - * Constructor. This is a simple pthread wrapper. - */ -Condition::Condition() -{ - pthread_cond_t* pCond = new pthread_cond_t; - - pthread_cond_init(pCond, NULL); - mState = pCond; -} - -/* - * Destructor. - */ -Condition::~Condition() -{ - pthread_cond_destroy((pthread_cond_t*) mState); - delete (pthread_cond_t*) mState; -} - -/* - * Wait on a condition variable. Lock the mutex before calling. - */ - -status_t Condition::wait(Mutex& mutex) -{ - assert(mutex.mState != NULL); - - int cc; - while ((cc = pthread_cond_wait((pthread_cond_t*)mState, - (pthread_mutex_t*) mutex.mState)) == EINTR) ; - return -cc; -} - -status_t Condition::wait(Mutex& mutex, nsecs_t abstime) -{ - assert(mutex.mState != NULL); - - struct timespec ts; - ts.tv_sec = abstime/1000000000; - ts.tv_nsec = abstime-(ts.tv_sec*1000000000); - - int cc; - while ((cc = pthread_cond_timedwait((pthread_cond_t*)mState, - (pthread_mutex_t*) mutex.mState, &ts)) == EINTR) ; - return -cc; -} - -status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) -{ - return wait(mutex, systemTime()+reltime); -} - -/* - * Signal the condition variable, allowing one thread to continue. - */ -void Condition::signal() -{ - pthread_cond_signal((pthread_cond_t*) mState); -} - -/* - * Signal the condition variable, allowing all threads to continue. - */ -void Condition::broadcast() -{ - pthread_cond_broadcast((pthread_cond_t*) mState); -} - -#elif defined(HAVE_FUTEX) -#if 0 -#pragma mark - -#endif - -#define STATE ((futex_cond_t*) (&mState)) - -/* - * Constructor. This is a simple pthread wrapper. - */ -Condition::Condition() -{ - futex_cond_init(STATE); -} - -/* - * Destructor. - */ -Condition::~Condition() -{ -} - -/* - * Wait on a condition variable. Lock the mutex before calling. - */ - -status_t Condition::wait(Mutex& mutex) -{ - assert(mutex.mState != NULL); - - int res; - while ((res = futex_cond_wait(STATE, - (futex_mutex_t*)(&mutex.mState), FUTEX_WAIT_INFINITE)) == -EINTR) ; - - return -res; -} - -status_t Condition::wait(Mutex& mutex, nsecs_t abstime) -{ - nsecs_t reltime = abstime - systemTime(); - if (reltime <= 0) return true; - return waitRelative(mutex, reltime); -} - -status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) -{ - assert(mutex.mState != NULL); - int res; - unsigned msec = ns2ms(reltime); - if(msec == 0) - return true; - // This code will not time out at the correct time if interrupted by signals - while ((res = futex_cond_wait(STATE, - (futex_mutex_t*)(&mutex.mState), msec)) == -EINTR) ; - return res; -} - -/* - * Signal the condition variable, allowing one thread to continue. - */ -void Condition::signal() -{ - futex_cond_signal(STATE); -} - -/* - * Signal the condition variable, allowing all threads to continue. - */ -void Condition::broadcast() -{ - futex_cond_broadcast(STATE); -} - -#undef STATE - +#if defined(HAVE_PTHREADS) +// implemented as inlines in threads.h #elif defined(HAVE_WIN32_THREADS) -#if 0 -#pragma mark - -#endif /* * Windows doesn't have a condition variable solution. It's possible @@ -753,14 +484,6 @@ status_t Condition::wait(Mutex& mutex) return ((WinCondition*)mState)->wait(condState, hMutex, NULL); } -status_t Condition::wait(Mutex& mutex, nsecs_t abstime) -{ - WinCondition* condState = (WinCondition*) mState; - HANDLE hMutex = (HANDLE) mutex.mState; - - return ((WinCondition*)mState)->wait(condState, hMutex, &abstime); -} - status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) { return wait(mutex, systemTime()+reltime); @@ -841,11 +564,6 @@ void Condition::broadcast() // ---------------------------------------------------------------------------- -#if 0 -#pragma mark - -#pragma mark Thread::Thread -#endif - /* * This is our thread object! */ diff --git a/libs/utils/futex_synchro.c b/libs/utils/futex_synchro.c deleted file mode 100644 index ab48c6921..000000000 --- a/libs/utils/futex_synchro.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#include -#include - -#include -#include - -#include - -#include - - -// This futex glue code is need on desktop linux, but is already part of bionic. -#if !defined(HAVE_FUTEX_WRAPPERS) - -#include -#include -typedef unsigned int u32; -#define asmlinkage -#define __user -#include -#include - - -int futex (int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3) -{ - int err = syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3); - return err == 0 ? 0 : -errno; -} - -int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout) -{ - return futex((int*)ftx, FUTEX_WAIT, val, timeout, NULL, 0); -} - -int __futex_wake(volatile void *ftx, int count) -{ - return futex((int*)ftx, FUTEX_WAKE, count, NULL, NULL, 0); -} - -int __atomic_cmpxchg(int old, int _new, volatile int *ptr) -{ - return android_atomic_cmpxchg(old, _new, ptr); -} - -int __atomic_swap(int _new, volatile int *ptr) -{ - return android_atomic_swap(_new, ptr); -} - -int __atomic_dec(volatile int *ptr) -{ - return android_atomic_dec(ptr); -} - -#else // !defined(__arm__) - -int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout); -int __futex_wake(volatile void *ftx, int count); - -int __atomic_cmpxchg(int old, int _new, volatile int *ptr); -int __atomic_swap(int _new, volatile int *ptr); -int __atomic_dec(volatile int *ptr); - -#endif // !defined(HAVE_FUTEX_WRAPPERS) - - -// lock states -// -// 0: unlocked -// 1: locked, no waiters -// 2: locked, maybe waiters - -void futex_mutex_init(futex_mutex_t *m) -{ - m->value = 0; -} - -int futex_mutex_lock(futex_mutex_t *m, unsigned msec) -{ - if(__atomic_cmpxchg(0, 1, &m->value) == 0) { - return 0; - } - if(msec == FUTEX_WAIT_INFINITE) { - while(__atomic_swap(2, &m->value) != 0) { - __futex_wait(&m->value, 2, 0); - } - } else { - struct timespec ts; - ts.tv_sec = msec / 1000; - ts.tv_nsec = (msec % 1000) * 1000000; - while(__atomic_swap(2, &m->value) != 0) { - if(__futex_wait(&m->value, 2, &ts) == -ETIMEDOUT) { - return -1; - } - } - } - return 0; -} - -int futex_mutex_trylock(futex_mutex_t *m) -{ - if(__atomic_cmpxchg(0, 1, &m->value) == 0) { - return 0; - } - return -1; -} - -void futex_mutex_unlock(futex_mutex_t *m) -{ - if(__atomic_dec(&m->value) != 1) { - m->value = 0; - __futex_wake(&m->value, 1); - } -} - -/* XXX *technically* there is a race condition that could allow - * XXX a signal to be missed. If thread A is preempted in _wait() - * XXX after unlocking the mutex and before waiting, and if other - * XXX threads call signal or broadcast UINT_MAX times (exactly), - * XXX before thread A is scheduled again and calls futex_wait(), - * XXX then the signal will be lost. - */ - -void futex_cond_init(futex_cond_t *c) -{ - c->value = 0; -} - -int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec) -{ - if(msec == FUTEX_WAIT_INFINITE){ - int oldvalue = c->value; - futex_mutex_unlock(m); - __futex_wait(&c->value, oldvalue, 0); - futex_mutex_lock(m, FUTEX_WAIT_INFINITE); - return 0; - } else { - int oldvalue = c->value; - struct timespec ts; - ts.tv_sec = msec / 1000; - ts.tv_nsec = (msec % 1000) * 1000000; - futex_mutex_unlock(m); - const int err = __futex_wait(&c->value, oldvalue, &ts); - futex_mutex_lock(m, FUTEX_WAIT_INFINITE); - return err; - } -} - -void futex_cond_signal(futex_cond_t *c) -{ - __atomic_dec(&c->value); - __futex_wake(&c->value, 1); -} - -void futex_cond_broadcast(futex_cond_t *c) -{ - __atomic_dec(&c->value); - __futex_wake(&c->value, INT_MAX); -} -