blob: 2b3218fc1358b1e57bf333744987774208357e80 [file] [log] [blame]
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "private-lib-core.h"
#ifdef LWS_HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
int
lws_dll2_foreach_safe(struct lws_dll2_owner *owner, void *user,
int (*cb)(struct lws_dll2 *d, void *user))
{
lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp, owner->head) {
if (cb(p, user))
return 1;
} lws_end_foreach_dll_safe(p, tp);
return 0;
}
void
lws_dll2_add_head(struct lws_dll2 *d, struct lws_dll2_owner *owner)
{
if (!lws_dll2_is_detached(d)) {
assert(0); /* only wholly detached things can be added */
return;
}
/* our next guy is current first guy, if any */
if (owner->head != d)
d->next = owner->head;
/* if there is a next guy, set his prev ptr to our next ptr */
if (d->next)
d->next->prev = d;
/* there is nobody previous to us, we are the head */
d->prev = NULL;
/* set the first guy to be us */
owner->head = d;
if (!owner->tail)
owner->tail = d;
d->owner = owner;
owner->count++;
}
/*
* add us to the list that 'after' is in, just before him
*/
void
lws_dll2_add_before(struct lws_dll2 *d, struct lws_dll2 *after)
{
lws_dll2_owner_t *owner = after->owner;
if (!lws_dll2_is_detached(d)) {
assert(0); /* only wholly detached things can be added */
return;
}
if (lws_dll2_is_detached(after)) {
assert(0); /* can't add after something detached */
return;
}
d->owner = owner;
/* we need to point forward to after */
d->next = after;
/* we need to point back to after->prev */
d->prev = after->prev;
/* guy that used to point to after, needs to point to us */
if (after->prev)
after->prev->next = d;
else
owner->head = d;
/* then after needs to point back to us */
after->prev = d;
owner->count++;
}
void
lws_dll2_add_tail(struct lws_dll2 *d, struct lws_dll2_owner *owner)
{
if (!lws_dll2_is_detached(d)) {
assert(0); /* only wholly detached things can be added */
return;
}
/* our previous guy is current last guy */
d->prev = owner->tail;
/* if there is a prev guy, set his next ptr to our prev ptr */
if (d->prev)
d->prev->next = d;
/* our next ptr is NULL */
d->next = NULL;
/* set the last guy to be us */
owner->tail = d;
/* list head is also us if we're the first */
if (!owner->head)
owner->head = d;
d->owner = owner;
owner->count++;
}
void
lws_dll2_remove(struct lws_dll2 *d)
{
if (lws_dll2_is_detached(d))
return;
/* if we have a next guy, set his prev to our prev */
if (d->next)
d->next->prev = d->prev;
/* if we have a previous guy, set his next to our next */
if (d->prev)
d->prev->next = d->next;
/* if we have phead, track the tail and head if it points to us... */
if (d->owner->tail == d)
d->owner->tail = d->prev;
if (d->owner->head == d)
d->owner->head = d->next;
d->owner->count--;
/* we're out of the list, we should not point anywhere any more */
d->owner = NULL;
d->prev = NULL;
d->next = NULL;
}
void
lws_dll2_clear(struct lws_dll2 *d)
{
d->owner = NULL;
d->prev = NULL;
d->next = NULL;
}
void
lws_dll2_owner_clear(struct lws_dll2_owner *d)
{
d->head = NULL;
d->tail = NULL;
d->count = 0;
}
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))
{
lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
lws_dll2_get_head(own)) {
assert(p != d);
if (compare(p, d) >= 0) {
/* drop us in before this guy */
lws_dll2_add_before(d, p);
// lws_dll2_describe(own, "post-insert");
return;
}
} lws_end_foreach_dll_safe(p, tp);
/*
* Either nobody on the list yet to compare him to, or he's the
* furthest away timeout... stick him at the tail end
*/
lws_dll2_add_tail(d, own);
}
#if defined(_DEBUG)
void
lws_dll2_describe(lws_dll2_owner_t *owner, const char *desc)
{
int n = 1;
lwsl_info("%s: %s: owner %p: count %d, head %p, tail %p\n",
__func__, desc, owner, (int)owner->count, owner->head, owner->tail);
lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
lws_dll2_get_head(owner)) {
lwsl_info("%s: %d: %p: owner %p, prev %p, next %p\n",
__func__, n++, p, p->owner, p->prev, p->next);
} lws_end_foreach_dll_safe(p, tp);
}
#endif