248 lines
8.3 KiB
C
248 lines
8.3 KiB
C
#ifndef UC_TAILQ_H_
|
|
#define UC_TAILQ_H_
|
|
|
|
#include "utils.h"
|
|
|
|
/**
|
|
* Doubly Linked List.
|
|
* It is used either as
|
|
* 1) a linked list "head" - a node serving to hold pointer to the
|
|
* first and last node in a list
|
|
* 2) a linked list entry - a node in the linked list
|
|
*
|
|
* This is variant of sys/queue.h TAILQ which avoids too many conditionals.
|
|
* The struct TailQ serves both as an entry/node in a linked list,
|
|
* and as head of a linked list.
|
|
*
|
|
* Note that unlike the sys/queue.h TAILQ, the list does
|
|
* not begin/end with a NULL pointer. For a entry node, the beginning/end
|
|
* is a back pointer to the head node.
|
|
*
|
|
* Traditional linked list TailQ
|
|
* node->prev == NULL node->prev == head
|
|
* node->next == NULL node->next == head
|
|
*
|
|
* Do not ever add an entry that's a NULL pointer.
|
|
*
|
|
*/
|
|
struct TailQ {
|
|
//pointer to next element, or for a head node,
|
|
//pointer to the first entry
|
|
struct TailQ *next;
|
|
//pointer to previous element, or for a head node,
|
|
//pointer to the last node
|
|
struct TailQ *prev;
|
|
};
|
|
|
|
#define UC_TAILQ_HEAD_INIT(name) {&(name), &(name)}
|
|
|
|
#define UC_TAILQ_HEAD(name)\
|
|
struct TailQ name = UC_TAILQ_HEAD_INIT(name)
|
|
|
|
//given 'ptr' as a pointer to a struct 'member',
|
|
//find the struct that ptr is the member of, where
|
|
//'type' is the type of the containing struct
|
|
//This is basically UC_CONTAINER_OF in ucore/utils.h, this is here
|
|
//to make tailq.h a standalone header
|
|
#define UC_TAILQ_CONTAINER(ptr, type, member) ({\
|
|
typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
|
(type *)((void *)(unsigned char *)__mptr - offsetof(type, member) ); })
|
|
|
|
|
|
static UC_INLINE void uc_tailq_init(struct TailQ *head)
|
|
{
|
|
head->prev = head;
|
|
head->next = head;
|
|
}
|
|
|
|
/** Test if the tailq is empty
|
|
*/
|
|
static UC_INLINE int uc_tailq_empty(const struct TailQ *head)
|
|
{
|
|
return head->next == head;
|
|
}
|
|
|
|
/** Insert the entry between prev and next
|
|
*/
|
|
static UC_INLINE void uc_tailq_insert(struct TailQ *entry,
|
|
struct TailQ *prev,
|
|
struct TailQ *next)
|
|
{
|
|
entry->prev = prev;
|
|
prev->next = entry;
|
|
|
|
entry->next = next;
|
|
next->prev = entry;
|
|
}
|
|
|
|
/** Insert entry to the tail(end) of the tailq
|
|
*/
|
|
static UC_INLINE void uc_tailq_insert_tail(struct TailQ *head, struct TailQ *entry)
|
|
{
|
|
//head becomes entry->next, signalling the end of the tailq
|
|
uc_tailq_insert(entry, head->prev, head);
|
|
}
|
|
|
|
/** Insert entry to the head(start) of the tailq
|
|
*/
|
|
static UC_INLINE void uc_tailq_insert_head(struct TailQ *head, struct TailQ *entry)
|
|
{
|
|
//head becomes entry->prev, signalling the end of the tailq
|
|
uc_tailq_insert(entry, head, head->next);
|
|
}
|
|
|
|
/** Link the first and second entry together,
|
|
*/
|
|
static UC_INLINE void uc_tailq_link(struct TailQ *first, struct TailQ *second)
|
|
{
|
|
first->next = second;
|
|
second->prev = first;
|
|
}
|
|
|
|
/** Remove the entry from the tailq it is part of.
|
|
* (It *must* already be part of a tailq.
|
|
*/
|
|
static UC_INLINE void uc_tailq_remove(struct TailQ *entry)
|
|
{
|
|
uc_tailq_link(entry->prev, entry->next);
|
|
|
|
//help catch illegal use:
|
|
entry->next = (void*)0x101;
|
|
entry->prev = (void*)0x102;
|
|
}
|
|
|
|
/** Move entry from its current tailq to the head of another tailq.
|
|
* (entry must be part of a tailq)
|
|
*/
|
|
static UC_INLINE void uc_tailq_move_head(struct TailQ *entry, struct TailQ *head)
|
|
{
|
|
uc_tailq_link(entry->prev, entry->next);
|
|
uc_tailq_insert(entry, head, head->next);
|
|
}
|
|
|
|
/** Move entry from its current tailq to the tail of another tailq.
|
|
* (entry must be part of a tailq)
|
|
*/
|
|
static UC_INLINE void uc_tailq_move_tail(struct TailQ *entry, struct TailQ *head)
|
|
{
|
|
uc_tailq_link(entry->prev, entry->next);
|
|
uc_tailq_insert(entry, head->prev, head);
|
|
}
|
|
|
|
//FIRST/NEXT/LAST/PREV macros similar to sys/queue.h
|
|
//Note that unlike the standard TAILQ, you have to check
|
|
// != head instead of != NULL to determine if the tailq entry
|
|
// exists
|
|
|
|
#define UC_TAILQ_FIRST(head)\
|
|
((head)->next)
|
|
|
|
#define UC_TAILQ_NEXT(entry)\
|
|
((entry)->next)
|
|
|
|
#define UC_TAILQ_LAST(head)\
|
|
((head)->prev)
|
|
|
|
#define UC_TAILQ_PREV(entry)\
|
|
((entry)->prev)
|
|
|
|
/** Iterate over a tailq. The tailq cannot be altered while iterating.
|
|
*
|
|
* @param entry a struct TailQ* to which each element is assigned.
|
|
* @param head the struct TailQ* head of the tailq
|
|
*/
|
|
#define UC_TAILQ_FOREACH(entry, head)\
|
|
for ((entry) = UC_TAILQ_FIRST(head); \
|
|
(entry) != (head); \
|
|
(entry) = UC_TAILQ_NEXT(entry))
|
|
|
|
/** Iterate over the containing element in a tailq.
|
|
* The tailq cannot be altered while iterating.
|
|
*
|
|
* @param ptr a pointer to the struct which the tailq nodes are member of
|
|
* @param member the member of ptr that is the tailq node
|
|
* @param head the struct TailQ* head of the tailq
|
|
*/
|
|
#define UC_TAILQ_FOREACH_CONTAINER(ptr, member, head)\
|
|
for ((ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_FIRST(head), typeof(*ptr), member);\
|
|
&(ptr)->member != (head);\
|
|
(ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_NEXT(&(ptr)->member), typeof(*ptr), member))
|
|
|
|
/** Iterate over a tailq in reverse order.
|
|
* The tailq cannot be altered while iterating.
|
|
*
|
|
* @param entry a struct TailQ* to which each element is assigned.
|
|
* @param head the struct TailQ* head of the tailq
|
|
*/
|
|
#define UC_TAILQ_FOREACH_REVERSE(entry, head)\
|
|
for ((entry) = UC_TAILQ_LAST(entry); \
|
|
(entry) != (head); \
|
|
(entry) = UC_TAILQ_PREV(entry)
|
|
|
|
/** Iterate over the containing element in a tailq in reverse.
|
|
* The tailq cannot be altered while iterating.
|
|
*
|
|
* @param ptr a pointer to the struct which the tailq nodes are member of
|
|
* @param member the member of ptr that is the tailq node
|
|
* @param head the struct TailQ* head of the tailq
|
|
*/
|
|
#define UC_TAILQ_FOREACH_REVERSE_CONTAINER(ptr, member, head)\
|
|
for ((ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_LAST(head), typeof(*ptr), member);\
|
|
&(ptr)->member != (head);\
|
|
(ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_PREV(&(ptr)->member), typeof(*ptr), member))
|
|
|
|
/** Iterate over a tailq. safe to remove the entry when iterating.
|
|
*
|
|
* @param entry a struct TailQ* to which each element is assigned.
|
|
* @param nxt a struct TailQ* needed for temporary storage.
|
|
* @param head the struct TailQ* head of the tailq
|
|
*/
|
|
#define UC_TAILQ_FOREACH_SAFE(entry, nxt, head)\
|
|
for ((entry) = UC_TAILQ_FIRST(head), (nxt) = UC_TAILQ_NEXT(entry); \
|
|
(entry) != (head); \
|
|
(entry) = (nxt), (nxt) = UC_TAILQ_NEXT(entry))\
|
|
|
|
/** Iterate over the containing element in a tailq, safe to remove
|
|
* the entry when iterating
|
|
*
|
|
* @param ptr a pointer to the struct which the tailq nodes are member of
|
|
* @param nxt same type as ptr needed for temporary storage.
|
|
* @param member the member of ptr that is the tailq node
|
|
* @param head the struct TailQ* head of the tailq
|
|
*/
|
|
#define UC_TAILQ_FOREACH_CONTAINER_SAFE(ptr, nxt, member, head)\
|
|
for ((ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_FIRST(head), typeof(*ptr), member),\
|
|
(nxt) = UC_TAILQ_CONTAINER(UC_TAILQ_NEXT(&(ptr)->member), typeof(*ptr), member);\
|
|
&(ptr)->member != (head);\
|
|
(ptr) = (nxt),\
|
|
(nxt) = UC_TAILQ_CONTAINER(UC_TAILQ_NEXT(&(ptr)->member), typeof(*ptr), member))
|
|
|
|
/** Iterate over a tailq in reverse order. safe to remove the entry when
|
|
* iterating.
|
|
*
|
|
* @param entry a struct TailQ* to which each element is assigned.
|
|
* @param prv a struct TailQ* needed for temporary storage.
|
|
* @param head the struct TailQ* head of the tailq
|
|
*/
|
|
#define UC_TAILQ_FOREACH_REVERSE_SAFE(entry, prv, head)\
|
|
for ((entry) = UC_TAILQ_LAST(head), (prv) = UC_TAILQ_PREV(entry); \
|
|
(entry) != (head); \
|
|
(entry) = (prv), (prv) = UC_TAILQ_PREV(entry))\
|
|
|
|
/** Iterate over the containing element in a tailq in reverse order, safe
|
|
* to remove the entry when iterating
|
|
*
|
|
* @param ptr a pointer to the struct which the tailq nodes are member of
|
|
* @param prv same type as ptr needed for temporary storage.
|
|
* @param member the member of ptr that is the tailq node
|
|
* @param head the struct TailQ* head of the tailq
|
|
*/
|
|
#define UC_TAILQ_FOREACH_REVERSE_CONTAINER_SAFE(ptr, prv, member, head)\
|
|
for ((ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_LAST(head), typeof(*ptr), member),\
|
|
(prv) = UC_TAILQ_CONTAINER(UC_TAILQ_PREV(&(ptr)->member), typeof(*ptr), member);\
|
|
&(ptr)->member != (head);\
|
|
(ptr) = (prv),\
|
|
(prv) = UC_TAILQ_CONTAINER(UC_TAILQ_NEXT(&(ptr)->member), typeof(*ptr), member))
|
|
|
|
#endif
|