Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec0f1f67 authored by Mathias Agopian's avatar Mathias Agopian
Browse files

implement Mutex and Condition with pthread instead of calling futex directly.

internally pthread uses futex. the implementation consists of simple inlines
there are no implementation files anymore.
parent 98b34b3f
Loading
Loading
Loading
Loading
+0 −60
Original line number Diff line number Diff line
/*
 * 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
+86 −4
Original line number Diff line number Diff line
@@ -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!
+4 −1
Original line number Diff line number Diff line
@@ -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");
+2 −12
Original line number Diff line number Diff line
@@ -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

+4 −286
Original line number Diff line number Diff line
@@ -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!
 */
Loading