xref: /rockchip-linux_mpp/osal/mpp_list.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
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