urcu/annotate: Add CMM annotation
[urcu.git] / include / urcu / annotate.h
diff --git a/include/urcu/annotate.h b/include/urcu/annotate.h
new file mode 100644 (file)
index 0000000..37e7f03
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * urcu/annotate.h
+ *
+ * Userspace RCU - annotation header.
+ *
+ * Copyright 2023 - Olivier Dion <odion@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * WARNING!
+ *
+ * This API is highly experimental. There is zero guarantees of stability
+ * between releases.
+ *
+ * You have been warned.
+ */
+#ifndef _URCU_ANNOTATE_H
+#define _URCU_ANNOTATE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <urcu/compiler.h>
+
+enum cmm_annotate {
+       CMM_ANNOTATE_VOID,
+       CMM_ANNOTATE_LOAD,
+       CMM_ANNOTATE_STORE,
+       CMM_ANNOTATE_MB,
+};
+
+typedef enum cmm_annotate cmm_annotate_t __attribute__((unused));
+
+#define cmm_annotate_define(name)              \
+       cmm_annotate_t name = CMM_ANNOTATE_VOID
+
+#ifdef CMM_SANITIZE_THREAD
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+extern void __tsan_acquire(void *);
+extern void __tsan_release(void *);
+# ifdef __cplusplus
+}
+# endif
+
+# define cmm_annotate_die(msg)                                         \
+       do {                                                            \
+               fprintf(stderr,                                         \
+                       "(" __FILE__ ":%s@%u) Annotation ERROR: %s\n",  \
+                       __func__, __LINE__, msg);                       \
+               abort();                                                \
+       } while (0)
+
+/* Only used for typechecking in macros. */
+static inline cmm_annotate_t cmm_annotate_dereference(cmm_annotate_t *group)
+{
+       return *group;
+}
+
+# define cmm_annotate_group_mb_acquire(group)                          \
+       do {                                                            \
+               switch (cmm_annotate_dereference(group)) {              \
+               case CMM_ANNOTATE_VOID:                                 \
+                       break;                                          \
+               case CMM_ANNOTATE_LOAD:                                 \
+                       break;                                          \
+               case CMM_ANNOTATE_STORE:                                \
+                       cmm_annotate_die("store for acquire group");    \
+                       break;                                          \
+               case CMM_ANNOTATE_MB:                                   \
+                       cmm_annotate_die(                               \
+                               "redundant mb for acquire group"        \
+                                       );                              \
+                       break;                                          \
+               }                                                       \
+               *(group) = CMM_ANNOTATE_MB;                             \
+       } while (0)
+
+# define cmm_annotate_group_mb_release(group)                          \
+       do {                                                            \
+               switch (cmm_annotate_dereference(group)) {              \
+               case CMM_ANNOTATE_VOID:                                 \
+                       break;                                          \
+               case CMM_ANNOTATE_LOAD:                                 \
+                       cmm_annotate_die("load before release group");  \
+                       break;                                          \
+               case CMM_ANNOTATE_STORE:                                \
+                       cmm_annotate_die(                               \
+                               "store before release group"            \
+                                       );                              \
+                       break;                                          \
+               case CMM_ANNOTATE_MB:                                   \
+                       cmm_annotate_die(                               \
+                               "redundant mb of release group"         \
+                                       );                              \
+                       break;                                          \
+               }                                                       \
+               *(group) = CMM_ANNOTATE_MB;                             \
+       } while (0)
+
+# define cmm_annotate_group_mem_acquire(group, mem)                    \
+       do {                                                            \
+               __tsan_acquire((void*)(mem));                           \
+               switch (cmm_annotate_dereference(group)) {              \
+               case CMM_ANNOTATE_VOID:                                 \
+                       *(group) = CMM_ANNOTATE_LOAD;                   \
+                       break;                                          \
+               case CMM_ANNOTATE_MB:                                   \
+                       cmm_annotate_die(                               \
+                               "load after mb for acquire group"       \
+                                       );                              \
+                       break;                                          \
+               default:                                                \
+                       break;                                          \
+               }                                                       \
+       } while (0)
+
+# define cmm_annotate_group_mem_release(group, mem)            \
+       do {                                                    \
+               __tsan_release((void*)(mem));                   \
+               switch (cmm_annotate_dereference(group)) {      \
+               case CMM_ANNOTATE_MB:                           \
+                       break;                                  \
+               default:                                        \
+                       cmm_annotate_die(                       \
+                               "missing mb for release group"  \
+                                       );                      \
+               }                                               \
+       } while (0)
+
+# define cmm_annotate_mem_acquire(mem)         \
+       __tsan_acquire((void*)(mem))
+
+# define cmm_annotate_mem_release(mem)         \
+       __tsan_release((void*)(mem))
+#else
+
+# define cmm_annotate_group_mb_acquire(group)  \
+       (void) (group)
+
+# define cmm_annotate_group_mb_release(group)  \
+       (void) (group)
+
+# define cmm_annotate_group_mem_acquire(group, mem)    \
+       (void) (group)
+
+# define cmm_annotate_group_mem_release(group, mem)    \
+       (void) (group)
+
+# define cmm_annotate_mem_acquire(mem)         \
+       do { } while (0)
+
+# define cmm_annotate_mem_release(mem)         \
+       do { } while (0)
+
+#endif  /* CMM_SANITIZE_THREAD */
+
+#endif /* _URCU_ANNOTATE_H */
This page took 0.024826 seconds and 4 git commands to generate.