[PATCHv2] gpio: add simple get/set helpers for GPIO lines
by Martin Hundebøll
The Linux kernel GPIO api operates with chips, lines, handles, and
events.
The chip and line structures represent info about gpio chips, and
gpio lines, respectively. They are used to e.g. lookup a line with a
certain name, and/or line flags.
The handle structure is used to "obtain" a handle to one or more gpio
lines on a chip. Until the file descriptor in this handle is closed, the
gpio lines cannot be used by others. The same file descriptor is used
when setting or getting the line values (one can also set the initial
value when obtaining handles for output lines).
The event structure is used to get a file descriptor that can be used
with select/poll to wait for changes in line levels.
This commit add simple support for setting and getting the value for a
single gpio line. It does so by obtaining a line handle to get/set the
value, and then release the handle immediately again.
Functionality that could be implemented, but is postponed until the need
arises includes:
* looking up a gpio line by its name
* setting/getting multiple gpio lines with a single function
* waiting for events
* holding on to handles
Some of the above probably require adding structures to represent gpio
lines and events, while handles should be private to the class.
---
Changes since v1:
* added gpiochip info and corresponding getters
* changed "line" to "line_num" a few places
Changes since RFC:
* added gpio.h to ell.h
* changed copyright to Geanix
* open gpiochip in l_gpio_chip_new()
* open gpiochip read-only
* added input checks
* clear ioctl structs with memset instead of = {0}
* reorder error-paths
Makefile.am | 6 +-
ell/ell.h | 1 +
ell/ell.sym | 7 +++
ell/gpio.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++
ell/gpio.h | 49 +++++++++++++++
5 files changed, 236 insertions(+), 2 deletions(-)
create mode 100644 ell/gpio.c
create mode 100644 ell/gpio.h
diff --git a/Makefile.am b/Makefile.am
index 8401972..0ecb9a1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -51,7 +51,8 @@ pkginclude_HEADERS = ell/ell.h \
ell/dhcp.h \
ell/cert.h \
ell/ecc.h \
- ell/ecdh.h
+ ell/ecdh.h \
+ ell/gpio.h
lib_LTLIBRARIES = ell/libell.la
@@ -119,7 +120,8 @@ ell_libell_la_SOURCES = $(linux_headers) \
ell/ecc.h \
ell/ecc-external.c \
ell/ecc.c \
- ell/ecdh.c
+ ell/ecdh.c \
+ ell/gpio.c
ell_libell_la_LDFLAGS = -no-undefined \
-Wl,--version-script=$(top_srcdir)/ell/ell.sym \
diff --git a/ell/ell.h b/ell/ell.h
index aab6417..fb1dd79 100644
--- a/ell/ell.h
+++ b/ell/ell.h
@@ -59,3 +59,4 @@
#include <ell/cert.h>
#include <ell/ecc.h>
#include <ell/ecdh.h>
+#include <ell/gpio.h>
diff --git a/ell/ell.sym b/ell/ell.sym
index 841bc49..793e4c3 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -463,6 +463,13 @@ global:
/* ecdh */
l_ecdh_generate_key_pair;
l_ecdh_generate_shared_secret;
+ /* gpio */
+ l_gpio_chip_new;
+ l_gpio_chip_free;
+ l_gpio_chip_get_label;
+ l_gpio_chip_get_num_lines;
+ l_gpio_chip_get_line_value;
+ l_gpio_chip_set_line_value;
local:
*;
};
diff --git a/ell/gpio.c b/ell/gpio.c
new file mode 100644
index 0000000..83032f9
--- /dev/null
+++ b/ell/gpio.c
@@ -0,0 +1,175 @@
+/*
+ *
+ * Embedded Linux library
+ *
+ * Copyright (C) 2018 Geanix. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <linux/gpio.h>
+
+#include "util.h"
+#include "gpio.h"
+#include "private.h"
+
+struct l_gpio_chip {
+ int fd;
+ char *label;
+ uint32_t num_lines;
+};
+
+LIB_EXPORT struct l_gpio_chip *l_gpio_chip_new(const char *chip_name)
+{
+ struct l_gpio_chip *chip;
+ struct gpiochip_info info;
+ char *path;
+ int ret;
+
+ if (!chip_name)
+ return NULL;
+
+ chip = l_new(struct l_gpio_chip, 1);
+
+ path = l_strdup_printf("/dev/%s", chip_name);
+ chip->fd = open(path, O_RDONLY | O_CLOEXEC);
+ l_free(path);
+
+ if (chip->fd < 0) {
+ l_free(chip);
+ return NULL;
+ }
+
+ memset(&info, 0, sizeof(info));
+
+ ret = ioctl(chip->fd, GPIO_GET_CHIPINFO_IOCTL, &info);
+ if (ret < 0) {
+ l_free(chip);
+ return NULL;
+ }
+
+ if (info.label)
+ chip->label = l_strndup(info.label, sizeof(info.label));
+
+ chip->num_lines = info.lines;
+
+ return chip;
+}
+
+LIB_EXPORT void l_gpio_chip_free(struct l_gpio_chip *chip)
+{
+ if (!chip)
+ return;
+
+ if (chip->fd >= 0)
+ close(chip->fd);
+
+ l_free(chip->label);
+ l_free(chip);
+}
+
+LIB_EXPORT const char *l_gpio_chip_get_label(struct l_gpio_chip *chip)
+{
+ if (!chip)
+ return NULL;
+
+ return chip->label;
+}
+
+LIB_EXPORT uint32_t l_gpio_chip_get_num_lines(struct l_gpio_chip *chip)
+{
+ if (!chip)
+ return 0;
+
+ return chip->num_lines;
+}
+
+LIB_EXPORT bool l_gpio_chip_get_line_value(struct l_gpio_chip *chip,
+ uint32_t line_num, bool *value)
+{
+ struct gpiohandle_request req;
+ struct gpiohandle_data data;
+ int ret;
+
+ if (!chip)
+ return false;
+
+ if (line_num >= chip->num_lines)
+ return false;
+
+ if (chip->fd < 0)
+ return false;
+
+ memset(&req, 0, sizeof(req));
+ req.lineoffsets[0] = line_num;
+ req.lines = 1;
+ req.flags = GPIOHANDLE_REQUEST_INPUT;
+
+ ret = ioctl(chip->fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
+ if (ret < 0 || req.fd <= 0)
+ return false;
+
+ memset(&data, 0, sizeof(data));
+
+ ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
+
+ close(req.fd);
+
+ if (ret < 0)
+ return false;
+
+ if (value)
+ *value = !!data.values[0];
+
+ return true;
+}
+
+LIB_EXPORT bool l_gpio_chip_set_line_value(struct l_gpio_chip *chip,
+ uint32_t line_num, bool value)
+{
+ struct gpiohandle_request req;
+ int ret;
+
+ if (!chip)
+ return false;
+
+ if (line_num >= chip->num_lines)
+ return false;
+
+ if (chip->fd < 0)
+ return false;
+
+ memset(&req, 0, sizeof(req));
+ req.lineoffsets[0] = line_num;
+ req.lines = 1;
+ req.flags = GPIOHANDLE_REQUEST_OUTPUT;
+ req.default_values[0] = value;
+
+ ret = ioctl(chip->fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
+ if (ret < 0 || req.fd <= 0)
+ return false;
+
+ close(req.fd);
+
+ return true;
+}
diff --git a/ell/gpio.h b/ell/gpio.h
new file mode 100644
index 0000000..9f4ae6a
--- /dev/null
+++ b/ell/gpio.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Embedded Linux library
+ *
+ * Copyright (C) 2011-2018 Intel Corporation. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __ELL_GPIO_H
+#define __ELL_GPIO_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct l_gpio_chip;
+
+struct l_gpio_chip *l_gpio_chip_new(const char *chip_name);
+void l_gpio_chip_free(struct l_gpio_chip *chip);
+
+const char *l_gpio_chip_get_label(struct l_gpio_chip *chip);
+uint32_t l_gpio_chip_get_num_lines(struct l_gpio_chip *chip);
+bool l_gpio_chip_get_line_value(struct l_gpio_chip *chip, uint32_t line_num,
+ bool *value);
+bool l_gpio_chip_set_line_value(struct l_gpio_chip *chip, uint32_t line_num,
+ bool value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ELL_GPIO_H */
--
2.20.0
3 years
[PATCH 0/2] Allow connection to a tcp dbus address
by Ramon Henrique
This patch came from a demand in a project with industrial IoT for
monitoring a PLC (creating supervisor apps). The infrastructure was
built from a DBus service that can be accessed by a front-end in the
same local network.
Ramon Ribeiro (2):
dbus: Add support to tcp address
unit: dbus: Add unit test to dbus tcp address
.gitignore | 1 +
Makefile.am | 3 +
ell/dbus.c | 95 ++++++++++++++++++-
unit/dbus.conf | 2 +
unit/test-dbus-tcp.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 358 insertions(+), 4 deletions(-)
create mode 100644 unit/test-dbus-tcp.c
--
2.11.0
3 years, 2 months
[PATCH 1/2] utf8: Don't rely on char being signed
by Andrew Zaborowski
Even if it gets forced by compile flags in a future commit it's better
to avoid this char usage.
Reported-by: Natanael Copa
Tested-by: Natanael Copa
---
ell/utf8.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ell/utf8.c b/ell/utf8.c
index e9998f7..edc2fc0 100644
--- a/ell/utf8.c
+++ b/ell/utf8.c
@@ -93,7 +93,7 @@ LIB_EXPORT int l_utf8_get_codepoint(const char *str, size_t len, wchar_t *cp)
if (len == 0)
return 0;
- if (str[0] > 0) {
+ if ((signed char) str[0] > 0) {
*cp = str[0];
return 1;
}
--
2.19.1
3 years, 3 months
[PATCH 1/2] unit: add utf8_validate_test80 test
by Michael Tretter
UTF-8 requires the form 10xxxxxx for the second, third and forth bytes
of a well-formed byte sequences.
Add a test for the string "ße" encoded using the Latin-1 Supplement
block. This is a relatively common German letter combination and valid
Unicode, but not UTF-8.
---
unit/test-utf8.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/unit/test-utf8.c b/unit/test-utf8.c
index 3768506..9b5bc6e 100644
--- a/unit/test-utf8.c
+++ b/unit/test-utf8.c
@@ -815,6 +815,17 @@ static struct utf8_validate_test utf8_validate_test79 = {
.ucs4_len = 5,
};
+static const char utf8_80[] = { 0xdf, 0x65 };
+static const wchar_t ucs4_80[] = { 0xffff };
+
+static struct utf8_validate_test utf8_validate_test80 = {
+ .utf8 = utf8_80,
+ .utf8_len = 2,
+ .type = UTF8_VALIDATE_TYPE_NOTUNICODE,
+ .ucs4 = ucs4_80,
+ .ucs4_len = 1,
+};
+
static void test_utf8_codepoint(const struct utf8_validate_test *test)
{
unsigned int i, pos;
@@ -1085,6 +1096,8 @@ int main(int argc, char *argv[])
&utf8_validate_test78);
l_test_add("Validate UTF 79", test_utf8_validate,
&utf8_validate_test79);
+ l_test_add("Validate UTF 80", test_utf8_validate,
+ &utf8_validate_test80);
l_test_add("Strlen UTF 1", test_utf8_strlen,
&utf8_strlen_test1);
--
2.21.0
3 years, 3 months
[PATCH 1/4] ecc: Clear point coordinates, use explicit_bzero
by Andrew Zaborowski
We would only zero out memory used by the scalar type because
Diffie-Hellman secrets are scalars, but in PWD the PWD and PK values may
be points so also clear those. Update l_ecc_scalar_free to use
explicit_bzero too.
---
ell/ecc.c | 7 ++++++-
ell/ecdh.c | 2 --
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/ell/ecc.c b/ell/ecc.c
index 88c8373..5fa91a8 100644
--- a/ell/ecc.c
+++ b/ell/ecc.c
@@ -541,6 +541,11 @@ LIB_EXPORT ssize_t l_ecc_point_get_data(const struct l_ecc_point *p, void *buf,
LIB_EXPORT void l_ecc_point_free(struct l_ecc_point *p)
{
+ if (unlikely(!p))
+ return;
+
+ explicit_bzero(p->x, p->curve->ndigits * 8);
+ explicit_bzero(p->y, p->curve->ndigits * 8);
l_free(p);
}
@@ -612,7 +617,7 @@ LIB_EXPORT void l_ecc_scalar_free(struct l_ecc_scalar *c)
if (unlikely(!c))
return;
- memset(c->c, 0, c->curve->ndigits * 8);
+ explicit_bzero(c->c, c->curve->ndigits * 8);
l_free(c);
}
diff --git a/ell/ecdh.c b/ell/ecdh.c
index 5ecbd44..a10189f 100644
--- a/ell/ecdh.c
+++ b/ell/ecdh.c
@@ -100,8 +100,6 @@ LIB_EXPORT bool l_ecdh_generate_shared_secret(
*secret = _ecc_constant_new(curve, product->x, curve->ndigits * 8);
- memset(product->x, 0, curve->ndigits * 8);
- memset(product->y, 0, curve->ndigits * 8);
l_ecc_point_free(product);
l_ecc_scalar_free(z);
--
2.19.1
3 years, 3 months
[PATCH v2] unit: Add l_uintset_intersect tests
by Tim Kourt
---
unit/test-uintset.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 91 insertions(+)
diff --git a/unit/test-uintset.c b/unit/test-uintset.c
index 4488cd9..99888b3 100644
--- a/unit/test-uintset.c
+++ b/unit/test-uintset.c
@@ -262,6 +262,91 @@ static void test_uintset_foreach(const void *data)
l_uintset_free(check);
}
+static void test_uintset_intersect_sanity_test(const void *data)
+{
+ struct l_uintset *set_a;
+ struct l_uintset *set_b;
+
+ assert(!l_uintset_intersect(NULL, NULL));
+
+ set_a = l_uintset_new_from_range(0, 5);
+ assert(!l_uintset_intersect(NULL, set_a));
+ assert(!l_uintset_intersect(set_a, NULL));
+
+ set_b = l_uintset_new_from_range(4, 10);
+ assert(!l_uintset_intersect(set_a, set_b));
+
+ l_uintset_free(set_a);
+ l_uintset_free(set_b);
+}
+
+struct uintset_data {
+ const uint32_t min;
+ const uint32_t max;
+ const uint32_t *vals;
+ const uint32_t size;
+};
+
+struct uintset_intersect_data {
+ const struct uintset_data set_a;
+ const struct uintset_data set_b;
+ const struct uintset_data set_r;
+};
+
+static const uint32_t vals1[] = { 1, 2, 3 };
+static const uint32_t vals2[] = { 3, 4};
+static const uint32_t vals3[] = { 3 };
+
+static const struct uintset_intersect_data intersect_data_1 = {
+ .set_a = { 0, 4, vals1, L_ARRAY_SIZE(vals1) },
+ .set_b = { 0, 4, vals2, L_ARRAY_SIZE(vals2) },
+ .set_r = { 0, 4, vals3, L_ARRAY_SIZE(vals3) },
+};
+
+static const uint32_t vals4[] = { 0, 1, 64, 127 };
+static const uint32_t vals5[] = { 1, 25, 64, 66, 127, 135 };
+static const uint32_t vals6[] = { 1, 64, 127 };
+
+static const struct uintset_intersect_data intersect_data_2 = {
+ .set_a = { 0, 191, vals4, L_ARRAY_SIZE(vals4) },
+ .set_b = { 0, 191, vals5, L_ARRAY_SIZE(vals5) },
+ .set_r = { 0, 191, vals6, L_ARRAY_SIZE(vals6) },
+};
+
+static void test_uintset_intersect_test(const void *user_data)
+{
+ const struct uintset_intersect_data *data = user_data;
+ struct l_uintset *set_a;
+ struct l_uintset *set_b;
+ struct l_uintset *set_r;
+ size_t i;
+
+ set_a = l_uintset_new_from_range(data->set_a.min, data->set_a.max);
+
+ for (i = 0; i < data->set_a.size; i++)
+ l_uintset_put(set_a, data->set_a.vals[i]);
+
+ set_b = l_uintset_new_from_range(data->set_b.min, data->set_b.max);
+
+ for (i = 0; i < data->set_b.size; i++)
+ l_uintset_put(set_b, data->set_b.vals[i]);
+
+ set_r = l_uintset_intersect(set_a, set_b);
+
+ assert(set_r);
+
+ for (i = 0; i < data->set_r.size; i++) {
+ assert(l_uintset_contains(set_r, data->set_r.vals[i]));
+ assert(l_uintset_take(set_r, data->set_r.vals[i]));
+ }
+
+ assert(l_uintset_find_max(set_r) == l_uintset_get_max(set_r) + 1);
+
+ l_uintset_free(set_a);
+ l_uintset_free(set_b);
+ l_uintset_free(set_r);
+}
+
int main(int argc, char *argv[])
{
l_test_init(&argc, &argv);
@@ -273,6 +358,12 @@ int main(int argc, char *argv[])
l_test_add("l_uintset for each tests", test_uintset_foreach, NULL);
l_test_add("l_uintset find unused tests", test_uintset_find_unused,
NULL);
+ l_test_add("l_uintset intersect sanity check",
+ test_uintset_intersect_sanity_test, NULL);
+ l_test_add("l_uintset intersect test 1", test_uintset_intersect_test,
+ &intersect_data_1);
+ l_test_add("l_uintset intersect test 2", test_uintset_intersect_test,
+ &intersect_data_2);
return l_test_run();
}
--
2.13.6
3 years, 3 months
[PATCH 1/2] uintset: Add l_uintset_intersect
by Tim Kourt
l_uintset_intersect computes the intersection of two sets
of an equal base.
---
ell/uintset.c | 37 +++++++++++++++++++++++++++++++++++++
ell/uintset.h | 3 +++
2 files changed, 40 insertions(+)
diff --git a/ell/uintset.c b/ell/uintset.c
index 3f20098..60a9822 100644
--- a/ell/uintset.c
+++ b/ell/uintset.c
@@ -469,3 +469,40 @@ LIB_EXPORT void l_uintset_foreach(struct l_uintset *set,
bit = find_next_bit(set->bits, set->size, bit + 1))
function(set->min + bit, user_data);
}
+
+/**
+ * l_uintset_intersect:
+ * @set_a: The set of numbers
+ * @set_b: The set of numbers
+ *
+ * Intersects the two sets of numbers of an equal base, e.g.:
+ * l_uintset_get_min(set_a) must be equal to l_uintset_get_min(set_b) and
+ * l_uintset_get_max(set_a) must be equal to l_uintset_get_max(set_b)
+ *
+ * Returns: A newly allocated l_uintset object containing the intersection of
+ * @set_a and @set_b. If the bases are not equal returns NULL. If either @set_a
+ * or @set_b is NULL returns NULL.
+ **/
+LIB_EXPORT struct l_uintset *l_uintset_intersect(const struct l_uintset *set_a,
+ const struct l_uintset *set_b)
+{
+ struct l_uintset *intersection;
+ uint32_t offset;
+ uint32_t offset_max;
+
+ if (unlikely(!set_a || !set_b))
+ return NULL;
+
+ if (unlikely(set_a->min != set_b->min || set_a->max != set_b->max))
+ return NULL;
+
+ intersection = l_uintset_new_from_range(set_a->min, set_a->max);
+
+ offset_max = (set_a->size + BITS_PER_LONG - 1) / BITS_PER_LONG;
+
+ for (offset = 0; offset < offset_max; offset++)
+ intersection->bits[offset] =
+ set_a->bits[offset] & set_b->bits[offset];
+
+ return intersection;
+}
diff --git a/ell/uintset.h b/ell/uintset.h
index dd03cd7..c05a21b 100644
--- a/ell/uintset.h
+++ b/ell/uintset.h
@@ -55,6 +55,9 @@ uint32_t l_uintset_find_unused(struct l_uintset *set, uint32_t start);
void l_uintset_foreach(struct l_uintset *set,
l_uintset_foreach_func_t function, void *user_data);
+struct l_uintset *l_uintset_intersect(const struct l_uintset *set_a,
+ const struct l_uintset *set_b);
+
#ifdef __cplusplus
}
#endif
--
2.13.6
3 years, 3 months
[PATCH 1/2] uintset: Add l_uintset_foreach
by Tim Kourt
Enables an efficient traversal through the numbers in the set.
---
ell/uintset.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
ell/uintset.h | 7 ++++++-
2 files changed, 72 insertions(+), 2 deletions(-)
diff --git a/ell/uintset.c b/ell/uintset.c
index 1d96e68..3f20098 100644
--- a/ell/uintset.c
+++ b/ell/uintset.c
@@ -2,7 +2,7 @@
*
* Embedded Linux library
*
- * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ * Copyright (C) 2015-2019 Intel Corporation. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -122,6 +122,49 @@ static unsigned long find_last_bit(const unsigned long *addr, unsigned int size)
return size;
}
+static unsigned long find_next_bit(const unsigned long *addr,
+ unsigned long size,
+ unsigned long bit)
+{
+ unsigned long mask;
+ unsigned long offset;
+
+ if (bit >= size)
+ return size;
+
+ addr += bit / BITS_PER_LONG;
+ offset = bit % BITS_PER_LONG;
+ bit -= offset;
+
+ if (offset) {
+ mask = *addr & ~(~0UL >> (BITS_PER_LONG - offset));
+ if (mask)
+ return bit + __ffs(mask);
+
+ bit += BITS_PER_LONG;
+ addr++;
+ }
+
+ for (size -= bit; size >= BITS_PER_LONG;
+ size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
+ if (!*addr)
+ continue;
+
+ return bit + __ffs(*addr);
+ }
+
+ if (!size)
+ return bit;
+
+ mask = *addr & (~0UL >> (BITS_PER_LONG - size));
+ if (mask)
+ bit += __ffs(mask);
+ else
+ bit += size;
+
+ return bit;
+}
+
struct l_uintset {
unsigned long *bits;
uint16_t size;
@@ -404,3 +447,25 @@ LIB_EXPORT uint32_t l_uintset_find_min(struct l_uintset *set)
return bit + set->min;
}
+
+/**
+ * l_uintset_foreach:
+ * @set: The set of numbers
+ * @function: callback function
+ * @user_data: user data given to callback function
+ *
+ * Call @function for every given number in @set.
+ **/
+LIB_EXPORT void l_uintset_foreach(struct l_uintset *set,
+ l_uintset_foreach_func_t function,
+ void *user_data)
+{
+ unsigned int bit;
+
+ if (unlikely(!set || !function))
+ return;
+
+ for (bit = find_first_bit(set->bits, set->size); bit < set->size;
+ bit = find_next_bit(set->bits, set->size, bit + 1))
+ function(set->min + bit, user_data);
+}
diff --git a/ell/uintset.h b/ell/uintset.h
index 474c5e4..dd03cd7 100644
--- a/ell/uintset.h
+++ b/ell/uintset.h
@@ -2,7 +2,7 @@
*
* Embedded Linux library
*
- * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ * Copyright (C) 2015-2019 Intel Corporation. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -31,6 +31,8 @@ extern "C" {
#include <stddef.h>
#include <stdbool.h>
+typedef void (*l_uintset_foreach_func_t) (uint32_t number, void *user_data);
+
struct l_uintset;
struct l_uintset *l_uintset_new_from_range(uint32_t min, uint32_t max);
@@ -50,6 +52,9 @@ uint32_t l_uintset_find_min(struct l_uintset *set);
uint32_t l_uintset_find_unused_min(struct l_uintset *set);
uint32_t l_uintset_find_unused(struct l_uintset *set, uint32_t start);
+void l_uintset_foreach(struct l_uintset *set,
+ l_uintset_foreach_func_t function, void *user_data);
+
#ifdef __cplusplus
}
#endif
--
2.13.6
3 years, 3 months
[PATCH 1/2] uintset: Add l_uintset_intersect
by Tim Kourt
l_uintset_intersect computes the intersection of two sets.
In addition, it introduces find_next_bit(…) that is used to
efficiently loop through the set bits in the set and may have
multiple implication in the future.
---
ell/uintset.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ell/uintset.h | 3 ++
2 files changed, 99 insertions(+)
diff --git a/ell/uintset.c b/ell/uintset.c
index 1d96e68..6b657b8 100644
--- a/ell/uintset.c
+++ b/ell/uintset.c
@@ -122,6 +122,49 @@ static unsigned long find_last_bit(const unsigned long *addr, unsigned int size)
return size;
}
+static unsigned long find_next_bit(const unsigned long *addr,
+ unsigned long size,
+ unsigned long bit)
+{
+ unsigned long mask;
+ unsigned long offset;
+
+ if (bit >= size)
+ return size;
+
+ addr += bit / BITS_PER_LONG;
+ offset = bit % BITS_PER_LONG;
+ bit -= offset;
+
+ if (offset) {
+ mask = *addr & ~(~0UL >> (BITS_PER_LONG - offset));
+ if (mask)
+ return bit + __ffs(mask);
+
+ bit += BITS_PER_LONG;
+ addr++;
+ }
+
+ for (size -= bit; size >= BITS_PER_LONG;
+ size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
+ if (!*addr)
+ continue;
+
+ return bit + __ffs(*addr);
+ }
+
+ if (!size)
+ return bit;
+
+ mask = *addr & (~0UL >> (BITS_PER_LONG - size));
+ if (mask)
+ bit += __ffs(mask);
+ else
+ bit += size;
+
+ return bit;
+}
+
struct l_uintset {
unsigned long *bits;
uint16_t size;
@@ -404,3 +447,56 @@ LIB_EXPORT uint32_t l_uintset_find_min(struct l_uintset *set)
return bit + set->min;
}
+
+/**
+ * l_uintset_intersect:
+ * @set_a: The set of numbers
+ * @set_b: The set of numbers
+ *
+ * Returns: A newly allocated l_uintset object containing intersection of
+ * @set_a and @set_b. If @set_a and @set_b cannot be intersected returns NULL.
+ * If either @set_a or @set_b is NULL returns NULL.
+ **/
+LIB_EXPORT struct l_uintset *l_uintset_intersect(const struct l_uintset *set_a,
+ const struct l_uintset *set_b)
+{
+ struct l_uintset *intersection;
+ uint32_t min;
+ uint32_t max;
+ unsigned int bit_a;
+ unsigned int bit_b;
+
+ if (unlikely(!set_a) || unlikely(!set_b))
+ return NULL;
+
+ if (set_a->max < set_b->min || set_b->max < set_a->min)
+ return NULL;
+
+ min = set_a->min <= set_b->min ? set_a->min : set_b->min;
+ max = set_a->max >= set_b->max ? set_a->max : set_b->max;
+
+ intersection = l_uintset_new_from_range(min, max);
+
+ bit_a = find_first_bit(set_a->bits, set_a->size);
+ bit_b = find_first_bit(set_b->bits, set_b->size);
+
+ while (bit_a < set_a->size && bit_b < set_b->size) {
+ if (set_a->min + bit_a < set_b->min + bit_b) {
+ bit_a = find_next_bit(set_a->bits, set_a->size,
+ bit_a + 1);
+ continue;
+ }
+
+ if (set_a->min + bit_a > set_b->min + bit_b) {
+ bit_b = find_next_bit(set_b->bits, set_b->size,
+ bit_b + 1);
+ continue;
+ }
+
+ l_uintset_put(intersection, set_a->min + bit_a);
+ bit_a = find_next_bit(set_a->bits, set_a->size, bit_a + 1);
+ bit_b = find_next_bit(set_b->bits, set_b->size, bit_b + 1);
+ }
+
+ return intersection;
+}
diff --git a/ell/uintset.h b/ell/uintset.h
index 474c5e4..9986086 100644
--- a/ell/uintset.h
+++ b/ell/uintset.h
@@ -50,6 +50,9 @@ uint32_t l_uintset_find_min(struct l_uintset *set);
uint32_t l_uintset_find_unused_min(struct l_uintset *set);
uint32_t l_uintset_find_unused(struct l_uintset *set, uint32_t start);
+struct l_uintset *l_uintset_intersect(const struct l_uintset *set_a,
+ const struct l_uintset *set_b);
+
#ifdef __cplusplus
}
#endif
--
2.13.6
3 years, 3 months
[PATCH 0/5] Support C89 ELL builds
by Ossama Othman
This patch set provides several simple changes to enable C89 support
in ELL.
Ossama Othman (5):
ell: Use __inline__ instead of inline for C89.
ell: Do not use C99 '//' single line comment.
settings: Explicitly enable strto{u}ll() for C89.
string: Use __va_copy() for pre-C99 builds.
unit: Remove C99 loop variable declaration.
ell/asn1-private.h | 4 ++++
ell/dbus.c | 2 +-
ell/netlink.c | 2 +-
ell/settings.c | 4 ++++
ell/string.c | 4 ++++
ell/utf8.h | 4 ++++
ell/util.h | 4 ++++
unit/test-dbus-message.c | 3 ++-
8 files changed, 24 insertions(+), 3 deletions(-)
--
2.17.1
3 years, 3 months