xref: /openbmc/qemu/include/qemu/lockcnt.h (revision 0ae50e8e)
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