1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _LIBS_UTILS_MUTEX_H
18#define _LIBS_UTILS_MUTEX_H
19
20#include <stdint.h>
21#include <sys/types.h>
22#include <time.h>
23
24#if !defined(_WIN32)
25# include <pthread.h>
26#endif
27
28#include <utils/Errors.h>
29#include <utils/Timers.h>
30
31// ---------------------------------------------------------------------------
32namespace android {
33// ---------------------------------------------------------------------------
34
35class Condition;
36
37/*
38 * Simple mutex class.  The implementation is system-dependent.
39 *
40 * The mutex must be unlocked by the thread that locked it.  They are not
41 * recursive, i.e. the same thread can't lock it multiple times.
42 */
43class Mutex {
44public:
45    enum {
46        PRIVATE = 0,
47        SHARED = 1
48    };
49
50                Mutex();
51                Mutex(const char* name);
52                Mutex(int type, const char* name = NULL);
53                ~Mutex();
54
55    // lock or unlock the mutex
56    status_t    lock();
57    void        unlock();
58
59    // lock if possible; returns 0 on success, error otherwise
60    status_t    tryLock();
61
62#if HAVE_ANDROID_OS
63    // lock the mutex, but don't wait longer than timeoutMilliseconds.
64    // Returns 0 on success, TIMED_OUT for failure due to timeout expiration.
65    //
66    // OSX doesn't have pthread_mutex_timedlock() or equivalent. To keep
67    // capabilities consistent across host OSes, this method is only available
68    // when building Android binaries.
69    status_t    timedLock(nsecs_t timeoutMilliseconds);
70#endif
71
72    // Manages the mutex automatically. It'll be locked when Autolock is
73    // constructed and released when Autolock goes out of scope.
74    class Autolock {
75    public:
76        inline Autolock(Mutex& mutex) : mLock(mutex)  { mLock.lock(); }
77        inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
78        inline ~Autolock() { mLock.unlock(); }
79    private:
80        Mutex& mLock;
81    };
82
83private:
84    friend class Condition;
85
86    // A mutex cannot be copied
87                Mutex(const Mutex&);
88    Mutex&      operator = (const Mutex&);
89
90#if !defined(_WIN32)
91    pthread_mutex_t mMutex;
92#else
93    void    _init();
94    void*   mState;
95#endif
96};
97
98// ---------------------------------------------------------------------------
99
100#if !defined(_WIN32)
101
102inline Mutex::Mutex() {
103    pthread_mutex_init(&mMutex, NULL);
104}
105inline Mutex::Mutex(__attribute__((unused)) const char* name) {
106    pthread_mutex_init(&mMutex, NULL);
107}
108inline Mutex::Mutex(int type, __attribute__((unused)) const char* name) {
109    if (type == SHARED) {
110        pthread_mutexattr_t attr;
111        pthread_mutexattr_init(&attr);
112        pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
113        pthread_mutex_init(&mMutex, &attr);
114        pthread_mutexattr_destroy(&attr);
115    } else {
116        pthread_mutex_init(&mMutex, NULL);
117    }
118}
119inline Mutex::~Mutex() {
120    pthread_mutex_destroy(&mMutex);
121}
122inline status_t Mutex::lock() {
123    return -pthread_mutex_lock(&mMutex);
124}
125inline void Mutex::unlock() {
126    pthread_mutex_unlock(&mMutex);
127}
128inline status_t Mutex::tryLock() {
129    return -pthread_mutex_trylock(&mMutex);
130}
131#if HAVE_ANDROID_OS
132inline status_t Mutex::timedLock(nsecs_t timeoutNs) {
133    const struct timespec ts = {
134        /* .tv_sec = */ static_cast<time_t>(timeoutNs / 1000000000),
135        /* .tv_nsec = */ static_cast<long>(timeoutNs % 1000000000),
136    };
137    return -pthread_mutex_timedlock(&mMutex, &ts);
138}
139#endif
140
141#endif // !defined(_WIN32)
142
143// ---------------------------------------------------------------------------
144
145/*
146 * Automatic mutex.  Declare one of these at the top of a function.
147 * When the function returns, it will go out of scope, and release the
148 * mutex.
149 */
150
151typedef Mutex::Autolock AutoMutex;
152
153// ---------------------------------------------------------------------------
154}; // namespace android
155// ---------------------------------------------------------------------------
156
157#endif // _LIBS_UTILS_MUTEX_H
158