[glib: 1/2] gmessages: Add g_warning_once()



commit 15e3b6f136245b4e9b4b9ed225610b2fb84423d1
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Thu Aug 8 09:37:48 2019 +0200

    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");

 docs/reference/glib/glib-sections.txt |  1 +
 glib/gmessages.h                      | 38 +++++++++++++++++++++++++++++++++++
 tests/testglib.c                      | 21 +++++++++++++++++++
 3 files changed, 60 insertions(+)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index f6073c21d..eea025c92 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -1411,6 +1411,7 @@ g_log
 g_logv
 g_message
 g_warning
+g_warning_once
 g_critical
 g_error
 g_info
diff --git a/glib/gmessages.h b/glib/gmessages.h
index 95d60c5be..e910f7b73 100644
--- a/glib/gmessages.h
+++ b/glib/gmessages.h
@@ -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
diff --git a/tests/testglib.c b/tests/testglib.c
index 372ddae2c..f49a6d99d 100644
--- a/tests/testglib.c
+++ b/tests/testglib.c
@@ -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();


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]