#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
#define UNIQ __COUNTER__
-/* Note that this works differently from pthread_once(): this macro does
- * not synchronize code execution, i.e. code that is run conditionalized
- * on this macro will run concurrently to all other code conditionalized
- * the same way, there's no ordering or completion enforced. */
+/* The macro is true when the code block is called first time, and is false for the second and later times.
+ * Note that this works differently from pthread_once(): this macro does not synchronize code execution, i.e.
+ * code that is run conditionalized on this macro will run concurrently to all other code conditionalized the
+ * same way, there's no ordering or completion enforced. */
#define ONCE __ONCE(UNIQ_T(_once_, UNIQ))
-#define __ONCE(o) \
- ({ \
- static bool (o) = false; \
- __atomic_exchange_n(&(o), true, __ATOMIC_SEQ_CST); \
+#define __ONCE(o) \
+ ({ \
+ static bool (o) = false; \
+ !__atomic_exchange_n(&(o), true, __ATOMIC_SEQ_CST); \
})
#define U64_KB UINT64_C(1024)
assert_se(startswith(__FILE__, RELATIVE_SOURCE_PATH "/"));
}
+static void test_log_once_impl(void) {
+ log_once(LOG_INFO, "This should be logged in LOG_INFO at first, then in LOG_DEBUG later.");
+ log_once(LOG_DEBUG, "This should be logged only once in LOG_DEBUG.");
+ ASSERT_ERROR(log_once_errno(LOG_INFO, SYNTHETIC_ERRNO(ENOANO),
+ "This should be logged with errno in LOG_INFO at first, then in LOG_DEBUG later: %m"),
+ ENOANO);
+ ASSERT_ERROR(log_once_errno(LOG_DEBUG, SYNTHETIC_ERRNO(EBADMSG),
+ "This should be logged only once with errno in LOG_DEBUG: %m"),
+ EBADMSG);
+}
+
+static void test_log_once(void) {
+ for (unsigned i = 0; i < 4; i++)
+ test_log_once_impl();
+}
+
static void test_log_struct(void) {
log_struct(LOG_INFO,
"MESSAGE=Waldo PID="PID_FMT" (no errno)", getpid_cached(),
assert_se(log_info_errno(SYNTHETIC_ERRNO(EUCLEAN), "foo") == -EUCLEAN);
+ test_log_once();
+
for (int target = 0; target < _LOG_TARGET_MAX; target++) {
log_set_target(target);
log_open();
assert_se(u64_multiply_safe(UINT64_MAX, UINT64_MAX) == 0);
}
+static void test_once_impl(void) {
+ static unsigned count = 0;
+
+ if (ONCE) {
+ log_info("This should be logged only once.");
+ count++;
+ }
+
+ ASSERT_EQ(count, 1u);
+}
+
+TEST(once) {
+ for (unsigned i = 0; i < 20; i++)
+ test_once_impl();
+}
+
DEFINE_TEST_MAIN(LOG_INFO);