1 /* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
22 
23 #ifndef NDB_SAFE_MUTEX_HPP
24 #define NDB_SAFE_MUTEX_HPP
25 
26 #include <ndb_global.h>
27 #include <thr_cond.h>
28 #include <thr_mutex.h>
29 #include <assert.h>
30 #include <ndb_types.h>
31 #include <NdbOut.hpp>
32 
33 #define JAM_FILE_ID 220
34 
35 
36 /*
37  * Recursive mutex with recursion limit >= 1.  Intended for debugging.
38  * One should rewrite caller code until limit 1 works.
39  *
40  * The implementation uses a default mutex.  If limit is > 1 or debug
41  * is specified then a recursive mutex is simulated.  Operating system
42  * recursive mutex (if any) is not used.  The simulation is several
43  * times slower.  There is a unit test testSafeMutex.
44  *
45  * The caller currently is multi-threaded disk data.  Here it is easy
46  * to verify that the mutex is released within a time-slice.
47  */
48 
49 class SafeMutex {
50   const char* const m_name;
51   const Uint32 m_limit; // error if usage exceeds this
52   const bool m_debug;   // use recursive implementation even for limit 1
53   const bool m_simple;
54   native_mutex_t m_mutex;
55   native_cond_t m_cond;
56   my_thread_t m_owner;
57   bool m_initdone;
58   Uint32 m_level;
59   Uint32 m_usage;       // max level used so far
60   int m_errcode;
61   int m_errline;
62   int err(int errcode, int errline);
63   friend class NdbOut& operator<<(NdbOut&, const SafeMutex&);
64 
65 public:
SafeMutex(const char * name,Uint32 limit,bool debug)66   SafeMutex(const char* name, Uint32 limit, bool debug) :
67     m_name(name),
68     m_limit(limit),
69     m_debug(debug),
70     m_simple(!(limit > 1 || debug))
71   {
72     assert(m_limit >= 1),
73     m_owner = 0;        // wl4391_todo assuming numeric non-zero
74     m_initdone = false;
75     m_level = 0;
76     m_usage = 0;
77     m_errcode = 0;
78     m_errline = 0;
79   };
~SafeMutex()80   ~SafeMutex() {
81     if (m_initdone)
82       (void)destroy();
83   }
84 
85   enum {
86     // caller must crash on any error - recovery is not possible
87     ErrState = -101,    // user error
88     ErrLevel = -102,    // level exceeded limit
89     ErrOwner = -103,    // unlock when not owner
90     ErrNolock = -104    // unlock when no lock
91   };
92   int create();
93   int destroy();
94   int lock();
95   int unlock();
96 
97 private:
98   int lock_impl();
99   int unlock_impl();
100 };
101 
102 
103 #undef JAM_FILE_ID
104 
105 #endif
106