|
@@ -209,31 +209,38 @@ typedef struct GraphLockable { } GraphLockable;
|
|
|
* unlocked. TSA_ASSERT_SHARED() makes sure that the following calls know that
|
|
|
* we hold the lock while unlocking is left unchecked.
|
|
|
*/
|
|
|
-static inline GraphLockable * TSA_ASSERT_SHARED(graph_lock) TSA_NO_TSA coroutine_fn
|
|
|
+static inline GraphLockable * TSA_ACQUIRE_SHARED(graph_lock) coroutine_fn
|
|
|
graph_lockable_auto_lock(GraphLockable *x)
|
|
|
{
|
|
|
bdrv_graph_co_rdlock();
|
|
|
return x;
|
|
|
}
|
|
|
|
|
|
-static inline void TSA_NO_TSA coroutine_fn
|
|
|
-graph_lockable_auto_unlock(GraphLockable *x)
|
|
|
+static inline void TSA_RELEASE_SHARED(graph_lock) coroutine_fn
|
|
|
+graph_lockable_auto_unlock(GraphLockable **x)
|
|
|
{
|
|
|
bdrv_graph_co_rdunlock();
|
|
|
}
|
|
|
|
|
|
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GraphLockable, graph_lockable_auto_unlock)
|
|
|
+#define GRAPH_AUTO_UNLOCK __attribute__((cleanup(graph_lockable_auto_unlock)))
|
|
|
|
|
|
+/*
|
|
|
+ * @var is only used to break the loop after the first iteration.
|
|
|
+ * @unlock_var can't be unlocked and then set to NULL because TSA wants the lock
|
|
|
+ * to be held at the start of every iteration of the loop.
|
|
|
+ */
|
|
|
#define WITH_GRAPH_RDLOCK_GUARD_(var) \
|
|
|
- for (g_autoptr(GraphLockable) var = graph_lockable_auto_lock(GML_OBJ_()); \
|
|
|
+ for (GraphLockable *unlock_var GRAPH_AUTO_UNLOCK = \
|
|
|
+ graph_lockable_auto_lock(GML_OBJ_()), \
|
|
|
+ *var = unlock_var; \
|
|
|
var; \
|
|
|
- graph_lockable_auto_unlock(var), var = NULL)
|
|
|
+ var = NULL)
|
|
|
|
|
|
#define WITH_GRAPH_RDLOCK_GUARD() \
|
|
|
WITH_GRAPH_RDLOCK_GUARD_(glue(graph_lockable_auto, __COUNTER__))
|
|
|
|
|
|
#define GRAPH_RDLOCK_GUARD(x) \
|
|
|
- g_autoptr(GraphLockable) \
|
|
|
+ GraphLockable * GRAPH_AUTO_UNLOCK \
|
|
|
glue(graph_lockable_auto, __COUNTER__) G_GNUC_UNUSED = \
|
|
|
graph_lockable_auto_lock(GML_OBJ_())
|
|
|
|