source: trunk/debian/packages/libubox/trunk/safe_list.c @ 857

Last change on this file since 857 was 857, checked in by amain, 4 years ago

libubox: initial import / part 4

File size: 2.8 KB
Line 
1/*
2 * safe_list - linked list protected against recursive iteration with deletes
3 *
4 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include "safe_list.h"
20
21struct safe_list_iterator {
22        struct safe_list_iterator **head;
23        struct safe_list_iterator *next_i;
24        struct safe_list *next;
25};
26
27static void
28__safe_list_set_iterator(struct safe_list *list,
29                         struct safe_list_iterator *i)
30{
31        struct safe_list_iterator *next_i;
32        struct safe_list *next;
33
34        next = list_entry(list->list.next, struct safe_list, list);
35        next_i = next->i;
36
37        next->i = i;
38        i->next = next;
39        i->head = &next->i;
40
41        i->next_i = next_i;
42        if (next_i)
43                next_i->head = &i->next_i;
44}
45
46static void
47__safe_list_del_iterator(struct safe_list_iterator *i)
48{
49        *i->head = i->next_i;
50        if (i->next_i)
51                i->next_i->head = i->head;
52}
53
54static void
55__safe_list_move_iterator(struct safe_list *list,
56                          struct safe_list_iterator *i)
57{
58        __safe_list_del_iterator(i);
59        __safe_list_set_iterator(list, i);
60}
61
62int safe_list_for_each(struct safe_list *head,
63                       int (*cb)(void *ctx, struct safe_list *list),
64                       void *ctx)
65{
66        struct safe_list_iterator i;
67        struct safe_list *cur;
68        int ret = 0;
69
70        for (cur = list_entry(head->list.next, struct safe_list, list),
71             __safe_list_set_iterator(cur, &i);
72             cur != head;
73             cur = i.next, __safe_list_move_iterator(cur, &i)) {
74                ret = cb(ctx, cur);
75                if (ret)
76                        break;
77        }
78
79        __safe_list_del_iterator(&i);
80        return ret;
81}
82
83void safe_list_add(struct safe_list *list, struct safe_list *head)
84{
85        list->i = NULL;
86        list_add_tail(&list->list, &head->list);
87}
88
89void safe_list_add_first(struct safe_list *list, struct safe_list *head)
90{
91        list->i = NULL;
92        list_add(&list->list, &head->list);
93}
94
95void safe_list_del(struct safe_list *list)
96{
97        struct safe_list_iterator *i, *next_i, **tail;
98        struct safe_list *next;
99
100        next = list_entry(list->list.next, struct safe_list, list);
101        list_del(&list->list);
102
103        if (!list->i)
104                return;
105
106        next_i = next->i;
107        tail = &next->i;
108
109        for (i = list->i; i; i = i->next_i) {
110                tail = &i->next_i;
111                i->next = next;
112        }
113
114        next->i = list->i;
115        list->i->head = &next->i;
116        *tail = next_i;
117        if (next_i)
118                next_i->head = tail;
119
120        list->i = NULL;
121}
Note: See TracBrowser for help on using the repository browser.