Blame lib/list_head.c

Packit c22fc9
/*
Packit c22fc9
 * Soft:        Keepalived is a failover program for the LVS project
Packit c22fc9
 *              <www.linuxvirtualserver.org>. It monitor & manipulate
Packit c22fc9
 *              a loadbalanced server pool using multi-layer checks.
Packit c22fc9
 *		In addition it provides a VRRPv2 & VRRPv3 stack.
Packit c22fc9
 *
Packit c22fc9
 * Author:      Alexandre Cassen, <acassen@corp.free.fr>
Packit c22fc9
 *
Packit c22fc9
 *              This program is distributed in the hope that it will be useful,
Packit c22fc9
 *              but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit c22fc9
 *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Packit c22fc9
 *              See the GNU General Public License for more details.
Packit c22fc9
 *
Packit c22fc9
 *              This program is free software; you can redistribute it and/or
Packit c22fc9
 *              modify it under the terms of the GNU General Public License
Packit c22fc9
 *              as published by the Free Software Foundation; either version
Packit c22fc9
 *              2 of the License, or (at your option) any later version.
Packit c22fc9
 *
Packit c22fc9
 * Copyright (C) 2018 Alexandre Cassen, <acassen@corp.free.fr>
Packit c22fc9
 */
Packit c22fc9
Packit c22fc9
#include "list_head.h"
Packit Service dfccb1
#include "warnings.h"
Packit Service dfccb1
Packit c22fc9
Packit c22fc9
void list_sort(struct list_head *head,
Packit c22fc9
	       int (*cmp)(struct list_head *a, struct list_head *b))
Packit c22fc9
{
Packit c22fc9
	struct list_head *p, *q, *e, *list, *tail, *oldhead;
Packit Service dfccb1
	unsigned insize, nmerges, psize, qsize, i;
Packit c22fc9
Packit c22fc9
	list = head->next;
Packit c22fc9
	list_head_del(head);
Packit c22fc9
	insize = 1;
Packit c22fc9
Packit c22fc9
	while (1) {
Packit c22fc9
		p = oldhead = list;
Packit c22fc9
		list = tail = NULL;
Packit c22fc9
		nmerges = 0;
Packit c22fc9
Packit c22fc9
		while (p) {
Packit c22fc9
			nmerges++;
Packit c22fc9
			q = p;
Packit c22fc9
			psize = 0;
Packit c22fc9
			for (i = 0; i < insize; i++) {
Packit c22fc9
				psize++;
Packit c22fc9
				q = q->next == oldhead ? NULL : q->next;
Packit c22fc9
				if (!q)
Packit c22fc9
					break;
Packit c22fc9
			}
Packit c22fc9
Packit c22fc9
			qsize = insize;
Packit c22fc9
			while (psize > 0 || (qsize > 0 && q)) {
Packit c22fc9
				if (!psize) {
Packit c22fc9
					e = q;
Packit c22fc9
					q = q->next;
Packit c22fc9
					qsize--;
Packit c22fc9
					if (q == oldhead)
Packit c22fc9
						q = NULL;
Packit c22fc9
				} else if (!qsize || !q) {
Packit c22fc9
					e = p;
Packit c22fc9
					p = p->next;
Packit c22fc9
					psize--;
Packit c22fc9
				} else if (cmp(p, q) <= 0) {
Packit c22fc9
					e = p;
Packit c22fc9
					p = p->next;
Packit c22fc9
					psize--;
Packit c22fc9
				} else {
Packit c22fc9
					e = q;
Packit c22fc9
					q = q->next;
Packit c22fc9
					qsize--;
Packit c22fc9
					if (q == oldhead)
Packit c22fc9
						q = NULL;
Packit c22fc9
				}
Packit c22fc9
				if (tail)
Packit c22fc9
					tail->next = e;
Packit c22fc9
				else
Packit c22fc9
					list = e;
Packit c22fc9
				e->prev = tail;
Packit c22fc9
				tail = e;
Packit c22fc9
			}
Packit c22fc9
			p = q;
Packit c22fc9
		}
Packit c22fc9
Packit c22fc9
		tail->next = list;
Packit c22fc9
		list->prev = tail;
Packit c22fc9
Packit c22fc9
		if (nmerges <= 1)
Packit c22fc9
			break;
Packit c22fc9
Packit c22fc9
		insize *= 2;
Packit c22fc9
	}
Packit c22fc9
Packit c22fc9
	head->next = list;
Packit c22fc9
	head->prev = list->prev;
Packit c22fc9
	list->prev->next = head;
Packit c22fc9
	list->prev = head;
Packit c22fc9
}