LCOV - code coverage report
Current view: top level - lib - list_sort.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 46 50 92.0 %
Date: 2015-04-12 14:34:49 Functions: 3 3 100.0 %

          Line data    Source code
       1             : 
       2             : #define pr_fmt(fmt) "list_sort_test: " fmt
       3             : 
       4             : #include <linux/kernel.h>
       5             : #include <linux/module.h>
       6             : #include <linux/list_sort.h>
       7             : #include <linux/slab.h>
       8             : #include <linux/list.h>
       9             : 
      10             : #define MAX_LIST_LENGTH_BITS 20
      11             : 
      12             : /*
      13             :  * Returns a list organized in an intermediate format suited
      14             :  * to chaining of merge() calls: null-terminated, no reserved or
      15             :  * sentinel head node, "prev" links not maintained.
      16             :  */
      17         352 : static struct list_head *merge(void *priv,
      18             :                                 int (*cmp)(void *priv, struct list_head *a,
      19             :                                         struct list_head *b),
      20             :                                 struct list_head *a, struct list_head *b)
      21             : {
      22             :         struct list_head head, *tail = &head;
      23             : 
      24        1302 :         while (a && b) {
      25             :                 /* if equal, take 'a' -- important for sort stability */
      26         598 :                 if ((*cmp)(priv, a, b) <= 0) {
      27         552 :                         tail->next = a;
      28         552 :                         a = a->next;
      29             :                 } else {
      30          46 :                         tail->next = b;
      31          46 :                         b = b->next;
      32             :                 }
      33         598 :                 tail = tail->next;
      34             :         }
      35         352 :         tail->next = a?:b;
      36         352 :         return head.next;
      37             : }
      38             : 
      39             : /*
      40             :  * Combine final list merge with restoration of standard doubly-linked
      41             :  * list structure.  This approach duplicates code from merge(), but
      42             :  * runs faster than the tidier alternatives of either a separate final
      43             :  * prev-link restoration pass, or maintaining the prev links
      44             :  * throughout.
      45             :  */
      46        2496 : static void merge_and_restore_back_links(void *priv,
      47             :                                 int (*cmp)(void *priv, struct list_head *a,
      48             :                                         struct list_head *b),
      49             :                                 struct list_head *head,
      50             :                                 struct list_head *a, struct list_head *b)
      51             : {
      52             :         struct list_head *tail = head;
      53             :         u8 count = 0;
      54             : 
      55        5100 :         while (a && b) {
      56             :                 /* if equal, take 'a' -- important for sort stability */
      57         108 :                 if ((*cmp)(priv, a, b) <= 0) {
      58          87 :                         tail->next = a;
      59          87 :                         a->prev = tail;
      60          87 :                         a = a->next;
      61             :                 } else {
      62          21 :                         tail->next = b;
      63          21 :                         b->prev = tail;
      64          21 :                         b = b->next;
      65             :                 }
      66         108 :                 tail = tail->next;
      67             :         }
      68        2496 :         tail->next = a ? : b;
      69             : 
      70             :         do {
      71             :                 /*
      72             :                  * In worst cases this loop may run many iterations.
      73             :                  * Continue callbacks to the client even though no
      74             :                  * element comparison is needed, so the client's cmp()
      75             :                  * routine can invoke cond_resched() periodically.
      76             :                  */
      77        2740 :                 if (unlikely(!(++count)))
      78           0 :                         (*cmp)(priv, tail->next, tail->next);
      79             : 
      80        2740 :                 tail->next->prev = tail;
      81        2740 :                 tail = tail->next;
      82        2740 :         } while (tail->next);
      83             : 
      84        2496 :         tail->next = head;
      85        2496 :         head->prev = tail;
      86        2496 : }
      87             : 
      88             : /**
      89             :  * list_sort - sort a list
      90             :  * @priv: private data, opaque to list_sort(), passed to @cmp
      91             :  * @head: the list to sort
      92             :  * @cmp: the elements comparison function
      93             :  *
      94             :  * This function implements "merge sort", which has O(nlog(n))
      95             :  * complexity.
      96             :  *
      97             :  * The comparison function @cmp must return a negative value if @a
      98             :  * should sort before @b, and a positive value if @a should sort after
      99             :  * @b. If @a and @b are equivalent, and their original relative
     100             :  * ordering is to be preserved, @cmp must return 0.
     101             :  */
     102        2496 : void list_sort(void *priv, struct list_head *head,
     103             :                 int (*cmp)(void *priv, struct list_head *a,
     104             :                         struct list_head *b))
     105             : {
     106             :         struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists
     107             :                                                 -- last slot is a sentinel */
     108             :         int lev;  /* index into part[] */
     109             :         int max_lev = 0;
     110             :         struct list_head *list;
     111             : 
     112        2496 :         if (list_empty(head))
     113           0 :                 return;
     114             : 
     115        2496 :         memset(part, 0, sizeof(part));
     116             : 
     117        2496 :         head->prev->next = NULL;
     118        2496 :         list = head->next;
     119             : 
     120        7840 :         while (list) {
     121             :                 struct list_head *cur = list;
     122        2848 :                 list = list->next;
     123        2848 :                 cur->next = NULL;
     124             : 
     125        3165 :                 for (lev = 0; part[lev]; lev++) {
     126         317 :                         cur = merge(priv, cmp, part[lev], cur);
     127         317 :                         part[lev] = NULL;
     128             :                 }
     129        2848 :                 if (lev > max_lev) {
     130         129 :                         if (unlikely(lev >= ARRAY_SIZE(part)-1)) {
     131           0 :                                 printk_once(KERN_DEBUG "list too long for efficiency\n");
     132           0 :                                 lev--;
     133             :                         }
     134             :                         max_lev = lev;
     135             :                 }
     136        2848 :                 part[lev] = cur;
     137             :         }
     138             : 
     139         129 :         for (lev = 0; lev < max_lev; lev++)
     140         129 :                 if (part[lev])
     141          35 :                         list = merge(priv, cmp, part[lev], list);
     142             : 
     143        2496 :         merge_and_restore_back_links(priv, cmp, head, part[max_lev], list);
     144             : }
     145             : EXPORT_SYMBOL(list_sort);
     146             : 
     147             : #ifdef CONFIG_TEST_LIST_SORT
     148             : 
     149             : #include <linux/random.h>
     150             : 
     151             : /*
     152             :  * The pattern of set bits in the list length determines which cases
     153             :  * are hit in list_sort().
     154             :  */
     155             : #define TEST_LIST_LEN (512+128+2) /* not including head */
     156             : 
     157             : #define TEST_POISON1 0xDEADBEEF
     158             : #define TEST_POISON2 0xA324354C
     159             : 
     160             : struct debug_el {
     161             :         unsigned int poison1;
     162             :         struct list_head list;
     163             :         unsigned int poison2;
     164             :         int value;
     165             :         unsigned serial;
     166             : };
     167             : 
     168             : /* Array, containing pointers to all elements in the test list */
     169             : static struct debug_el **elts __initdata;
     170             : 
     171             : static int __init check(struct debug_el *ela, struct debug_el *elb)
     172             : {
     173             :         if (ela->serial >= TEST_LIST_LEN) {
     174             :                 pr_err("error: incorrect serial %d\n", ela->serial);
     175             :                 return -EINVAL;
     176             :         }
     177             :         if (elb->serial >= TEST_LIST_LEN) {
     178             :                 pr_err("error: incorrect serial %d\n", elb->serial);
     179             :                 return -EINVAL;
     180             :         }
     181             :         if (elts[ela->serial] != ela || elts[elb->serial] != elb) {
     182             :                 pr_err("error: phantom element\n");
     183             :                 return -EINVAL;
     184             :         }
     185             :         if (ela->poison1 != TEST_POISON1 || ela->poison2 != TEST_POISON2) {
     186             :                 pr_err("error: bad poison: %#x/%#x\n",
     187             :                         ela->poison1, ela->poison2);
     188             :                 return -EINVAL;
     189             :         }
     190             :         if (elb->poison1 != TEST_POISON1 || elb->poison2 != TEST_POISON2) {
     191             :                 pr_err("error: bad poison: %#x/%#x\n",
     192             :                         elb->poison1, elb->poison2);
     193             :                 return -EINVAL;
     194             :         }
     195             :         return 0;
     196             : }
     197             : 
     198             : static int __init cmp(void *priv, struct list_head *a, struct list_head *b)
     199             : {
     200             :         struct debug_el *ela, *elb;
     201             : 
     202             :         ela = container_of(a, struct debug_el, list);
     203             :         elb = container_of(b, struct debug_el, list);
     204             : 
     205             :         check(ela, elb);
     206             :         return ela->value - elb->value;
     207             : }
     208             : 
     209             : static int __init list_sort_test(void)
     210             : {
     211             :         int i, count = 1, err = -ENOMEM;
     212             :         struct debug_el *el;
     213             :         struct list_head *cur;
     214             :         LIST_HEAD(head);
     215             : 
     216             :         pr_debug("start testing list_sort()\n");
     217             : 
     218             :         elts = kcalloc(TEST_LIST_LEN, sizeof(*elts), GFP_KERNEL);
     219             :         if (!elts) {
     220             :                 pr_err("error: cannot allocate memory\n");
     221             :                 return err;
     222             :         }
     223             : 
     224             :         for (i = 0; i < TEST_LIST_LEN; i++) {
     225             :                 el = kmalloc(sizeof(*el), GFP_KERNEL);
     226             :                 if (!el) {
     227             :                         pr_err("error: cannot allocate memory\n");
     228             :                         goto exit;
     229             :                 }
     230             :                  /* force some equivalencies */
     231             :                 el->value = prandom_u32() % (TEST_LIST_LEN / 3);
     232             :                 el->serial = i;
     233             :                 el->poison1 = TEST_POISON1;
     234             :                 el->poison2 = TEST_POISON2;
     235             :                 elts[i] = el;
     236             :                 list_add_tail(&el->list, &head);
     237             :         }
     238             : 
     239             :         list_sort(NULL, &head, cmp);
     240             : 
     241             :         err = -EINVAL;
     242             :         for (cur = head.next; cur->next != &head; cur = cur->next) {
     243             :                 struct debug_el *el1;
     244             :                 int cmp_result;
     245             : 
     246             :                 if (cur->next->prev != cur) {
     247             :                         pr_err("error: list is corrupted\n");
     248             :                         goto exit;
     249             :                 }
     250             : 
     251             :                 cmp_result = cmp(NULL, cur, cur->next);
     252             :                 if (cmp_result > 0) {
     253             :                         pr_err("error: list is not sorted\n");
     254             :                         goto exit;
     255             :                 }
     256             : 
     257             :                 el = container_of(cur, struct debug_el, list);
     258             :                 el1 = container_of(cur->next, struct debug_el, list);
     259             :                 if (cmp_result == 0 && el->serial >= el1->serial) {
     260             :                         pr_err("error: order of equivalent elements not "
     261             :                                 "preserved\n");
     262             :                         goto exit;
     263             :                 }
     264             : 
     265             :                 if (check(el, el1)) {
     266             :                         pr_err("error: element check failed\n");
     267             :                         goto exit;
     268             :                 }
     269             :                 count++;
     270             :         }
     271             :         if (head.prev != cur) {
     272             :                 pr_err("error: list is corrupted\n");
     273             :                 goto exit;
     274             :         }
     275             : 
     276             : 
     277             :         if (count != TEST_LIST_LEN) {
     278             :                 pr_err("error: bad list length %d", count);
     279             :                 goto exit;
     280             :         }
     281             : 
     282             :         err = 0;
     283             : exit:
     284             :         for (i = 0; i < TEST_LIST_LEN; i++)
     285             :                 kfree(elts[i]);
     286             :         kfree(elts);
     287             :         return err;
     288             : }
     289             : module_init(list_sort_test);
     290             : #endif /* CONFIG_TEST_LIST_SORT */

Generated by: LCOV version 1.11