blob: 3ee5c6b8e4185e81891e7008db50a8046aa2a850 [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Mark Slee9f0c6512007-02-28 23:58:26 +000019
Mark Sleef5f2be42006-09-05 21:05:31 +000020#ifndef _THRIFT_CONCURRENCY_MUTEX_H_
21#define _THRIFT_CONCURRENCY_MUTEX_H_ 1
Marc Slemko66949872006-07-15 01:52:39 +000022
boz19cee902007-09-22 23:08:11 +000023#include <boost/shared_ptr.hpp>
boz19cee902007-09-22 23:08:11 +000024
T Jake Lucianib5e62212009-01-31 22:36:20 +000025namespace apache { namespace thrift { namespace concurrency {
Marc Slemko66949872006-07-15 01:52:39 +000026
David Reiss7a2065d2010-03-09 05:20:04 +000027#ifndef THRIFT_NO_CONTENTION_PROFILING
28
29/**
30 * Determines if the Thrift Mutex and ReadWriteMutex classes will attempt to
31 * profile their blocking acquire methods. If this value is set to non-zero,
32 * Thrift will attempt to invoke the callback once every profilingSampleRate
33 * times. However, as the sampling is not synchronized the rate is not
34 * guranateed, and could be subject to big bursts and swings. Please ensure
35 * your sampling callback is as performant as your application requires.
36 *
37 * The callback will get called with the wait time taken to lock the mutex in
38 * usec and a (void*) that uniquely identifies the Mutex (or ReadWriteMutex)
39 * being locked.
40 *
41 * The enableMutexProfiling() function is unsynchronized; calling this function
42 * while profiling is already enabled may result in race conditions. On
43 * architectures where a pointer assignment is atomic, this is safe but there
44 * is no guarantee threads will agree on a single callback within any
45 * particular time period.
46 */
47typedef void (*MutexWaitCallback)(const void* id, int64_t waitTimeMicros);
48void enableMutexProfiling(int32_t profilingSampleRate,
49 MutexWaitCallback callback);
50
51#endif
52
Mark Sleef5f2be42006-09-05 21:05:31 +000053/**
54 * A simple mutex class
55 *
Mark Sleef5f2be42006-09-05 21:05:31 +000056 * @version $Id:$
57 */
Marc Slemko66949872006-07-15 01:52:39 +000058class Mutex {
Marc Slemko66949872006-07-15 01:52:39 +000059 public:
David Reissc6dab612008-06-10 22:55:13 +000060 typedef void (*Initializer)(void*);
61
62 Mutex(Initializer init = DEFAULT_INITIALIZER);
boz19cee902007-09-22 23:08:11 +000063 virtual ~Mutex() {}
Marc Slemko66949872006-07-15 01:52:39 +000064 virtual void lock() const;
boz5362e702007-08-15 20:55:36 +000065 virtual bool trylock() const;
David Reiss4e19f192010-03-09 05:19:59 +000066 virtual bool timedlock(int64_t milliseconds) const;
Marc Slemko66949872006-07-15 01:52:39 +000067 virtual void unlock() const;
68
David Reissb9db49c2010-03-09 05:19:30 +000069 void* getUnderlyingImpl() const;
70
David Reissc6dab612008-06-10 22:55:13 +000071 static void DEFAULT_INITIALIZER(void*);
David Reissc6dab612008-06-10 22:55:13 +000072 static void ADAPTIVE_INITIALIZER(void*);
David Reissc6dab612008-06-10 22:55:13 +000073 static void RECURSIVE_INITIALIZER(void*);
David Reissc6dab612008-06-10 22:55:13 +000074
Marc Slemko66949872006-07-15 01:52:39 +000075 private:
boz19cee902007-09-22 23:08:11 +000076
Marc Slemko66949872006-07-15 01:52:39 +000077 class impl;
yunfang14542962007-10-03 22:59:41 +000078 boost::shared_ptr<impl> impl_;
Marc Slemko66949872006-07-15 01:52:39 +000079};
80
bozcce81842007-07-06 22:27:52 +000081class ReadWriteMutex {
82public:
83 ReadWriteMutex();
boz19cee902007-09-22 23:08:11 +000084 virtual ~ReadWriteMutex() {}
bozcce81842007-07-06 22:27:52 +000085
86 // these get the lock and block until it is done successfully
87 virtual void acquireRead() const;
88 virtual void acquireWrite() const;
89
90 // these attempt to get the lock, returning false immediately if they fail
91 virtual bool attemptRead() const;
92 virtual bool attemptWrite() const;
93
94 // this releases both read and write locks
95 virtual void release() const;
David Reiss0c90f6f2008-02-06 22:18:40 +000096
bozcce81842007-07-06 22:27:52 +000097private:
boz19cee902007-09-22 23:08:11 +000098
bozcce81842007-07-06 22:27:52 +000099 class impl;
yunfang14542962007-10-03 22:59:41 +0000100 boost::shared_ptr<impl> impl_;
bozcce81842007-07-06 22:27:52 +0000101};
102
Mark Slee85287d32007-07-09 19:50:30 +0000103class Guard {
David Reiss0c90f6f2008-02-06 22:18:40 +0000104 public:
David Reiss4e19f192010-03-09 05:19:59 +0000105 Guard(const Mutex& value, int64_t timeout = 0) : mutex_(&value) {
106 if (timeout == 0) {
107 value.lock();
108 } else if (timeout < 0) {
109 if (!value.trylock()) {
110 mutex_ = NULL;
111 }
112 } else {
113 if (!value.timedlock(timeout)) {
114 mutex_ = NULL;
115 }
116 }
Marc Slemko66949872006-07-15 01:52:39 +0000117 }
bozcce81842007-07-06 22:27:52 +0000118 ~Guard() {
David Reiss4e19f192010-03-09 05:19:59 +0000119 if (mutex_) {
120 mutex_->unlock();
121 }
122 }
123
124 operator bool() const {
125 return (mutex_ != NULL);
Marc Slemko66949872006-07-15 01:52:39 +0000126 }
127
128 private:
David Reiss4e19f192010-03-09 05:19:59 +0000129 const Mutex* mutex_;
Marc Slemko66949872006-07-15 01:52:39 +0000130};
131
David Reisse96fa552010-03-09 05:19:37 +0000132// Can be used as second argument to RWGuard to make code more readable
133// as to whether we're doing acquireRead() or acquireWrite().
134enum RWGuardType {
135 RW_READ = 0,
Roger Meier0069cc42010-10-13 18:10:18 +0000136 RW_WRITE = 1
David Reisse96fa552010-03-09 05:19:37 +0000137};
138
139
yunfanga36f5db2007-07-14 01:23:05 +0000140class RWGuard {
David Reiss0c90f6f2008-02-06 22:18:40 +0000141 public:
David Reisse96fa552010-03-09 05:19:37 +0000142 RWGuard(const ReadWriteMutex& value, bool write = false)
143 : rw_mutex_(value) {
yunfanga36f5db2007-07-14 01:23:05 +0000144 if (write) {
145 rw_mutex_.acquireWrite();
David Reiss96d23882007-07-26 21:10:32 +0000146 } else {
yunfanga36f5db2007-07-14 01:23:05 +0000147 rw_mutex_.acquireRead();
David Reiss96d23882007-07-26 21:10:32 +0000148 }
David Reiss0c90f6f2008-02-06 22:18:40 +0000149 }
David Reisse96fa552010-03-09 05:19:37 +0000150
151 RWGuard(const ReadWriteMutex& value, RWGuardType type)
152 : rw_mutex_(value) {
153 if (type == RW_WRITE) {
154 rw_mutex_.acquireWrite();
155 } else {
156 rw_mutex_.acquireRead();
157 }
158 }
yunfanga36f5db2007-07-14 01:23:05 +0000159 ~RWGuard() {
160 rw_mutex_.release();
David Reiss0c90f6f2008-02-06 22:18:40 +0000161 }
162 private:
boz19cee902007-09-22 23:08:11 +0000163 const ReadWriteMutex& rw_mutex_;
David Reiss0c90f6f2008-02-06 22:18:40 +0000164};
yunfanga36f5db2007-07-14 01:23:05 +0000165
Marc Slemko66949872006-07-15 01:52:39 +0000166
David Reisseaa61e42007-12-20 21:42:05 +0000167// A little hack to prevent someone from trying to do "Guard(m);"
David Reissbe378f22009-05-07 00:41:18 +0000168// Such a use is invalid because the temporary Guard object is
169// destoryed at the end of the line, releasing the lock.
David Reisseaa61e42007-12-20 21:42:05 +0000170// Sorry for polluting the global namespace, but I think it's worth it.
171#define Guard(m) incorrect_use_of_Guard(m)
172#define RWGuard(m) incorrect_use_of_RWGuard(m)
173
174
T Jake Lucianib5e62212009-01-31 22:36:20 +0000175}}} // apache::thrift::concurrency
Marc Slemko66949872006-07-15 01:52:39 +0000176
Mark Sleef5f2be42006-09-05 21:05:31 +0000177#endif // #ifndef _THRIFT_CONCURRENCY_MUTEX_H_