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 // ---------------------------------------------------------------------------
32 namespace android {
33 // ---------------------------------------------------------------------------
34 
35 class 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  */
43 class Mutex {
44 public:
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:
Autolock(Mutex & mutex)76         inline Autolock(Mutex& mutex) : mLock(mutex)  { mLock.lock(); }
Autolock(Mutex * mutex)77         inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
~Autolock()78         inline ~Autolock() { mLock.unlock(); }
79     private:
80         Mutex& mLock;
81     };
82 
83 private:
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 
Mutex()102 inline Mutex::Mutex() {
103     pthread_mutex_init(&mMutex, NULL);
104 }
Mutex(const char * name)105 inline Mutex::Mutex(__attribute__((unused)) const char* name) {
106     pthread_mutex_init(&mMutex, NULL);
107 }
Mutex(int type,const char * name)108 inline 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 }
~Mutex()119 inline Mutex::~Mutex() {
120     pthread_mutex_destroy(&mMutex);
121 }
lock()122 inline status_t Mutex::lock() {
123     return -pthread_mutex_lock(&mMutex);
124 }
unlock()125 inline void Mutex::unlock() {
126     pthread_mutex_unlock(&mMutex);
127 }
tryLock()128 inline status_t Mutex::tryLock() {
129     return -pthread_mutex_trylock(&mMutex);
130 }
131 #if HAVE_ANDROID_OS
timedLock(nsecs_t timeoutNs)132 inline 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 
151 typedef Mutex::Autolock AutoMutex;
152 
153 // ---------------------------------------------------------------------------
154 }; // namespace android
155 // ---------------------------------------------------------------------------
156 
157 #endif // _LIBS_UTILS_MUTEX_H
158