1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
|
.\"
.\"
.\" Copyright (c) 2009, Sun Microsystems Inc. All Rights Reserved.
.\" Copyright 2022 Oxide Computer Company
.\"
.\" 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]
.\"
.Dd January 16, 2022
.Dt LIST_CREATE 9F
.Os
.Sh NAME
.Nm list_create ,
.Nm list_destroy ,
.Nm list_insert_after ,
.Nm list_insert_before ,
.Nm list_insert_head ,
.Nm list_insert_tail ,
.Nm list_remove ,
.Nm list_remove_head ,
.Nm list_remove_tail ,
.Nm list_head ,
.Nm list_tail ,
.Nm list_next ,
.Nm list_prev ,
.Nm list_is_empty, ,
.Nm list_link_init ,
.Nm list_link_active ,
.Nm list_move_tail ,
.Nm list_link_replace
.Nd list functions
.Sh SYNOPSIS
.In sys/list.h
.Ft void
.Fo list_create
.Fa "list_t *list"
.Fa "size_t size"
.Fa "size_t offset"
.Fc
.Ft void
.Fo list_destroy
.Fa "list_t *list"
.Fc
.Ft void
.Fo list_insert_after
.Fa "list_t *list"
.Fa "void *reference_item"
.Fa "void *new_item"
.Fc
.Ft void
.Fo list_insert_before
.Fa "list_t *list"
.Fa "void *reference_item"
.Fa "void *new_item"
.Fc
.Ft void
.Fo list_insert_head
.Fa "list_t *list*"
.Fa "void *new_item"
.Fc
.Ft void
.Fo list_insert_tail
.Fa "list_t *list"
.Fa "void *new_item"
.Fc
.Ft void
.Fo list_remove
.Fa "list_t *list"
.Fa "void *item"
.Fc
.Ft "void *"
.Fo list_remove_head
.Fa "list_t *list"
.Fc
.Ft "void *"
.Fo list_remove_tail
.Fa "list_t *list"
.Fc
.Ft "void *"
.Fo list_head
.Fa "list_t *list"
.Fc
.Ft "void *"
.Fo list_tail
.Fa "list_t *list"
.Fc
.Ft "void *"
.Fo list_next
.Fa "list_t *list"
.Fa "void *reference_item"
.Fc
.Ft "void *"
.Fo list_prev
.Fa "list_t *list"
.Fa "void *reference_item"
.Fc
.Ft int
.Fo list_is_empty
.Fa "list_t *list"
.Fc
.Ft void
.Fo list_link_init
.Fa "list_node_t *node"
.Fc
.Ft int
.Fo list_link_active
.Fa "list_node_t *node"
.Fc
.Ft void
.Fo list_move_tail
.Fa "list_t *dst"
.Fa "list_t *src"
.Fc
.Ft void
.Fo list_link_replace
.Fa "list_node_t *lold"
.Fa "list_node_t *lnew"
.Fc
.Sh DESCRIPTION
These functions provide a generic doubly-linked list implementation.
To utilize it, simply embed a
.Vt list_node_t
field in the structures that will constitute the linked list elements and pass
the
.Vt list_node_t
field offset to
.Fn list_create
in the appropriate
parameter
.Pq see below .
A single
.Vt list_node_t
field can only be used in a single list simultaneously, so to add a structure to
multiple lists, embed multiple
.Vt list_node_t
fields in your user structure.
.Pp
Please note that a
.Vt list_node_t
contains pointers back to its parent
.Vt list_t
so you cannot copy the
.Vt list_t
around once it has been initialized.
In particular, this kind of construct will not work:
.Bd -literal -offset indent
struct { list_t l; } a, b;
list_create(&a.l, ...);
b = a; <= This will break the list in `b', as the `l' element
in `a' got copied to a different memory address.
.Ed
.Pp
To do this you must move the list items to the new list using functions
such as
.Fn list_move_tail .
.Pp
The
.Fn list_create
function initializes a new list.
The driver supplies the storage for the list handle, the size of an individual
element, and the offset of a
.Vt list_node_t
within the element to use for the links of the list.
.Pp
The
.Fn list_destroy
function destroys the list handle, including freeing any resources that may have
been internally allocated for the list.
The list must be empty when this function is called.
.Pp
The
.Fn list_insert_after
and
.Fn list_insert_before
functions insert
.Fa new_item
into the linked list at a location after or before the reference item, which
must already be on the list.
.Pp
The
.Fn list_insert_head
and
.Fn list_insert_tail
functions insert the
.Fa new_item
on the list at either the head or tail of the list.
The head is the first item, the tail is the last item.
.Pp
The
.Fn list_remove
function removes the item from the list.
.Pp
The
.Fn list_remove_head
and
.Fn list_remove_tail
functions remove the head
.Pq first
or tail
.Pq last
item from the list.
The item removed is returned to the caller.
If the list is empty when these functions are called, then no change is made and
.Dv NULL
is returned to the caller.
.Pp
The
.Fn list_head
and
.Fn list_tail
functions simply return the head
.Pq first
or tail
.Pq last
item on the list.
.Dv NULL
is returned if the list is empty.
.Pp
The
.Fn list_next
and
.Fn list_prev
functions return the next or previous item in the list, relative to the named
reference item which must be linked on the list.
If the referenced item is either the last entry in the list for
.Fn list_next
or the first entry in the list for
.Fn list_prev ,
then the functions will return
.Dv NULL .
This is useful for iterating over a list with the following pattern:
.Bd -literal -offset indent
list_t list_t;
\&...
for (foo_t *foo = list_head(&list_t); foo != NULL;
foo = list_next(&list_t, foo)) {
/* Process each entry of the list */
}
for (foo_t *foo = list_tail(&list_t); foo != NULL;
foo = list_prev(&list_t, foo)) {
/* Same thing, but in reverse */
}
.Ed
.Pp
The
.Fn list_is_empty
function returns 0 if the list has items in it, or non-zero otherwise.
.Pp
The
.Fn list_link_init
function initializes the
.Vt list_node_t .
It is functionally equivalent to
.Fo bzero
.Fa "node"
.Fa "sizeof (*node)"
.Fc ; .
.Pp
The
.Fn list_link_active
function returns non-zero if the node is on an active list.
.Pp
The
.Fn list_move_tail
function is used to append the items on the
.Fa src
list to the end of the
.Fa dst
list.
It is mandatory that the two lists were initialized using identical size and
offset parameters.
Upon completion, the
.Fa src
list will be empty.
.Pp
The
.Fn list_link_replace
function replaces
.Fa lold
node on an active list with the
.Fa lnew
node.
When the function is called the
.Fa lnew
node must not be linked on any list.
Upon completion the
.Fa lold
node will be left unlinked from any list.
.Sh INTERFACE STABILITY
.Sy Committed
|