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