Merge change 6898
* changes: implement Mutex and Condition with pthread instead of calling futex directly.
This commit is contained in:
@@ -1,60 +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.
|
||||
*/
|
||||
|
||||
#ifndef _FUTEX_SYNCHRO_H
|
||||
#define _FUTEX_SYNCHRO_H
|
||||
|
||||
#ifndef HAVE_FUTEX
|
||||
#error "HAVE_FUTEX not defined"
|
||||
#endif
|
||||
|
||||
#define FUTEX_WAIT_INFINITE (0)
|
||||
|
||||
typedef struct futex_mutex_t futex_mutex_t;
|
||||
|
||||
struct futex_mutex_t
|
||||
{
|
||||
volatile int value;
|
||||
};
|
||||
|
||||
typedef struct futex_cond_t futex_cond_t;
|
||||
|
||||
struct futex_cond_t
|
||||
{
|
||||
volatile int value;
|
||||
};
|
||||
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void futex_mutex_init(futex_mutex_t *m);
|
||||
int futex_mutex_lock(futex_mutex_t *m, unsigned msec);
|
||||
void futex_mutex_unlock(futex_mutex_t *m);
|
||||
int futex_mutex_trylock(futex_mutex_t *m);
|
||||
|
||||
void futex_cond_init(futex_cond_t *c);
|
||||
int futex_cond_wait(futex_cond_t *c, futex_mutex_t *m, unsigned msec);
|
||||
void futex_cond_signal(futex_cond_t *c);
|
||||
void futex_cond_broadcast(futex_cond_t *c);
|
||||
|
||||
#if __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _FUTEX_SYNCHRO_H
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#if defined(HAVE_PTHREADS)
|
||||
# include <pthread.h>
|
||||
#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!
|
||||
|
||||
@@ -111,7 +111,10 @@ MessageList::value_type MessageQueue::waitMessage(nsecs_t timeout)
|
||||
if (nextEventTime > 0) {
|
||||
// we're about to wait, flush the binder command buffer
|
||||
IPCThreadState::self()->flushCommands();
|
||||
mCondition.wait(mLock, nextEventTime);
|
||||
const nsecs_t reltime = nextEventTime - systemTime();
|
||||
if (reltime > 0) {
|
||||
mCondition.waitRelative(mLock, reltime);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//LOGD("going to wait");
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -38,10 +38,6 @@
|
||||
# define HAVE_CREATETHREAD // Cygwin, vs. HAVE__BEGINTHREADEX for MinGW
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_FUTEX)
|
||||
#include <private/utils/futex_synchro.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PRCTL)
|
||||
#include <sys/prctl.h>
|
||||
#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!
|
||||
*/
|
||||
|
||||
@@ -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 <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <private/utils/futex_synchro.h>
|
||||
|
||||
|
||||
// This futex glue code is need on desktop linux, but is already part of bionic.
|
||||
#if !defined(HAVE_FUTEX_WRAPPERS)
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
typedef unsigned int u32;
|
||||
#define asmlinkage
|
||||
#define __user
|
||||
#include <linux/futex.h>
|
||||
#include <utils/Atomic.h>
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user