diff options
Diffstat (limited to 'lib/plist.c')
| -rw-r--r-- | lib/plist.c | 135 | 
1 files changed, 115 insertions, 20 deletions
diff --git a/lib/plist.c b/lib/plist.c index 1471988d9190..0ae7e6431726 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -28,6 +28,8 @@  #ifdef CONFIG_DEBUG_PI_LIST +static struct plist_head test_head; +  static void plist_check_prev_next(struct list_head *t, struct list_head *p,  				  struct list_head *n)  { @@ -54,12 +56,13 @@ static void plist_check_list(struct list_head *top)  static void plist_check_head(struct plist_head *head)  { -	WARN_ON(!head->rawlock && !head->spinlock); +	WARN_ON(head != &test_head && !head->rawlock && !head->spinlock);  	if (head->rawlock)  		WARN_ON_SMP(!raw_spin_is_locked(head->rawlock));  	if (head->spinlock)  		WARN_ON_SMP(!spin_is_locked(head->spinlock)); -	plist_check_list(&head->prio_list); +	if (!plist_head_empty(head)) +		plist_check_list(&plist_first(head)->prio_list);  	plist_check_list(&head->node_list);  } @@ -75,25 +78,33 @@ static void plist_check_head(struct plist_head *head)   */  void plist_add(struct plist_node *node, struct plist_head *head)  { -	struct plist_node *iter; +	struct plist_node *first, *iter, *prev = NULL; +	struct list_head *node_next = &head->node_list;  	plist_check_head(head);  	WARN_ON(!plist_node_empty(node)); +	WARN_ON(!list_empty(&node->prio_list)); + +	if (plist_head_empty(head)) +		goto ins_node; -	list_for_each_entry(iter, &head->prio_list, plist.prio_list) { -		if (node->prio < iter->prio) -			goto lt_prio; -		else if (node->prio == iter->prio) { -			iter = list_entry(iter->plist.prio_list.next, -					struct plist_node, plist.prio_list); -			goto eq_prio; +	first = iter = plist_first(head); + +	do { +		if (node->prio < iter->prio) { +			node_next = &iter->node_list; +			break;  		} -	} -lt_prio: -	list_add_tail(&node->plist.prio_list, &iter->plist.prio_list); -eq_prio: -	list_add_tail(&node->plist.node_list, &iter->plist.node_list); +		prev = iter; +		iter = list_entry(iter->prio_list.next, +				struct plist_node, prio_list); +	} while (iter != first); + +	if (!prev || prev->prio != node->prio) +		list_add_tail(&node->prio_list, &iter->prio_list); +ins_node: +	list_add_tail(&node->node_list, node_next);  	plist_check_head(head);  } @@ -108,14 +119,98 @@ void plist_del(struct plist_node *node, struct plist_head *head)  {  	plist_check_head(head); -	if (!list_empty(&node->plist.prio_list)) { -		struct plist_node *next = plist_first(&node->plist); +	if (!list_empty(&node->prio_list)) { +		if (node->node_list.next != &head->node_list) { +			struct plist_node *next; + +			next = list_entry(node->node_list.next, +					struct plist_node, node_list); -		list_move_tail(&next->plist.prio_list, &node->plist.prio_list); -		list_del_init(&node->plist.prio_list); +			/* add the next plist_node into prio_list */ +			if (list_empty(&next->prio_list)) +				list_add(&next->prio_list, &node->prio_list); +		} +		list_del_init(&node->prio_list);  	} -	list_del_init(&node->plist.node_list); +	list_del_init(&node->node_list);  	plist_check_head(head);  } + +#ifdef CONFIG_DEBUG_PI_LIST +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/init.h> + +static struct plist_node __initdata test_node[241]; + +static void __init plist_test_check(int nr_expect) +{ +	struct plist_node *first, *prio_pos, *node_pos; + +	if (plist_head_empty(&test_head)) { +		BUG_ON(nr_expect != 0); +		return; +	} + +	prio_pos = first = plist_first(&test_head); +	plist_for_each(node_pos, &test_head) { +		if (nr_expect-- < 0) +			break; +		if (node_pos == first) +			continue; +		if (node_pos->prio == prio_pos->prio) { +			BUG_ON(!list_empty(&node_pos->prio_list)); +			continue; +		} + +		BUG_ON(prio_pos->prio > node_pos->prio); +		BUG_ON(prio_pos->prio_list.next != &node_pos->prio_list); +		prio_pos = node_pos; +	} + +	BUG_ON(nr_expect != 0); +	BUG_ON(prio_pos->prio_list.next != &first->prio_list); +} + +static int  __init plist_test(void) +{ +	int nr_expect = 0, i, loop; +	unsigned int r = local_clock(); + +	printk(KERN_INFO "start plist test\n"); +	plist_head_init(&test_head, NULL); +	for (i = 0; i < ARRAY_SIZE(test_node); i++) +		plist_node_init(test_node + i, 0); + +	for (loop = 0; loop < 1000; loop++) { +		r = r * 193939 % 47629; +		i = r % ARRAY_SIZE(test_node); +		if (plist_node_empty(test_node + i)) { +			r = r * 193939 % 47629; +			test_node[i].prio = r % 99; +			plist_add(test_node + i, &test_head); +			nr_expect++; +		} else { +			plist_del(test_node + i, &test_head); +			nr_expect--; +		} +		plist_test_check(nr_expect); +	} + +	for (i = 0; i < ARRAY_SIZE(test_node); i++) { +		if (plist_node_empty(test_node + i)) +			continue; +		plist_del(test_node + i, &test_head); +		nr_expect--; +		plist_test_check(nr_expect); +	} + +	printk(KERN_INFO "end plist test\n"); +	return 0; +} + +module_init(plist_test); + +#endif  | 
