root/usr/src/uts/common/io/xge/hal/include/xge-list.h
/*
 * 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-2006 Neterion, Inc.
 */

#ifndef XGE_LIST_H
#define XGE_LIST_H

#include "xge-debug.h"

__EXTERN_BEGIN_DECLS

/**
 * struct xge_list_t - List item.
 * @prev: Previous list item.
 * @next: Next list item.
 *
 * Item of a bi-directional linked list.
 */
typedef struct xge_list_t {
        struct xge_list_t* prev;
        struct xge_list_t* next;
} xge_list_t;

/**
 * xge_list_init - Initialize linked list.
 * header: first element of the list (head)
 *
 * Initialize linked list.
 * See also: xge_list_t{}.
 */
static inline void xge_list_init (xge_list_t *header)
{
        header->next = header;
        header->prev = header;
}

/**
 * xge_list_is_empty - Is the list empty?
 * header: first element of the list (head)
 *
 * Determine whether the bi-directional list is empty. Return '1' in
 * case of 'empty'.
 * See also: xge_list_t{}.
 */
static inline int xge_list_is_empty(xge_list_t *header)
{
    xge_assert(header != NULL);

    return header->next == header;
}

/**
 * xge_list_first_get - Return the first item from the linked list.
 * header: first element of the list (head)
 *
 * Returns the next item from the header.
 * Returns NULL if the next item is header itself
 * See also: xge_list_remove(), xge_list_insert(), xge_list_t{}.
 */
static inline xge_list_t *xge_list_first_get(xge_list_t *header)
{
        xge_assert(header != NULL);
        xge_assert(header->next != NULL);
        xge_assert(header->prev != NULL);

        if(header->next == header)
                return NULL;
        else
                return header->next;
}

/**
 * xge_list_remove - Remove the specified item from the linked list.
 * item: element of the list
 *
 * Remove item from a list.
 * See also: xge_list_insert(), xge_list_t{}.
 */
static inline void xge_list_remove(xge_list_t *item)
{
        xge_assert(item != NULL);
        xge_assert(item->next != NULL);
        xge_assert(item->prev != NULL);

        item->next->prev = item->prev;
        item->prev->next = item->next;
#ifdef XGE_DEBUG_ASSERT
        item->next = item->prev = NULL;
#endif
}

/**
 * xge_list_insert - Insert a new item after the specified item.
 * new_item: new element of the list
 * prev_item: element of the list after which the new element is
 *             inserted
 *
 * Insert new item (new_item) after given item (prev_item).
 * See also: xge_list_remove(), xge_list_insert_before(), xge_list_t{}.
 */
static inline void xge_list_insert (xge_list_t *new_item,
                                    xge_list_t *prev_item)
{
        xge_assert(new_item  != NULL);
        xge_assert(prev_item != NULL);
        xge_assert(prev_item->next != NULL);

        new_item->next = prev_item->next;
        new_item->prev = prev_item;
        prev_item->next->prev = new_item;
        prev_item->next = new_item;
}

/**
 * xge_list_insert_before - Insert a new item before the specified item.
 * new_item: new element of the list
 * next_item: element of the list after which the new element is inserted
 *
 * Insert new item (new_item) before given item (next_item).
 */
static inline void xge_list_insert_before (xge_list_t *new_item,
                                           xge_list_t *next_item)
{
        xge_assert(new_item  != NULL);
        xge_assert(next_item != NULL);
        xge_assert(next_item->next != NULL);

        new_item->next = next_item;
        new_item->prev = next_item->prev;
        next_item->prev->next = new_item;
        next_item->prev = new_item;
}

#define xge_list_for_each(_p, _h) \
        for (_p = (_h)->next, xge_os_prefetch(_p->next); _p != (_h); \
                _p = _p->next, xge_os_prefetch(_p->next))

#define xge_list_for_each_safe(_p, _n, _h) \
        for (_p = (_h)->next, _n = _p->next; _p != (_h); \
                _p = _n, _n = _p->next)

#ifdef __GNUC__
/**
 * xge_container_of - Given a member, return the containing structure.
 * @ptr:        the pointer to the member.
 * @type:       the type of the container struct this is embedded in.
 * @member:     the name of the member within the struct.
 *
 * Cast a member of a structure out to the containing structure.
 */
#define xge_container_of(ptr, type, member) ({                  \
         __typeof( ((type *)0)->member ) *__mptr = (ptr);       \
        (type *)(void *)( (char *)__mptr - ((size_t) &((type *)0)->member) );})
#else
/* type unsafe version */
#define xge_container_of(ptr, type, member) \
                ((type*)(void*)((char*)(ptr) - ((size_t) &((type *)0)->member)))
#endif

/**
 * xge_offsetof - Offset of the member in the containing structure.
 * @t:  struct name.
 * @m:  the name of the member within the struct.
 *
 * Return the offset of the member @m in the structure @t.
 */
#define xge_offsetof(t, m) ((size_t) (&((t *)0)->m))

__EXTERN_END_DECLS

#endif /* XGE_LIST_H */