1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 
27 #ifdef LWS_HAVE_SYS_TYPES_H
28 #include <sys/types.h>
29 #endif
30 
31 int
lws_dll2_foreach_safe(struct lws_dll2_owner * owner,void * user,int (* cb)(struct lws_dll2 * d,void * user))32 lws_dll2_foreach_safe(struct lws_dll2_owner *owner, void *user,
33 		      int (*cb)(struct lws_dll2 *d, void *user))
34 {
35 	lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp, owner->head) {
36 		if (cb(p, user))
37 			return 1;
38 	} lws_end_foreach_dll_safe(p, tp);
39 
40 	return 0;
41 }
42 
43 void
lws_dll2_add_head(struct lws_dll2 * d,struct lws_dll2_owner * owner)44 lws_dll2_add_head(struct lws_dll2 *d, struct lws_dll2_owner *owner)
45 {
46 	if (!lws_dll2_is_detached(d)) {
47 		assert(0); /* only wholly detached things can be added */
48 		return;
49 	}
50 
51 	/* our next guy is current first guy, if any */
52 	if (owner->head != d)
53 		d->next = owner->head;
54 
55 	/* if there is a next guy, set his prev ptr to our next ptr */
56 	if (d->next)
57 		d->next->prev = d;
58 	/* there is nobody previous to us, we are the head */
59 	d->prev = NULL;
60 
61 	/* set the first guy to be us */
62 	owner->head = d;
63 
64 	if (!owner->tail)
65 		owner->tail = d;
66 
67 	d->owner = owner;
68 	owner->count++;
69 }
70 
71 /*
72  * add us to the list that 'after' is in, just before him
73  */
74 
75 void
lws_dll2_add_before(struct lws_dll2 * d,struct lws_dll2 * after)76 lws_dll2_add_before(struct lws_dll2 *d, struct lws_dll2 *after)
77 {
78 	lws_dll2_owner_t *owner = after->owner;
79 
80 	if (!lws_dll2_is_detached(d)) {
81 		assert(0); /* only wholly detached things can be added */
82 		return;
83 	}
84 
85 	if (lws_dll2_is_detached(after)) {
86 		assert(0); /* can't add after something detached */
87 		return;
88 	}
89 
90 	d->owner = owner;
91 
92 	/* we need to point forward to after */
93 
94 	d->next = after;
95 
96 	/* we need to point back to after->prev */
97 
98 	d->prev = after->prev;
99 
100 	/* guy that used to point to after, needs to point to us */
101 
102 	if (after->prev)
103 		after->prev->next = d;
104 	else
105 		owner->head = d;
106 
107 	/* then after needs to point back to us */
108 
109 	after->prev = d;
110 
111 	owner->count++;
112 }
113 
114 void
lws_dll2_add_tail(struct lws_dll2 * d,struct lws_dll2_owner * owner)115 lws_dll2_add_tail(struct lws_dll2 *d, struct lws_dll2_owner *owner)
116 {
117 	if (!lws_dll2_is_detached(d)) {
118 		assert(0); /* only wholly detached things can be added */
119 		return;
120 	}
121 
122 	/* our previous guy is current last guy */
123 	d->prev = owner->tail;
124 	/* if there is a prev guy, set his next ptr to our prev ptr */
125 	if (d->prev)
126 		d->prev->next = d;
127 	/* our next ptr is NULL */
128 	d->next = NULL;
129 	/* set the last guy to be us */
130 	owner->tail = d;
131 
132 	/* list head is also us if we're the first */
133 	if (!owner->head)
134 		owner->head = d;
135 
136 	d->owner = owner;
137 	owner->count++;
138 }
139 
140 void
lws_dll2_remove(struct lws_dll2 * d)141 lws_dll2_remove(struct lws_dll2 *d)
142 {
143 	if (lws_dll2_is_detached(d))
144 		return;
145 
146 	/* if we have a next guy, set his prev to our prev */
147 	if (d->next)
148 		d->next->prev = d->prev;
149 
150 	/* if we have a previous guy, set his next to our next */
151 	if (d->prev)
152 		d->prev->next = d->next;
153 
154 	/* if we have phead, track the tail and head if it points to us... */
155 
156 	if (d->owner->tail == d)
157 		d->owner->tail = d->prev;
158 
159 	if (d->owner->head == d)
160 		d->owner->head = d->next;
161 
162 	d->owner->count--;
163 
164 	/* we're out of the list, we should not point anywhere any more */
165 	d->owner = NULL;
166 	d->prev = NULL;
167 	d->next = NULL;
168 }
169 
170 void
lws_dll2_clear(struct lws_dll2 * d)171 lws_dll2_clear(struct lws_dll2 *d)
172 {
173 	d->owner = NULL;
174 	d->prev = NULL;
175 	d->next = NULL;
176 }
177 
178 void
lws_dll2_owner_clear(struct lws_dll2_owner * d)179 lws_dll2_owner_clear(struct lws_dll2_owner *d)
180 {
181 	d->head = NULL;
182 	d->tail = NULL;
183 	d->count = 0;
184 }
185 
186 void
lws_dll2_add_sorted(lws_dll2_t * d,lws_dll2_owner_t * own,int (* compare)(const lws_dll2_t * d,const lws_dll2_t * i))187 lws_dll2_add_sorted(lws_dll2_t *d, lws_dll2_owner_t *own,
188 		    int (*compare)(const lws_dll2_t *d, const lws_dll2_t *i))
189 {
190 	lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
191 				   lws_dll2_get_head(own)) {
192 		assert(p != d);
193 
194 		if (compare(p, d) >= 0) {
195 			/* drop us in before this guy */
196 			lws_dll2_add_before(d, p);
197 
198 			// lws_dll2_describe(own, "post-insert");
199 
200 			return;
201 		}
202 	} lws_end_foreach_dll_safe(p, tp);
203 
204 	/*
205 	 * Either nobody on the list yet to compare him to, or he's the
206 	 * furthest away timeout... stick him at the tail end
207 	 */
208 
209 	lws_dll2_add_tail(d, own);
210 }
211 
212 #if defined(_DEBUG)
213 
214 void
lws_dll2_describe(lws_dll2_owner_t * owner,const char * desc)215 lws_dll2_describe(lws_dll2_owner_t *owner, const char *desc)
216 {
217 	int n = 1;
218 
219 	lwsl_info("%s: %s: owner %p: count %d, head %p, tail %p\n",
220 		    __func__, desc, owner, (int)owner->count, owner->head, owner->tail);
221 
222 	lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
223 				   lws_dll2_get_head(owner)) {
224 		lwsl_info("%s:    %d: %p: owner %p, prev %p, next %p\n",
225 			    __func__, n++, p, p->owner, p->prev, p->next);
226 	} lws_end_foreach_dll_safe(p, tp);
227 }
228 
229 #endif
230