libgpiod: use a per-thread variable for storing errors
authorBartosz Golaszewski <bartekgola@gmail.com>
Mon, 2 Jan 2017 12:31:58 +0000 (13:31 +0100)
committerBartosz Golaszewski <bartekgola@gmail.com>
Mon, 2 Jan 2017 12:37:59 +0000 (13:37 +0100)
The kernel-like trick with embedding error numbers in pointers can't
be guaranteed to work on all architectures. Use a per-thread variable
instead and add corresponding routines to access it.

Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
core.c
gpiod.h
gpiodetect.c
gpioinfo.c
gpioset.c

diff --git a/core.c b/core.c
index b24eb42e5fcffa3bc6e7aec565de78ba1363bf3f..8eef6d4a9de9fbbda75306eda4b53b876547067a 100644 (file)
--- a/core.c
+++ b/core.c
@@ -25,6 +25,8 @@ static const char dev_dir[] = "/dev/";
 static const char cdev_prefix[] = "gpiochip";
 static const char libgpiod_consumer[] = "libgpiod";
 
+static __thread int last_error;
+
 static void * zalloc(size_t size)
 {
        void *ptr;
@@ -43,6 +45,16 @@ static bool is_unsigned_int(const char *str)
        return *str == '\0';
 }
 
+int gpiod_errno(void)
+{
+       return last_error;
+}
+
+const char * gpiod_strerror(int errnum)
+{
+       return strerror(errnum);
+}
+
 int gpiod_simple_get_value(const char *device, unsigned int offset)
 {
        struct gpiod_chip *chip;
@@ -50,20 +62,20 @@ int gpiod_simple_get_value(const char *device, unsigned int offset)
        int status, value;
 
        chip = gpiod_chip_open_lookup(device);
-       if (GPIOD_IS_ERR(chip))
-               return GPIOD_PTR_ERR(chip);
+       if (!chip)
+               return -1;
 
        line = gpiod_chip_get_line(chip, offset);
-       if (GPIOD_IS_ERR(line)) {
+       if (!line) {
                gpiod_chip_close(chip);
-               return GPIOD_PTR_ERR(line);
+               return -1;
        }
 
        status = gpiod_line_request(line, libgpiod_consumer,
                                    GPIOD_DIRECTION_IN, 0, 0);
        if (status < 0) {
                gpiod_chip_close(chip);
-               return status;
+               return -1;
        }
 
        value = gpiod_line_get_value(line);
@@ -81,20 +93,20 @@ int gpiod_simple_set_value(const char *device, unsigned int offset, int value)
        int status;
 
        chip = gpiod_chip_open_lookup(device);
-       if (GPIOD_IS_ERR(chip))
-               return GPIOD_PTR_ERR(chip);
+       if (!chip)
+               return -1;
 
        line = gpiod_chip_get_line(chip, offset);
-       if (GPIOD_IS_ERR(line)) {
+       if (!line) {
                gpiod_chip_close(chip);
-               return GPIOD_PTR_ERR(line);
+               return -1;
        }
 
        status = gpiod_line_request(line, libgpiod_consumer,
                                    GPIOD_DIRECTION_OUT, value, 0);
        if (status < 0) {
                gpiod_chip_close(chip);
-               return status;
+               return -1;
        }
 
        gpiod_line_release(line);
@@ -185,8 +197,10 @@ int gpiod_line_request(struct gpiod_line *line, const char *consumer,
        fd = gpiod_chip_get_fd(chip);
 
        status = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, req);
-       if (status < 0)
-               return -errno;
+       if (status < 0) {
+               last_error = errno;
+               return -1;
+       }
 
        line->requested = true;
 
@@ -209,14 +223,18 @@ int gpiod_line_get_value(struct gpiod_line *line)
        struct gpiohandle_data data;
        int status;
 
-       if (!gpiod_line_is_requested(line))
-               return -EPERM;
+       if (!gpiod_line_is_requested(line)) {
+               last_error = -EPERM;
+               return -1;
+       }
 
        memset(&data, 0, sizeof(data));
 
        status = ioctl(line->lreq.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
-       if (status < 0)
-               return -errno;
+       if (status < 0) {
+               last_error = errno;
+               return -1;
+       }
 
        return data.values[0];
 }
@@ -226,15 +244,19 @@ int gpiod_line_set_value(struct gpiod_line *line, int value)
        struct gpiohandle_data data;
        int status;
 
-       if (!gpiod_line_is_requested(line))
-               return -EPERM;
+       if (!gpiod_line_is_requested(line)) {
+               last_error = -EPERM;
+               return -1;
+       }
 
        memset(&data, 0, sizeof(data));
        data.values[0] = value ? 1 : 0;
 
        status = ioctl(line->lreq.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
-       if (status < 0)
-               return -errno;
+       if (status < 0) {
+               last_error = errno;
+               return -1;
+       }
 
        return 0;
 }
@@ -252,13 +274,16 @@ struct gpiod_chip * gpiod_chip_open(const char *path)
        int status, fd;
 
        fd = open(path, O_RDWR);
-       if (fd < 0)
-               return GPIOD_ERR_PTR(-errno);
+       if (fd < 0) {
+               last_error = errno;
+               return NULL;
+       }
 
        chip = zalloc(sizeof(*chip));
        if (!chip) {
                close(fd);
-               return GPIOD_ERR_PTR(-ENOMEM);
+               last_error = ENOMEM;
+               return NULL;
        }
 
        chip->fd = fd;
@@ -267,14 +292,16 @@ struct gpiod_chip * gpiod_chip_open(const char *path)
        if (status < 0) {
                close(chip->fd);
                free(chip);
-               return GPIOD_ERR_PTR(-errno);
+               last_error = errno;
+               return NULL;
        }
 
        chip->lines = zalloc(chip->cinfo.lines * sizeof(*chip->lines));
        if (!chip->lines) {
                close(chip->fd);
                free(chip);
-               return GPIOD_ERR_PTR(-ENOMEM);
+               last_error = ENOMEM;
+               return NULL;
        }
 
        return chip;
@@ -287,8 +314,10 @@ struct gpiod_chip * gpiod_chip_open_by_name(const char *name)
        int status;
 
        status = asprintf(&path, "%s%s", dev_dir, name);
-       if (status < 0)
-               return GPIOD_ERR_PTR(-errno);
+       if (status < 0) {
+               last_error = errno;
+               return NULL;
+       }
 
        chip = gpiod_chip_open(path);
        free(path);
@@ -303,8 +332,10 @@ struct gpiod_chip * gpiod_chip_open_by_number(unsigned int num)
        int status;
 
        status = asprintf(&path, "%s%s%u", dev_dir, cdev_prefix, num);
-       if (!status)
-               return GPIOD_ERR_PTR(-ENOMEM);
+       if (!status) {
+               last_error = errno;
+               return NULL;
+       }
 
        chip = gpiod_chip_open(path);
        free(path);
@@ -351,8 +382,10 @@ gpiod_chip_get_line(struct gpiod_chip *chip, unsigned int offset)
        struct gpiod_line *line;
        int status;
 
-       if (offset >= chip->cinfo.lines)
-               return GPIOD_ERR_PTR(-EINVAL);
+       if (offset >= chip->cinfo.lines) {
+               last_error = EINVAL;
+               return NULL;
+       }
 
        line = &chip->lines[offset];
 
@@ -360,8 +393,10 @@ gpiod_chip_get_line(struct gpiod_chip *chip, unsigned int offset)
        line->linfo.line_offset = offset;
 
        status = ioctl(chip->fd, GPIO_GET_LINEINFO_IOCTL, &line->linfo);
-       if (status < 0)
-               return GPIOD_ERR_PTR(-errno);
+       if (status < 0) {
+               last_error = errno;
+               return NULL;
+       }
 
        line->chip = chip;
 
@@ -389,12 +424,16 @@ struct gpiod_chip_iter * gpiod_chip_iter_new(void)
        struct gpiod_chip_iter *new;
 
        new = zalloc(sizeof(*new));
-       if (!new)
-               return GPIOD_ERR_PTR(-ENOMEM);
+       if (!new) {
+               last_error = ENOMEM;
+               return NULL;
+       }
 
        new->dir = opendir(dev_dir);
-       if (!new->dir)
-               return GPIOD_ERR_PTR(-errno);
+       if (!new->dir) {
+               last_error = errno;
+               return NULL;
+       }
 
        return new;
 }
diff --git a/gpiod.h b/gpiod.h
index 0af089bccbcf6ac817c3fe8dbffa02b24b17a4a5..0cc86b043fd2f6bb6652d1c8a7a6dd6828e40fbd 100644 (file)
--- a/gpiod.h
+++ b/gpiod.h
@@ -25,22 +25,9 @@ extern "C" {
 
 #define GPIOD_BIT(nr)          (1UL << (nr))
 
-#define __GPIOD_MAX_ERRNO      4095
+int gpiod_errno(void) GPIOD_API;
 
-static inline void * GPIOD_ERR_PTR(long error)
-{
-       return (void *)error;
-}
-
-static inline long GPIOD_PTR_ERR(const void *ptr)
-{
-       return (long)ptr;
-}
-
-static inline bool GPIOD_IS_ERR(const void *ptr)
-{
-       return (uintptr_t)ptr >= ((unsigned int) - __GPIOD_MAX_ERRNO);
-}
+const char * gpiod_strerror(int errnum) GPIOD_API;
 
 int gpiod_simple_get_value(const char *device, unsigned int offset) GPIOD_API;
 
@@ -135,7 +122,7 @@ gpiod_chip_iter_next(struct gpiod_chip_iter *iter) GPIOD_API;
 
 #define gpiod_foreach_chip(iter, chip)                                 \
        for ((chip) = gpiod_chip_iter_next(iter);                       \
-            (chip) && !GPIOD_IS_ERR(chip);                             \
+            (chip);                                                    \
             (chip) = gpiod_chip_iter_next(iter))
 
 struct gpiod_line_iter {
@@ -160,7 +147,7 @@ gpiod_chip_line_next(struct gpiod_chip *chip, struct gpiod_line_iter *iter)
 
 #define gpiod_chip_foreach_line(iter, chip, line)                      \
        for ((line) = gpiod_chip_line_next(chip, iter);                 \
-            (line) && !(GPIOD_IS_ERR(line));                           \
+            (line);                                                    \
             (line) = gpiod_chip_line_next(chip, iter))
 
 #ifdef __cplusplus
index a11be5e8c4147e0cead8e5f4cfd67879769766de..9678c13e1e200ecfacf4f056de64e521b20b77eb 100644 (file)
@@ -17,7 +17,6 @@ int main(int argc, char **argv)
 {
        struct gpiod_chip_iter *iter;
        struct gpiod_chip *chip;
-       int status;
 
        if (argc != 1) {
                printf("Usage: %s\n", argv[0]);
@@ -27,9 +26,11 @@ int main(int argc, char **argv)
        }
 
        iter = gpiod_chip_iter_new();
-       if (GPIOD_IS_ERR(iter)) {
-               status = GPIOD_PTR_ERR(iter);
-               goto err;
+       if (!iter) {
+               fprintf(stderr, "%s: unable to access gpio chips: %s\n",
+                       argv[0], gpiod_strerror(gpiod_errno()));
+
+               return EXIT_FAILURE;
        }
 
        gpiod_foreach_chip(iter, chip) {
@@ -41,16 +42,5 @@ int main(int argc, char **argv)
 
        gpiod_chip_iter_free(iter);
 
-       if (GPIOD_IS_ERR(chip)) {
-               status = GPIOD_PTR_ERR(chip);
-               goto err;
-       }
-
        return EXIT_SUCCESS;
-
-err:
-       fprintf(stderr, "%s: unable to access gpio chips: %s\n",
-               argv[0], strerror(-status));
-
-       return EXIT_FAILURE;
 }
index 4ca4d0069ba484199d8c751e7d2775f70d89b2bc..57ded125cbfa8e10b0eafe31dd85e4be4905ea77 100644 (file)
@@ -47,11 +47,11 @@ int main(int argc, char **argv)
 
        for (i = 1; i < argc; i++) {
                chip = gpiod_chip_open_lookup(argv[i]);
-               if (GPIOD_IS_ERR(chip)) {
+               if (!chip) {
                        fprintf(stderr,
                                "%s: unable to access %s: %s\n",
                                argv[0], argv[i],
-                               strerror(-GPIOD_PTR_ERR(chip)));
+                               gpiod_strerror(gpiod_errno()));
                        continue;
                }
 
index 67dd04511a4e5876ed51ed113ccf279e443f7b43..3870cf39f847eae9273abe1218df89ab8b8a8950 100644 (file)
--- a/gpioset.c
+++ b/gpioset.c
@@ -53,18 +53,18 @@ int main(int argc, char **argv)
        }
 
        chip = gpiod_chip_open_lookup(device);
-       if (GPIOD_IS_ERR(chip)) {
+       if (!chip) {
                fprintf(stderr,
                        "%s: error accessing gpiochip %s: %s\n",
-                       argv[0], device, strerror(-GPIOD_PTR_ERR(chip)));
+                       argv[0], device, gpiod_strerror(gpiod_errno()));
                return EXIT_FAILURE;
        }
 
        line = gpiod_chip_get_line(chip, offset);
-       if (GPIOD_IS_ERR(line)) {
+       if (!line) {
                fprintf(stderr,
                        "%s: error accessing line %u: %s\n",
-                       argv[0], offset, strerror(-GPIOD_PTR_ERR(chip)));
+                       argv[0], offset, gpiod_strerror(gpiod_errno()));
                return EXIT_FAILURE;
        }
 
@@ -72,7 +72,7 @@ int main(int argc, char **argv)
        if (status < 0) {
                fprintf(stderr,
                        "%s: error requesting GPIO line: %s\n",
-                       argv[0], strerror(-status));
+                       argv[0], gpiod_strerror(gpiod_errno()));
                return EXIT_FAILURE;
        }
 
@@ -80,7 +80,7 @@ int main(int argc, char **argv)
        if (status < 0) {
                fprintf(stderr,
                        "%s: error setting GPIO value: %s\n",
-                       argv[0], strerror(-status));
+                       argv[0], gpiod_strerror(gpiod_errno()));
                return EXIT_FAILURE;
        }