]> xenbits.xensource.com Git - unikraft/unikraft.git/commitdiff
include: Add strong/weak reference counting
authorAndrei Tatar <andrei@unikraft.io>
Thu, 16 Nov 2023 18:04:30 +0000 (19:04 +0100)
committerSimon Kuenzer <simon@unikraft.io>
Tue, 28 Nov 2023 18:24:42 +0000 (19:24 +0100)
This change adds a utility header implementing a reference counting
scheme that supports regular (strong) as well as weak references.

Signed-off-by: Andrei Tatar <andrei@unikraft.io>
Reviewed-by: Simon Kuenzer <simon@unikraft.io>
Approved-by: Simon Kuenzer <simon@unikraft.io>
GitHub-Closes: #1160

include/uk/weak_refcount.h [new file with mode: 0644]

diff --git a/include/uk/weak_refcount.h b/include/uk/weak_refcount.h
new file mode 100644 (file)
index 0000000..83d8e77
--- /dev/null
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors.
+ * Licensed under the BSD-3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ */
+
+/* Strong/Weak reference counting */
+
+#ifndef __UK_WEAK_REFCOUNT_H__
+#define __UK_WEAK_REFCOUNT_H__
+
+#include <uk/refcount.h>
+#include <uk/assert.h>
+
+struct uk_swrefcount {
+       __atomic refcount; /* Total number of references */
+       __atomic strong; /* Number of strong references; <= .refcount */
+};
+
+#define UK_SWREFCOUNT_INITIALIZER(r, s) ((struct uk_swrefcount){ \
+       .refcount = UK_REFCOUNT_INITIALIZER((r)), \
+       .strong = UK_REFCOUNT_INITIALIZER((s)), \
+})
+
+/**
+ * Initialize refcount with `ref` references, of which `strong` are strong.
+ */
+static inline
+void uk_swrefcount_init(struct uk_swrefcount *sw, __u32 ref, __u32 strong)
+{
+       UK_ASSERT(ref >= strong);
+       uk_refcount_init(&sw->refcount, ref);
+       uk_refcount_init(&sw->strong, strong);
+}
+
+/**
+ * Acquire a weak reference on `sw`.
+ */
+static inline
+void uk_swrefcount_acquire_weak(struct uk_swrefcount *sw)
+{
+       uk_refcount_acquire(&sw->refcount);
+}
+
+/**
+ * Acquire a strong reference on `sw`.
+ */
+static inline
+void uk_swrefcount_acquire(struct uk_swrefcount *sw)
+{
+       uk_swrefcount_acquire_weak(sw);
+       uk_refcount_acquire(&sw->strong);
+}
+
+#define UK_SWREFCOUNT_LAST_STRONG 2 /* Released last strong reference */
+#define UK_SWREFCOUNT_LAST_REF    1 /* Released last reference */
+
+/**
+ * Release a weak reference on `sw` and return whether it was the last.
+ *
+ * @return
+ *   0 if there are more references left, or UK_SWREFCOUNT_LAST_REF if not.
+ */
+static inline
+int uk_swrefcount_release_weak(struct uk_swrefcount *sw)
+{
+       return uk_refcount_release(&sw->refcount) ? UK_SWREFCOUNT_LAST_REF : 0;
+}
+
+/**
+ * Release a strong reference on `sw` and return whether it was the last.
+ *
+ * @return
+ *   0 if there are more references left, otherwise a bitwise OR of:
+ *   UK_SWREFCOUNT_LAST_STRONG, if we released the last strong reference
+ *   UK_SWREFCOUNT_LAST_REF, if we released the last reference
+ */
+static inline
+int uk_swrefcount_release(struct uk_swrefcount *sw)
+{
+       int ret = 0;
+
+       if (uk_refcount_release(&sw->strong))
+               ret |= UK_SWREFCOUNT_LAST_STRONG;
+       return ret | uk_swrefcount_release_weak(sw);
+}
+
+#endif /* __UK_WEAK_REFCOUNT_H__ */