1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * QemuLockCnt implementation 4 * 5 * Copyright Red Hat, Inc. 2017 6 * 7 * Author: 8 * Paolo Bonzini <pbonzini@redhat.com> 9 * 10 */ 11 12 #ifndef QEMU_LOCKCNT_H 13 #define QEMU_LOCKCNT_H 14 15 #include "qemu/thread.h" 16 17 typedef struct QemuLockCnt QemuLockCnt; 18 19 struct QemuLockCnt { 20 #ifndef CONFIG_LINUX 21 QemuMutex mutex; 22 #endif 23 unsigned count; 24 }; 25 26 /** 27 * qemu_lockcnt_init: initialize a QemuLockcnt 28 * @lockcnt: the lockcnt to initialize 29 * 30 * Initialize lockcnt's counter to zero and prepare its mutex 31 * for usage. 32 */ 33 void qemu_lockcnt_init(QemuLockCnt *lockcnt); 34 35 /** 36 * qemu_lockcnt_destroy: destroy a QemuLockcnt 37 * @lockcnt: the lockcnt to destruct 38 * 39 * Destroy lockcnt's mutex. 40 */ 41 void qemu_lockcnt_destroy(QemuLockCnt *lockcnt); 42 43 /** 44 * qemu_lockcnt_inc: increment a QemuLockCnt's counter 45 * @lockcnt: the lockcnt to operate on 46 * 47 * If the lockcnt's count is zero, wait for critical sections 48 * to finish and increment lockcnt's count to 1. If the count 49 * is not zero, just increment it. 50 * 51 * Because this function can wait on the mutex, it must not be 52 * called while the lockcnt's mutex is held by the current thread. 53 * For the same reason, qemu_lockcnt_inc can also contribute to 54 * AB-BA deadlocks. This is a sample deadlock scenario:: 55 * 56 * thread 1 thread 2 57 * ------------------------------------------------------- 58 * qemu_lockcnt_lock(&lc1); 59 * qemu_lockcnt_lock(&lc2); 60 * qemu_lockcnt_inc(&lc2); 61 * qemu_lockcnt_inc(&lc1); 62 */ 63 void qemu_lockcnt_inc(QemuLockCnt *lockcnt); 64 65 /** 66 * qemu_lockcnt_dec: decrement a QemuLockCnt's counter 67 * @lockcnt: the lockcnt to operate on 68 */ 69 void qemu_lockcnt_dec(QemuLockCnt *lockcnt); 70 71 /** 72 * qemu_lockcnt_dec_and_lock: decrement a QemuLockCnt's counter and 73 * possibly lock it. 74 * @lockcnt: the lockcnt to operate on 75 * 76 * Decrement lockcnt's count. If the new count is zero, lock 77 * the mutex and return true. Otherwise, return false. 78 */ 79 bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt); 80 81 /** 82 * qemu_lockcnt_dec_if_lock: possibly decrement a QemuLockCnt's counter and 83 * lock it. 84 * @lockcnt: the lockcnt to operate on 85 * 86 * If the count is 1, decrement the count to zero, lock 87 * the mutex and return true. Otherwise, return false. 88 */ 89 bool qemu_lockcnt_dec_if_lock(QemuLockCnt *lockcnt); 90 91 /** 92 * qemu_lockcnt_lock: lock a QemuLockCnt's mutex. 93 * @lockcnt: the lockcnt to operate on 94 * 95 * Remember that concurrent visits are not blocked unless the count is 96 * also zero. You can use qemu_lockcnt_count to check for this inside a 97 * critical section. 98 */ 99 void qemu_lockcnt_lock(QemuLockCnt *lockcnt); 100 101 /** 102 * qemu_lockcnt_unlock: release a QemuLockCnt's mutex. 103 * @lockcnt: the lockcnt to operate on. 104 */ 105 void qemu_lockcnt_unlock(QemuLockCnt *lockcnt); 106 107 /** 108 * qemu_lockcnt_inc_and_unlock: combined unlock/increment on a QemuLockCnt. 109 * @lockcnt: the lockcnt to operate on. 110 * 111 * This is the same as 112 * 113 * qemu_lockcnt_unlock(lockcnt); 114 * qemu_lockcnt_inc(lockcnt); 115 * 116 * but more efficient. 117 */ 118 void qemu_lockcnt_inc_and_unlock(QemuLockCnt *lockcnt); 119 120 /** 121 * qemu_lockcnt_count: query a LockCnt's count. 122 * @lockcnt: the lockcnt to query. 123 * 124 * Note that the count can change at any time. Still, while the 125 * lockcnt is locked, one can usefully check whether the count 126 * is non-zero. 127 */ 128 unsigned qemu_lockcnt_count(QemuLockCnt *lockcnt); 129 130 #endif 131