core: switch to reference counting for gpio chip objects
authorBartosz Golaszewski <bgolaszewski@baylibre.com>
Thu, 21 Jan 2021 10:34:57 +0000 (11:34 +0100)
committerBartosz Golaszewski <bgolaszewski@baylibre.com>
Thu, 18 Mar 2021 08:34:15 +0000 (09:34 +0100)
The preferred approach in low-level system libraries is to make all
exposed data structures opaque and use reference counting for their
memory management. This changes the chip objects to only close their
underlying character device and release all resources once the reference
count goes down to 0. We remove the gpiod_chip_close() function and
replace it with gpiod_chip_ref() and gpiod_chip_unref().

Other objects in the API will either be removed or are not opaque yet
and will be reworked later.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
bindings/cxx/chip.cpp
bindings/python/gpiodmodule.c
include/gpiod.h
lib/core.c
tests/gpiod-test.h
tools/gpiodetect.c
tools/gpiofind.c
tools/gpioget.c
tools/gpioinfo.c
tools/gpiomon.c
tools/gpioset.c

index 527fb34c389152ac410bdedd5ba578a31bcef2d3..0886717884b7f93c8566964770e395062c21704b 100644 (file)
@@ -13,7 +13,7 @@ namespace {
 
 void chip_deleter(::gpiod_chip* chip)
 {
-       ::gpiod_chip_close(chip);
+       ::gpiod_chip_unref(chip);
 }
 
 } /* namespace */
index ac0fd83072c87058d884878535e631a875c54fd1..e54c3ad77090e7c8af38780a3ba63d7d82cb2fc7 100644 (file)
@@ -1953,7 +1953,7 @@ static int gpiod_Chip_init(gpiod_ChipObject *self,
 static void gpiod_Chip_dealloc(gpiod_ChipObject *self)
 {
        if (self->chip)
-               gpiod_chip_close(self->chip);
+               gpiod_chip_unref(self->chip);
 
        PyObject_Del(self);
 }
@@ -1981,7 +1981,7 @@ static PyObject *gpiod_Chip_close(gpiod_ChipObject *self,
        if (gpiod_ChipIsClosed(self))
                return NULL;
 
-       gpiod_chip_close(self->chip);
+       gpiod_chip_unref(self->chip);
        self->chip = NULL;
 
        Py_RETURN_NONE;
index 6ed9c6c4b49e4c54d8418784aeccb0eea18dd60b..71abb2a8244751f56b0738e741fd71d3840703cc 100644 (file)
@@ -81,10 +81,18 @@ bool gpiod_is_gpiochip_device(const char *path) GPIOD_API;
 struct gpiod_chip *gpiod_chip_open(const char *path) GPIOD_API;
 
 /**
- * @brief Close a GPIO chip handle and release all allocated resources.
+ * @brief Increase the refcount on this GPIO object.
  * @param chip The GPIO chip object.
+ * @return Passed reference to the GPIO chip.
  */
-void gpiod_chip_close(struct gpiod_chip *chip) GPIOD_API;
+struct gpiod_chip *gpiod_chip_ref(struct gpiod_chip *chip) GPIOD_API;
+
+/**
+ * @brief Decrease the refcount on this GPIO object. If the refcount reaches 0,
+ *        close the chip device and free all associated resources.
+ * @param chip The GPIO chip object.
+ */
+void gpiod_chip_unref(struct gpiod_chip *chip) GPIOD_API;
 
 /**
  * @brief Get the GPIO chip name as represented in the kernel.
index 077ea3e9482c625ba6fd10d5c306b0a08ad331bf..bab438f14f92b6da7e3fc3c3b88a3d6ca56cf1b3 100644 (file)
@@ -64,6 +64,8 @@ struct gpiod_line {
 };
 
 struct gpiod_chip {
+       int refcount;
+
        struct gpiod_line **lines;
        unsigned int num_lines;
 
@@ -297,6 +299,7 @@ struct gpiod_chip *gpiod_chip_open(const char *path)
 
        chip->fd = fd;
        chip->num_lines = info.lines;
+       chip->refcount = 1;
 
        /*
         * GPIO device must have a name - don't bother checking this field. In
@@ -324,11 +327,21 @@ err_close_fd:
        return NULL;
 }
 
-void gpiod_chip_close(struct gpiod_chip *chip)
+struct gpiod_chip *gpiod_chip_ref(struct gpiod_chip *chip)
+{
+       chip->refcount++;
+       return chip;
+}
+
+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];
index 2688d3cb409c4528d6ff5411ea0c1a2d49237dbf..a093f83512cc4fc9e5b8fda96e772d65b1feb91b 100644 (file)
@@ -22,7 +22,7 @@
 typedef struct gpiod_chip gpiod_chip_struct;
 typedef struct gpiod_line_bulk gpiod_line_bulk_struct;
 
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(gpiod_chip_struct, gpiod_chip_close);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(gpiod_chip_struct, gpiod_chip_unref);
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(gpiod_line_bulk_struct, gpiod_line_bulk_free);
 
 /* These are private definitions and should not be used directly. */
index 7a2015e62a10fc8a0410ab924cc27f706a1acbb6..9f4c28c65b3478c11a502416c816adc3d1df0022 100644 (file)
@@ -80,7 +80,7 @@ int main(int argc, char **argv)
                       gpiod_chip_label(chip),
                       gpiod_chip_num_lines(chip));
 
-               gpiod_chip_close(chip);
+               gpiod_chip_unref(chip);
                free(entries[i]);
        }
 
index 0fc07d98de551a245d45762925e8c0a6952240ca..83af76bbb6b3e1600b94f39eb825df384a5f9791 100644 (file)
@@ -77,7 +77,7 @@ int main(int argc, char **argv)
                if (offset >= 0) {
                        printf("%s %u\n",
                               gpiod_chip_name(chip), offset);
-                       gpiod_chip_close(chip);
+                       gpiod_chip_unref(chip);
                        return EXIT_SUCCESS;
                }
        }
index 527dc222a73d44ba838bb6cda59a9ef4628a35fd..ceeec566683a180f34d9e9e3aa7e80314a436cfb 100644 (file)
@@ -123,7 +123,7 @@ int main(int argc, char **argv)
        printf("\n");
 
        gpiod_line_release_bulk(lines);
-       gpiod_chip_close(chip);
+       gpiod_chip_unref(chip);
        gpiod_line_bulk_free(lines);
        free(values);
        free(offsets);
index 84588bc5fcac2a4d0796cda6a0496a5e0fe5f97a..eba8c72e4be47f18d97a22e382fd84e8ae36cc87 100644 (file)
@@ -230,7 +230,7 @@ int main(int argc, char **argv)
 
                        list_lines(chip);
 
-                       gpiod_chip_close(chip);
+                       gpiod_chip_unref(chip);
                }
        } else {
                for (i = 0; i < argc; i++) {
@@ -240,7 +240,7 @@ int main(int argc, char **argv)
 
                        list_lines(chip);
 
-                       gpiod_chip_close(chip);
+                       gpiod_chip_unref(chip);
                }
        }
 
index 8bf2c7009d3d791b342a91860bfaab24321017ee..dda9f6f0c93df712bd548cf96b99ac76ab944876 100644 (file)
@@ -306,7 +306,7 @@ done:
        gpiod_line_release_bulk(lines);
        gpiod_line_bulk_free(lines);
        gpiod_line_bulk_free(evlines);
-       gpiod_chip_close(chip);
+       gpiod_chip_unref(chip);
 
        return EXIT_SUCCESS;
 }
index 7e9d88fdee5f524d52d9b80bdb735a11444840a4..a088ec6416abd073f434b64e143ce2326aa98d95 100644 (file)
@@ -305,7 +305,7 @@ int main(int argc, char **argv)
        mode->callback(&cbdata);
 
        gpiod_line_release_bulk(lines);
-       gpiod_chip_close(chip);
+       gpiod_chip_unref(chip);
        gpiod_line_bulk_free(lines);
        free(offsets);
        free(values);