diff options
author | hselasky <hselasky@FreeBSD.org> | 2016-05-23 12:03:40 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2016-05-23 12:03:40 +0000 |
commit | 704290bfa2b697b24d77e129af0ff7c804aaedca (patch) | |
tree | b3a9924afa6f050c0c897138c7432e08f1a8d1de | |
parent | 024c1d0e21075d1388cb9d72e892c74a2edadbc4 (diff) | |
download | FreeBSD-src-704290bfa2b697b24d77e129af0ff7c804aaedca.zip FreeBSD-src-704290bfa2b697b24d77e129af0ff7c804aaedca.tar.gz |
Add more list_xxx() functions to the LinuxKPI.
Obtained from: kmacy @
MFC after: 1 week
Sponsored by: Mellanox Technologies
-rw-r--r-- | sys/compat/linuxkpi/common/include/linux/list.h | 19 | ||||
-rw-r--r-- | sys/compat/linuxkpi/common/src/linux_compat.c | 42 |
2 files changed, 61 insertions, 0 deletions
diff --git a/sys/compat/linuxkpi/common/include/linux/list.h b/sys/compat/linuxkpi/common/include/linux/list.h index 1357555..fff5243 100644 --- a/sys/compat/linuxkpi/common/include/linux/list.h +++ b/sys/compat/linuxkpi/common/include/linux/list.h @@ -109,6 +109,13 @@ list_replace(struct list_head *old, struct list_head *new) } static inline void +list_replace_init(struct list_head *old, struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +static inline void linux_list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { @@ -132,9 +139,18 @@ list_del_init(struct list_head *entry) #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + +#define list_first_entry_or_null(ptr, type, member) \ + (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) + #define list_next_entry(ptr, member) \ list_entry(((ptr)->member.next), typeof(*(ptr)), member) +#define list_prev_entry(ptr, member) \ + list_entry(((ptr)->member.prev), typeof(*(ptr)), member) + #define list_for_each(p, head) \ for (p = (head)->next; p != (head); p = (p)->next) @@ -436,4 +452,7 @@ static inline int list_is_last(const struct list_head *list, (pos) && ({ n = (pos)->member.next; 1; }); \ pos = hlist_entry_safe(n, typeof(*(pos)), member)) +extern void list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv, + struct list_head *a, struct list_head *b)); + #endif /* _LINUX_LIST_H_ */ diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c index 77b18a3..670ffc0 100644 --- a/sys/compat/linuxkpi/common/src/linux_compat.c +++ b/sys/compat/linuxkpi/common/src/linux_compat.c @@ -72,6 +72,7 @@ __FBSDID("$FreeBSD$"); #include <linux/interrupt.h> #include <linux/uaccess.h> #include <linux/kernel.h> +#include <linux/list.h> #include <vm/vm_pager.h> @@ -1358,6 +1359,47 @@ unregister_inetaddr_notifier(struct notifier_block *nb) return (0); } +struct list_sort_thunk { + int (*cmp)(void *, struct list_head *, struct list_head *); + void *priv; +}; + +static inline int +linux_le_cmp(void *priv, const void *d1, const void *d2) +{ + struct list_head *le1, *le2; + struct list_sort_thunk *thunk; + + thunk = priv; + le1 = *(__DECONST(struct list_head **, d1)); + le2 = *(__DECONST(struct list_head **, d2)); + return ((thunk->cmp)(thunk->priv, le1, le2)); +} + +void +list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv, + struct list_head *a, struct list_head *b)) +{ + struct list_sort_thunk thunk; + struct list_head **ar, *le; + size_t count, i; + + count = 0; + list_for_each(le, head) + count++; + ar = malloc(sizeof(struct list_head *) * count, M_KMALLOC, M_WAITOK); + i = 0; + list_for_each(le, head) + ar[i++] = le; + thunk.cmp = cmp; + thunk.priv = priv; + qsort_r(ar, count, sizeof(struct list_head *), &thunk, linux_le_cmp); + INIT_LIST_HEAD(head); + for (i = 0; i < count; i++) + list_add_tail(ar[i], head); + free(ar, M_KMALLOC); +} + void linux_irq_handler(void *ent) { |