blob: 09b938e5b1bdb0fb78cf097539b8115c91867106 [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
James E. King, III82ae9572017-08-05 12:23:54 -040023#include <thrift/stdcxx.h>
Bryan Duxburyc58c9e82011-09-01 16:52:56 +000024#include <boost/noncopyable.hpp>
Jim King9de9b1f2015-04-30 16:03:34 -040025#include <stdint.h>
boz19cee902007-09-22 23:08:11 +000026
Konrad Grochowski16a23a62014-11-13 15:33:38 +010027namespace apache {
28namespace thrift {
29namespace concurrency {
Marc Slemko66949872006-07-15 01:52:39 +000030
David Reiss7a2065d2010-03-09 05:20:04 +000031#ifndef THRIFT_NO_CONTENTION_PROFILING
32
33/**
34 * Determines if the Thrift Mutex and ReadWriteMutex classes will attempt to
35 * profile their blocking acquire methods. If this value is set to non-zero,
36 * Thrift will attempt to invoke the callback once every profilingSampleRate
37 * times. However, as the sampling is not synchronized the rate is not
38 * guranateed, and could be subject to big bursts and swings. Please ensure
39 * your sampling callback is as performant as your application requires.
40 *
41 * The callback will get called with the wait time taken to lock the mutex in
42 * usec and a (void*) that uniquely identifies the Mutex (or ReadWriteMutex)
43 * being locked.
44 *
45 * The enableMutexProfiling() function is unsynchronized; calling this function
46 * while profiling is already enabled may result in race conditions. On
47 * architectures where a pointer assignment is atomic, this is safe but there
48 * is no guarantee threads will agree on a single callback within any
49 * particular time period.
50 */
51typedef void (*MutexWaitCallback)(const void* id, int64_t waitTimeMicros);
Konrad Grochowski16a23a62014-11-13 15:33:38 +010052void enableMutexProfiling(int32_t profilingSampleRate, MutexWaitCallback callback);
David Reiss7a2065d2010-03-09 05:20:04 +000053
54#endif
55
Mark Sleef5f2be42006-09-05 21:05:31 +000056/**
James E. King, III00d42522017-04-04 09:32:45 -040057 * NOTE: All mutex implementations throw an exception on failure. See each
58 * specific implementation to understand the exception type(s) used.
59 */
60
61/**
Mark Sleef5f2be42006-09-05 21:05:31 +000062 * A simple mutex class
63 *
Mark Sleef5f2be42006-09-05 21:05:31 +000064 * @version $Id:$
65 */
Marc Slemko66949872006-07-15 01:52:39 +000066class Mutex {
Konrad Grochowski16a23a62014-11-13 15:33:38 +010067public:
David Reissc6dab612008-06-10 22:55:13 +000068 typedef void (*Initializer)(void*);
69
70 Mutex(Initializer init = DEFAULT_INITIALIZER);
boz19cee902007-09-22 23:08:11 +000071 virtual ~Mutex() {}
James E. King, III00d42522017-04-04 09:32:45 -040072
Marc Slemko66949872006-07-15 01:52:39 +000073 virtual void lock() const;
boz5362e702007-08-15 20:55:36 +000074 virtual bool trylock() const;
David Reiss4e19f192010-03-09 05:19:59 +000075 virtual bool timedlock(int64_t milliseconds) const;
Marc Slemko66949872006-07-15 01:52:39 +000076 virtual void unlock() const;
77
David Reissb9db49c2010-03-09 05:19:30 +000078 void* getUnderlyingImpl() const;
79
James E. King, III00d42522017-04-04 09:32:45 -040080 // If you attempt to use one of these and it fails to link, it means
81 // your version of pthreads does not support it - try another one.
David Reissc6dab612008-06-10 22:55:13 +000082 static void ADAPTIVE_INITIALIZER(void*);
James E. King, III00d42522017-04-04 09:32:45 -040083 static void DEFAULT_INITIALIZER(void*);
84 static void ERRORCHECK_INITIALIZER(void*);
David Reissc6dab612008-06-10 22:55:13 +000085 static void RECURSIVE_INITIALIZER(void*);
David Reissc6dab612008-06-10 22:55:13 +000086
Konrad Grochowski16a23a62014-11-13 15:33:38 +010087private:
Marc Slemko66949872006-07-15 01:52:39 +000088 class impl;
James E. King, III82ae9572017-08-05 12:23:54 -040089 stdcxx::shared_ptr<impl> impl_;
Marc Slemko66949872006-07-15 01:52:39 +000090};
91
bozcce81842007-07-06 22:27:52 +000092class ReadWriteMutex {
93public:
94 ReadWriteMutex();
boz19cee902007-09-22 23:08:11 +000095 virtual ~ReadWriteMutex() {}
bozcce81842007-07-06 22:27:52 +000096
97 // these get the lock and block until it is done successfully
98 virtual void acquireRead() const;
99 virtual void acquireWrite() const;
100
101 // these attempt to get the lock, returning false immediately if they fail
102 virtual bool attemptRead() const;
103 virtual bool attemptWrite() const;
104
105 // this releases both read and write locks
106 virtual void release() const;
David Reiss0c90f6f2008-02-06 22:18:40 +0000107
bozcce81842007-07-06 22:27:52 +0000108private:
109 class impl;
James E. King, III82ae9572017-08-05 12:23:54 -0400110 stdcxx::shared_ptr<impl> impl_;
bozcce81842007-07-06 22:27:52 +0000111};
112
Roger Meier3fc48192011-12-11 21:05:35 +0000113/**
114 * A ReadWriteMutex that guarantees writers will not be starved by readers:
115 * When a writer attempts to acquire the mutex, all new readers will be
116 * blocked from acquiring the mutex until the writer has acquired and
117 * released it. In some operating systems, this may already be guaranteed
118 * by a regular ReadWriteMutex.
119 */
120class NoStarveReadWriteMutex : public ReadWriteMutex {
121public:
122 NoStarveReadWriteMutex();
123
124 virtual void acquireRead() const;
125 virtual void acquireWrite() const;
126
127private:
128 Mutex mutex_;
129 mutable volatile bool writerWaiting_;
130};
131
Bryan Duxburyc58c9e82011-09-01 16:52:56 +0000132class Guard : boost::noncopyable {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100133public:
David Reiss4e19f192010-03-09 05:19:59 +0000134 Guard(const Mutex& value, int64_t timeout = 0) : mutex_(&value) {
135 if (timeout == 0) {
136 value.lock();
137 } else if (timeout < 0) {
138 if (!value.trylock()) {
139 mutex_ = NULL;
140 }
141 } else {
142 if (!value.timedlock(timeout)) {
143 mutex_ = NULL;
144 }
145 }
Marc Slemko66949872006-07-15 01:52:39 +0000146 }
bozcce81842007-07-06 22:27:52 +0000147 ~Guard() {
David Reiss4e19f192010-03-09 05:19:59 +0000148 if (mutex_) {
149 mutex_->unlock();
150 }
151 }
152
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100153 operator bool() const { return (mutex_ != NULL); }
Marc Slemko66949872006-07-15 01:52:39 +0000154
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100155private:
David Reiss4e19f192010-03-09 05:19:59 +0000156 const Mutex* mutex_;
Marc Slemko66949872006-07-15 01:52:39 +0000157};
158
David Reisse96fa552010-03-09 05:19:37 +0000159// Can be used as second argument to RWGuard to make code more readable
160// as to whether we're doing acquireRead() or acquireWrite().
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100161enum RWGuardType { RW_READ = 0, RW_WRITE = 1 };
David Reisse96fa552010-03-09 05:19:37 +0000162
Jake Farrell2e9f5102011-09-09 04:32:36 +0000163class RWGuard : boost::noncopyable {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100164public:
165 RWGuard(const ReadWriteMutex& value, bool write = false) : rw_mutex_(value) {
166 if (write) {
167 rw_mutex_.acquireWrite();
168 } else {
169 rw_mutex_.acquireRead();
David Reiss0c90f6f2008-02-06 22:18:40 +0000170 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100171 }
David Reisse96fa552010-03-09 05:19:37 +0000172
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100173 RWGuard(const ReadWriteMutex& value, RWGuardType type) : rw_mutex_(value) {
174 if (type == RW_WRITE) {
175 rw_mutex_.acquireWrite();
176 } else {
177 rw_mutex_.acquireRead();
David Reisse96fa552010-03-09 05:19:37 +0000178 }
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100179 }
180 ~RWGuard() { rw_mutex_.release(); }
181
182private:
183 const ReadWriteMutex& rw_mutex_;
David Reiss0c90f6f2008-02-06 22:18:40 +0000184};
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100185}
186}
187} // apache::thrift::concurrency
Marc Slemko66949872006-07-15 01:52:39 +0000188
Mark Sleef5f2be42006-09-05 21:05:31 +0000189#endif // #ifndef _THRIFT_CONCURRENCY_MUTEX_H_