summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYu-Ping Wu <yupingso@chromium.org>2021-06-22 17:40:01 +0800
committerPatrick Georgi <pgeorgi@google.com>2021-06-26 10:09:06 +0000
commitfc3576ab06a33bd3733ea37341fd3b0094e1298c (patch)
tree300ce0d78cd4e36df25c740270c56205b646dc26
parent6cd4d320398961aff5ac5de3d380d64c542edabb (diff)
downloadcoreboot-fc3576ab06a33bd3733ea37341fd3b0094e1298c.tar.gz
coreboot-fc3576ab06a33bd3733ea37341fd3b0094e1298c.tar.bz2
coreboot-fc3576ab06a33bd3733ea37341fd3b0094e1298c.zip
helpers: Introduce retry macro
Introduce a macro retry(attempts, condition, expr) for retrying a condition, which is extensively used in coreboot. Example usage: if (!retry(3, read32(REG) == 0, mdelay(1)) printk(BIOS_ERR, "Error waiting for REG to be 0\n"); BUG=none TEST=make tests/commonlib/bsd/helpers-test TEST=emerge-cherry coreboot BRANCH=none Change-Id: I421e4dcab949616bd68b3a14231da744b9f74eeb Signed-off-by: Yu-Ping Wu <yupingso@chromium.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/55778 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Julius Werner <jwerner@chromium.org>
-rw-r--r--src/commonlib/bsd/include/commonlib/bsd/helpers.h35
-rw-r--r--tests/commonlib/Makefile.inc2
-rw-r--r--tests/commonlib/bsd/Makefile.inc5
-rw-r--r--tests/commonlib/bsd/helpers-test.c41
4 files changed, 83 insertions, 0 deletions
diff --git a/src/commonlib/bsd/include/commonlib/bsd/helpers.h b/src/commonlib/bsd/include/commonlib/bsd/helpers.h
index 4e6ebeefdd48..376ebaef11cf 100644
--- a/src/commonlib/bsd/include/commonlib/bsd/helpers.h
+++ b/src/commonlib/bsd/include/commonlib/bsd/helpers.h
@@ -88,4 +88,39 @@
/* Calculate size of structure member. */
#define member_size(type, member) (sizeof(((type *)0)->member))
+#define _retry_impl(attempts, condition, expr, ...) \
+({ \
+ __typeof__(condition) _retry_ret = \
+ (__typeof__(condition))0; \
+ int _retry_attempts = (attempts); \
+ do { \
+ _retry_ret = (condition); \
+ if (_retry_ret) \
+ break; \
+ if (--_retry_attempts > 0) { \
+ expr; \
+ } else { \
+ break; \
+ } \
+ } while (1); \
+ _retry_ret; \
+})
+
+/*
+ * Helper macro to retry until a condition becomes true or the maximum number
+ * of attempts is reached. Two forms are supported:
+ *
+ * 1. retry(attempts, condition)
+ * 2. retry(attempts, condition, expr)
+ *
+ * @param attempts Maximum attempts.
+ * @param condition Condition to retry for.
+ * @param expr Procedure to run between each evaluation to "condition".
+ *
+ * @return Condition value if it evaluates to true within the maximum attempts;
+ * 0 otherwise.
+ */
+#define retry(attempts, condition, ...) \
+ _retry_impl(attempts, condition, __VA_ARGS__)
+
#endif /* COMMONLIB_BSD_HELPERS_H */
diff --git a/tests/commonlib/Makefile.inc b/tests/commonlib/Makefile.inc
index c620754e33c7..054e7db16de3 100644
--- a/tests/commonlib/Makefile.inc
+++ b/tests/commonlib/Makefile.inc
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
+subdirs-y += bsd
+
tests-y += region-test
region-test-srcs += tests/commonlib/region-test.c
diff --git a/tests/commonlib/bsd/Makefile.inc b/tests/commonlib/bsd/Makefile.inc
new file mode 100644
index 000000000000..56664d037cc2
--- /dev/null
+++ b/tests/commonlib/bsd/Makefile.inc
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+tests-y += helpers-test
+
+helpers-test-srcs += tests/commonlib/bsd/helpers-test.c
diff --git a/tests/commonlib/bsd/helpers-test.c b/tests/commonlib/bsd/helpers-test.c
new file mode 100644
index 000000000000..ec3f98bed17a
--- /dev/null
+++ b/tests/commonlib/bsd/helpers-test.c
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <commonlib/bsd/helpers.h>
+#include <tests/test.h>
+
+static void func(void)
+{
+ function_called();
+}
+
+static void test_retry(void **state)
+{
+ int count;
+
+ /* 2-argument form */
+ count = 0;
+ assert_true(retry(3, ++count == 1));
+ count = 0;
+ assert_true(retry(3, ++count == 3));
+ count = 0;
+ assert_false(retry(3, ++count == 4));
+
+ /* 3-argument form */
+ expect_function_calls(func, 9);
+ assert_null(retry(10, NULL, func()));
+
+ assert_int_equal(retry(10, 999, func()), 999);
+
+ count = 0;
+ expect_function_calls(func, 3);
+ assert_true(retry(10, ++count == 4, func()));
+}
+
+int main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_retry),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}