aboutsummaryrefslogtreecommitdiffstats
path: root/lib/list_sort.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2010-02-22 16:20:34 -0800
committerH. Peter Anvin <hpa@zytor.com>2010-02-22 16:20:34 -0800
commitd02e30c31c57683a66ed68a1bcff900ca78f6d56 (patch)
treec3ce99a00061bcc1199b50fa838147d876c56717 /lib/list_sort.c
parent0fdc7a8022c3eaff6b5ee27ffb9e913e5e58d8e9 (diff)
parentaef55d4922e62a0d887e60d87319f3718aec6ced (diff)
downloadkernel_samsung_smdk4412-d02e30c31c57683a66ed68a1bcff900ca78f6d56.zip
kernel_samsung_smdk4412-d02e30c31c57683a66ed68a1bcff900ca78f6d56.tar.gz
kernel_samsung_smdk4412-d02e30c31c57683a66ed68a1bcff900ca78f6d56.tar.bz2
Merge branch 'x86/irq' into x86/apic
Merge reason: Conflicts in arch/x86/kernel/apic/io_apic.c Resolved Conflicts: arch/x86/kernel/apic/io_apic.c Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'lib/list_sort.c')
-rw-r--r--lib/list_sort.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/lib/list_sort.c b/lib/list_sort.c
new file mode 100644
index 0000000..19d11e0
--- /dev/null
+++ b/lib/list_sort.c
@@ -0,0 +1,102 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list_sort.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+/**
+ * list_sort - sort a list.
+ * @priv: private data, passed to @cmp
+ * @head: the list to sort
+ * @cmp: the elements comparison function
+ *
+ * This function has been implemented by Mark J Roberts <mjr@znex.org>. It
+ * implements "merge sort" which has O(nlog(n)) complexity. The list is sorted
+ * in ascending order.
+ *
+ * The comparison function @cmp is supposed to return a negative value if @a is
+ * less than @b, and a positive value if @a is greater than @b. If @a and @b
+ * are equivalent, then it does not matter what this function returns.
+ */
+void list_sort(void *priv, struct list_head *head,
+ int (*cmp)(void *priv, struct list_head *a,
+ struct list_head *b))
+{
+ struct list_head *p, *q, *e, *list, *tail, *oldhead;
+ int insize, nmerges, psize, qsize, i;
+
+ if (list_empty(head))
+ return;
+
+ list = head->next;
+ list_del(head);
+ insize = 1;
+ for (;;) {
+ p = oldhead = list;
+ list = tail = NULL;
+ nmerges = 0;
+
+ while (p) {
+ nmerges++;
+ q = p;
+ psize = 0;
+ for (i = 0; i < insize; i++) {
+ psize++;
+ q = q->next == oldhead ? NULL : q->next;
+ if (!q)
+ break;
+ }
+
+ qsize = insize;
+ while (psize > 0 || (qsize > 0 && q)) {
+ if (!psize) {
+ e = q;
+ q = q->next;
+ qsize--;
+ if (q == oldhead)
+ q = NULL;
+ } else if (!qsize || !q) {
+ e = p;
+ p = p->next;
+ psize--;
+ if (p == oldhead)
+ p = NULL;
+ } else if (cmp(priv, p, q) <= 0) {
+ e = p;
+ p = p->next;
+ psize--;
+ if (p == oldhead)
+ p = NULL;
+ } else {
+ e = q;
+ q = q->next;
+ qsize--;
+ if (q == oldhead)
+ q = NULL;
+ }
+ if (tail)
+ tail->next = e;
+ else
+ list = e;
+ e->prev = tail;
+ tail = e;
+ }
+ p = q;
+ }
+
+ tail->next = list;
+ list->prev = tail;
+
+ if (nmerges <= 1)
+ break;
+
+ insize *= 2;
+ }
+
+ head->next = list;
+ head->prev = list->prev;
+ list->prev->next = head;
+ list->prev = head;
+}
+
+EXPORT_SYMBOL(list_sort);