diff mbox series

[RFC,v3,1/8] eal: annotate spinlock and rwlock

Message ID 20220411110013.18624-2-david.marchand@redhat.com (mailing list archive)
State Deferred
Delegated to: David Marchand
Headers show
Series vhost lock annotations | expand

Commit Message

David Marchand April 11, 2022, 11 a.m. UTC
clang offers some thread safety checks, statically verifying that locks
are taken and released in the code.
To use those checks, the full code leading to taking or releasing locks
must be annotated with some attributes.

Wrap those attributes into our own set of macros.

rwlock and the "normal" spinlock are instrumented.

A component may enable this check by setting annotate_locks = true
in its meson.build.

Note: those checks might be of interest out of DPDK, but it
requires that the including application locks are annotated.
On the other hand, applications out there might have been using
those same checks.
To be on the safe side, keep this instrumentation under a
RTE_ANNOTATE_LOCKS internal build flag.

Signed-off-by: David Marchand <david.marchand@redhat.com>
---
Changes since RFC v2:
- fixed rwlock trylock,
- instrumented _tm spinlocks,
- aligned attribute names to clang,

---
 drivers/meson.build                    |  5 ++
 lib/eal/arm/include/rte_rwlock.h       |  4 ++
 lib/eal/arm/include/rte_spinlock.h     |  6 +++
 lib/eal/include/generic/rte_rwlock.h   | 27 +++++++++--
 lib/eal/include/generic/rte_spinlock.h | 40 ++++++++++-----
 lib/eal/include/meson.build            |  1 +
 lib/eal/include/rte_lock_annotations.h | 67 ++++++++++++++++++++++++++
 lib/eal/ppc/include/rte_rwlock.h       |  4 ++
 lib/eal/ppc/include/rte_spinlock.h     |  9 ++++
 lib/eal/x86/include/rte_rwlock.h       |  4 ++
 lib/eal/x86/include/rte_spinlock.h     |  9 ++++
 lib/meson.build                        |  5 ++
 12 files changed, 164 insertions(+), 17 deletions(-)
 create mode 100644 lib/eal/include/rte_lock_annotations.h

Comments

Maxime Coquelin April 21, 2022, 1:48 p.m. UTC | #1
Hi David,

On 4/11/22 13:00, David Marchand wrote:
> clang offers some thread safety checks, statically verifying that locks
> are taken and released in the code.
> To use those checks, the full code leading to taking or releasing locks
> must be annotated with some attributes.
> 
> Wrap those attributes into our own set of macros.
> 
> rwlock and the "normal" spinlock are instrumented.
> 
> A component may enable this check by setting annotate_locks = true
> in its meson.build.
> 
> Note: those checks might be of interest out of DPDK, but it
> requires that the including application locks are annotated.
> On the other hand, applications out there might have been using
> those same checks.
> To be on the safe side, keep this instrumentation under a
> RTE_ANNOTATE_LOCKS internal build flag.
> 
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
> Changes since RFC v2:
> - fixed rwlock trylock,
> - instrumented _tm spinlocks,
> - aligned attribute names to clang,
> 
> ---
>   drivers/meson.build                    |  5 ++
>   lib/eal/arm/include/rte_rwlock.h       |  4 ++
>   lib/eal/arm/include/rte_spinlock.h     |  6 +++
>   lib/eal/include/generic/rte_rwlock.h   | 27 +++++++++--
>   lib/eal/include/generic/rte_spinlock.h | 40 ++++++++++-----
>   lib/eal/include/meson.build            |  1 +
>   lib/eal/include/rte_lock_annotations.h | 67 ++++++++++++++++++++++++++
>   lib/eal/ppc/include/rte_rwlock.h       |  4 ++
>   lib/eal/ppc/include/rte_spinlock.h     |  9 ++++
>   lib/eal/x86/include/rte_rwlock.h       |  4 ++
>   lib/eal/x86/include/rte_spinlock.h     |  9 ++++
>   lib/meson.build                        |  5 ++
>   12 files changed, 164 insertions(+), 17 deletions(-)
>   create mode 100644 lib/eal/include/rte_lock_annotations.h
> 


Thanks for working on this. I think this lock annotation feature is very
useful, and will help to catch bugs when libs and drivers will adopt it.

Acked-by: Maxime Coquelin <maxime.coquelin@redhat.com>

Regards,
Maxime
David Marchand April 28, 2022, 12:16 p.m. UTC | #2
On Thu, Apr 21, 2022 at 3:48 PM Maxime Coquelin
<maxime.coquelin@redhat.com> wrote:
>
> Hi David,
>
> On 4/11/22 13:00, David Marchand wrote:
> > clang offers some thread safety checks, statically verifying that locks
> > are taken and released in the code.
> > To use those checks, the full code leading to taking or releasing locks
> > must be annotated with some attributes.
> >
> > Wrap those attributes into our own set of macros.
> >
> > rwlock and the "normal" spinlock are instrumented.
> >
> > A component may enable this check by setting annotate_locks = true
> > in its meson.build.
> >
> > Note: those checks might be of interest out of DPDK, but it
> > requires that the including application locks are annotated.
> > On the other hand, applications out there might have been using
> > those same checks.
> > To be on the safe side, keep this instrumentation under a
> > RTE_ANNOTATE_LOCKS internal build flag.
> >
> > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > ---
> > Changes since RFC v2:
> > - fixed rwlock trylock,
> > - instrumented _tm spinlocks,
> > - aligned attribute names to clang,
> >
> > ---
> >   drivers/meson.build                    |  5 ++
> >   lib/eal/arm/include/rte_rwlock.h       |  4 ++
> >   lib/eal/arm/include/rte_spinlock.h     |  6 +++
> >   lib/eal/include/generic/rte_rwlock.h   | 27 +++++++++--
> >   lib/eal/include/generic/rte_spinlock.h | 40 ++++++++++-----
> >   lib/eal/include/meson.build            |  1 +
> >   lib/eal/include/rte_lock_annotations.h | 67 ++++++++++++++++++++++++++
> >   lib/eal/ppc/include/rte_rwlock.h       |  4 ++
> >   lib/eal/ppc/include/rte_spinlock.h     |  9 ++++
> >   lib/eal/x86/include/rte_rwlock.h       |  4 ++
> >   lib/eal/x86/include/rte_spinlock.h     |  9 ++++
> >   lib/meson.build                        |  5 ++
> >   12 files changed, 164 insertions(+), 17 deletions(-)
> >   create mode 100644 lib/eal/include/rte_lock_annotations.h
> >
>
>
> Thanks for working on this. I think this lock annotation feature is very
> useful, and will help to catch bugs when libs and drivers will adopt it.
>

Thanks for the review.
We need some documentation about those annotations.
I'll add this and post a non RFC series.
diff mbox series

Patch

diff --git a/drivers/meson.build b/drivers/meson.build
index 1d8123b00c..c81c8c0eff 100644
--- a/drivers/meson.build
+++ b/drivers/meson.build
@@ -87,6 +87,7 @@  foreach subpath:subdirs
         build = true # set to false to disable, e.g. missing deps
         reason = '<unknown reason>' # set if build == false to explain
         name = drv
+        annotate_locks = false
         sources = []
         headers = []
         objs = []
@@ -152,6 +153,10 @@  foreach subpath:subdirs
         enabled_drivers += name
         lib_name = '_'.join(['rte', class, name])
         cflags += '-DRTE_LOG_DEFAULT_LOGTYPE=' + '.'.join([log_prefix, name])
+        if annotate_locks and cc.has_argument('-Wthread-safety')
+            cflags += '-DRTE_ANNOTATE_LOCKS'
+            cflags += '-Wthread-safety'
+        endif
         dpdk_conf.set(lib_name.to_upper(), 1)
 
         dpdk_extra_ldflags += pkgconfig_extra_libs
diff --git a/lib/eal/arm/include/rte_rwlock.h b/lib/eal/arm/include/rte_rwlock.h
index 18bb37b036..575f171670 100644
--- a/lib/eal/arm/include/rte_rwlock.h
+++ b/lib/eal/arm/include/rte_rwlock.h
@@ -13,24 +13,28 @@  extern "C" {
 
 static inline void
 rte_rwlock_read_lock_tm(rte_rwlock_t *rwl)
+	__rte_no_thread_safety_analysis
 {
 	rte_rwlock_read_lock(rwl);
 }
 
 static inline void
 rte_rwlock_read_unlock_tm(rte_rwlock_t *rwl)
+	__rte_no_thread_safety_analysis
 {
 	rte_rwlock_read_unlock(rwl);
 }
 
 static inline void
 rte_rwlock_write_lock_tm(rte_rwlock_t *rwl)
+	__rte_no_thread_safety_analysis
 {
 	rte_rwlock_write_lock(rwl);
 }
 
 static inline void
 rte_rwlock_write_unlock_tm(rte_rwlock_t *rwl)
+	__rte_no_thread_safety_analysis
 {
 	rte_rwlock_write_unlock(rwl);
 }
diff --git a/lib/eal/arm/include/rte_spinlock.h b/lib/eal/arm/include/rte_spinlock.h
index a973763c23..2970de5c3c 100644
--- a/lib/eal/arm/include/rte_spinlock.h
+++ b/lib/eal/arm/include/rte_spinlock.h
@@ -23,36 +23,42 @@  static inline int rte_tm_supported(void)
 
 static inline void
 rte_spinlock_lock_tm(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	rte_spinlock_lock(sl); /* fall-back */
 }
 
 static inline int
 rte_spinlock_trylock_tm(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	return rte_spinlock_trylock(sl);
 }
 
 static inline void
 rte_spinlock_unlock_tm(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	rte_spinlock_unlock(sl);
 }
 
 static inline void
 rte_spinlock_recursive_lock_tm(rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis
 {
 	rte_spinlock_recursive_lock(slr); /* fall-back */
 }
 
 static inline void
 rte_spinlock_recursive_unlock_tm(rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis
 {
 	rte_spinlock_recursive_unlock(slr);
 }
 
 static inline int
 rte_spinlock_recursive_trylock_tm(rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis
 {
 	return rte_spinlock_recursive_trylock(slr);
 }
diff --git a/lib/eal/include/generic/rte_rwlock.h b/lib/eal/include/generic/rte_rwlock.h
index da9bc3e9c0..145851f9c0 100644
--- a/lib/eal/include/generic/rte_rwlock.h
+++ b/lib/eal/include/generic/rte_rwlock.h
@@ -23,6 +23,7 @@  extern "C" {
 
 #include <rte_common.h>
 #include <rte_atomic.h>
+#include <rte_lock_annotations.h>
 #include <rte_pause.h>
 
 /**
@@ -30,7 +31,7 @@  extern "C" {
  *
  * cnt is -1 when write lock is held, and > 0 when read locks are held.
  */
-typedef struct {
+typedef struct __rte_lockable {
 	volatile int32_t cnt; /**< -1 when W lock held, > 0 when R locks held. */
 } rte_rwlock_t;
 
@@ -59,6 +60,8 @@  rte_rwlock_init(rte_rwlock_t *rwl)
  */
 static inline void
 rte_rwlock_read_lock(rte_rwlock_t *rwl)
+	__rte_shared_lock_function(rwl)
+	__rte_no_thread_safety_analysis
 {
 	int32_t x;
 	int success = 0;
@@ -91,6 +94,8 @@  rte_rwlock_read_lock(rte_rwlock_t *rwl)
 __rte_experimental
 static inline int
 rte_rwlock_read_trylock(rte_rwlock_t *rwl)
+	__rte_shared_trylock_function(0, rwl)
+	__rte_no_thread_safety_analysis
 {
 	int32_t x;
 	int success = 0;
@@ -115,6 +120,8 @@  rte_rwlock_read_trylock(rte_rwlock_t *rwl)
  */
 static inline void
 rte_rwlock_read_unlock(rte_rwlock_t *rwl)
+	__rte_unlock_function(rwl)
+	__rte_no_thread_safety_analysis
 {
 	__atomic_fetch_sub(&rwl->cnt, 1, __ATOMIC_RELEASE);
 }
@@ -135,6 +142,8 @@  rte_rwlock_read_unlock(rte_rwlock_t *rwl)
 __rte_experimental
 static inline int
 rte_rwlock_write_trylock(rte_rwlock_t *rwl)
+	__rte_exclusive_trylock_function(0, rwl)
+	__rte_no_thread_safety_analysis
 {
 	int32_t x;
 
@@ -154,6 +163,8 @@  rte_rwlock_write_trylock(rte_rwlock_t *rwl)
  */
 static inline void
 rte_rwlock_write_lock(rte_rwlock_t *rwl)
+	__rte_exclusive_lock_function(rwl)
+	__rte_no_thread_safety_analysis
 {
 	int32_t x;
 	int success = 0;
@@ -178,6 +189,8 @@  rte_rwlock_write_lock(rte_rwlock_t *rwl)
  */
 static inline void
 rte_rwlock_write_unlock(rte_rwlock_t *rwl)
+	__rte_unlock_function(rwl)
+	__rte_no_thread_safety_analysis
 {
 	__atomic_store_n(&rwl->cnt, 0, __ATOMIC_RELEASE);
 }
@@ -196,7 +209,8 @@  rte_rwlock_write_unlock(rte_rwlock_t *rwl)
  *   A pointer to a rwlock structure.
  */
 static inline void
-rte_rwlock_read_lock_tm(rte_rwlock_t *rwl);
+rte_rwlock_read_lock_tm(rte_rwlock_t *rwl)
+	__rte_shared_lock_function(rwl);
 
 /**
  * Commit hardware memory transaction or release the read lock if the lock is used as a fall-back
@@ -205,7 +219,8 @@  rte_rwlock_read_lock_tm(rte_rwlock_t *rwl);
  *   A pointer to the rwlock structure.
  */
 static inline void
-rte_rwlock_read_unlock_tm(rte_rwlock_t *rwl);
+rte_rwlock_read_unlock_tm(rte_rwlock_t *rwl)
+	__rte_unlock_function(rwl);
 
 /**
  * Try to execute critical section in a hardware memory transaction, if it
@@ -221,7 +236,8 @@  rte_rwlock_read_unlock_tm(rte_rwlock_t *rwl);
  *   A pointer to a rwlock structure.
  */
 static inline void
-rte_rwlock_write_lock_tm(rte_rwlock_t *rwl);
+rte_rwlock_write_lock_tm(rte_rwlock_t *rwl)
+	__rte_exclusive_lock_function(rwl);
 
 /**
  * Commit hardware memory transaction or release the write lock if the lock is used as a fall-back
@@ -230,7 +246,8 @@  rte_rwlock_write_lock_tm(rte_rwlock_t *rwl);
  *   A pointer to a rwlock structure.
  */
 static inline void
-rte_rwlock_write_unlock_tm(rte_rwlock_t *rwl);
+rte_rwlock_write_unlock_tm(rte_rwlock_t *rwl)
+	__rte_unlock_function(rwl);
 
 #ifdef __cplusplus
 }
diff --git a/lib/eal/include/generic/rte_spinlock.h b/lib/eal/include/generic/rte_spinlock.h
index 40fe49d5ad..684bfac96c 100644
--- a/lib/eal/include/generic/rte_spinlock.h
+++ b/lib/eal/include/generic/rte_spinlock.h
@@ -22,12 +22,13 @@ 
 #ifdef RTE_FORCE_INTRINSICS
 #include <rte_common.h>
 #endif
+#include <rte_lock_annotations.h>
 #include <rte_pause.h>
 
 /**
  * The rte_spinlock_t type.
  */
-typedef struct {
+typedef struct __rte_lockable {
 	volatile int locked; /**< lock status 0 = unlocked, 1 = locked */
 } rte_spinlock_t;
 
@@ -55,11 +56,13 @@  rte_spinlock_init(rte_spinlock_t *sl)
  *   A pointer to the spinlock.
  */
 static inline void
-rte_spinlock_lock(rte_spinlock_t *sl);
+rte_spinlock_lock(rte_spinlock_t *sl)
+	__rte_exclusive_lock_function(sl);
 
 #ifdef RTE_FORCE_INTRINSICS
 static inline void
 rte_spinlock_lock(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	int exp = 0;
 
@@ -79,11 +82,13 @@  rte_spinlock_lock(rte_spinlock_t *sl)
  *   A pointer to the spinlock.
  */
 static inline void
-rte_spinlock_unlock (rte_spinlock_t *sl);
+rte_spinlock_unlock(rte_spinlock_t *sl)
+	__rte_unlock_function(sl);
 
 #ifdef RTE_FORCE_INTRINSICS
 static inline void
-rte_spinlock_unlock (rte_spinlock_t *sl)
+rte_spinlock_unlock(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	__atomic_store_n(&sl->locked, 0, __ATOMIC_RELEASE);
 }
@@ -98,11 +103,13 @@  rte_spinlock_unlock (rte_spinlock_t *sl)
  *   1 if the lock is successfully taken; 0 otherwise.
  */
 static inline int
-rte_spinlock_trylock (rte_spinlock_t *sl);
+rte_spinlock_trylock(rte_spinlock_t *sl)
+	__rte_exclusive_trylock_function(1, sl);
 
 #ifdef RTE_FORCE_INTRINSICS
 static inline int
-rte_spinlock_trylock (rte_spinlock_t *sl)
+rte_spinlock_trylock(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	int exp = 0;
 	return __atomic_compare_exchange_n(&sl->locked, &exp, 1,
@@ -146,7 +153,8 @@  static inline int rte_tm_supported(void);
  *   A pointer to the spinlock.
  */
 static inline void
-rte_spinlock_lock_tm(rte_spinlock_t *sl);
+rte_spinlock_lock_tm(rte_spinlock_t *sl)
+	__rte_exclusive_lock_function(sl);
 
 /**
  * Commit hardware memory transaction or release the spinlock if
@@ -156,7 +164,8 @@  rte_spinlock_lock_tm(rte_spinlock_t *sl);
  *   A pointer to the spinlock.
  */
 static inline void
-rte_spinlock_unlock_tm(rte_spinlock_t *sl);
+rte_spinlock_unlock_tm(rte_spinlock_t *sl)
+	__rte_unlock_function(sl);
 
 /**
  * Try to execute critical section in a hardware memory transaction,
@@ -175,7 +184,8 @@  rte_spinlock_unlock_tm(rte_spinlock_t *sl);
  *   or lock is successfully taken; 0 otherwise.
  */
 static inline int
-rte_spinlock_trylock_tm(rte_spinlock_t *sl);
+rte_spinlock_trylock_tm(rte_spinlock_t *sl)
+	__rte_exclusive_trylock_function(1, sl);
 
 /**
  * The rte_spinlock_recursive_t type.
@@ -211,6 +221,7 @@  static inline void rte_spinlock_recursive_init(rte_spinlock_recursive_t *slr)
  *   A pointer to the recursive spinlock.
  */
 static inline void rte_spinlock_recursive_lock(rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis
 {
 	int id = rte_gettid();
 
@@ -227,6 +238,7 @@  static inline void rte_spinlock_recursive_lock(rte_spinlock_recursive_t *slr)
  *   A pointer to the recursive spinlock.
  */
 static inline void rte_spinlock_recursive_unlock(rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis
 {
 	if (--(slr->count) == 0) {
 		slr->user = -1;
@@ -244,6 +256,7 @@  static inline void rte_spinlock_recursive_unlock(rte_spinlock_recursive_t *slr)
  *   1 if the lock is successfully taken; 0 otherwise.
  */
 static inline int rte_spinlock_recursive_trylock(rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis
 {
 	int id = rte_gettid();
 
@@ -271,7 +284,8 @@  static inline int rte_spinlock_recursive_trylock(rte_spinlock_recursive_t *slr)
  *   A pointer to the recursive spinlock.
  */
 static inline void rte_spinlock_recursive_lock_tm(
-	rte_spinlock_recursive_t *slr);
+	rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis;
 
 /**
  * Commit hardware memory transaction or release the recursive spinlock
@@ -281,7 +295,8 @@  static inline void rte_spinlock_recursive_lock_tm(
  *   A pointer to the recursive spinlock.
  */
 static inline void rte_spinlock_recursive_unlock_tm(
-	rte_spinlock_recursive_t *slr);
+	rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis;
 
 /**
  * Try to execute critical section in a hardware memory transaction,
@@ -300,6 +315,7 @@  static inline void rte_spinlock_recursive_unlock_tm(
  *   or lock is successfully taken; 0 otherwise.
  */
 static inline int rte_spinlock_recursive_trylock_tm(
-	rte_spinlock_recursive_t *slr);
+	rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis;
 
 #endif /* _RTE_SPINLOCK_H_ */
diff --git a/lib/eal/include/meson.build b/lib/eal/include/meson.build
index 9700494816..a20b8d7e23 100644
--- a/lib/eal/include/meson.build
+++ b/lib/eal/include/meson.build
@@ -27,6 +27,7 @@  headers += files(
         'rte_keepalive.h',
         'rte_launch.h',
         'rte_lcore.h',
+        'rte_lock_annotations.h',
         'rte_log.h',
         'rte_malloc.h',
         'rte_memory.h',
diff --git a/lib/eal/include/rte_lock_annotations.h b/lib/eal/include/rte_lock_annotations.h
new file mode 100644
index 0000000000..bcaf4193f7
--- /dev/null
+++ b/lib/eal/include/rte_lock_annotations.h
@@ -0,0 +1,67 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 Red Hat, Inc.
+ */
+
+#ifndef RTE_LOCK_ANNOTATIONS_H
+#define RTE_LOCK_ANNOTATIONS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef RTE_ANNOTATE_LOCKS
+
+#define __rte_lockable \
+	__attribute__((lockable))
+
+#define __rte_guarded_by(...) \
+	__attribute__((guarded_by(__VA_ARGS__)))
+#define __rte_guarded_var \
+	__attribute__((guarded_var))
+
+#define __rte_exclusive_locks_required(...) \
+	__attribute__((exclusive_locks_required(__VA_ARGS__)))
+#define __rte_exclusive_lock_function(...) \
+	__attribute__((exclusive_lock_function(__VA_ARGS__)))
+#define __rte_exclusive_trylock_function(ret, ...) \
+	__attribute__((exclusive_trylock_function(ret, __VA_ARGS__)))
+
+#define __rte_shared_locks_required(...) \
+	__attribute__((shared_locks_required(__VA_ARGS__)))
+#define __rte_shared_lock_function(...) \
+	__attribute__((shared_lock_function(__VA_ARGS__)))
+#define __rte_shared_trylock_function(ret, ...) \
+	__attribute__((shared_trylock_function(ret, __VA_ARGS__)))
+
+#define __rte_unlock_function(...) \
+	__attribute__((unlock_function(__VA_ARGS__)))
+
+#define __rte_no_thread_safety_analysis \
+	__attribute__((no_thread_safety_analysis))
+
+#else /* ! RTE_ANNOTATE_LOCKS */
+
+#define __rte_lockable
+
+#define __rte_guarded_by(...)
+#define __rte_guarded_var
+
+#define __rte_exclusive_locks_required(...)
+#define __rte_exclusive_lock_function(...)
+#define __rte_exclusive_trylock_function(...)
+
+#define __rte_shared_locks_required(...)
+#define __rte_shared_lock_function(...)
+#define __rte_shared_trylock_function(...)
+
+#define __rte_unlock_function(...)
+
+#define __rte_no_thread_safety_analysis
+
+#endif /* RTE_ANNOTATE_LOCKS */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTE_LOCK_ANNOTATIONS_H */
diff --git a/lib/eal/ppc/include/rte_rwlock.h b/lib/eal/ppc/include/rte_rwlock.h
index 9fadc04076..d7a5b61b8e 100644
--- a/lib/eal/ppc/include/rte_rwlock.h
+++ b/lib/eal/ppc/include/rte_rwlock.h
@@ -11,24 +11,28 @@  extern "C" {
 
 static inline void
 rte_rwlock_read_lock_tm(rte_rwlock_t *rwl)
+	__rte_no_thread_safety_analysis
 {
 	rte_rwlock_read_lock(rwl);
 }
 
 static inline void
 rte_rwlock_read_unlock_tm(rte_rwlock_t *rwl)
+	__rte_no_thread_safety_analysis
 {
 	rte_rwlock_read_unlock(rwl);
 }
 
 static inline void
 rte_rwlock_write_lock_tm(rte_rwlock_t *rwl)
+	__rte_no_thread_safety_analysis
 {
 	rte_rwlock_write_lock(rwl);
 }
 
 static inline void
 rte_rwlock_write_unlock_tm(rte_rwlock_t *rwl)
+	__rte_no_thread_safety_analysis
 {
 	rte_rwlock_write_unlock(rwl);
 }
diff --git a/lib/eal/ppc/include/rte_spinlock.h b/lib/eal/ppc/include/rte_spinlock.h
index 149ec245c7..979abea16d 100644
--- a/lib/eal/ppc/include/rte_spinlock.h
+++ b/lib/eal/ppc/include/rte_spinlock.h
@@ -20,6 +20,7 @@  extern "C" {
 
 static inline void
 rte_spinlock_lock(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	while (__sync_lock_test_and_set(&sl->locked, 1))
 		while (sl->locked)
@@ -28,12 +29,14 @@  rte_spinlock_lock(rte_spinlock_t *sl)
 
 static inline void
 rte_spinlock_unlock(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	__sync_lock_release(&sl->locked);
 }
 
 static inline int
 rte_spinlock_trylock(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	return __sync_lock_test_and_set(&sl->locked, 1) == 0;
 }
@@ -47,36 +50,42 @@  static inline int rte_tm_supported(void)
 
 static inline void
 rte_spinlock_lock_tm(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	rte_spinlock_lock(sl); /* fall-back */
 }
 
 static inline int
 rte_spinlock_trylock_tm(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	return rte_spinlock_trylock(sl);
 }
 
 static inline void
 rte_spinlock_unlock_tm(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	rte_spinlock_unlock(sl);
 }
 
 static inline void
 rte_spinlock_recursive_lock_tm(rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis
 {
 	rte_spinlock_recursive_lock(slr); /* fall-back */
 }
 
 static inline void
 rte_spinlock_recursive_unlock_tm(rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis
 {
 	rte_spinlock_recursive_unlock(slr);
 }
 
 static inline int
 rte_spinlock_recursive_trylock_tm(rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis
 {
 	return rte_spinlock_recursive_trylock(slr);
 }
diff --git a/lib/eal/x86/include/rte_rwlock.h b/lib/eal/x86/include/rte_rwlock.h
index eec4c7123c..1796b69265 100644
--- a/lib/eal/x86/include/rte_rwlock.h
+++ b/lib/eal/x86/include/rte_rwlock.h
@@ -14,6 +14,7 @@  extern "C" {
 
 static inline void
 rte_rwlock_read_lock_tm(rte_rwlock_t *rwl)
+	__rte_no_thread_safety_analysis
 {
 	if (likely(rte_try_tm(&rwl->cnt)))
 		return;
@@ -22,6 +23,7 @@  rte_rwlock_read_lock_tm(rte_rwlock_t *rwl)
 
 static inline void
 rte_rwlock_read_unlock_tm(rte_rwlock_t *rwl)
+	__rte_no_thread_safety_analysis
 {
 	if (unlikely(rwl->cnt))
 		rte_rwlock_read_unlock(rwl);
@@ -31,6 +33,7 @@  rte_rwlock_read_unlock_tm(rte_rwlock_t *rwl)
 
 static inline void
 rte_rwlock_write_lock_tm(rte_rwlock_t *rwl)
+	__rte_no_thread_safety_analysis
 {
 	if (likely(rte_try_tm(&rwl->cnt)))
 		return;
@@ -39,6 +42,7 @@  rte_rwlock_write_lock_tm(rte_rwlock_t *rwl)
 
 static inline void
 rte_rwlock_write_unlock_tm(rte_rwlock_t *rwl)
+	__rte_no_thread_safety_analysis
 {
 	if (unlikely(rwl->cnt))
 		rte_rwlock_write_unlock(rwl);
diff --git a/lib/eal/x86/include/rte_spinlock.h b/lib/eal/x86/include/rte_spinlock.h
index e2e2b2643c..0b20ddfd73 100644
--- a/lib/eal/x86/include/rte_spinlock.h
+++ b/lib/eal/x86/include/rte_spinlock.h
@@ -23,6 +23,7 @@  extern "C" {
 #ifndef RTE_FORCE_INTRINSICS
 static inline void
 rte_spinlock_lock(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	int lock_val = 1;
 	asm volatile (
@@ -43,6 +44,7 @@  rte_spinlock_lock(rte_spinlock_t *sl)
 
 static inline void
 rte_spinlock_unlock (rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	int unlock_val = 0;
 	asm volatile (
@@ -54,6 +56,7 @@  rte_spinlock_unlock (rte_spinlock_t *sl)
 
 static inline int
 rte_spinlock_trylock (rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	int lockval = 1;
 
@@ -121,6 +124,7 @@  rte_try_tm(volatile int *lock)
 
 static inline void
 rte_spinlock_lock_tm(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	if (likely(rte_try_tm(&sl->locked)))
 		return;
@@ -130,6 +134,7 @@  rte_spinlock_lock_tm(rte_spinlock_t *sl)
 
 static inline int
 rte_spinlock_trylock_tm(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	if (likely(rte_try_tm(&sl->locked)))
 		return 1;
@@ -139,6 +144,7 @@  rte_spinlock_trylock_tm(rte_spinlock_t *sl)
 
 static inline void
 rte_spinlock_unlock_tm(rte_spinlock_t *sl)
+	__rte_no_thread_safety_analysis
 {
 	if (unlikely(sl->locked))
 		rte_spinlock_unlock(sl);
@@ -148,6 +154,7 @@  rte_spinlock_unlock_tm(rte_spinlock_t *sl)
 
 static inline void
 rte_spinlock_recursive_lock_tm(rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis
 {
 	if (likely(rte_try_tm(&slr->sl.locked)))
 		return;
@@ -157,6 +164,7 @@  rte_spinlock_recursive_lock_tm(rte_spinlock_recursive_t *slr)
 
 static inline void
 rte_spinlock_recursive_unlock_tm(rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis
 {
 	if (unlikely(slr->sl.locked))
 		rte_spinlock_recursive_unlock(slr);
@@ -166,6 +174,7 @@  rte_spinlock_recursive_unlock_tm(rte_spinlock_recursive_t *slr)
 
 static inline int
 rte_spinlock_recursive_trylock_tm(rte_spinlock_recursive_t *slr)
+	__rte_no_thread_safety_analysis
 {
 	if (likely(rte_try_tm(&slr->sl.locked)))
 		return 1;
diff --git a/lib/meson.build b/lib/meson.build
index 24adbe44c9..909133ea64 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -112,6 +112,7 @@  foreach l:libraries
     reason = '<unknown reason>' # set if build == false to explain why
     name = l
     use_function_versioning = false
+    annotate_locks = false
     sources = []
     headers = []
     indirect_headers = [] # public headers not directly included by apps
@@ -184,6 +185,10 @@  foreach l:libraries
         cflags += '-DRTE_USE_FUNCTION_VERSIONING'
     endif
     cflags += '-DRTE_LOG_DEFAULT_LOGTYPE=lib.' + l
+    if annotate_locks and cc.has_argument('-Wthread-safety')
+        cflags += '-DRTE_ANNOTATE_LOCKS'
+        cflags += '-Wthread-safety'
+    endif
 
     # first build static lib
     static_lib = static_library(libname,