__bug_cond; /* let's return the condition */ \
})
+/* This one is equivalent except that it only emits the message once by
+ * maintaining a static counter. This may be used with warnings to detect
+ * certain unexpected conditions in field. Later on, in cores it will be
+ * possible to verify these counters.
+ */
+#define _BUG_ON_ONCE(cond, file, line, crash, pfx, sfx) \
+ __BUG_ON_ONCE(cond, file, line, crash, pfx, sfx)
+
+#define __BUG_ON_ONCE(cond, file, line, crash, pfx, sfx) \
+ ({ \
+ static int __match_count_##line; \
+ int __bug_cond = !!(cond); \
+ if (unlikely(__bug_cond) && \
+ !_HA_ATOMIC_FETCH_ADD(&__match_count_##line, 1)) { \
+ const char msg[] = "\n" pfx "condition \"" #cond "\" matched at " file ":" #line "" sfx "\n"; \
+ DISGUISE(write(2, msg, __builtin_strlen(msg))); \
+ if (crash) \
+ ABORT_NOW(); \
+ else \
+ DUMP_TRACE(); \
+ } \
+ __bug_cond; /* let's return the condition */ \
+ })
+
/* BUG_ON: complains if <cond> is true when DEBUG_STRICT or DEBUG_STRICT_NOCRASH
* are set, does nothing otherwise. With DEBUG_STRICT in addition it immediately
* crashes using ABORT_NOW() above.
*/
#if defined(DEBUG_STRICT)
-#define BUG_ON(cond) _BUG_ON(cond, __FILE__, __LINE__, 1, "FATAL: bug ", "")
-#define WARN_ON(cond) _BUG_ON(cond, __FILE__, __LINE__, 0, "WARNING: ", " (please report to developers)")
+#define BUG_ON(cond) _BUG_ON (cond, __FILE__, __LINE__, 1, "FATAL: bug ", "")
+#define WARN_ON(cond) _BUG_ON (cond, __FILE__, __LINE__, 0, "WARNING: ", " (please report to developers)")
+#define WARN_ON_ONCE(cond) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: ", " (please report to developers)")
#elif defined(DEBUG_STRICT_NOCRASH)
-#define BUG_ON(cond) _BUG_ON(cond, __FILE__, __LINE__, 0, "FATAL: bug ", " (not crashing but process is untrusted now)")
-#define WARN_ON(cond) _BUG_ON(cond, __FILE__, __LINE__, 0, "WARNING: ", " (please report to developers)")
+#define BUG_ON(cond) _BUG_ON (cond, __FILE__, __LINE__, 0, "FATAL: bug ", " (not crashing but process is untrusted now)")
+#define WARN_ON(cond) _BUG_ON (cond, __FILE__, __LINE__, 0, "WARNING: ", " (please report to developers)")
+#define WARN_ON_ONCE(cond) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: ", " (please report to developers)")
#else
#define BUG_ON(cond)
#define WARN_ON(cond)
+#define WARN_ON_ONCE(cond)
#endif
/* When not optimizing, clang won't remove that code, so only compile it in when optimizing */
return 1;
}
+/* parse a "debug dev warn1" command. It always returns 1.
+ * Note: we make sure not to make the function static so that it appears in the trace.
+ */
+int debug_parse_cli_warn1(char **args, char *payload, struct appctx *appctx, void *private)
+{
+ if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
+ return 1;
+
+ _HA_ATOMIC_INC(&debug_commands_issued);
+ WARN_ON_ONCE(one > zero);
+ return 1;
+}
+
/* parse a "debug dev close" command. It always returns 1. */
static int debug_parse_cli_close(char **args, char *payload, struct appctx *appctx, void *private)
{
{{ "debug", "dev", "sym", NULL }, "debug dev sym <addr> : resolve symbol address", debug_parse_cli_sym, NULL, NULL, NULL, ACCESS_EXPERT },
{{ "debug", "dev", "tkill", NULL }, "debug dev tkill [thr] [sig] : send signal to thread", debug_parse_cli_tkill, NULL, NULL, NULL, ACCESS_EXPERT },
{{ "debug", "dev", "warn", NULL }, "debug dev warn : call WARN_ON() and possibly crash", debug_parse_cli_warn, NULL, NULL, NULL, ACCESS_EXPERT },
+ {{ "debug", "dev", "warn1", NULL }, "debug dev warn1 : call WARN_ON_ONCE() and possibly crash", debug_parse_cli_warn1, NULL, NULL, NULL, ACCESS_EXPERT },
{{ "debug", "dev", "write", NULL }, "debug dev write [size] : write that many bytes in return", debug_parse_cli_write, NULL, NULL, NULL, ACCESS_EXPERT },
#if defined(HA_HAVE_DUMP_LIBS)
{{ "show", "libs", NULL, NULL }, "show libs : show loaded object files and libraries", debug_parse_cli_show_libs, NULL, NULL },