OpenSolaris_b135/lib/udapl/udapl_tavor/common/dapl_llist.c

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
 */

/*
 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 *
 * MODULE: dapl_llist.c
 *
 * PURPOSE: Manage doubly linked lists within the DAPL Reference Implementation
 *
 *	A link list head points to the first member of a linked list, but
 *	is itself not a member of the list.
 *
 *          +---------------------------------------------+
 *          |      entry         entry         entry      |
 *  HEAD -> |    +-------+     +-------+     +-------+    |
 *          +--> | flink | --> | flink | --> | flink | >--+
 *	         | data  |     | data  |     | data  |
 *	    +--< | blink | <-- | blink | <-- | blink | <--|
 *          |    +-------+     +-------+     +-------+    |
 *          |                                             |
 *          +---------------------------------------------+
 *
 * Note:  Each of the remove functions takes an assertion failure if
 *        an element cannot be removed from the list.
 *
 * $Id: dapl_llist.c,v 1.9 2003/06/13 12:21:11 sjs2 Exp $
 */

#include "dapl.h"

/*
 * dapl_llist_init_head()
 *
 * Purpose: initialize a linked list head
 */
void
dapl_llist_init_head(DAPL_LLIST_HEAD *head)
{
	*head = NULL;
}

/*
 * dapl_llist_init_entry()
 *
 * Purpose: initialize a linked list entry
 */
void
dapl_llist_init_entry(DAPL_LLIST_ENTRY *entry)
{
	entry->blink = NULL;
	entry->flink = NULL;
	entry->data = 0;
	entry->list_head = NULL;
}

/*
 * dapl_llist_is_empty()
 *
 * Purpose: returns TRUE if the linked list is empty
 */
DAT_BOOLEAN
dapl_llist_is_empty(DAPL_LLIST_HEAD *head)
{
	return (*head == NULL);
}

/*
 * dapl_llist_add_head()
 *
 * Purpose: Add an entry to the head of a linked list
 */
void
dapl_llist_add_head(DAPL_LLIST_HEAD *head,
		DAPL_LLIST_ENTRY *entry,
		void *data)
{
	DAPL_LLIST_ENTRY *first;

	/* deal with empty list */
	if (dapl_llist_is_empty(head)) {
		entry->flink = entry;
		entry->blink = entry;
	} else {
		first = *head;
		entry->flink = first;
		entry->blink = first->blink;
		first->blink->flink = entry;
		first->blink = entry;
	}

	*head		= entry;
	entry->data	= data;
	entry->list_head = head;
}

/*
 * dapl_llist_add_tail()
 *
 * Purpose: Add an entry to the tail of a linked list
 */
void
dapl_llist_add_tail(DAPL_LLIST_HEAD *head,
	DAPL_LLIST_ENTRY *entry,
	void *data)
{
	DAPL_LLIST_ENTRY *last;

	/* deal with empty list */
	if (dapl_llist_is_empty(head)) {
		*head = entry;
		entry->flink = entry;
		entry->blink = entry;
	} else {
		last = (*head)->blink;
		entry->flink = last->flink;
		entry->blink = last;
		last->flink->blink = entry;
		last->flink = entry;
	}
	entry->data = data;
	entry->list_head = head;
}


/*
 * dapl_llist_add_entry()
 *
 * Purpose: Add an entry before an element in the list
 */
void
dapl_llist_add_entry(DAPL_LLIST_HEAD * head,
		DAPL_LLIST_ENTRY * entry,
		DAPL_LLIST_ENTRY * new_entry,
		void * data)
{
	DAPL_LLIST_ENTRY *last;

	/* deal with empty list */
	if (dapl_llist_is_empty(head)) {
		*head = entry;
		entry->flink = entry;
		entry->blink = entry;
	} else {
		last = entry->blink;
		entry->blink = new_entry;
		last->flink  = new_entry;

		new_entry->flink = entry;
		new_entry->blink = last;

	}
	new_entry->data = data;
	new_entry->list_head = head;
}

/*
 * dapl_llist_remove_head()
 *
 * Purpose: Remove the first entry of a linked list
 */
void *
dapl_llist_remove_head(DAPL_LLIST_HEAD *head)
{
	DAPL_LLIST_ENTRY *first;

	dapl_os_assert(!dapl_llist_is_empty(head));
	first = *head;
	*head = first->flink;

	first->flink->blink = first->blink;
	first->blink->flink = first->flink;

	if (first->flink == first) {
		*head = NULL;
	}
	/* clean up the links for good measure */
	first->flink = NULL;
	first->blink = NULL;
	first->list_head = NULL;
	return (first->data);
}

/*
 * dapl_llist_remove_tail()
 *
 * Purpose: Remove the last entry of a linked list
 */
void *
dapl_llist_remove_tail(DAPL_LLIST_HEAD *head)
{
	DAPL_LLIST_ENTRY *last;

	dapl_os_assert(!dapl_llist_is_empty(head));
	last = (*head)->blink;

	last->blink->flink = last->flink;
	last->flink->blink = last->blink;

	if (last->flink == last) {
		*head = NULL;
	}
	/* clean up the links for good measure */
	last->flink = NULL;
	last->blink = NULL;
	last->list_head = NULL;

	return (last->data);
}

/*
 * dapl_llist_remove_entry()
 *
 * Purpose: Remove the specified entry from a linked list
 */
void *
dapl_llist_remove_entry(DAPL_LLIST_HEAD *head, DAPL_LLIST_ENTRY *entry)
{
	DAPL_LLIST_ENTRY *first;

	dapl_os_assert(!dapl_llist_is_empty(head));
	first = *head;

	/* if it's the first entry, pull it off */
	if (first == entry) {
		(*head) = first->flink;
		/* if it was the only entry, kill the list */
		if (first->flink == first) {
			(*head) = NULL;
		}
	}
#ifdef VERIFY_LINKED_LIST
	else {
		DAPL_LLIST_ENTRY *try_entry;

		try_entry = first->flink;
		for (;;) {
			if (try_entry == first) {
				/*
				 * not finding the element on the list
				 * is a BAD thing
				 */
				dapl_os_assert(0);
				break;
			}
			if (try_entry == entry) {
				break;
			}
			try_entry = try_entry->flink;
		}
	}
#endif /* VERIFY_LINKED_LIST */

	dapl_os_assert(entry->list_head == head);
	entry->list_head = NULL;

	entry->flink->blink = entry->blink;
	entry->blink->flink = entry->flink;
	entry->flink = NULL;
	entry->blink = NULL;

	return (entry->data);
}

/*
 * dapl_llist_peek_head
 */

void *
dapl_llist_peek_head(DAPL_LLIST_HEAD *head)
{
	DAPL_LLIST_ENTRY *first;

	dapl_os_assert(!dapl_llist_is_empty(head));
	first = *head;
	return (first->data);
}


/*
 * dapl_llist_next_entry
 *
 * Obtain the next entry in the list, return NULL when we get to the
 * head
 */

void *
dapl_llist_next_entry(IN    DAPL_LLIST_HEAD 	*head,
    IN    DAPL_LLIST_ENTRY 	*cur_ent)
{
	DAPL_LLIST_ENTRY *next;

	dapl_os_assert(!dapl_llist_is_empty(head));
	if (cur_ent == NULL) {
		next = *head;
	} else {
		next = cur_ent->flink;
		if (next == *head) {
			return (NULL);
		}
	}
	return (next->data);
}

/*
 * dapl_llist_debug_print_list()
 *
 * Purpose: Prints the linked list for debugging
 */
void
dapl_llist_debug_print_list(DAPL_LLIST_HEAD *head)
{
	DAPL_LLIST_ENTRY * entry;
	DAPL_LLIST_ENTRY * first;
	first = *head;
	if (!first) {
		dapl_dbg_log(DAPL_DBG_TYPE_RTN, "EMPTY_LIST\n");
		return;
	}
	dapl_dbg_log(DAPL_DBG_TYPE_RTN, "HEAD %p\n", *head);
	dapl_dbg_log(DAPL_DBG_TYPE_RTN, "Entry %p %p %p %p\n",
	    first,
	    first->flink,
	    first->blink,
	    first->data);
	entry = first->flink;
	while (entry != first) {
		dapl_dbg_log(DAPL_DBG_TYPE_RTN, "Entry %p %p %p %p\n",
		    entry,
		    entry->flink,
		    entry->blink,
		    entry->data);
		entry = entry->flink;
	}
}