From: Yu Watanabe Date: Wed, 10 Sep 2025 23:39:17 +0000 (+0900) Subject: macro: flip ONCE macro to make log_once() and friend actually log once X-Git-Tag: v257.10~38 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c0edaa95e692318d6480541d8d47b35adad46c78;p=thirdparty%2Fsystemd.git macro: flip ONCE macro to make log_once() and friend actually log once Previously, ONCE is false for the first time, and true for later times, hence log_once() and log_once_errno() suppress logging in the first call, rather than later calls. Fortunately, ONCE macro is only used in log_once() and log_once_errno(), hence this only fixes spurious logging. (cherry picked from commit acd33c5df8ba35bcfa595ea0be9f74afa6aab289) (cherry picked from commit d21fa647d204f9d7275a5370580e9211ffe14aec) --- diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h index 35758b5b189..74c057b294d 100644 --- a/src/fundamental/macro-fundamental.h +++ b/src/fundamental/macro-fundamental.h @@ -151,15 +151,15 @@ #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) diff --git a/src/test/test-log.c b/src/test/test-log.c index 57cab632690..4c4be738acf 100644 --- a/src/test/test-log.c +++ b/src/test/test-log.c @@ -45,6 +45,22 @@ static void test_file(void) { 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(), @@ -236,6 +252,8 @@ int main(int argc, char* argv[]) { 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(); diff --git a/src/test/test-macro.c b/src/test/test-macro.c index c4c533777dc..29e8b09e3cc 100644 --- a/src/test/test-macro.c +++ b/src/test/test-macro.c @@ -1228,4 +1228,20 @@ TEST(ASSERT) { ASSERT_SIGNAL(ASSERT_NE_ID128(SD_ID128_NULL, SD_ID128_NULL), SIGABRT); } +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);