gmessages: Add g_warning_once()

In many places the pattern

    static gboolean warned_once = FALSE;
    if (!warned_once)
      {
        g_warning ("This and that");
        warned_once = TRUE;
      }

is used to not spam the same warning message over and over again. Add a
helper in glib for this, allowing the above statement to be changed to

    g_warning_once ("This and that");
This commit is contained in:
Jonas Ådahl 2019-08-08 09:37:48 +02:00
parent 35e26151a8
commit 15e3b6f136
3 changed files with 60 additions and 0 deletions

View File

@ -1411,6 +1411,7 @@ g_log
g_logv
g_message
g_warning
g_warning_once
g_critical
g_error
g_info

View File

@ -30,6 +30,7 @@
#endif
#include <stdarg.h>
#include <glib/gatomic.h>
#include <glib/gtypes.h>
#include <glib/gmacros.h>
#include <glib/gvariant.h>
@ -453,6 +454,43 @@ g_debug (const gchar *format,
}
#endif /* !__GNUC__ */
/**
* g_warning_once:
* @...: format string, followed by parameters to insert
* into the format string (as with printf())
*
* Logs a warning only once.
*
* g_warning_once() calls g_warning() with the passed message the first time
* the statement is executed; subsequent times it is a no-op.
*
* Note! On platforms where the compiler doesn't support variadic macros, the
* warning is printed each time instead of only once.
*
* Since: 2.64
*/
#if defined(G_HAVE_ISO_VARARGS) && !G_ANALYZER_ANALYZING
#define g_warning_once(...) \
G_STMT_START { \
static volatile int G_PASTE (_GWarningOnceBoolean, __LINE__) = 0; \
if (g_atomic_int_compare_and_exchange (&G_PASTE (_GWarningOnceBoolean, __LINE__), \
0, 1)) \
g_warning (__VA_ARGS__); \
} G_STMT_END \
GLIB_AVAILABLE_MACRO_IN_2_64
#elif defined(G_HAVE_GNUC_VARARGS) && !G_ANALYZER_ANALYZING
#define g_warning_once(format...) \
G_STMT_START { \
static volatile int G_PASTE (_GWarningOnceBoolean, __LINE__) = 0; \
if (g_atomic_int_compare_and_exchange (&G_PASTE (_GWarningOnceBoolean, __LINE__), \
0, 1)) \
g_warning (format); \
} G_STMT_END \
GLIB_AVAILABLE_MACRO_IN_2_64
#else
#define g_warning_once g_warning
#endif
/**
* GPrintFunc:
* @string: the message to output

View File

@ -574,6 +574,26 @@ log_warning_error_tests (void)
g_test_assert_expected_messages ();
}
static void
log_warning_rate_limited_tests (void)
{
#if defined(G_HAVE_ISO_VARARGS) || defined(G_HAVE_GNUC_VARARGS)
int i;
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"*harmless single warning 1*");
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"*harmless single warning 2*");
for (i = 0; i < 10; i++)
g_warning_once ("harmless single warning 1");
for (i = 0; i < 10; i++)
g_warning_once ("harmless single warning 2");
g_test_assert_expected_messages ();
#else
g_test_skip ("Variadic macro support not available");
#endif
}
static void
timer_tests (void)
{
@ -1684,6 +1704,7 @@ main (int argc,
g_test_add_func ("/testglib/Parse Debug Strings", test_g_parse_debug_string);
g_test_add_func ("/testglib/GMemChunk (deprecated)", test_mem_chunks);
g_test_add_func ("/testglib/Warnings & Errors", log_warning_error_tests);
g_test_add_func ("/testglib/Warnings (rate limited)", log_warning_rate_limited_tests);
g_test_add_func ("/testglib/Timers (slow)", timer_tests);
return g_test_run();