@@ -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
@@ -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)
new file mode 100644
@@ -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);
+}
@@ -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__ */
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