[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 01/35] WIP: coroutine: annotate coroutine with clang
From: |
Marc-André Lureau |
Subject: |
[Qemu-devel] [PATCH 01/35] WIP: coroutine: annotate coroutine with clang thread safety attributes |
Date: |
Wed, 5 Jul 2017 00:03:12 +0200 |
It is possible to use clang -Wthread-safety to do some basic coroutine
checks:
http://lists.llvm.org/pipermail/cfe-dev/2017-June/054372.html
https://clang.llvm.org/docs/ThreadSafetyAnalysis.html
This will basically check that you don't call accidentally a coroutine
function from a non-coroutine, as this may crash at run time if the
coroutine function yields.
I had to modify clang to support annotations on typedef and function
pointers, and check some function assignments/arguments. The end
result is quire far from ready for upstream review, but could serve as
basis for more checks or work. (https://github.com/elmarco/clang
qemu-ta branch)
Signed-off-by: Marc-André Lureau <address@hidden>
---
include/qemu/coroutine.h | 31 ++++++++++++++++++++++++++++++-
util/coroutine-sigaltstack.c | 2 ++
util/coroutine-ucontext.c | 2 ++
util/coroutine-win32.c | 2 ++
util/qemu-coroutine.c | 2 ++
5 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
index a4509bd977..35ff394f51 100644
--- a/include/qemu/coroutine.h
+++ b/include/qemu/coroutine.h
@@ -28,6 +28,34 @@
* These functions are re-entrant and may be used outside the global mutex.
*/
+/* clang thread-safety attributes, used for static analysis of the CFG */
+#if defined(__clang__) && (!defined(SWIG))
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#else
+#define THREAD_ANNOTATION_ATTRIBUTE__(x)
+#endif
+
+#define TAA_ROLE \
+ THREAD_ANNOTATION_ATTRIBUTE__(capability("role"))
+
+#define TAA_REQUIRES(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
+
+#define TAA_ACQUIRE(R) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(R))
+
+#define TAA_RELEASE(R) \
+ THREAD_ANNOTATION_ATTRIBUTE__(release_capability(R))
+
+#define TAA_NO_ANALYSYS \
+ THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
+typedef int TAA_ROLE coroutine_role;
+extern coroutine_role _coroutine_fn;
+
+static inline void co_role_acquire(coroutine_role R) TAA_ACQUIRE(R)
TAA_NO_ANALYSYS {}
+static inline void co_role_release(coroutine_role R) TAA_RELEASE(R)
TAA_NO_ANALYSYS {}
+
/**
* Mark a function that executes in coroutine context
*
@@ -42,7 +70,8 @@
* ....
* }
*/
-#define coroutine_fn
+
+#define coroutine_fn TAA_REQUIRES(_coroutine_fn)
typedef struct Coroutine Coroutine;
diff --git a/util/coroutine-sigaltstack.c b/util/coroutine-sigaltstack.c
index f6fc49a0e5..05d1a378d1 100644
--- a/util/coroutine-sigaltstack.c
+++ b/util/coroutine-sigaltstack.c
@@ -98,7 +98,9 @@ static void coroutine_bootstrap(CoroutineSigAltStack *self,
Coroutine *co)
}
while (true) {
+ co_role_acquire(_coroutine_fn);
co->entry(co->entry_arg);
+ co_role_release(_coroutine_fn);
qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
}
}
diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c
index 6621f3f692..010fbaedf1 100644
--- a/util/coroutine-ucontext.c
+++ b/util/coroutine-ucontext.c
@@ -76,7 +76,9 @@ static void coroutine_trampoline(int i0, int i1)
}
while (true) {
+ co_role_acquire(_coroutine_fn);
co->entry(co->entry_arg);
+ co_role_release(_coroutine_fn);
qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
}
}
diff --git a/util/coroutine-win32.c b/util/coroutine-win32.c
index de6bd4fd3e..75a3bed543 100644
--- a/util/coroutine-win32.c
+++ b/util/coroutine-win32.c
@@ -64,7 +64,9 @@ static void CALLBACK coroutine_trampoline(void *co_)
Coroutine *co = co_;
while (true) {
+ co_role_acquire(_coroutine_fn);
co->entry(co->entry_arg);
+ co_role_release(_coroutine_fn);
qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
}
}
diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c
index d6095c1d5a..efa0f20e69 100644
--- a/util/qemu-coroutine.c
+++ b/util/qemu-coroutine.c
@@ -25,6 +25,8 @@ enum {
POOL_BATCH_SIZE = 64,
};
+coroutine_role _coroutine_fn;
+
/** Free list to speed up creation */
static QSLIST_HEAD(, Coroutine) release_pool = QSLIST_HEAD_INITIALIZER(pool);
static unsigned int release_pool_size;
--
2.13.1.395.gf7b71de06