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