static int lldp_make_space(sd_lldp *lldp, size_t extra) { usec_t t = USEC_INFINITY; bool changed = false; assert(lldp); /* Remove all entries that are past their TTL, and more until at least the specified number of extra entries * are free. */ for (;;) { _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; n = prioq_peek(lldp->neighbor_by_expiry); if (!n) break; sd_lldp_neighbor_ref(n); if (hashmap_size(lldp->neighbor_by_id) > LESS_BY(lldp->neighbors_max, extra)) goto remove_one; if (t == USEC_INFINITY) t = now(clock_boottime_or_monotonic()); if (n->until > t) break; remove_one: lldp_neighbor_unlink(n); lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n); changed = true; } return changed; }
static void test_max(void) { static const struct { int a; int b[CONST_MAX(10, 100)]; } val1 = { .a = CONST_MAX(10, 100), }; int d = 0; unsigned long x = 12345; unsigned long y = 54321; const char str[] = "a_string_constant"; const unsigned long long arr[] = {9999ULL, 10ULL, 0ULL, 3000ULL, 2000ULL, 1000ULL, 100ULL, 9999999ULL}; void *p = (void *)str; void *q = (void *)&str[16]; log_info("/* %s */", __func__); assert_cc(sizeof(val1.b) == sizeof(int) * 100); /* CONST_MAX returns (void) instead of a value if the passed arguments * are not of the same type or not constant expressions. */ assert_cc(__builtin_types_compatible_p(typeof(CONST_MAX(1, 10)), int)); assert_cc(__builtin_types_compatible_p(typeof(CONST_MAX(1, 1U)), void)); assert_se(val1.a == 100); assert_se(MAX(++d, 0) == 1); assert_se(d == 1); assert_cc(MAXSIZE(char[3], uint16_t) == 3); assert_cc(MAXSIZE(char[3], uint32_t) == 4); assert_cc(MAXSIZE(char, long) == sizeof(long)); assert_se(MAX(-5, 5) == 5); assert_se(MAX(5, 5) == 5); assert_se(MAX(MAX(1, MAX(2, MAX(3, 4))), 5) == 5); assert_se(MAX(MAX(1, MAX(2, MAX(3, 2))), 1) == 3); assert_se(MAX(MIN(1, MIN(2, MIN(3, 4))), 5) == 5); assert_se(MAX(MAX(1, MIN(2, MIN(3, 2))), 1) == 2); assert_se(LESS_BY(8, 4) == 4); assert_se(LESS_BY(8, 8) == 0); assert_se(LESS_BY(4, 8) == 0); assert_se(LESS_BY(16, LESS_BY(8, 4)) == 12); assert_se(LESS_BY(4, LESS_BY(8, 4)) == 0); assert_se(CMP(3, 5) == -1); assert_se(CMP(5, 3) == 1); assert_se(CMP(5, 5) == 0); assert_se(CMP(x, y) == -1); assert_se(CMP(y, x) == 1); assert_se(CMP(x, x) == 0); assert_se(CMP(y, y) == 0); assert_se(CMP(UINT64_MAX, (uint64_t) 0) == 1); assert_se(CMP((uint64_t) 0, UINT64_MAX) == -1); assert_se(CMP(UINT64_MAX, UINT64_MAX) == 0); assert_se(CMP(INT64_MIN, INT64_MAX) == -1); assert_se(CMP(INT64_MAX, INT64_MIN) == 1); assert_se(CMP(INT64_MAX, INT64_MAX) == 0); assert_se(CMP(INT64_MIN, INT64_MIN) == 0); assert_se(CMP(INT64_MAX, (int64_t) 0) == 1); assert_se(CMP((int64_t) 0, INT64_MIN) == 1); assert_se(CMP(INT64_MIN, (int64_t) 0) == -1); assert_se(CMP((int64_t) 0, INT64_MAX) == -1); assert_se(CMP(&str[2], &str[7]) == -1); assert_se(CMP(&str[2], &str[2]) == 0); assert_se(CMP(&str[7], (const char *)str) == 1); assert_se(CMP(str[2], str[7]) == 1); assert_se(CMP(str[7], *str) == 1); assert_se(CMP((const unsigned long long *)arr, &arr[3]) == -1); assert_se(CMP(*arr, arr[3]) == 1); assert_se(CMP(p, q) == -1); assert_se(CMP(q, p) == 1); assert_se(CMP(p, p) == 0); assert_se(CMP(q, q) == 0); assert_se(CLAMP(-5, 0, 1) == 0); assert_se(CLAMP(5, 0, 1) == 1); assert_se(CLAMP(5, -10, 1) == 1); assert_se(CLAMP(5, -10, 10) == 5); assert_se(CLAMP(CLAMP(0, -10, 10), CLAMP(-5, 10, 20), CLAMP(100, -5, 20)) == 10); } #pragma GCC diagnostic push #ifdef __clang__ # pragma GCC diagnostic ignored "-Waddress-of-packed-member" #endif static void test_container_of(void) { struct mytype { uint8_t pad1[3]; uint64_t v1; uint8_t pad2[2]; uint32_t v2; } myval = { }; log_info("/* %s */", __func__); assert_cc(sizeof(myval) >= 17); assert_se(container_of(&myval.v1, struct mytype, v1) == &myval); assert_se(container_of(&myval.v2, struct mytype, v2) == &myval); assert_se(container_of(&container_of(&myval.v2, struct mytype, v2)->v1, struct mytype, v1) == &myval); }
static void test_max(void) { static const struct { int a; int b[CONST_MAX(10, 100)]; } val1 = { .a = CONST_MAX(10, 100), }; int d = 0; assert_cc(sizeof(val1.b) == sizeof(int) * 100); /* CONST_MAX returns (void) instead of a value if the passed arguments * are not of the same type or not constant expressions. */ assert_cc(__builtin_types_compatible_p(typeof(CONST_MAX(1, 10)), int)); assert_cc(__builtin_types_compatible_p(typeof(CONST_MAX(1, 1U)), void)); assert_se(val1.a == 100); assert_se(MAX(++d, 0) == 1); assert_se(d == 1); assert_cc(MAXSIZE(char[3], uint16_t) == 3); assert_cc(MAXSIZE(char[3], uint32_t) == 4); assert_cc(MAXSIZE(char, long) == sizeof(long)); assert_se(MAX(-5, 5) == 5); assert_se(MAX(5, 5) == 5); assert_se(MAX(MAX(1, MAX(2, MAX(3, 4))), 5) == 5); assert_se(MAX(MAX(1, MAX(2, MAX(3, 2))), 1) == 3); assert_se(MAX(MIN(1, MIN(2, MIN(3, 4))), 5) == 5); assert_se(MAX(MAX(1, MIN(2, MIN(3, 2))), 1) == 2); assert_se(LESS_BY(8, 4) == 4); assert_se(LESS_BY(8, 8) == 0); assert_se(LESS_BY(4, 8) == 0); assert_se(LESS_BY(16, LESS_BY(8, 4)) == 12); assert_se(LESS_BY(4, LESS_BY(8, 4)) == 0); assert_se(CLAMP(-5, 0, 1) == 0); assert_se(CLAMP(5, 0, 1) == 1); assert_se(CLAMP(5, -10, 1) == 1); assert_se(CLAMP(5, -10, 10) == 5); assert_se(CLAMP(CLAMP(0, -10, 10), CLAMP(-5, 10, 20), CLAMP(100, -5, 20)) == 10); } #pragma GCC diagnostic push #ifdef __clang__ # pragma GCC diagnostic ignored "-Waddress-of-packed-member" #endif static void test_container_of(void) { struct mytype { uint8_t pad1[3]; uint64_t v1; uint8_t pad2[2]; uint32_t v2; } _packed_ myval = { }; assert_cc(sizeof(myval) == 17); assert_se(container_of(&myval.v1, struct mytype, v1) == &myval); assert_se(container_of(&myval.v2, struct mytype, v2) == &myval); assert_se(container_of(&container_of(&myval.v2, struct mytype, v2)->v1, struct mytype, v1) == &myval); }