1 /* 2 Bacula(R) - The Network Backup Solution 3 4 Copyright (C) 2000-2020 Kern Sibbald 5 6 The original author of Bacula is Kern Sibbald, with contributions 7 from many others, a complete list can be found in the file AUTHORS. 8 9 You may use this file and others of this release according to the 10 license defined in the LICENSE file, which includes the Affero General 11 Public License, v3.0 ("AGPLv3") and some additional permissions and 12 terms pursuant to its AGPLv3 Section 7. 13 14 This notice must be preserved when any source code is 15 conveyed and/or propagated. 16 17 Bacula(R) is a registered trademark of Kern Sibbald. 18 */ 19 20 #ifndef LOCKMGR_H 21 #define LOCKMGR_H 1 22 23 #include "mutex_list.h" /* Manage mutex with priority in a central place */ 24 25 /* 26 * P and V op that don't use the lock manager (for memory allocation or on 27 * win32) 28 */ 29 void lmgr_p(pthread_mutex_t *m); 30 void lmgr_v(pthread_mutex_t *m); 31 32 /* 33 * Get integer thread id 34 */ 35 intptr_t bthread_get_thread_id(); 36 37 /* 38 * Set the Thread Id of the current thread to limit I/O operations 39 */ 40 int bthread_change_uid(uid_t uid, gid_t gid); 41 42 #ifdef USE_LOCKMGR 43 44 typedef struct bthread_mutex_t 45 { 46 pthread_mutex_t mutex; 47 int priority; 48 } bthread_mutex_t; 49 50 /* 51 * We decide that a thread won't lock more than LMGR_MAX_LOCK at the same time 52 */ 53 #define LMGR_MAX_LOCK 32 54 55 int bthread_cond_wait_p(pthread_cond_t *cond, 56 bthread_mutex_t *mutex, 57 const char *file="*unknown*", int line=0); 58 59 int bthread_cond_timedwait_p(pthread_cond_t *cond, 60 bthread_mutex_t *mutex, 61 const struct timespec * abstime, 62 const char *file="*unknown*", int line=0); 63 64 /* Same with real pthread_mutex_t */ 65 int bthread_cond_wait_p(pthread_cond_t *cond, 66 pthread_mutex_t *mutex, 67 const char *file="*unknown*", int line=0); 68 69 int bthread_cond_timedwait_p(pthread_cond_t *cond, 70 pthread_mutex_t *mutex, 71 const struct timespec * abstime, 72 const char *file="*unknown*", int line=0); 73 74 /* Replacement of pthread_mutex_lock() but with real pthread_mutex_t */ 75 int bthread_mutex_lock_p(pthread_mutex_t *m, 76 const char *file="*unknown*", int line=0); 77 78 /* Replacement for pthread_mutex_unlock() but with real pthread_mutex_t */ 79 int bthread_mutex_unlock_p(pthread_mutex_t *m, 80 const char *file="*unknown*", int line=0); 81 82 /* Replacement of pthread_mutex_lock() */ 83 int bthread_mutex_lock_p(bthread_mutex_t *m, 84 const char *file="*unknown*", int line=0); 85 86 /* Replacement of pthread_mutex_unlock() */ 87 int bthread_mutex_unlock_p(bthread_mutex_t *m, 88 const char *file="*unknown*", int line=0); 89 90 /* Test if this mutex is locked by the current thread 91 * 0 - not locked by the current thread 92 * 1 - locked by the current thread 93 */ 94 int lmgr_mutex_is_locked(void *m); 95 96 /* 97 * Use them when you want use your lock yourself (ie rwlock) 98 */ 99 100 /* Call before requesting the lock */ 101 void lmgr_pre_lock(void *m, int prio=0, 102 const char *file="*unknown*", int line=0); 103 104 /* Call after getting it */ 105 void lmgr_post_lock(); 106 107 /* Same as pre+post lock */ 108 void lmgr_do_lock(void *m, int prio=0, 109 const char *file="*unknown*", int line=0); 110 111 /* Call just before releasing the lock */ 112 void lmgr_do_unlock(void *m); 113 114 /* We use C++ mangling to make integration eaysier */ 115 int pthread_mutex_init(bthread_mutex_t *m, const pthread_mutexattr_t *attr); 116 int pthread_mutex_destroy(bthread_mutex_t *m); 117 118 void bthread_mutex_set_priority(bthread_mutex_t *m, int prio); 119 120 /* 121 * Each thread have to call this function to put a lmgr_thread_t object 122 * in the stack and be able to call mutex_lock/unlock 123 */ 124 void lmgr_init_thread(); 125 126 /* 127 * Know if the current thread is registred (used when we 128 * do not control thread creation) 129 */ 130 bool lmgr_thread_is_initialized(); 131 132 /* 133 * Call this function at the end of the thread 134 */ 135 void lmgr_cleanup_thread(); 136 137 /* 138 * Call this at the end of the program, it will release the 139 * global lock manager 140 */ 141 void lmgr_cleanup_main(); 142 143 /* 144 * Dump each lmgr_thread_t object to stdout 145 */ 146 void lmgr_dump(); 147 148 /* 149 * Search a deadlock 150 */ 151 bool lmgr_detect_deadlock(); 152 153 /* Bit flags */ 154 #define LMGR_EVENT_NONE 0 155 #define LMGR_EVENT_DUP 1 /* use strdup() to copy the comment (will set FREE) */ 156 #define LMGR_EVENT_FREE 2 /* use free() when overwriting/deleting the comment */ 157 #define LMGR_EVENT_INVALID 4 /* Used to mark the record invalid */ 158 159 /* 160 * Add event to the thread event list 161 */ 162 void lmgr_add_event_p(const char *comment, intptr_t user_data, int32_t flags, const char *file, int32_t line); 163 #define lmgr_add_event(c, u) lmgr_add_event_p(c, u, 0, __FILE__, __LINE__) 164 #define lmgr_add_event_flag(c, u, f) lmgr_add_event_p(c, u, (f), __FILE__, __LINE__) 165 166 /* 167 * Search a deadlock after a fatal signal 168 * no lock are granted, so the program must be 169 * stopped. 170 */ 171 bool lmgr_detect_deadlock_unlocked(); 172 173 /* 174 * This function will run your thread with lmgr_init_thread() and 175 * lmgr_cleanup_thread(). 176 */ 177 int lmgr_thread_create(pthread_t *thread, 178 const pthread_attr_t *attr, 179 void *(*start_routine)(void*), void *arg); 180 181 /* 182 * Can use SAFEKILL to check if the argument is a valid threadid 183 */ 184 int bthread_kill(pthread_t thread, int sig, 185 const char *file="*unknown*", int line=0); 186 187 #define BTHREAD_MUTEX_NO_PRIORITY {PTHREAD_MUTEX_INITIALIZER, 0} 188 #define BTHREAD_MUTEX_INITIALIZER BTHREAD_MUTEX_NO_PRIORITY 189 190 /* Define USE_LOCKMGR_PRIORITY to detect mutex wrong order */ 191 #ifdef USE_LOCKMGR_PRIORITY 192 # define BTHREAD_MUTEX_PRIORITY(p) {PTHREAD_MUTEX_INITIALIZER, p} 193 #else 194 # define BTHREAD_MUTEX_PRIORITY(p) BTHREAD_MUTEX_NO_PRIORITY 195 #endif 196 197 #define bthread_mutex_lock(x) bthread_mutex_lock_p(x, __FILE__, __LINE__) 198 #define bthread_mutex_unlock(x) bthread_mutex_unlock_p(x, __FILE__, __LINE__) 199 #define bthread_cond_wait(x,y) bthread_cond_wait_p(x,y, __FILE__, __LINE__) 200 #define bthread_cond_timedwait(x,y,z) bthread_cond_timedwait_p(x,y,z, __FILE__, __LINE__) 201 202 /* 203 * Define LOCKMGR_COMPLIANT to use real pthread functions 204 */ 205 #define real_P(x) lmgr_p(&(x)) 206 #define real_V(x) lmgr_v(&(x)) 207 208 #ifdef LOCKMGR_COMPLIANT 209 # define P(x) lmgr_p(&(x)) 210 # define pP(x) lmgr_p(x) 211 # define V(x) lmgr_v(&(x)) 212 # define pV(x) lmgr_v(x) 213 #else 214 # define P(x) bthread_mutex_lock_p(&(x), __FILE__, __LINE__) 215 # define pP(x) bthread_mutex_lock_p((x), __FILE__, __LINE__) 216 # define V(x) bthread_mutex_unlock_p(&(x), __FILE__, __LINE__) 217 # define pV(x) bthread_mutex_unlock_p((x), __FILE__, __LINE__) 218 # define pthread_create(a, b, c, d) lmgr_thread_create(a,b,c,d) 219 # define pthread_mutex_lock(x) bthread_mutex_lock(x) 220 # define pthread_mutex_unlock(x) bthread_mutex_unlock(x) 221 # define pthread_cond_wait(x,y) bthread_cond_wait(x,y) 222 # define pthread_cond_timedwait(x,y,z) bthread_cond_timedwait(x,y,z) 223 224 # ifdef USE_LOCKMGR_SAFEKILL 225 # define pthread_kill(a,b) bthread_kill((a),(b), __FILE__, __LINE__) 226 # endif 227 #endif 228 229 #else /* !USE_LOCKMGR */ 230 231 # define lmgr_detect_deadlock() 232 # define lmgr_add_event_p(c, u, f, l) 233 # define lmgr_add_event(c, u) 234 # define lmgr_dump() 235 # define lmgr_thread_is_initialized() (1) 236 # define lmgr_init_thread() 237 # define lmgr_cleanup_thread() 238 # define lmgr_pre_lock(m, prio, f, l) 239 # define lmgr_post_lock() 240 # define lmgr_do_lock(m, prio, f, l) 241 # define lmgr_do_unlock(m) 242 # define lmgr_cleanup_main() 243 # define bthread_mutex_set_priority(a,b) 244 # define bthread_mutex_lock(a) pthread_mutex_lock(a) 245 # define bthread_mutex_lock_p(a, f, l) pthread_mutex_lock(a) 246 # define bthread_mutex_unlock(a) pthread_mutex_unlock(a) 247 # define bthread_mutex_unlock_p(a, f, l) pthread_mutex_unlock(a) 248 # define lmgr_cond_wait(a,b) pthread_cond_wait(a,b) 249 # define lmgr_cond_timedwait(a,b,c) pthread_cond_timedwait(a,b,c) 250 # define bthread_mutex_t pthread_mutex_t 251 # define P(x) lmgr_p(&(x)) 252 # define pP(x) lmgr_p((x)) 253 # define V(x) lmgr_v(&(x)) 254 # define pV(x) lmgr_v((x)) 255 # define BTHREAD_MUTEX_PRIORITY(p) PTHREAD_MUTEX_INITIALIZER 256 # define BTHREAD_MUTEX_NO_PRIORITY PTHREAD_MUTEX_INITIALIZER 257 # define BTHREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER 258 # define lmgr_mutex_is_locked(m) (1) 259 # define bthread_cond_wait_p(w, x, y, z) pthread_cond_wait(w,x) 260 #endif /* USE_LOCKMGR */ 261 262 /* a very basic lock_guard implementation : 263 * Lock_guard is mostly usefull to garanty mutex unlocking. Also, it's exception safe. 264 * usage example: 265 * void foobar() 266 * { 267 * lock_guard protector(m_mutex); // m_mutex is locked 268 * // the following section is protected until the function exits and/or returns 269 * 270 * if (case == TRUE) 271 * { 272 * return; // when returning, m_mutex is unlocked 273 * } 274 * . 275 * . 276 * . 277 * 278 * // when the method exits, m_mutex is unlocked. 279 * } 280 */ 281 class lock_guard 282 { 283 public: 284 285 pthread_mutex_t &m_mutex; /* the class keeps a reference on the mutex*/ 286 lock_guard(pthread_mutex_t & mutex)287 explicit lock_guard(pthread_mutex_t &mutex) : m_mutex(mutex) 288 { 289 P(m_mutex); /* constructor locks the mutex*/ 290 } 291 ~lock_guard()292 ~lock_guard() 293 { 294 V(m_mutex); /* destructor unlocks the mutex*/ 295 } 296 }; 297 298 #endif /* LOCKMGR_H */ 299