master
h 130 lines 3.43 KB
Raw
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 HAVE_FUTEX
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