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@xxxxxxxx> --- 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 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@xxxxxxxxx> 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@xxxxxxxx> + +#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__ */ -- 2.30.1