1 /*        $NetBSD: pthread_queue.h,v 1.7 2022/04/19 20:32:17 rillig Exp $       */
2 
3 /*-
4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Nathan J. Williams.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #ifndef _LIB_PTHREAD_QUEUE_H
33 #define _LIB_PTHREAD_QUEUE_H
34 
35 /*
36  * Definition of a queue interface for the pthread library.
37  * Style modeled on the sys/queue.h macros; implementation taken from
38  * the tail queue, with the added property of static initializability
39  * (and a corresponding extra cost in the _INSERT_TAIL() function.
40 */
41 
42 /*
43  * Queue definitions.
44  */
45 
46 #define PTQ_HEAD(name, type)                                                    \
47 struct name {                                                                             \
48           struct type *ptqh_first;/* first element */                           \
49           struct type **ptqh_last;/* addr of last next element */               \
50 }
51 
52 #define PTQ_HEAD_INITIALIZER { NULL, NULL }
53 
54 #define PTQ_ENTRY(type)                                                                   \
55 struct {                                                                        \
56           struct type *ptqe_next;       /* next element */                      \
57           struct type **ptqe_prev;/* address of previous next element */        \
58 }
59 
60 /*
61  * Queue functions.
62  */
63 
64 #define   PTQ_INIT(head) do {                                                   \
65           (head)->ptqh_first = NULL;                                            \
66           (head)->ptqh_last = &(head)->ptqh_first;                              \
67 } while (0)
68 
69 #define   PTQ_INSERT_HEAD(head, elm, field) do {                                \
70           if (((elm)->field.ptqe_next = (head)->ptqh_first) != NULL)  \
71                     (head)->ptqh_first->field.ptqe_prev =                       \
72                         &(elm)->field.ptqe_next;                                \
73           else                                                                            \
74                     (head)->ptqh_last = &(elm)->field.ptqe_next;                \
75           (head)->ptqh_first = (elm);                                           \
76           (elm)->field.ptqe_prev = &(head)->ptqh_first;                         \
77 } while (0)
78 
79 #define   PTQ_INSERT_TAIL(head, elm, field) do {                                \
80           (elm)->field.ptqe_next = NULL;                                                  \
81           if ((head)->ptqh_last == NULL)                                                  \
82                     (head)->ptqh_last = &(head)->ptqh_first;                    \
83           (elm)->field.ptqe_prev = (head)->ptqh_last;                           \
84           *(head)->ptqh_last = (elm);                                           \
85           (head)->ptqh_last = &(elm)->field.ptqe_next;                          \
86 } while (0)
87 
88 #define   PTQ_INSERT_AFTER(head, listelm, elm, field) do {            \
89           if (((elm)->field.ptqe_next = (listelm)->field.ptqe_next) != NULL)\
90                     (elm)->field.ptqe_next->field.ptqe_prev =                   \
91                         &(elm)->field.ptqe_next;                                \
92           else                                                                            \
93                     (head)->ptqh_last = &(elm)->field.ptqe_next;                \
94           (listelm)->field.ptqe_next = (elm);                                   \
95           (elm)->field.ptqe_prev = &(listelm)->field.ptqe_next;                 \
96 } while (0)
97 
98 #define   PTQ_INSERT_BEFORE(listelm, elm, field) do {                           \
99           (elm)->field.ptqe_prev = (listelm)->field.ptqe_prev;                  \
100           (elm)->field.ptqe_next = (listelm);                                   \
101           *(listelm)->field.ptqe_prev = (elm);                                  \
102           (listelm)->field.ptqe_prev = &(elm)->field.ptqe_next;                 \
103 } while (0)
104 
105 #define   PTQ_REMOVE(head, elm, field) do {                                     \
106           if (((elm)->field.ptqe_next) != NULL)                                 \
107                     (elm)->field.ptqe_next->field.ptqe_prev =                   \
108                         (elm)->field.ptqe_prev;                                 \
109           else                                                                            \
110                     (head)->ptqh_last = (elm)->field.ptqe_prev;                 \
111           *(elm)->field.ptqe_prev = (elm)->field.ptqe_next;           \
112 } while (0)
113 
114 /*
115  * Queue access methods.
116  */
117 
118 #define   PTQ_EMPTY(head)                         ((head)->ptqh_first == NULL)
119 #define   PTQ_FIRST(head)                         ((head)->ptqh_first)
120 #define   PTQ_NEXT(elm, field)                    ((elm)->field.ptqe_next)
121 
122 #define   PTQ_LAST(head, headname)                                              \
123           (*(((struct headname *)(void *)((head)->ptqh_last))->ptqh_last))
124 #define   PTQ_PREV(elm, headname, field)                                                  \
125           (*(((struct headname *)(void *)((elm)->field.ptqe_prev))->ptqh_last))
126 
127 #define   PTQ_FOREACH(var, head, field)                                         \
128           for ((var) = ((head)->ptqh_first);                                    \
129                     (var);                                                                \
130                     (var) = ((var)->field.ptqe_next))
131 
132 #define   PTQ_FOREACH_REVERSE(var, head, headname, field)                       \
133           for ((var) = (*(((struct headname *)(void *)((head)->ptqh_last))->ptqh_last));  \
134                     (var);                                                                \
135                     (var) = (*(((struct headname *)(void *)((var)->field.ptqe_prev))->ptqh_last)))
136 
137 #endif /* _LIB_PTHREAD_QUEUE_H */
138