We can use reference counter to ease up object lifetime management.
This patch adds very basic support for reference counters. refcnt
should be used in the following way:

1. Protected structure should have refcnt_t field

2. This field should be initialized with refcnt_init() during object
construction.

3. If code holds a valid pointer to a structure/object it can increase
refcount with refcnt_get(). No additional locking is required.

4. Code should call refcnt_put() before dropping pointer to a
protected structure. `destructor` is a call back function that should
destruct object and free all resources, including structure protected
itself. Destructor will be called if reference counter reaches zero.

5. If code does not hold a valid pointer to a protected structure it
should use other locking mechanism to obtain a pointer. For example,
it should lock a list that hold protected objects.

Signed-off-by: Volodymyr Babchuk <volodymyr_babc...@epam.com>

---
v3:
  - moved in from another patch series
  - used structure to encapsulate refcnt_t
  - removed #ifndef NDEBUG in favor of just calling ASSERT
  - added assertion to refcnt_put
  - added saturation support: code catches overflow and underflow
  - added EMACS magic at end of the file
  - fixed formatting
---
 xen/include/xen/refcnt.h | 59 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 xen/include/xen/refcnt.h

diff --git a/xen/include/xen/refcnt.h b/xen/include/xen/refcnt.h
new file mode 100644
index 0000000000..1ac05d927c
--- /dev/null
+++ b/xen/include/xen/refcnt.h
@@ -0,0 +1,59 @@
+#ifndef __XEN_REFCNT_H__
+#define __XEN_REFCNT_H__
+
+#include <asm/atomic.h>
+#include <asm/bug.h>
+
+#define REFCNT_SATURATED (INT_MIN / 2)
+
+typedef struct {
+    atomic_t refcnt;
+} refcnt_t;
+
+static inline void refcnt_init(refcnt_t *refcnt)
+{
+    atomic_set(&refcnt->refcnt, 1);
+}
+
+static inline int refcnt_read(refcnt_t *refcnt)
+{
+    return atomic_read(&refcnt->refcnt);
+}
+
+static inline void refcnt_get(refcnt_t *refcnt)
+{
+    int old = atomic_add_unless(&refcnt->refcnt, 1, 0);
+
+    if ( unlikely(old < 0) || unlikely (old + 1 < 0) )
+    {
+        atomic_set(&refcnt->refcnt, REFCNT_SATURATED);
+        printk(XENLOG_ERR"refcnt saturation: old = %d\n", old);
+        WARN();
+    }
+}
+
+static inline void refcnt_put(refcnt_t *refcnt, void (*destructor)(refcnt_t 
*refcnt))
+{
+    int ret = atomic_dec_return(&refcnt->refcnt);
+
+    if ( ret == 0 )
+        destructor(refcnt);
+
+    if ( unlikely(ret < 0))
+    {
+        atomic_set(&refcnt->refcnt, REFCNT_SATURATED);
+        printk(XENLOG_ERR"refcnt already hit 0: val = %d\n", ret);
+        WARN();
+    }
+}
+
+#endif
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.39.2

Reply via email to