]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
atomics: Add a ref_get() variant returning non-zero on overflows
authorMartin Willi <martin@strongswan.org>
Wed, 10 Jan 2024 15:38:54 +0000 (16:38 +0100)
committerMartin Willi <martin@strongswan.org>
Fri, 16 Feb 2024 09:11:11 +0000 (10:11 +0100)
This is useful for users using ref_get() for unique identifier allocation,
but the zero value has special meaning.

src/libstrongswan/tests/suites/test_utils.c
src/libstrongswan/utils/utils/atomics.h

index e4463f2d007a2069811fe74c2c8c733a7b159b80..4662fa88674ae223e40381f81fbfcd96cbf98b92 100644 (file)
@@ -256,6 +256,26 @@ START_TEST(test_round)
 }
 END_TEST
 
+/*******************************************************************************
+ * ref_get/put
+ */
+
+START_TEST(test_refs)
+{
+       refcount_t r = 0xfffffffe;
+
+       ck_assert_int_eq(ref_cur(&r), 0xfffffffe);
+       ck_assert_int_eq(ref_get(&r), 0xffffffff);
+       ck_assert_int_eq(ref_get_nonzero(&r), 1);
+       ck_assert_int_eq(ref_get_nonzero(&r), 2);
+       ck_assert_int_eq(ref_cur(&r), 2);
+       ck_assert(!ref_put(&r));
+       ck_assert_int_eq(ref_cur(&r), 1);
+       ck_assert(ref_put(&r));
+       ck_assert_int_eq(ref_cur(&r), 0);
+}
+END_TEST
+
 /*******************************************************************************
  * streq
  */
@@ -1272,6 +1292,10 @@ Suite *utils_suite_create()
        tcase_add_test(tc, test_round);
        suite_add_tcase(s, tc);
 
+       tc = tcase_create("refcount");
+       tcase_add_test(tc, test_refs);
+       suite_add_tcase(s, tc);
+
        tc = tcase_create("string helper");
        tcase_add_loop_test(tc, test_streq, 0, countof(streq_data));
        tcase_add_loop_test(tc, test_strneq, 0, countof(strneq_data));
index 0fcd99e18eea534101620a58a2d6cab64d5f71e2..58f1cd92ec502b2e7825db0bb49598e841b60830 100644 (file)
@@ -124,6 +124,33 @@ bool cas_ptr(void **ptr, void *oldval, void *newval);
 
 #endif /* HAVE_GCC_ATOMIC_OPERATIONS */
 
+/**
+ * Get a new reference, but skip zero on overflow.
+ *
+ * If a reference counter is used to allocate unique identifiers, the
+ * refcount value may overflow if it is never decremented. The 0 identifier
+ * may have special semantics, hence returning can be problematic for some
+ * users.
+ *
+ * This call does an additional ref_get() if ref_get() overflows and returns
+ * zero. This ensures that zero is never returned, in the assumption that it
+ * has special meaning.
+ *
+ * @param ref  pointer to ref counter
+ * @return             new value of ref
+ */
+static inline refcount_t ref_get_nonzero(refcount_t *ref)
+{
+       refcount_t v;
+
+       v = ref_get(ref);
+       if (v == 0)
+       {
+               v = ref_get(ref);
+       }
+       return v;
+}
+
 /**
  * Initialize atomics utility functions
  */