1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright 2015 Rockchip Electronics Co. LTD
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Licensed under the Apache License, Version 2.0 (the "License");
5*4882a593Smuzhiyun * you may not use this file except in compliance with the License.
6*4882a593Smuzhiyun * You may obtain a copy of the License at
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * http://www.apache.org/licenses/LICENSE-2.0
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * Unless required by applicable law or agreed to in writing, software
11*4882a593Smuzhiyun * distributed under the License is distributed on an "AS IS" BASIS,
12*4882a593Smuzhiyun * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4882a593Smuzhiyun * See the License for the specific language governing permissions and
14*4882a593Smuzhiyun * limitations under the License.
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #define MODULE_TAG "mpp_list"
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include <stdlib.h>
20*4882a593Smuzhiyun #include <string.h>
21*4882a593Smuzhiyun #include <stdarg.h>
22*4882a593Smuzhiyun #include <errno.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #include "mpp_log.h"
25*4882a593Smuzhiyun #include "mpp_list.h"
26*4882a593Smuzhiyun #include "mpp_common.h"
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define LIST_DEBUG(fmt, ...) mpp_log(fmt, ## __VA_ARGS__)
30*4882a593Smuzhiyun #define LIST_ERROR(fmt, ...) mpp_err(fmt, ## __VA_ARGS__)
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun RK_U32 mpp_list::keys = 0;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun typedef struct mpp_list_node {
35*4882a593Smuzhiyun mpp_list_node* prev;
36*4882a593Smuzhiyun mpp_list_node* next;
37*4882a593Smuzhiyun RK_U32 key;
38*4882a593Smuzhiyun RK_S32 size;
39*4882a593Smuzhiyun } mpp_list_node;
40*4882a593Smuzhiyun
list_node_init(mpp_list_node * node)41*4882a593Smuzhiyun static inline void list_node_init(mpp_list_node *node)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun node->prev = node->next = node;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
list_node_init_with_key_and_size(mpp_list_node * node,RK_U32 key,RK_S32 size)46*4882a593Smuzhiyun static inline void list_node_init_with_key_and_size(mpp_list_node *node, RK_U32 key, RK_S32 size)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun list_node_init(node);
49*4882a593Smuzhiyun node->key = key;
50*4882a593Smuzhiyun node->size = size;
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun
create_list(void * data,RK_S32 size,RK_U32 key)53*4882a593Smuzhiyun static mpp_list_node* create_list(void *data, RK_S32 size, RK_U32 key)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun mpp_list_node *node = (mpp_list_node*)malloc(sizeof(mpp_list_node) + size);
56*4882a593Smuzhiyun if (node) {
57*4882a593Smuzhiyun void *dst = (void*)(node + 1);
58*4882a593Smuzhiyun list_node_init_with_key_and_size(node, key, size);
59*4882a593Smuzhiyun memcpy(dst, data, size);
60*4882a593Smuzhiyun } else {
61*4882a593Smuzhiyun LIST_ERROR("failed to allocate list node");
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun return node;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
_mpp_list_add(mpp_list_node * _new,mpp_list_node * prev,mpp_list_node * next)66*4882a593Smuzhiyun static inline void _mpp_list_add(mpp_list_node * _new, mpp_list_node * prev, mpp_list_node * next)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun next->prev = _new;
69*4882a593Smuzhiyun _new->next = next;
70*4882a593Smuzhiyun _new->prev = prev;
71*4882a593Smuzhiyun prev->next = _new;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
mpp_list_add(mpp_list_node * _new,mpp_list_node * head)74*4882a593Smuzhiyun static inline void mpp_list_add(mpp_list_node *_new, mpp_list_node *head)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun _mpp_list_add(_new, head, head->next);
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
mpp_list_add_tail(mpp_list_node * _new,mpp_list_node * head)79*4882a593Smuzhiyun static inline void mpp_list_add_tail(mpp_list_node *_new, mpp_list_node *head)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun _mpp_list_add(_new, head->prev, head);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
add_at_head(void * data,RK_S32 size)84*4882a593Smuzhiyun RK_S32 mpp_list::add_at_head(void *data, RK_S32 size)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun RK_S32 ret = -EINVAL;
87*4882a593Smuzhiyun if (head) {
88*4882a593Smuzhiyun mpp_list_node *node = create_list(data, size, 0);
89*4882a593Smuzhiyun if (node) {
90*4882a593Smuzhiyun mpp_list_add(node, head);
91*4882a593Smuzhiyun count++;
92*4882a593Smuzhiyun ret = 0;
93*4882a593Smuzhiyun } else {
94*4882a593Smuzhiyun ret = -ENOMEM;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun return ret;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun
add_at_tail(void * data,RK_S32 size)100*4882a593Smuzhiyun RK_S32 mpp_list::add_at_tail(void *data, RK_S32 size)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun RK_S32 ret = -EINVAL;
103*4882a593Smuzhiyun if (head) {
104*4882a593Smuzhiyun mpp_list_node *node = create_list(data, size, 0);
105*4882a593Smuzhiyun if (node) {
106*4882a593Smuzhiyun mpp_list_add_tail(node, head);
107*4882a593Smuzhiyun count++;
108*4882a593Smuzhiyun ret = 0;
109*4882a593Smuzhiyun } else {
110*4882a593Smuzhiyun ret = -ENOMEM;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun return ret;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
release_list(mpp_list_node * node,void * data,RK_S32 size)116*4882a593Smuzhiyun static void release_list(mpp_list_node*node, void *data, RK_S32 size)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun void *src = (void*)(node + 1);
119*4882a593Smuzhiyun if (node->size == size) {
120*4882a593Smuzhiyun if (data)
121*4882a593Smuzhiyun memcpy(data, src, size);
122*4882a593Smuzhiyun } else {
123*4882a593Smuzhiyun LIST_ERROR("node size check failed when release_list");
124*4882a593Smuzhiyun size = (size < node->size) ? (size) : (node->size);
125*4882a593Smuzhiyun if (data)
126*4882a593Smuzhiyun memcpy(data, src, size);
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun free(node);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
_mpp_list_del(mpp_list_node * prev,mpp_list_node * next)131*4882a593Smuzhiyun static inline void _mpp_list_del(mpp_list_node *prev, mpp_list_node *next)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun next->prev = prev;
134*4882a593Smuzhiyun prev->next = next;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
mpp_list_del_init(mpp_list_node * node)137*4882a593Smuzhiyun static inline void mpp_list_del_init(mpp_list_node *node)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun _mpp_list_del(node->prev, node->next);
140*4882a593Smuzhiyun list_node_init(node);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
_list_del_node_no_lock(mpp_list_node * node,void * data,RK_S32 size)143*4882a593Smuzhiyun static inline void _list_del_node_no_lock(mpp_list_node *node, void *data, RK_S32 size)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun mpp_list_del_init(node);
146*4882a593Smuzhiyun release_list(node, data, size);
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
del_at_head(void * data,RK_S32 size)149*4882a593Smuzhiyun RK_S32 mpp_list::del_at_head(void *data, RK_S32 size)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun RK_S32 ret = -EINVAL;
152*4882a593Smuzhiyun if (head && count) {
153*4882a593Smuzhiyun _list_del_node_no_lock(head->next, data, size);
154*4882a593Smuzhiyun count--;
155*4882a593Smuzhiyun ret = 0;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun return ret;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
del_at_tail(void * data,RK_S32 size)160*4882a593Smuzhiyun RK_S32 mpp_list::del_at_tail(void *data, RK_S32 size)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun RK_S32 ret = -EINVAL;
163*4882a593Smuzhiyun if (head && count) {
164*4882a593Smuzhiyun _list_del_node_no_lock(head->prev, data, size);
165*4882a593Smuzhiyun count--;
166*4882a593Smuzhiyun ret = 0;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun return ret;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
create_list_with_size(void * data,RK_S32 size,RK_U32 key)171*4882a593Smuzhiyun static mpp_list_node* create_list_with_size(void *data, RK_S32 size, RK_U32 key)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun mpp_list_node *node = (mpp_list_node*)malloc(sizeof(mpp_list_node) +
174*4882a593Smuzhiyun sizeof(size) + size);
175*4882a593Smuzhiyun if (node) {
176*4882a593Smuzhiyun RK_S32 *dst = (RK_S32 *)(node + 1);
177*4882a593Smuzhiyun list_node_init_with_key_and_size(node, key, size);
178*4882a593Smuzhiyun *dst++ = size;
179*4882a593Smuzhiyun memcpy(dst, data, size);
180*4882a593Smuzhiyun } else {
181*4882a593Smuzhiyun LIST_ERROR("failed to allocate list node");
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun return node;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
fifo_wr(void * data,RK_S32 size)186*4882a593Smuzhiyun RK_S32 mpp_list::fifo_wr(void *data, RK_S32 size)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun RK_S32 ret = -EINVAL;
189*4882a593Smuzhiyun if (head) {
190*4882a593Smuzhiyun mpp_list_node *node = create_list_with_size(data, size, 0);
191*4882a593Smuzhiyun if (node) {
192*4882a593Smuzhiyun mpp_list_add_tail(node, head);
193*4882a593Smuzhiyun count++;
194*4882a593Smuzhiyun ret = 0;
195*4882a593Smuzhiyun } else {
196*4882a593Smuzhiyun ret = -ENOMEM;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun return ret;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
release_list_with_size(mpp_list_node * node,void * data,RK_S32 * size)202*4882a593Smuzhiyun static void release_list_with_size(mpp_list_node* node, void *data, RK_S32 *size)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun RK_S32 *src = (RK_S32*)(node + 1);
205*4882a593Smuzhiyun RK_S32 data_size = *src++;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun *size = data_size;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun if (data)
210*4882a593Smuzhiyun memcpy(data, src, data_size);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun free(node);
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
fifo_rd(void * data,RK_S32 * size)215*4882a593Smuzhiyun RK_S32 mpp_list::fifo_rd(void *data, RK_S32 *size)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun RK_S32 ret = -EINVAL;
218*4882a593Smuzhiyun if (head && count) {
219*4882a593Smuzhiyun mpp_list_node *node = head->next;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun mpp_list_del_init(node);
222*4882a593Smuzhiyun release_list_with_size(node, data, size);
223*4882a593Smuzhiyun count--;
224*4882a593Smuzhiyun ret = 0;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun return ret;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
list_is_empty()229*4882a593Smuzhiyun RK_S32 mpp_list::list_is_empty()
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun RK_S32 ret = (count == 0);
232*4882a593Smuzhiyun return ret;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
list_size()235*4882a593Smuzhiyun RK_S32 mpp_list::list_size()
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun RK_S32 ret = count;
238*4882a593Smuzhiyun return ret;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
add_by_key(void * data,RK_S32 size,RK_U32 * key)241*4882a593Smuzhiyun RK_S32 mpp_list::add_by_key(void *data, RK_S32 size, RK_U32 *key)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun RK_S32 ret = 0;
244*4882a593Smuzhiyun if (head) {
245*4882a593Smuzhiyun RK_U32 list_key = get_key();
246*4882a593Smuzhiyun *key = list_key;
247*4882a593Smuzhiyun mpp_list_node *node = create_list(data, size, list_key);
248*4882a593Smuzhiyun if (node) {
249*4882a593Smuzhiyun mpp_list_add_tail(node, head);
250*4882a593Smuzhiyun count++;
251*4882a593Smuzhiyun ret = 0;
252*4882a593Smuzhiyun } else {
253*4882a593Smuzhiyun ret = -ENOMEM;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun return ret;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun
del_by_key(void * data,RK_S32 size,RK_U32 key)259*4882a593Smuzhiyun RK_S32 mpp_list::del_by_key(void *data, RK_S32 size, RK_U32 key)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun RK_S32 ret = 0;
262*4882a593Smuzhiyun if (head && count) {
263*4882a593Smuzhiyun struct mpp_list_node *tmp = head->next;
264*4882a593Smuzhiyun ret = -EINVAL;
265*4882a593Smuzhiyun while (tmp->next != head) {
266*4882a593Smuzhiyun if (tmp->key == key) {
267*4882a593Smuzhiyun _list_del_node_no_lock(tmp, data, size);
268*4882a593Smuzhiyun count--;
269*4882a593Smuzhiyun break;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun return ret;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun
show_by_key(void * data,RK_U32 key)277*4882a593Smuzhiyun RK_S32 mpp_list::show_by_key(void *data, RK_U32 key)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun RK_S32 ret = -EINVAL;
280*4882a593Smuzhiyun (void)data;
281*4882a593Smuzhiyun (void)key;
282*4882a593Smuzhiyun return ret;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
flush()285*4882a593Smuzhiyun RK_S32 mpp_list::flush()
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun if (head) {
288*4882a593Smuzhiyun while (count) {
289*4882a593Smuzhiyun mpp_list_node* node = head->next;
290*4882a593Smuzhiyun mpp_list_del_init(node);
291*4882a593Smuzhiyun if (destroy) {
292*4882a593Smuzhiyun destroy((void*)(node + 1));
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun free(node);
295*4882a593Smuzhiyun count--;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun signal();
299*4882a593Smuzhiyun return 0;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
wait_lt(RK_S64 timeout,RK_S32 val)302*4882a593Smuzhiyun MPP_RET mpp_list::wait_lt(RK_S64 timeout, RK_S32 val)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun if (list_size() < val)
305*4882a593Smuzhiyun return MPP_OK;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun if (!timeout)
308*4882a593Smuzhiyun return MPP_NOK;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun if (timeout < 0)
311*4882a593Smuzhiyun wait();
312*4882a593Smuzhiyun else
313*4882a593Smuzhiyun wait(timeout);
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun return list_size() < val ? MPP_OK : MPP_NOK;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
wait_le(RK_S64 timeout,RK_S32 val)318*4882a593Smuzhiyun MPP_RET mpp_list::wait_le(RK_S64 timeout, RK_S32 val)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun if (list_size() <= val)
321*4882a593Smuzhiyun return MPP_OK;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun if (!timeout)
324*4882a593Smuzhiyun return MPP_NOK;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun if (timeout < 0)
327*4882a593Smuzhiyun wait();
328*4882a593Smuzhiyun else
329*4882a593Smuzhiyun wait(timeout);
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun return list_size() <= val ? MPP_OK : MPP_NOK;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
wait_gt(RK_S64 timeout,RK_S32 val)334*4882a593Smuzhiyun MPP_RET mpp_list::wait_gt(RK_S64 timeout, RK_S32 val)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun if (list_size() > val)
337*4882a593Smuzhiyun return MPP_OK;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun if (!timeout)
340*4882a593Smuzhiyun return MPP_NOK;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun if (timeout < 0)
343*4882a593Smuzhiyun wait();
344*4882a593Smuzhiyun else
345*4882a593Smuzhiyun wait(timeout);
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun return list_size() > val ? MPP_OK : MPP_NOK;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
wait_ge(RK_S64 timeout,RK_S32 val)350*4882a593Smuzhiyun MPP_RET mpp_list::wait_ge(RK_S64 timeout, RK_S32 val)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun if (list_size() >= val)
353*4882a593Smuzhiyun return MPP_OK;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun if (!timeout)
356*4882a593Smuzhiyun return MPP_NOK;
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun if (timeout < 0)
359*4882a593Smuzhiyun wait();
360*4882a593Smuzhiyun else
361*4882a593Smuzhiyun wait(timeout);
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun return list_size() >= val ? MPP_OK : MPP_NOK;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
get_key()366*4882a593Smuzhiyun RK_U32 mpp_list::get_key()
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun return keys++;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
mpp_list(node_destructor func)371*4882a593Smuzhiyun mpp_list::mpp_list(node_destructor func)
372*4882a593Smuzhiyun : destroy(NULL),
373*4882a593Smuzhiyun head(NULL),
374*4882a593Smuzhiyun count(0)
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun destroy = func;
377*4882a593Smuzhiyun head = (mpp_list_node*)malloc(sizeof(mpp_list_node));
378*4882a593Smuzhiyun if (NULL == head) {
379*4882a593Smuzhiyun LIST_ERROR("failed to allocate list header");
380*4882a593Smuzhiyun } else {
381*4882a593Smuzhiyun list_node_init_with_key_and_size(head, 0, 0);
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
~mpp_list()385*4882a593Smuzhiyun mpp_list::~mpp_list()
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun flush();
388*4882a593Smuzhiyun if (head) free(head);
389*4882a593Smuzhiyun head = NULL;
390*4882a593Smuzhiyun destroy = NULL;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun /* list sort porting from kernel list_sort.c */
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun /*
396*4882a593Smuzhiyun * Returns a list organized in an intermediate format suited
397*4882a593Smuzhiyun * to chaining of merge() calls: null-terminated, no reserved or
398*4882a593Smuzhiyun * sentinel head node, "prev" links not maintained.
399*4882a593Smuzhiyun */
merge(void * priv,list_cmp_func_t cmp,struct list_head * a,struct list_head * b)400*4882a593Smuzhiyun static struct list_head *merge(void *priv, list_cmp_func_t cmp,
401*4882a593Smuzhiyun struct list_head *a, struct list_head *b)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun struct list_head *head, **tail = &head;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun for (;;) {
406*4882a593Smuzhiyun /* if equal, take 'a' -- important for sort stability */
407*4882a593Smuzhiyun if (cmp(priv, a, b) <= 0) {
408*4882a593Smuzhiyun *tail = a;
409*4882a593Smuzhiyun tail = &a->next;
410*4882a593Smuzhiyun a = a->next;
411*4882a593Smuzhiyun if (!a) {
412*4882a593Smuzhiyun *tail = b;
413*4882a593Smuzhiyun break;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun } else {
416*4882a593Smuzhiyun *tail = b;
417*4882a593Smuzhiyun tail = &b->next;
418*4882a593Smuzhiyun b = b->next;
419*4882a593Smuzhiyun if (!b) {
420*4882a593Smuzhiyun *tail = a;
421*4882a593Smuzhiyun break;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun return head;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun /*
429*4882a593Smuzhiyun * Combine final list merge with restoration of standard doubly-linked
430*4882a593Smuzhiyun * list structure. This approach duplicates code from merge(), but
431*4882a593Smuzhiyun * runs faster than the tidier alternatives of either a separate final
432*4882a593Smuzhiyun * prev-link restoration pass, or maintaining the prev links
433*4882a593Smuzhiyun * throughout.
434*4882a593Smuzhiyun */
merge_final(void * priv,list_cmp_func_t cmp,struct list_head * head,struct list_head * a,struct list_head * b)435*4882a593Smuzhiyun static void merge_final(void *priv, list_cmp_func_t cmp, struct list_head *head,
436*4882a593Smuzhiyun struct list_head *a, struct list_head *b)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun struct list_head *tail = head;
439*4882a593Smuzhiyun RK_U8 count = 0;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun for (;;) {
442*4882a593Smuzhiyun /* if equal, take 'a' -- important for sort stability */
443*4882a593Smuzhiyun if (cmp(priv, a, b) <= 0) {
444*4882a593Smuzhiyun tail->next = a;
445*4882a593Smuzhiyun a->prev = tail;
446*4882a593Smuzhiyun tail = a;
447*4882a593Smuzhiyun a = a->next;
448*4882a593Smuzhiyun if (!a)
449*4882a593Smuzhiyun break;
450*4882a593Smuzhiyun } else {
451*4882a593Smuzhiyun tail->next = b;
452*4882a593Smuzhiyun b->prev = tail;
453*4882a593Smuzhiyun tail = b;
454*4882a593Smuzhiyun b = b->next;
455*4882a593Smuzhiyun if (!b) {
456*4882a593Smuzhiyun b = a;
457*4882a593Smuzhiyun break;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun /* Finish linking remainder of list b on to tail */
463*4882a593Smuzhiyun tail->next = b;
464*4882a593Smuzhiyun do {
465*4882a593Smuzhiyun /*
466*4882a593Smuzhiyun * If the merge is highly unbalanced (e.g. the input is
467*4882a593Smuzhiyun * already sorted), this loop may run many iterations.
468*4882a593Smuzhiyun * Continue callbacks to the client even though no
469*4882a593Smuzhiyun * element comparison is needed, so the client's cmp()
470*4882a593Smuzhiyun * routine can invoke cond_resched() periodically.
471*4882a593Smuzhiyun */
472*4882a593Smuzhiyun if (!++count)
473*4882a593Smuzhiyun cmp(priv, b, b);
474*4882a593Smuzhiyun b->prev = tail;
475*4882a593Smuzhiyun tail = b;
476*4882a593Smuzhiyun b = b->next;
477*4882a593Smuzhiyun } while (b);
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun /* And the final links to make a circular doubly-linked list */
480*4882a593Smuzhiyun tail->next = head;
481*4882a593Smuzhiyun head->prev = tail;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun
list_sort(void * priv,struct list_head * head,list_cmp_func_t cmp)484*4882a593Smuzhiyun void list_sort(void *priv, struct list_head *head, list_cmp_func_t cmp)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun struct list_head *list = head->next, *pending = NULL;
487*4882a593Smuzhiyun size_t count = 0; /* Count of pending */
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun if (list == head->prev) /* Zero or one elements */
490*4882a593Smuzhiyun return;
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun /* Convert to a null-terminated singly-linked list. */
493*4882a593Smuzhiyun head->prev->next = NULL;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun /*
496*4882a593Smuzhiyun * Data structure invariants:
497*4882a593Smuzhiyun * - All lists are singly linked and null-terminated; prev
498*4882a593Smuzhiyun * pointers are not maintained.
499*4882a593Smuzhiyun * - pending is a prev-linked "list of lists" of sorted
500*4882a593Smuzhiyun * sublists awaiting further merging.
501*4882a593Smuzhiyun * - Each of the sorted sublists is power-of-two in size.
502*4882a593Smuzhiyun * - Sublists are sorted by size and age, smallest & newest at front.
503*4882a593Smuzhiyun * - There are zero to two sublists of each size.
504*4882a593Smuzhiyun * - A pair of pending sublists are merged as soon as the number
505*4882a593Smuzhiyun * of following pending elements equals their size (i.e.
506*4882a593Smuzhiyun * each time count reaches an odd multiple of that size).
507*4882a593Smuzhiyun * That ensures each later final merge will be at worst 2:1.
508*4882a593Smuzhiyun * - Each round consists of:
509*4882a593Smuzhiyun * - Merging the two sublists selected by the highest bit
510*4882a593Smuzhiyun * which flips when count is incremented, and
511*4882a593Smuzhiyun * - Adding an element from the input as a size-1 sublist.
512*4882a593Smuzhiyun */
513*4882a593Smuzhiyun do {
514*4882a593Smuzhiyun size_t bits;
515*4882a593Smuzhiyun struct list_head **tail = &pending;
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun /* Find the least-significant clear bit in count */
518*4882a593Smuzhiyun for (bits = count; bits & 1; bits >>= 1)
519*4882a593Smuzhiyun tail = &(*tail)->prev;
520*4882a593Smuzhiyun /* Do the indicated merge */
521*4882a593Smuzhiyun if (bits) {
522*4882a593Smuzhiyun struct list_head *a = *tail, *b = a->prev;
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun a = merge(priv, cmp, b, a);
525*4882a593Smuzhiyun /* Install the merged result in place of the inputs */
526*4882a593Smuzhiyun a->prev = b->prev;
527*4882a593Smuzhiyun *tail = a;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /* Move one element from input list to pending */
531*4882a593Smuzhiyun list->prev = pending;
532*4882a593Smuzhiyun pending = list;
533*4882a593Smuzhiyun list = list->next;
534*4882a593Smuzhiyun pending->next = NULL;
535*4882a593Smuzhiyun count++;
536*4882a593Smuzhiyun } while (list);
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun /* End of input; merge together all the pending lists. */
539*4882a593Smuzhiyun list = pending;
540*4882a593Smuzhiyun pending = pending->prev;
541*4882a593Smuzhiyun for (;;) {
542*4882a593Smuzhiyun struct list_head *next = pending->prev;
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun if (!next)
545*4882a593Smuzhiyun break;
546*4882a593Smuzhiyun list = merge(priv, cmp, pending, list);
547*4882a593Smuzhiyun pending = next;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun /* The final merge, rebuilding prev links */
550*4882a593Smuzhiyun merge_final(priv, cmp, head, pending, list);
551*4882a593Smuzhiyun }
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun #if BUILD_RK_LIST_TEST
554*4882a593Smuzhiyun #include "vpu_mem.h"
555*4882a593Smuzhiyun #include <stdio.h>
556*4882a593Smuzhiyun #include <stdlib.h>
557*4882a593Smuzhiyun #include <string.h>
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun #define LOOP_RK_LIST 600
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun #define COUNT_ADD 100
562*4882a593Smuzhiyun #define COUNT_DEL 99
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun volatile int err = 0;
565*4882a593Smuzhiyun
mpp_list_fifo_test(mpp_list * list_0)566*4882a593Smuzhiyun static int mpp_list_fifo_test(mpp_list *list_0)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun int count;
569*4882a593Smuzhiyun VPUMemLinear_t m;
570*4882a593Smuzhiyun for (count = 0; count < COUNT_ADD; count++) {
571*4882a593Smuzhiyun err |= VPUMallocLinear(&m, 100);
572*4882a593Smuzhiyun if (err) {
573*4882a593Smuzhiyun printf("VPUMallocLinear in mpp_list_fifo_test\n");
574*4882a593Smuzhiyun break;
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun err |= list_0->add_at_head(&m, sizeof(m));
577*4882a593Smuzhiyun if (err) {
578*4882a593Smuzhiyun printf("add_at_head in mpp_list_fifo_test\n");
579*4882a593Smuzhiyun break;
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun if (!err) {
584*4882a593Smuzhiyun for (count = 0; count < COUNT_DEL; count++) {
585*4882a593Smuzhiyun err |= list_0->del_at_tail(&m, sizeof(m));
586*4882a593Smuzhiyun if (err) {
587*4882a593Smuzhiyun printf("del_at_tail in mpp_list_fifo_test\n");
588*4882a593Smuzhiyun break;
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun err |= VPUFreeLinear(&m);
591*4882a593Smuzhiyun if (err) {
592*4882a593Smuzhiyun printf("VPUFreeLinear in mpp_list_fifo_test\n");
593*4882a593Smuzhiyun break;
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun return err;
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun
mpp_list_filo_test(mpp_list * list_0)600*4882a593Smuzhiyun static int mpp_list_filo_test(mpp_list *list_0)
601*4882a593Smuzhiyun {
602*4882a593Smuzhiyun int count;
603*4882a593Smuzhiyun VPUMemLinear_t m;
604*4882a593Smuzhiyun for (count = 0; count < COUNT_ADD + COUNT_DEL; count++) {
605*4882a593Smuzhiyun if (count & 1) {
606*4882a593Smuzhiyun err |= list_0->del_at_head(&m, sizeof(m));
607*4882a593Smuzhiyun if (err) {
608*4882a593Smuzhiyun printf("del_at_head in mpp_list_filo_test\n");
609*4882a593Smuzhiyun break;
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun err |= VPUFreeLinear(&m);
612*4882a593Smuzhiyun if (err) {
613*4882a593Smuzhiyun printf("VPUFreeLinear in mpp_list_fifo_test\n");
614*4882a593Smuzhiyun break;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun } else {
617*4882a593Smuzhiyun err |= VPUMallocLinear(&m, 100);
618*4882a593Smuzhiyun if (err) {
619*4882a593Smuzhiyun printf("VPUMallocLinear in mpp_list_filo_test\n");
620*4882a593Smuzhiyun break;
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun err |= list_0->add_at_head(&m, sizeof(m));
623*4882a593Smuzhiyun if (err) {
624*4882a593Smuzhiyun printf("add_at_head in mpp_list_fifo_test\n");
625*4882a593Smuzhiyun break;
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun return err;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun
mpp_list_test_loop_0(void * pdata)634*4882a593Smuzhiyun void *mpp_list_test_loop_0(void *pdata)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun int i;
637*4882a593Smuzhiyun mpp_list *list_0 = (mpp_list *)pdata;
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun printf("mpp_list test 0 loop start\n");
640*4882a593Smuzhiyun for (i = 0; i < LOOP_RK_LIST; i++) {
641*4882a593Smuzhiyun err |= mpp_list_filo_test(list_0);
642*4882a593Smuzhiyun if (err) break;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun if (err) {
646*4882a593Smuzhiyun printf("thread: found vpu mem operation err %d\n", err);
647*4882a593Smuzhiyun } else {
648*4882a593Smuzhiyun printf("thread: test done and found no err\n");
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun return NULL;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun
mpp_list_test_0()653*4882a593Smuzhiyun int mpp_list_test_0()
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun int i, err = 0;
656*4882a593Smuzhiyun printf("mpp_list test 0 FIFO start\n");
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun mpp_list *list_0 = new mpp_list((node_destructor)VPUFreeLinear);
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun pthread_t mThread;
661*4882a593Smuzhiyun pthread_attr_t attr;
662*4882a593Smuzhiyun pthread_attr_init(&attr);
663*4882a593Smuzhiyun pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun pthread_create(&mThread, &attr, mpp_list_test_loop_0, (void*)list_0);
666*4882a593Smuzhiyun pthread_attr_destroy(&attr);
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun for (i = 0; i < LOOP_RK_LIST; i++) {
669*4882a593Smuzhiyun err |= mpp_list_fifo_test(list_0);
670*4882a593Smuzhiyun if (err) break;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun if (err) {
673*4882a593Smuzhiyun printf("main : found mpp_list operation err %d\n", err);
674*4882a593Smuzhiyun } else {
675*4882a593Smuzhiyun printf("main : test done and found no err\n");
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun void *dummy;
679*4882a593Smuzhiyun pthread_join(mThread, &dummy);
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun printf("mpp_list test 0 end size %d\n", list_0->list_size());
682*4882a593Smuzhiyun delete list_0;
683*4882a593Smuzhiyun return err;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun #define TOTAL_RK_LIST_TEST_COUNT 1
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun typedef int (*RK_LIST_TEST_FUNC)(void);
689*4882a593Smuzhiyun RK_LIST_TEST_FUNC test_func[TOTAL_RK_LIST_TEST_COUNT] = {
690*4882a593Smuzhiyun mpp_list_test_0,
691*4882a593Smuzhiyun };
692*4882a593Smuzhiyun
main(int argc,char * argv[])693*4882a593Smuzhiyun int main(int argc, char *argv[])
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun int i, start = 0, end = 0;
696*4882a593Smuzhiyun if (argc < 2) {
697*4882a593Smuzhiyun end = TOTAL_RK_LIST_TEST_COUNT;
698*4882a593Smuzhiyun } else if (argc == 2) {
699*4882a593Smuzhiyun start = atoi(argv[1]);
700*4882a593Smuzhiyun end = start + 1;
701*4882a593Smuzhiyun } else if (argc == 3) {
702*4882a593Smuzhiyun start = atoi(argv[1]);
703*4882a593Smuzhiyun end = atoi(argv[2]);
704*4882a593Smuzhiyun } else {
705*4882a593Smuzhiyun printf("too many argc %d\n", argc);
706*4882a593Smuzhiyun return -1;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun if (start < 0 || start > TOTAL_RK_LIST_TEST_COUNT || end < 0 || end > TOTAL_RK_LIST_TEST_COUNT) {
709*4882a593Smuzhiyun printf("invalid input: start %d end %d\n", start, end);
710*4882a593Smuzhiyun return -1;
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun for (i = start; i < end; i++) {
713*4882a593Smuzhiyun int err = test_func[i]();
714*4882a593Smuzhiyun if (err) {
715*4882a593Smuzhiyun printf("test case %d return err %d\n", i, err);
716*4882a593Smuzhiyun break;
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun return 0;
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun #endif
722*4882a593Smuzhiyun
723