list_sort.c 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/list_sort.h>
  4. #include <linux/slab.h>
  5. #include <linux/list.h>
  6. /**
  7. * list_sort - sort a list.
  8. * @priv: private data, passed to @cmp
  9. * @head: the list to sort
  10. * @cmp: the elements comparison function
  11. *
  12. * This function has been implemented by Mark J Roberts <mjr@znex.org>. It
  13. * implements "merge sort" which has O(nlog(n)) complexity. The list is sorted
  14. * in ascending order.
  15. *
  16. * The comparison function @cmp is supposed to return a negative value if @a is
  17. * less than @b, and a positive value if @a is greater than @b. If @a and @b
  18. * are equivalent, then it does not matter what this function returns.
  19. */
  20. void list_sort(void *priv, struct list_head *head,
  21. int (*cmp)(void *priv, struct list_head *a,
  22. struct list_head *b))
  23. {
  24. struct list_head *p, *q, *e, *list, *tail, *oldhead;
  25. int insize, nmerges, psize, qsize, i;
  26. if (list_empty(head))
  27. return;
  28. list = head->next;
  29. list_del(head);
  30. insize = 1;
  31. for (;;) {
  32. p = oldhead = list;
  33. list = tail = NULL;
  34. nmerges = 0;
  35. while (p) {
  36. nmerges++;
  37. q = p;
  38. psize = 0;
  39. for (i = 0; i < insize; i++) {
  40. psize++;
  41. q = q->next == oldhead ? NULL : q->next;
  42. if (!q)
  43. break;
  44. }
  45. qsize = insize;
  46. while (psize > 0 || (qsize > 0 && q)) {
  47. if (!psize) {
  48. e = q;
  49. q = q->next;
  50. qsize--;
  51. if (q == oldhead)
  52. q = NULL;
  53. } else if (!qsize || !q) {
  54. e = p;
  55. p = p->next;
  56. psize--;
  57. if (p == oldhead)
  58. p = NULL;
  59. } else if (cmp(priv, p, q) <= 0) {
  60. e = p;
  61. p = p->next;
  62. psize--;
  63. if (p == oldhead)
  64. p = NULL;
  65. } else {
  66. e = q;
  67. q = q->next;
  68. qsize--;
  69. if (q == oldhead)
  70. q = NULL;
  71. }
  72. if (tail)
  73. tail->next = e;
  74. else
  75. list = e;
  76. e->prev = tail;
  77. tail = e;
  78. }
  79. p = q;
  80. }
  81. tail->next = list;
  82. list->prev = tail;
  83. if (nmerges <= 1)
  84. break;
  85. insize *= 2;
  86. }
  87. head->next = list;
  88. head->prev = list->prev;
  89. list->prev->next = head;
  90. list->prev = head;
  91. }
  92. EXPORT_SYMBOL(list_sort);