1*437bfbebSnyanmisaka /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2*437bfbebSnyanmisaka /*
3*437bfbebSnyanmisaka * Copyright (c) 2015 Rockchip Electronics Co., Ltd.
4*437bfbebSnyanmisaka */
5*437bfbebSnyanmisaka
6*437bfbebSnyanmisaka #define MODULE_TAG "mpp_list"
7*437bfbebSnyanmisaka
8*437bfbebSnyanmisaka #include <stdlib.h>
9*437bfbebSnyanmisaka #include <string.h>
10*437bfbebSnyanmisaka #include <stdarg.h>
11*437bfbebSnyanmisaka #include <errno.h>
12*437bfbebSnyanmisaka
13*437bfbebSnyanmisaka #include "mpp_mem.h"
14*437bfbebSnyanmisaka #include "mpp_list.h"
15*437bfbebSnyanmisaka #include "mpp_debug.h"
16*437bfbebSnyanmisaka #include "mpp_common.h"
17*437bfbebSnyanmisaka
18*437bfbebSnyanmisaka #define LIST_DEBUG(fmt, ...) mpp_log(fmt, ## __VA_ARGS__)
19*437bfbebSnyanmisaka #define LIST_ERROR(fmt, ...) mpp_err(fmt, ## __VA_ARGS__)
20*437bfbebSnyanmisaka
list_node_init(MppListNode * node)21*437bfbebSnyanmisaka static inline void list_node_init(MppListNode *node)
22*437bfbebSnyanmisaka {
23*437bfbebSnyanmisaka node->prev = node->next = node;
24*437bfbebSnyanmisaka }
25*437bfbebSnyanmisaka
list_node_init_with_key_and_size(MppListNode * node,rk_u32 key,rk_s32 size)26*437bfbebSnyanmisaka static inline void list_node_init_with_key_and_size(MppListNode *node, rk_u32 key, rk_s32 size)
27*437bfbebSnyanmisaka {
28*437bfbebSnyanmisaka list_node_init(node);
29*437bfbebSnyanmisaka node->key = key;
30*437bfbebSnyanmisaka node->size = size;
31*437bfbebSnyanmisaka }
32*437bfbebSnyanmisaka
create_list(void * data,rk_s32 size,rk_u32 key)33*437bfbebSnyanmisaka static MppListNode* create_list(void *data, rk_s32 size, rk_u32 key)
34*437bfbebSnyanmisaka {
35*437bfbebSnyanmisaka MppListNode *node = mpp_malloc_size(MppListNode, sizeof(MppListNode) + size);
36*437bfbebSnyanmisaka
37*437bfbebSnyanmisaka if (node) {
38*437bfbebSnyanmisaka void *dst = (void*)(node + 1);
39*437bfbebSnyanmisaka list_node_init_with_key_and_size(node, key, size);
40*437bfbebSnyanmisaka memcpy(dst, data, size);
41*437bfbebSnyanmisaka } else {
42*437bfbebSnyanmisaka LIST_ERROR("failed to allocate list node");
43*437bfbebSnyanmisaka }
44*437bfbebSnyanmisaka return node;
45*437bfbebSnyanmisaka }
46*437bfbebSnyanmisaka
_mpp_list_add(MppListNode * _new,MppListNode * prev,MppListNode * next)47*437bfbebSnyanmisaka static inline void _mpp_list_add(MppListNode * _new, MppListNode * prev, MppListNode * next)
48*437bfbebSnyanmisaka {
49*437bfbebSnyanmisaka next->prev = _new;
50*437bfbebSnyanmisaka _new->next = next;
51*437bfbebSnyanmisaka _new->prev = prev;
52*437bfbebSnyanmisaka prev->next = _new;
53*437bfbebSnyanmisaka }
54*437bfbebSnyanmisaka
mpp_list_add(MppListNode * _new,MppListNode * head)55*437bfbebSnyanmisaka static inline void mpp_list_add(MppListNode *_new, MppListNode *head)
56*437bfbebSnyanmisaka {
57*437bfbebSnyanmisaka _mpp_list_add(_new, head, head->next);
58*437bfbebSnyanmisaka }
59*437bfbebSnyanmisaka
mpp_list_add_tail(MppListNode * _new,MppListNode * head)60*437bfbebSnyanmisaka static inline void mpp_list_add_tail(MppListNode *_new, MppListNode *head)
61*437bfbebSnyanmisaka {
62*437bfbebSnyanmisaka _mpp_list_add(_new, head->prev, head);
63*437bfbebSnyanmisaka }
64*437bfbebSnyanmisaka
mpp_list_add_at_head(MppList * list,void * data,int size)65*437bfbebSnyanmisaka int mpp_list_add_at_head(MppList *list, void *data, int size)
66*437bfbebSnyanmisaka {
67*437bfbebSnyanmisaka rk_s32 ret = -EINVAL;
68*437bfbebSnyanmisaka
69*437bfbebSnyanmisaka if (list->head) {
70*437bfbebSnyanmisaka MppListNode *node = create_list(data, size, 0);
71*437bfbebSnyanmisaka if (node) {
72*437bfbebSnyanmisaka mpp_list_add(node, list->head);
73*437bfbebSnyanmisaka list->count++;
74*437bfbebSnyanmisaka ret = 0;
75*437bfbebSnyanmisaka } else {
76*437bfbebSnyanmisaka ret = -ENOMEM;
77*437bfbebSnyanmisaka }
78*437bfbebSnyanmisaka }
79*437bfbebSnyanmisaka return ret;
80*437bfbebSnyanmisaka }
81*437bfbebSnyanmisaka
mpp_list_add_at_tail(MppList * list,void * data,int size)82*437bfbebSnyanmisaka int mpp_list_add_at_tail(MppList *list, void *data, int size)
83*437bfbebSnyanmisaka {
84*437bfbebSnyanmisaka rk_s32 ret = -EINVAL;
85*437bfbebSnyanmisaka
86*437bfbebSnyanmisaka if (list->head) {
87*437bfbebSnyanmisaka MppListNode *node = create_list(data, size, 0);
88*437bfbebSnyanmisaka
89*437bfbebSnyanmisaka if (node) {
90*437bfbebSnyanmisaka mpp_list_add_tail(node, list->head);
91*437bfbebSnyanmisaka list->count++;
92*437bfbebSnyanmisaka ret = 0;
93*437bfbebSnyanmisaka } else {
94*437bfbebSnyanmisaka ret = -ENOMEM;
95*437bfbebSnyanmisaka }
96*437bfbebSnyanmisaka }
97*437bfbebSnyanmisaka return ret;
98*437bfbebSnyanmisaka }
99*437bfbebSnyanmisaka
release_list(MppListNode * node,void * data,rk_s32 size)100*437bfbebSnyanmisaka static void release_list(MppListNode*node, void *data, rk_s32 size)
101*437bfbebSnyanmisaka {
102*437bfbebSnyanmisaka void *src = (void*)(node + 1);
103*437bfbebSnyanmisaka
104*437bfbebSnyanmisaka if (node->size == size) {
105*437bfbebSnyanmisaka if (data)
106*437bfbebSnyanmisaka memcpy(data, src, size);
107*437bfbebSnyanmisaka } else {
108*437bfbebSnyanmisaka LIST_ERROR("node size check failed when release_list");
109*437bfbebSnyanmisaka size = (size < node->size) ? (size) : (node->size);
110*437bfbebSnyanmisaka if (data)
111*437bfbebSnyanmisaka memcpy(data, src, size);
112*437bfbebSnyanmisaka }
113*437bfbebSnyanmisaka mpp_free(node);
114*437bfbebSnyanmisaka }
115*437bfbebSnyanmisaka
_mpp_list_del(MppListNode * prev,MppListNode * next)116*437bfbebSnyanmisaka static inline void _mpp_list_del(MppListNode *prev, MppListNode *next)
117*437bfbebSnyanmisaka {
118*437bfbebSnyanmisaka next->prev = prev;
119*437bfbebSnyanmisaka prev->next = next;
120*437bfbebSnyanmisaka }
121*437bfbebSnyanmisaka
mpp_list_del_init(MppListNode * node)122*437bfbebSnyanmisaka static inline void mpp_list_del_init(MppListNode *node)
123*437bfbebSnyanmisaka {
124*437bfbebSnyanmisaka _mpp_list_del(node->prev, node->next);
125*437bfbebSnyanmisaka list_node_init(node);
126*437bfbebSnyanmisaka }
127*437bfbebSnyanmisaka
_list_del_node_no_lock(MppListNode * node,void * data,rk_s32 size)128*437bfbebSnyanmisaka static inline void _list_del_node_no_lock(MppListNode *node, void *data, rk_s32 size)
129*437bfbebSnyanmisaka {
130*437bfbebSnyanmisaka mpp_list_del_init(node);
131*437bfbebSnyanmisaka release_list(node, data, size);
132*437bfbebSnyanmisaka }
133*437bfbebSnyanmisaka
mpp_list_del_at_head(MppList * list,void * data,int size)134*437bfbebSnyanmisaka int mpp_list_del_at_head(MppList *list, void *data, int size)
135*437bfbebSnyanmisaka {
136*437bfbebSnyanmisaka rk_s32 ret = -EINVAL;
137*437bfbebSnyanmisaka
138*437bfbebSnyanmisaka if (list->head && list->count) {
139*437bfbebSnyanmisaka _list_del_node_no_lock(list->head->next, data, size);
140*437bfbebSnyanmisaka list->count--;
141*437bfbebSnyanmisaka ret = 0;
142*437bfbebSnyanmisaka }
143*437bfbebSnyanmisaka return ret;
144*437bfbebSnyanmisaka }
145*437bfbebSnyanmisaka
mpp_list_del_at_tail(MppList * list,void * data,int size)146*437bfbebSnyanmisaka int mpp_list_del_at_tail(MppList *list, void *data, int size)
147*437bfbebSnyanmisaka {
148*437bfbebSnyanmisaka rk_s32 ret = -EINVAL;
149*437bfbebSnyanmisaka
150*437bfbebSnyanmisaka if (list->head && list->count) {
151*437bfbebSnyanmisaka _list_del_node_no_lock(list->head->prev, data, size);
152*437bfbebSnyanmisaka list->count--;
153*437bfbebSnyanmisaka ret = 0;
154*437bfbebSnyanmisaka }
155*437bfbebSnyanmisaka return ret;
156*437bfbebSnyanmisaka }
create_list_with_size(void * data,rk_s32 size,rk_u32 key)157*437bfbebSnyanmisaka static MppListNode* create_list_with_size(void *data, rk_s32 size, rk_u32 key)
158*437bfbebSnyanmisaka {
159*437bfbebSnyanmisaka MppListNode *node = mpp_malloc_size(MppListNode, sizeof(MppListNode) + sizeof(size) + size);
160*437bfbebSnyanmisaka
161*437bfbebSnyanmisaka if (node) {
162*437bfbebSnyanmisaka rk_s32 *dst = (rk_s32 *)(node + 1);
163*437bfbebSnyanmisaka list_node_init_with_key_and_size(node, key, size);
164*437bfbebSnyanmisaka *dst++ = size;
165*437bfbebSnyanmisaka memcpy(dst, data, size);
166*437bfbebSnyanmisaka } else {
167*437bfbebSnyanmisaka LIST_ERROR("failed to allocate list node");
168*437bfbebSnyanmisaka }
169*437bfbebSnyanmisaka return node;
170*437bfbebSnyanmisaka }
171*437bfbebSnyanmisaka
mpp_list_fifo_wr(MppList * list,void * data,rk_s32 size)172*437bfbebSnyanmisaka rk_s32 mpp_list_fifo_wr(MppList *list, void *data, rk_s32 size)
173*437bfbebSnyanmisaka {
174*437bfbebSnyanmisaka rk_s32 ret = -EINVAL;
175*437bfbebSnyanmisaka
176*437bfbebSnyanmisaka if (list && list->head) {
177*437bfbebSnyanmisaka MppListNode *node = create_list_with_size(data, size, 0);
178*437bfbebSnyanmisaka
179*437bfbebSnyanmisaka if (node) {
180*437bfbebSnyanmisaka mpp_list_add_tail(node, list->head);
181*437bfbebSnyanmisaka list->count++;
182*437bfbebSnyanmisaka ret = 0;
183*437bfbebSnyanmisaka } else {
184*437bfbebSnyanmisaka ret = -ENOMEM;
185*437bfbebSnyanmisaka }
186*437bfbebSnyanmisaka }
187*437bfbebSnyanmisaka return ret;
188*437bfbebSnyanmisaka }
189*437bfbebSnyanmisaka
release_list_with_size(MppListNode * node,void * data,rk_s32 * size)190*437bfbebSnyanmisaka static void release_list_with_size(MppListNode* node, void *data, rk_s32 *size)
191*437bfbebSnyanmisaka {
192*437bfbebSnyanmisaka rk_s32 *src = (rk_s32*)(node + 1);
193*437bfbebSnyanmisaka rk_s32 data_size = *src++;
194*437bfbebSnyanmisaka
195*437bfbebSnyanmisaka *size = data_size;
196*437bfbebSnyanmisaka
197*437bfbebSnyanmisaka if (data)
198*437bfbebSnyanmisaka memcpy(data, src, data_size);
199*437bfbebSnyanmisaka
200*437bfbebSnyanmisaka mpp_free(node);
201*437bfbebSnyanmisaka }
202*437bfbebSnyanmisaka
mpp_list_fifo_rd(MppList * list,void * data,rk_s32 * size)203*437bfbebSnyanmisaka rk_s32 mpp_list_fifo_rd(MppList *list, void *data, rk_s32 *size)
204*437bfbebSnyanmisaka {
205*437bfbebSnyanmisaka rk_s32 ret = -EINVAL;
206*437bfbebSnyanmisaka
207*437bfbebSnyanmisaka if (list && list->head && list->count) {
208*437bfbebSnyanmisaka MppListNode *node = list->head->next;
209*437bfbebSnyanmisaka
210*437bfbebSnyanmisaka mpp_list_del_init(node);
211*437bfbebSnyanmisaka release_list_with_size(node, data, size);
212*437bfbebSnyanmisaka list->count--;
213*437bfbebSnyanmisaka ret = 0;
214*437bfbebSnyanmisaka }
215*437bfbebSnyanmisaka return ret;
216*437bfbebSnyanmisaka }
217*437bfbebSnyanmisaka
mpp_list_is_empty(MppList * list)218*437bfbebSnyanmisaka int mpp_list_is_empty(MppList *list)
219*437bfbebSnyanmisaka {
220*437bfbebSnyanmisaka return list->count == 0;
221*437bfbebSnyanmisaka }
222*437bfbebSnyanmisaka
mpp_list_size(MppList * list)223*437bfbebSnyanmisaka int mpp_list_size(MppList *list)
224*437bfbebSnyanmisaka {
225*437bfbebSnyanmisaka return list->count;
226*437bfbebSnyanmisaka }
227*437bfbebSnyanmisaka
mpp_list_add_by_key(MppList * list,void * data,rk_s32 size,rk_u32 * key)228*437bfbebSnyanmisaka rk_s32 mpp_list_add_by_key(MppList *list, void *data, rk_s32 size, rk_u32 *key)
229*437bfbebSnyanmisaka {
230*437bfbebSnyanmisaka rk_s32 ret = 0;
231*437bfbebSnyanmisaka
232*437bfbebSnyanmisaka if (list->head) {
233*437bfbebSnyanmisaka MppListNode *node;
234*437bfbebSnyanmisaka rk_u32 list_key = mpp_list_get_key(list);
235*437bfbebSnyanmisaka
236*437bfbebSnyanmisaka *key = list_key;
237*437bfbebSnyanmisaka node = create_list(data, size, list_key);
238*437bfbebSnyanmisaka if (node) {
239*437bfbebSnyanmisaka mpp_list_add_tail(node, list->head);
240*437bfbebSnyanmisaka list->count++;
241*437bfbebSnyanmisaka ret = 0;
242*437bfbebSnyanmisaka } else {
243*437bfbebSnyanmisaka ret = -ENOMEM;
244*437bfbebSnyanmisaka }
245*437bfbebSnyanmisaka }
246*437bfbebSnyanmisaka return ret;
247*437bfbebSnyanmisaka }
248*437bfbebSnyanmisaka
mpp_list_del_by_key(MppList * list,void * data,rk_s32 size,rk_u32 key)249*437bfbebSnyanmisaka rk_s32 mpp_list_del_by_key(MppList *list, void *data, rk_s32 size, rk_u32 key)
250*437bfbebSnyanmisaka {
251*437bfbebSnyanmisaka rk_s32 ret = 0;
252*437bfbebSnyanmisaka
253*437bfbebSnyanmisaka if (list && list->head && list->count) {
254*437bfbebSnyanmisaka MppListNode *tmp = list->head->next;
255*437bfbebSnyanmisaka
256*437bfbebSnyanmisaka ret = -EINVAL;
257*437bfbebSnyanmisaka while (tmp->next != list->head) {
258*437bfbebSnyanmisaka if (tmp->key == key) {
259*437bfbebSnyanmisaka _list_del_node_no_lock(tmp, data, size);
260*437bfbebSnyanmisaka list->count--;
261*437bfbebSnyanmisaka break;
262*437bfbebSnyanmisaka }
263*437bfbebSnyanmisaka tmp = tmp->next;
264*437bfbebSnyanmisaka }
265*437bfbebSnyanmisaka }
266*437bfbebSnyanmisaka return ret;
267*437bfbebSnyanmisaka }
268*437bfbebSnyanmisaka
269*437bfbebSnyanmisaka
mpp_list_show_by_key(MppList * list,void * data,rk_u32 key)270*437bfbebSnyanmisaka rk_s32 mpp_list_show_by_key(MppList *list, void *data, rk_u32 key)
271*437bfbebSnyanmisaka {
272*437bfbebSnyanmisaka rk_s32 ret = -EINVAL;
273*437bfbebSnyanmisaka
274*437bfbebSnyanmisaka (void)list;
275*437bfbebSnyanmisaka (void)data;
276*437bfbebSnyanmisaka (void)key;
277*437bfbebSnyanmisaka return ret;
278*437bfbebSnyanmisaka }
279*437bfbebSnyanmisaka
mpp_list_flush(MppList * list)280*437bfbebSnyanmisaka void mpp_list_flush(MppList* list)
281*437bfbebSnyanmisaka {
282*437bfbebSnyanmisaka if (list->head) {
283*437bfbebSnyanmisaka while (list->count) {
284*437bfbebSnyanmisaka MppListNode* node = list->head->next;
285*437bfbebSnyanmisaka
286*437bfbebSnyanmisaka mpp_list_del_init(node);
287*437bfbebSnyanmisaka
288*437bfbebSnyanmisaka if (list->destroy) {
289*437bfbebSnyanmisaka list->destroy((void*)(node + 1));
290*437bfbebSnyanmisaka }
291*437bfbebSnyanmisaka
292*437bfbebSnyanmisaka mpp_free(node);
293*437bfbebSnyanmisaka list->count--;
294*437bfbebSnyanmisaka }
295*437bfbebSnyanmisaka }
296*437bfbebSnyanmisaka
297*437bfbebSnyanmisaka mpp_list_signal(list);
298*437bfbebSnyanmisaka }
299*437bfbebSnyanmisaka
mpp_list_wait(MppList * list)300*437bfbebSnyanmisaka MPP_RET mpp_list_wait(MppList* list)
301*437bfbebSnyanmisaka {
302*437bfbebSnyanmisaka int ret;
303*437bfbebSnyanmisaka
304*437bfbebSnyanmisaka ret = mpp_mutex_cond_wait(&list->cond_lock);
305*437bfbebSnyanmisaka
306*437bfbebSnyanmisaka if (ret == 0) {
307*437bfbebSnyanmisaka return MPP_OK;
308*437bfbebSnyanmisaka } else if (ret == ETIMEDOUT) {
309*437bfbebSnyanmisaka return MPP_NOK;
310*437bfbebSnyanmisaka } else {
311*437bfbebSnyanmisaka return MPP_NOK;
312*437bfbebSnyanmisaka }
313*437bfbebSnyanmisaka }
314*437bfbebSnyanmisaka
mpp_list_wait_timed(MppList * list,rk_s64 timeout)315*437bfbebSnyanmisaka MPP_RET mpp_list_wait_timed(MppList *list, rk_s64 timeout)
316*437bfbebSnyanmisaka {
317*437bfbebSnyanmisaka int ret;
318*437bfbebSnyanmisaka
319*437bfbebSnyanmisaka ret = (MPP_RET)mpp_mutex_cond_timedwait(&list->cond_lock, timeout);
320*437bfbebSnyanmisaka
321*437bfbebSnyanmisaka if (ret == 0) {
322*437bfbebSnyanmisaka return MPP_OK;
323*437bfbebSnyanmisaka } else if (ret == ETIMEDOUT) {
324*437bfbebSnyanmisaka return MPP_NOK;
325*437bfbebSnyanmisaka } else {
326*437bfbebSnyanmisaka return MPP_NOK;
327*437bfbebSnyanmisaka }
328*437bfbebSnyanmisaka }
329*437bfbebSnyanmisaka
mpp_list_wait_lt(MppList * list,rk_s64 timeout,rk_s32 val)330*437bfbebSnyanmisaka MPP_RET mpp_list_wait_lt(MppList *list, rk_s64 timeout, rk_s32 val)
331*437bfbebSnyanmisaka {
332*437bfbebSnyanmisaka if (list->count < val)
333*437bfbebSnyanmisaka return MPP_OK;
334*437bfbebSnyanmisaka
335*437bfbebSnyanmisaka if (timeout < 0) {
336*437bfbebSnyanmisaka return mpp_list_wait(list);
337*437bfbebSnyanmisaka } else {
338*437bfbebSnyanmisaka return mpp_list_wait_timed(list, timeout);
339*437bfbebSnyanmisaka }
340*437bfbebSnyanmisaka }
341*437bfbebSnyanmisaka
mpp_list_wait_le(MppList * list,rk_s64 timeout,rk_s32 val)342*437bfbebSnyanmisaka MPP_RET mpp_list_wait_le(MppList *list, rk_s64 timeout, rk_s32 val)
343*437bfbebSnyanmisaka {
344*437bfbebSnyanmisaka if (list->count <= val)
345*437bfbebSnyanmisaka return MPP_OK;
346*437bfbebSnyanmisaka
347*437bfbebSnyanmisaka if (timeout < 0) {
348*437bfbebSnyanmisaka return mpp_list_wait(list);
349*437bfbebSnyanmisaka } else {
350*437bfbebSnyanmisaka return mpp_list_wait_timed(list, timeout);
351*437bfbebSnyanmisaka }
352*437bfbebSnyanmisaka }
353*437bfbebSnyanmisaka
mpp_list_wait_gt(MppList * list,rk_s64 timeout,rk_s32 val)354*437bfbebSnyanmisaka MPP_RET mpp_list_wait_gt(MppList *list, rk_s64 timeout, rk_s32 val)
355*437bfbebSnyanmisaka {
356*437bfbebSnyanmisaka if (list->count > val)
357*437bfbebSnyanmisaka return MPP_OK;
358*437bfbebSnyanmisaka
359*437bfbebSnyanmisaka if (timeout < 0) {
360*437bfbebSnyanmisaka return mpp_list_wait(list);
361*437bfbebSnyanmisaka } else {
362*437bfbebSnyanmisaka return mpp_list_wait_timed(list, timeout);
363*437bfbebSnyanmisaka }
364*437bfbebSnyanmisaka }
365*437bfbebSnyanmisaka
mpp_list_wait_ge(MppList * list,rk_s64 timeout,rk_s32 val)366*437bfbebSnyanmisaka MPP_RET mpp_list_wait_ge(MppList *list, rk_s64 timeout, rk_s32 val)
367*437bfbebSnyanmisaka {
368*437bfbebSnyanmisaka if (list->count >= val)
369*437bfbebSnyanmisaka return MPP_OK;
370*437bfbebSnyanmisaka
371*437bfbebSnyanmisaka if (timeout < 0) {
372*437bfbebSnyanmisaka return mpp_list_wait(list);
373*437bfbebSnyanmisaka } else {
374*437bfbebSnyanmisaka return mpp_list_wait_timed(list, timeout);
375*437bfbebSnyanmisaka }
376*437bfbebSnyanmisaka }
377*437bfbebSnyanmisaka
mpp_list_signal(MppList * list)378*437bfbebSnyanmisaka void mpp_list_signal(MppList *list)
379*437bfbebSnyanmisaka {
380*437bfbebSnyanmisaka mpp_mutex_cond_signal(&list->cond_lock);
381*437bfbebSnyanmisaka }
382*437bfbebSnyanmisaka
mpp_list_get_key(MppList * list)383*437bfbebSnyanmisaka rk_u32 mpp_list_get_key(MppList *list)
384*437bfbebSnyanmisaka {
385*437bfbebSnyanmisaka return list->keys++;
386*437bfbebSnyanmisaka }
387*437bfbebSnyanmisaka
mpp_list_create(node_destructor func)388*437bfbebSnyanmisaka MppList *mpp_list_create(node_destructor func)
389*437bfbebSnyanmisaka {
390*437bfbebSnyanmisaka MppList *list = mpp_malloc(MppList, 1);
391*437bfbebSnyanmisaka
392*437bfbebSnyanmisaka if (list == NULL) {
393*437bfbebSnyanmisaka LIST_ERROR("Failed to allocate memory for mpp_list.\n");
394*437bfbebSnyanmisaka return NULL;
395*437bfbebSnyanmisaka }
396*437bfbebSnyanmisaka
397*437bfbebSnyanmisaka list->destroy = func;
398*437bfbebSnyanmisaka list->count = 0;
399*437bfbebSnyanmisaka
400*437bfbebSnyanmisaka list->head = mpp_malloc(MppListNode, 1);
401*437bfbebSnyanmisaka if (list->head == NULL) {
402*437bfbebSnyanmisaka LIST_ERROR("Failed to allocate memory for list header.\n");
403*437bfbebSnyanmisaka mpp_free(list);
404*437bfbebSnyanmisaka return NULL;
405*437bfbebSnyanmisaka }
406*437bfbebSnyanmisaka
407*437bfbebSnyanmisaka list_node_init_with_key_and_size(list->head, 0, 0);
408*437bfbebSnyanmisaka
409*437bfbebSnyanmisaka mpp_mutex_cond_init(&list->cond_lock);
410*437bfbebSnyanmisaka
411*437bfbebSnyanmisaka return list;
412*437bfbebSnyanmisaka }
413*437bfbebSnyanmisaka
mpp_list_destroy(MppList * list)414*437bfbebSnyanmisaka void mpp_list_destroy(MppList *list)
415*437bfbebSnyanmisaka {
416*437bfbebSnyanmisaka MppListNode *node;
417*437bfbebSnyanmisaka
418*437bfbebSnyanmisaka if (!list)
419*437bfbebSnyanmisaka return;
420*437bfbebSnyanmisaka
421*437bfbebSnyanmisaka mpp_list_flush(list);
422*437bfbebSnyanmisaka
423*437bfbebSnyanmisaka node = list->head->next;
424*437bfbebSnyanmisaka while (node != list->head) {
425*437bfbebSnyanmisaka MppListNode *next = node->next;
426*437bfbebSnyanmisaka
427*437bfbebSnyanmisaka mpp_free(node);
428*437bfbebSnyanmisaka node = next;
429*437bfbebSnyanmisaka }
430*437bfbebSnyanmisaka
431*437bfbebSnyanmisaka mpp_mutex_cond_destroy(&list->cond_lock);
432*437bfbebSnyanmisaka
433*437bfbebSnyanmisaka mpp_free(list->head);
434*437bfbebSnyanmisaka list->head = NULL;
435*437bfbebSnyanmisaka
436*437bfbebSnyanmisaka mpp_free(list);
437*437bfbebSnyanmisaka list = NULL;
438*437bfbebSnyanmisaka }
439*437bfbebSnyanmisaka
440*437bfbebSnyanmisaka /* list sort porting from kernel list_sort.c */
441*437bfbebSnyanmisaka
442*437bfbebSnyanmisaka /*
443*437bfbebSnyanmisaka * Returns a list organized in an intermediate format suited
444*437bfbebSnyanmisaka * to chaining of merge() calls: null-terminated, no reserved or
445*437bfbebSnyanmisaka * sentinel head node, "prev" links not maintained.
446*437bfbebSnyanmisaka */
merge(void * priv,ListCmpFunc cmp,struct list_head * a,struct list_head * b)447*437bfbebSnyanmisaka static struct list_head *merge(void *priv, ListCmpFunc cmp,
448*437bfbebSnyanmisaka struct list_head *a, struct list_head *b)
449*437bfbebSnyanmisaka {
450*437bfbebSnyanmisaka struct list_head *head, **tail = &head;
451*437bfbebSnyanmisaka
452*437bfbebSnyanmisaka for (;;) {
453*437bfbebSnyanmisaka /* if equal, take 'a' -- important for sort stability */
454*437bfbebSnyanmisaka if (cmp(priv, a, b) <= 0) {
455*437bfbebSnyanmisaka *tail = a;
456*437bfbebSnyanmisaka tail = &a->next;
457*437bfbebSnyanmisaka a = a->next;
458*437bfbebSnyanmisaka if (!a) {
459*437bfbebSnyanmisaka *tail = b;
460*437bfbebSnyanmisaka break;
461*437bfbebSnyanmisaka }
462*437bfbebSnyanmisaka } else {
463*437bfbebSnyanmisaka *tail = b;
464*437bfbebSnyanmisaka tail = &b->next;
465*437bfbebSnyanmisaka b = b->next;
466*437bfbebSnyanmisaka if (!b) {
467*437bfbebSnyanmisaka *tail = a;
468*437bfbebSnyanmisaka break;
469*437bfbebSnyanmisaka }
470*437bfbebSnyanmisaka }
471*437bfbebSnyanmisaka }
472*437bfbebSnyanmisaka return head;
473*437bfbebSnyanmisaka }
474*437bfbebSnyanmisaka
475*437bfbebSnyanmisaka /*
476*437bfbebSnyanmisaka * Combine final list merge with restoration of standard doubly-linked
477*437bfbebSnyanmisaka * list structure. This approach duplicates code from merge(), but
478*437bfbebSnyanmisaka * runs faster than the tidier alternatives of either a separate final
479*437bfbebSnyanmisaka * prev-link restoration pass, or maintaining the prev links
480*437bfbebSnyanmisaka * throughout.
481*437bfbebSnyanmisaka */
merge_final(void * priv,ListCmpFunc cmp,struct list_head * head,struct list_head * a,struct list_head * b)482*437bfbebSnyanmisaka static void merge_final(void *priv, ListCmpFunc cmp, struct list_head *head,
483*437bfbebSnyanmisaka struct list_head *a, struct list_head *b)
484*437bfbebSnyanmisaka {
485*437bfbebSnyanmisaka struct list_head *tail = head;
486*437bfbebSnyanmisaka rk_u8 count = 0;
487*437bfbebSnyanmisaka
488*437bfbebSnyanmisaka for (;;) {
489*437bfbebSnyanmisaka /* if equal, take 'a' -- important for sort stability */
490*437bfbebSnyanmisaka if (cmp(priv, a, b) <= 0) {
491*437bfbebSnyanmisaka tail->next = a;
492*437bfbebSnyanmisaka a->prev = tail;
493*437bfbebSnyanmisaka tail = a;
494*437bfbebSnyanmisaka a = a->next;
495*437bfbebSnyanmisaka if (!a)
496*437bfbebSnyanmisaka break;
497*437bfbebSnyanmisaka } else {
498*437bfbebSnyanmisaka tail->next = b;
499*437bfbebSnyanmisaka b->prev = tail;
500*437bfbebSnyanmisaka tail = b;
501*437bfbebSnyanmisaka b = b->next;
502*437bfbebSnyanmisaka if (!b) {
503*437bfbebSnyanmisaka b = a;
504*437bfbebSnyanmisaka break;
505*437bfbebSnyanmisaka }
506*437bfbebSnyanmisaka }
507*437bfbebSnyanmisaka }
508*437bfbebSnyanmisaka
509*437bfbebSnyanmisaka /* Finish linking remainder of list b on to tail */
510*437bfbebSnyanmisaka tail->next = b;
511*437bfbebSnyanmisaka do {
512*437bfbebSnyanmisaka /*
513*437bfbebSnyanmisaka * If the merge is highly unbalanced (e.g. the input is
514*437bfbebSnyanmisaka * already sorted), this loop may run many iterations.
515*437bfbebSnyanmisaka * Continue callbacks to the client even though no
516*437bfbebSnyanmisaka * element comparison is needed, so the client's cmp()
517*437bfbebSnyanmisaka * routine can invoke cond_resched() periodically.
518*437bfbebSnyanmisaka */
519*437bfbebSnyanmisaka if (!++count)
520*437bfbebSnyanmisaka cmp(priv, b, b);
521*437bfbebSnyanmisaka b->prev = tail;
522*437bfbebSnyanmisaka tail = b;
523*437bfbebSnyanmisaka b = b->next;
524*437bfbebSnyanmisaka } while (b);
525*437bfbebSnyanmisaka
526*437bfbebSnyanmisaka /* And the final links to make a circular doubly-linked list */
527*437bfbebSnyanmisaka tail->next = head;
528*437bfbebSnyanmisaka head->prev = tail;
529*437bfbebSnyanmisaka }
530*437bfbebSnyanmisaka
list_sort(void * priv,struct list_head * head,ListCmpFunc cmp)531*437bfbebSnyanmisaka void list_sort(void *priv, struct list_head *head, ListCmpFunc cmp)
532*437bfbebSnyanmisaka {
533*437bfbebSnyanmisaka struct list_head *list = head->next, *pending = NULL;
534*437bfbebSnyanmisaka size_t count = 0; /* Count of pending */
535*437bfbebSnyanmisaka
536*437bfbebSnyanmisaka if (list == head->prev) /* Zero or one elements */
537*437bfbebSnyanmisaka return;
538*437bfbebSnyanmisaka
539*437bfbebSnyanmisaka /* Convert to a null-terminated singly-linked list. */
540*437bfbebSnyanmisaka head->prev->next = NULL;
541*437bfbebSnyanmisaka
542*437bfbebSnyanmisaka /*
543*437bfbebSnyanmisaka * Data structure invariants:
544*437bfbebSnyanmisaka * - All lists are singly linked and null-terminated; prev
545*437bfbebSnyanmisaka * pointers are not maintained.
546*437bfbebSnyanmisaka * - pending is a prev-linked "list of lists" of sorted
547*437bfbebSnyanmisaka * sublists awaiting further merging.
548*437bfbebSnyanmisaka * - Each of the sorted sublists is power-of-two in size.
549*437bfbebSnyanmisaka * - Sublists are sorted by size and age, smallest & newest at front.
550*437bfbebSnyanmisaka * - There are zero to two sublists of each size.
551*437bfbebSnyanmisaka * - A pair of pending sublists are merged as soon as the number
552*437bfbebSnyanmisaka * of following pending elements equals their size (i.e.
553*437bfbebSnyanmisaka * each time count reaches an odd multiple of that size).
554*437bfbebSnyanmisaka * That ensures each later final merge will be at worst 2:1.
555*437bfbebSnyanmisaka * - Each round consists of:
556*437bfbebSnyanmisaka * - Merging the two sublists selected by the highest bit
557*437bfbebSnyanmisaka * which flips when count is incremented, and
558*437bfbebSnyanmisaka * - Adding an element from the input as a size-1 sublist.
559*437bfbebSnyanmisaka */
560*437bfbebSnyanmisaka do {
561*437bfbebSnyanmisaka size_t bits;
562*437bfbebSnyanmisaka struct list_head **tail = &pending;
563*437bfbebSnyanmisaka
564*437bfbebSnyanmisaka /* Find the least-significant clear bit in count */
565*437bfbebSnyanmisaka for (bits = count; bits & 1; bits >>= 1)
566*437bfbebSnyanmisaka tail = &(*tail)->prev;
567*437bfbebSnyanmisaka /* Do the indicated merge */
568*437bfbebSnyanmisaka if (bits) {
569*437bfbebSnyanmisaka struct list_head *a = *tail, *b = a->prev;
570*437bfbebSnyanmisaka
571*437bfbebSnyanmisaka a = merge(priv, cmp, b, a);
572*437bfbebSnyanmisaka /* Install the merged result in place of the inputs */
573*437bfbebSnyanmisaka a->prev = b->prev;
574*437bfbebSnyanmisaka *tail = a;
575*437bfbebSnyanmisaka }
576*437bfbebSnyanmisaka
577*437bfbebSnyanmisaka /* Move one element from input list to pending */
578*437bfbebSnyanmisaka list->prev = pending;
579*437bfbebSnyanmisaka pending = list;
580*437bfbebSnyanmisaka list = list->next;
581*437bfbebSnyanmisaka pending->next = NULL;
582*437bfbebSnyanmisaka count++;
583*437bfbebSnyanmisaka } while (list);
584*437bfbebSnyanmisaka
585*437bfbebSnyanmisaka /* End of input; merge together all the pending lists. */
586*437bfbebSnyanmisaka list = pending;
587*437bfbebSnyanmisaka pending = pending->prev;
588*437bfbebSnyanmisaka for (;;) {
589*437bfbebSnyanmisaka struct list_head *next = pending->prev;
590*437bfbebSnyanmisaka
591*437bfbebSnyanmisaka if (!next)
592*437bfbebSnyanmisaka break;
593*437bfbebSnyanmisaka list = merge(priv, cmp, pending, list);
594*437bfbebSnyanmisaka pending = next;
595*437bfbebSnyanmisaka }
596*437bfbebSnyanmisaka /* The final merge, rebuilding prev links */
597*437bfbebSnyanmisaka merge_final(priv, cmp, head, pending, list);
598*437bfbebSnyanmisaka }
599