Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
Fengmin Zhu
RefinedC
Commits
e8e7d660
Commit
e8e7d660
authored
Dec 03, 2020
by
Rodolphe Lepigre
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add Linux list code.
parent
08d58e8b
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
1064 additions
and
0 deletions
+1064
-0
linux/list.c
linux/list.c
+1064
-0
No files found.
linux/list.c
0 → 100644
View file @
e8e7d660
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
// FIXME use normal includes instead of what follows.
//#include <linux/types.h>
//#include <linux/stddef.h>
//#include <linux/poison.h>
//#include <linux/const.h>
//#include <linux/kernel.h>
/** From linux/poison.h *****************************************************/
#define POISON_POINTER_DELTA 0
/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/
#define LIST_POISON1 ((void *) (0x100 + POISON_POINTER_DELTA))
#define LIST_POISON2 ((void *) (0x122 + POISON_POINTER_DELTA))
/****************************************************************************/
/** From ???? ***************************************************************/
#define WRITE_ONCE(x, val) x=(val)
#define READ_ONCE(x) (x)
/****************************************************************************/
/** From linux/stddef.h *****************************************************/
#define NULL ((void *) 0)
enum
{
false
=
0
,
true
=
1
};
/****************************************************************************/
/** From linux/types.h ******************************************************/
typedef
_Bool
bool
;
struct
list_head
{
struct
list_head
*
next
,
*
prev
;
};
struct
hlist_head
{
struct
hlist_node
*
first
;
};
struct
hlist_node
{
struct
hlist_node
*
next
,
**
pprev
;
};
/****************************************************************************/
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
/**
* INIT_LIST_HEAD - Initialize a list_head structure
* @list: list_head structure to be initialized.
*
* Initializes the list_head to point to itself. If it is a list header,
* the result is an empty list.
*/
static
inline
void
INIT_LIST_HEAD
(
struct
list_head
*
list
)
{
WRITE_ONCE
(
list
->
next
,
list
);
list
->
prev
=
list
;
}
#ifdef CONFIG_DEBUG_LIST
extern
bool
__list_add_valid
(
struct
list_head
*
new
,
struct
list_head
*
prev
,
struct
list_head
*
next
);
extern
bool
__list_del_entry_valid
(
struct
list_head
*
entry
);
#else
static
inline
bool
__list_add_valid
(
struct
list_head
*
new
,
struct
list_head
*
prev
,
struct
list_head
*
next
)
{
return
true
;
}
static
inline
bool
__list_del_entry_valid
(
struct
list_head
*
entry
)
{
return
true
;
}
#endif
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static
inline
void
__list_add
(
struct
list_head
*
new
,
struct
list_head
*
prev
,
struct
list_head
*
next
)
{
if
(
!
__list_add_valid
(
new
,
prev
,
next
))
return
;
next
->
prev
=
new
;
new
->
next
=
next
;
new
->
prev
=
prev
;
WRITE_ONCE
(
prev
->
next
,
new
);
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static
inline
void
list_add
(
struct
list_head
*
new
,
struct
list_head
*
head
)
{
__list_add
(
new
,
head
,
head
->
next
);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static
inline
void
list_add_tail
(
struct
list_head
*
new
,
struct
list_head
*
head
)
{
__list_add
(
new
,
head
->
prev
,
head
);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static
inline
void
__list_del
(
struct
list_head
*
prev
,
struct
list_head
*
next
)
{
next
->
prev
=
prev
;
WRITE_ONCE
(
prev
->
next
,
next
);
}
/*
* Delete a list entry and clear the 'prev' pointer.
*
* This is a special-purpose list clearing method used in the networking code
* for lists allocated as per-cpu, where we don't want to incur the extra
* WRITE_ONCE() overhead of a regular list_del_init(). The code that uses this
* needs to check the node 'prev' pointer instead of calling list_empty().
*/
static
inline
void
__list_del_clearprev
(
struct
list_head
*
entry
)
{
__list_del
(
entry
->
prev
,
entry
->
next
);
entry
->
prev
=
NULL
;
}
static
inline
void
__list_del_entry
(
struct
list_head
*
entry
)
{
if
(
!
__list_del_entry_valid
(
entry
))
return
;
__list_del
(
entry
->
prev
,
entry
->
next
);
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty() on entry does not return true after this, the entry is
* in an undefined state.
*/
static
inline
void
list_del
(
struct
list_head
*
entry
)
{
__list_del_entry
(
entry
);
entry
->
next
=
LIST_POISON1
;
entry
->
prev
=
LIST_POISON2
;
}
/**
* list_replace - replace old entry by new one
* @old : the element to be replaced
* @new : the new element to insert
*
* If @old was empty, it will be overwritten.
*/
static
inline
void
list_replace
(
struct
list_head
*
old
,
struct
list_head
*
new
)
{
new
->
next
=
old
->
next
;
new
->
next
->
prev
=
new
;
new
->
prev
=
old
->
prev
;
new
->
prev
->
next
=
new
;
}
/**
* list_replace_init - replace old entry by new one and initialize the old one
* @old : the element to be replaced
* @new : the new element to insert
*
* If @old was empty, it will be overwritten.
*/
static
inline
void
list_replace_init
(
struct
list_head
*
old
,
struct
list_head
*
new
)
{
list_replace
(
old
,
new
);
INIT_LIST_HEAD
(
old
);
}
/**
* list_swap - replace entry1 with entry2 and re-add entry1 at entry2's position
* @entry1: the location to place entry2
* @entry2: the location to place entry1
*/
static
inline
void
list_swap
(
struct
list_head
*
entry1
,
struct
list_head
*
entry2
)
{
struct
list_head
*
pos
=
entry2
->
prev
;
list_del
(
entry2
);
list_replace
(
entry1
,
entry2
);
if
(
pos
==
entry1
)
pos
=
entry2
;
list_add
(
entry1
,
pos
);
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static
inline
void
list_del_init
(
struct
list_head
*
entry
)
{
__list_del_entry
(
entry
);
INIT_LIST_HEAD
(
entry
);
}
/**
* list_move - delete from one list and add as another's head
* @list: the entry to move
* @head: the head that will precede our entry
*/
static
inline
void
list_move
(
struct
list_head
*
list
,
struct
list_head
*
head
)
{
__list_del_entry
(
list
);
list_add
(
list
,
head
);
}
/**
* list_move_tail - delete from one list and add as another's tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
static
inline
void
list_move_tail
(
struct
list_head
*
list
,
struct
list_head
*
head
)
{
__list_del_entry
(
list
);
list_add_tail
(
list
,
head
);
}
/**
* list_bulk_move_tail - move a subsection of a list to its tail
* @head: the head that will follow our entry
* @first: first entry to move
* @last: last entry to move, can be the same as first
*
* Move all entries between @first and including @last before @head.
* All three entries must belong to the same linked list.
*/
static
inline
void
list_bulk_move_tail
(
struct
list_head
*
head
,
struct
list_head
*
first
,
struct
list_head
*
last
)
{
first
->
prev
->
next
=
last
->
next
;
last
->
next
->
prev
=
first
->
prev
;
head
->
prev
->
next
=
first
;
first
->
prev
=
head
->
prev
;
last
->
next
=
head
;
head
->
prev
=
last
;
}
/**
* list_is_first -- tests whether @list is the first entry in list @head
* @list: the entry to test
* @head: the head of the list
*/
static
inline
int
list_is_first
(
const
struct
list_head
*
list
,
const
struct
list_head
*
head
)
{
return
list
->
prev
==
head
;
}
/**
* list_is_last - tests whether @list is the last entry in list @head
* @list: the entry to test
* @head: the head of the list
*/
static
inline
int
list_is_last
(
const
struct
list_head
*
list
,
const
struct
list_head
*
head
)
{
return
list
->
next
==
head
;
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static
inline
int
list_empty
(
const
struct
list_head
*
head
)
{
return
READ_ONCE
(
head
->
next
)
==
head
;
}
/**
* list_del_init_careful - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*
* This is the same as list_del_init(), except designed to be used
* together with list_empty_careful() in a way to guarantee ordering
* of other memory operations.
*
* Any memory operations done before a list_del_init_careful() are
* guaranteed to be visible after a list_empty_careful() test.
*/
// FIXME missing smp_store_release.
//static inline void list_del_init_careful(struct list_head *entry)
//{
// __list_del_entry(entry);
// entry->prev = entry;
// smp_store_release(&entry->next, entry);
//}
/**
* list_empty_careful - tests whether a list is empty and not being modified
* @head: the list to test
*
* Description:
* tests whether a list is empty _and_ checks that no other CPU might be
* in the process of modifying either member (next or prev)
*
* NOTE: using list_empty_careful() without synchronization
* can only be safe if the only activity that can happen
* to the list entry is list_del_init(). Eg. it cannot be used
* if another CPU could re-list_add() it.
*/
// FIXME missing smp_load_acquire.
//static inline int list_empty_careful(const struct list_head *head)
//{
// struct list_head *next = smp_load_acquire(&head->next);
// return (next == head) && (next == head->prev);
//}
/**
* list_rotate_left - rotate the list to the left
* @head: the head of the list
*/
static
inline
void
list_rotate_left
(
struct
list_head
*
head
)
{
struct
list_head
*
first
;
if
(
!
list_empty
(
head
))
{
first
=
head
->
next
;
list_move_tail
(
first
,
head
);
}
}
/**
* list_rotate_to_front() - Rotate list to specific item.
* @list: The desired new front of the list.
* @head: The head of the list.
*
* Rotates list so that @list becomes the new front of the list.
*/
static
inline
void
list_rotate_to_front
(
struct
list_head
*
list
,
struct
list_head
*
head
)
{
/*
* Deletes the list head from the list denoted by @head and
* places it as the tail of @list, this effectively rotates the
* list so that @list is at the front.
*/
list_move_tail
(
head
,
list
);
}
/**
* list_is_singular - tests whether a list has just one entry.
* @head: the list to test.
*/
static
inline
int
list_is_singular
(
const
struct
list_head
*
head
)
{
return
!
list_empty
(
head
)
&&
(
head
->
next
==
head
->
prev
);
}
static
inline
void
__list_cut_position
(
struct
list_head
*
list
,
struct
list_head
*
head
,
struct
list_head
*
entry
)
{
struct
list_head
*
new_first
=
entry
->
next
;
list
->
next
=
head
->
next
;
list
->
next
->
prev
=
list
;
list
->
prev
=
entry
;
entry
->
next
=
list
;
head
->
next
=
new_first
;
new_first
->
prev
=
head
;
}
/**
* list_cut_position - cut a list into two
* @list: a new list to add all removed entries
* @head: a list with entries
* @entry: an entry within head, could be the head itself
* and if so we won't cut the list
*
* This helper moves the initial part of @head, up to and
* including @entry, from @head to @list. You should
* pass on @entry an element you know is on @head. @list
* should be an empty list or a list you do not care about
* losing its data.
*
*/
static
inline
void
list_cut_position
(
struct
list_head
*
list
,
struct
list_head
*
head
,
struct
list_head
*
entry
)
{
if
(
list_empty
(
head
))
return
;
if
(
list_is_singular
(
head
)
&&
(
head
->
next
!=
entry
&&
head
!=
entry
))
return
;
if
(
entry
==
head
)
INIT_LIST_HEAD
(
list
);
else
__list_cut_position
(
list
,
head
,
entry
);
}
/**
* list_cut_before - cut a list into two, before given entry
* @list: a new list to add all removed entries
* @head: a list with entries
* @entry: an entry within head, could be the head itself
*
* This helper moves the initial part of @head, up to but
* excluding @entry, from @head to @list. You should pass
* in @entry an element you know is on @head. @list should
* be an empty list or a list you do not care about losing
* its data.
* If @entry == @head, all entries on @head are moved to
* @list.
*/
static
inline
void
list_cut_before
(
struct
list_head
*
list
,
struct
list_head
*
head
,
struct
list_head
*
entry
)
{
if
(
head
->
next
==
entry
)
{
INIT_LIST_HEAD
(
list
);
return
;
}
list
->
next
=
head
->
next
;
list
->
next
->
prev
=
list
;
list
->
prev
=
entry
->
prev
;
list
->
prev
->
next
=
list
;
head
->
next
=
entry
;
entry
->
prev
=
head
;
}
static
inline
void
__list_splice
(
const
struct
list_head
*
list
,
struct
list_head
*
prev
,
struct
list_head
*
next
)
{
struct
list_head
*
first
=
list
->
next
;
struct
list_head
*
last
=
list
->
prev
;
first
->
prev
=
prev
;
prev
->
next
=
first
;
last
->
next
=
next
;
next
->
prev
=
last
;
}
/**
* list_splice - join two lists, this is designed for stacks
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static
inline
void
list_splice
(
const
struct
list_head
*
list
,
struct
list_head
*
head
)
{
if
(
!
list_empty
(
list
))
__list_splice
(
list
,
head
,
head
->
next
);
}
/**
* list_splice_tail - join two lists, each list being a queue
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static
inline
void
list_splice_tail
(
struct
list_head
*
list
,
struct
list_head
*
head
)
{
if
(
!
list_empty
(
list
))
__list_splice
(
list
,
head
->
prev
,
head
);
}
/**
* list_splice_init - join two lists and reinitialise the emptied list.
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* The list at @list is reinitialised
*/
static
inline
void
list_splice_init
(
struct
list_head
*
list
,
struct
list_head
*
head
)
{
if
(
!
list_empty
(
list
))
{
__list_splice
(
list
,
head
,
head
->
next
);
INIT_LIST_HEAD
(
list
);
}
}
/**
* list_splice_tail_init - join two lists and reinitialise the emptied list
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* Each of the lists is a queue.
* The list at @list is reinitialised
*/
static
inline
void
list_splice_tail_init
(
struct
list_head
*
list
,
struct
list_head
*
head
)
{
if
(
!
list_empty
(
list
))
{
__list_splice
(
list
,
head
->
prev
,
head
);
INIT_LIST_HEAD
(
list
);
}
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* list_first_entry - get the first element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
/**
* list_last_entry - get the last element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_last_entry(ptr, type, member) \
list_entry((ptr)->prev, type, member)
/**
* list_first_entry_or_null - get the first element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*
* Note that if the list is empty, it returns NULL.
*/
#define list_first_entry_or_null(ptr, type, member) ({ \
struct list_head *head__ = (ptr); \
struct list_head *pos__ = READ_ONCE(head__->next); \
pos__ != head__ ? list_entry(pos__, type, member) : NULL; \
})
/**
* list_next_entry - get the next element in list
* @pos: the type * to cursor
* @member: the name of the list_head within the struct.
*/
#define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member)
/**
* list_prev_entry - get the prev element in list
* @pos: the type * to cursor
* @member: the name of the list_head within the struct.
*/
#define list_prev_entry(pos, member) \
list_entry((pos)->member.prev, typeof(*(pos)), member)
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* list_for_each_continue - continue iteration over a list
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*
* Continue to iterate over a list, continuing after the current position.
*/
#define list_for_each_continue(pos, head) \
for (pos = pos->next; pos != (head); pos = pos->next)
/**
* list_for_each_prev - iterate over a list backwards
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*/
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; pos != (head); pos = pos->prev)
/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop cursor.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/**
* list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
* @pos: the &struct list_head to use as a loop cursor.
* @n: another &struct list_head to use as temporary storage