[libgpiod,RFC,2/6] core: add refcounting helpers

Message ID 20210410145157.30718-3-brgl@bgdev.pl
State New
Headers show
Series
  • first draft of libgpiod v2.0 API
Related show

Commit Message

Bartosz Golaszewski April 10, 2021, 2:51 p.m.
In v2.0 all objects will be opaque and refcounted. Add a set of helper
functions and data structures for refcounting.

Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
---
 lib/Makefile.am |  2 +-
 lib/core.c      | 52 ++++++++++++++++++++++++++-----------------------
 lib/internal.c  | 22 +++++++++++++++++++++
 lib/internal.h  | 19 ++++++++++++++++++
 4 files changed, 70 insertions(+), 25 deletions(-)
 create mode 100644 lib/internal.c

Patch

diff --git a/lib/Makefile.am b/lib/Makefile.am
index 8441584..5c7f353 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -2,7 +2,7 @@ 
 # SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
 
 lib_LTLIBRARIES = libgpiod.la
-libgpiod_la_SOURCES = core.c helpers.c internal.h misc.c uapi/gpio.h
+libgpiod_la_SOURCES = core.c helpers.c internal.c internal.h misc.c uapi/gpio.h
 libgpiod_la_CFLAGS = -Wall -Wextra -g -std=gnu89
 libgpiod_la_CFLAGS += -fvisibility=hidden -I$(top_srcdir)/include/
 libgpiod_la_CFLAGS += -include $(top_builddir)/config.h
diff --git a/lib/core.c b/lib/core.c
index 2e7ee4b..0f3937b 100644
--- a/lib/core.c
+++ b/lib/core.c
@@ -65,7 +65,7 @@  struct gpiod_line {
 };
 
 struct gpiod_chip {
-	int refcount;
+	struct gpiod_refcount refcount;
 
 	struct gpiod_line **lines;
 	unsigned int num_lines;
@@ -246,6 +246,30 @@  out:
 	return ret;
 }
 
+static void chip_release(struct gpiod_refcount *refcount)
+{
+	struct gpiod_chip *chip;
+	struct gpiod_line *line;
+	unsigned int i;
+
+	chip = gpiod_container_of(refcount, struct gpiod_chip, refcount);
+
+	if (chip->lines) {
+		for (i = 0; i < chip->num_lines; i++) {
+			line = chip->lines[i];
+			if (line) {
+				gpiod_line_release(line);
+				free(line);
+			}
+		}
+
+		free(chip->lines);
+	}
+
+	close(chip->fd);
+	free(chip);
+}
+
 GPIOD_API struct gpiod_chip *gpiod_chip_open(const char *path)
 {
 	struct gpiochip_info info;
@@ -276,7 +300,7 @@  GPIOD_API struct gpiod_chip *gpiod_chip_open(const char *path)
 
 	chip->fd = fd;
 	chip->num_lines = info.lines;
-	chip->refcount = 1;
+	gpiod_refcount_init(&chip->refcount, chip_release);
 
 	/*
 	 * GPIO device must have a name - don't bother checking this field. In
@@ -306,33 +330,13 @@  err_close_fd:
 
 GPIOD_API struct gpiod_chip *gpiod_chip_ref(struct gpiod_chip *chip)
 {
-	chip->refcount++;
+	gpiod_refcount_ref(&chip->refcount);
 	return chip;
 }
 
 GPIOD_API void gpiod_chip_unref(struct gpiod_chip *chip)
 {
-	struct gpiod_line *line;
-	unsigned int i;
-
-	chip->refcount--;
-	if (chip->refcount > 0)
-		return;
-
-	if (chip->lines) {
-		for (i = 0; i < chip->num_lines; i++) {
-			line = chip->lines[i];
-			if (line) {
-				gpiod_line_release(line);
-				free(line);
-			}
-		}
-
-		free(chip->lines);
-	}
-
-	close(chip->fd);
-	free(chip);
+	gpiod_refcount_unref(&chip->refcount);
 }
 
 GPIOD_API const char *gpiod_chip_get_name(struct gpiod_chip *chip)
diff --git a/lib/internal.c b/lib/internal.c
new file mode 100644
index 0000000..52b9461
--- /dev/null
+++ b/lib/internal.c
@@ -0,0 +1,22 @@ 
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// SPDX-FileCopyrightText: 2021 Bartosz Golaszewski <brgl@bgdev.pl>
+
+#include "internal.h"
+
+void gpiod_refcount_init(struct gpiod_refcount *refcount,
+			 gpiod_refcount_release release)
+{
+	refcount->refcnt = 1;
+	refcount->release = release;
+}
+
+void gpiod_refcount_ref(struct gpiod_refcount *refcount)
+{
+	refcount->refcnt++;
+}
+
+void gpiod_refcount_unref(struct gpiod_refcount *refcount)
+{
+	if (--refcount->refcnt == 0)
+		refcount->release(refcount);
+}
diff --git a/lib/internal.h b/lib/internal.h
index 8b3f69a..a652879 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -4,8 +4,27 @@ 
 #ifndef __LIBGPIOD_GPIOD_INTERNAL_H__
 #define __LIBGPIOD_GPIOD_INTERNAL_H__
 
+#include <stddef.h>
+
 /* For internal library use only. */
 
 #define GPIOD_API __attribute__((visibility("default")))
 
+#define gpiod_container_of(ptr, type, member) ({			\
+	void *__mptr = (void *)(ptr);					\
+	((type *)(__mptr - offsetof(type, member))); })
+
+struct gpiod_refcount;
+typedef void (*gpiod_refcount_release)(struct gpiod_refcount *);
+
+struct gpiod_refcount {
+	unsigned int refcnt;
+	gpiod_refcount_release release;
+};
+
+void gpiod_refcount_init(struct gpiod_refcount *refcount,
+			 gpiod_refcount_release release);
+void gpiod_refcount_ref(struct gpiod_refcount *refcount);
+void gpiod_refcount_unref(struct gpiod_refcount *refcount);
+
 #endif /* __LIBGPIOD_GPIOD_INTERNAL_H__ */