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