From 806ce83308aa0b45d9a7b2b7ebd47354c8e1ad63 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 2 Jan 2017 13:31:58 +0100 Subject: [PATCH] libgpiod: use a per-thread variable for storing errors 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 --- core.c | 113 ++++++++++++++++++++++++++++++++++----------------- gpiod.h | 21 ++-------- gpiodetect.c | 20 +++------ gpioinfo.c | 4 +- gpioset.c | 12 +++--- 5 files changed, 93 insertions(+), 77 deletions(-) diff --git a/core.c b/core.c index b24eb42..8eef6d4 100644 --- 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 0af089b..0cc86b0 100644 --- 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 diff --git a/gpiodetect.c b/gpiodetect.c index a11be5e..9678c13 100644 --- a/gpiodetect.c +++ b/gpiodetect.c @@ -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; } diff --git a/gpioinfo.c b/gpioinfo.c index 4ca4d00..57ded12 100644 --- a/gpioinfo.c +++ b/gpioinfo.c @@ -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; } diff --git a/gpioset.c b/gpioset.c index 67dd045..3870cf3 100644 --- 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; } -- 2.30.2