summaryrefslogtreecommitdiff
path: root/amavutils/amthreadpool.c (plain)
blob: 601466324a12bc0054f9a8869f4ee4b3ffb60b03
1/*
2 * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
3 *
4 * This source code is subject to the terms and conditions defined in the
5 * file 'LICENSE' which is part of this source code package.
6 *
7 * Description:
8 */
9
10
11#include <amthreadpool.h>
12#include <itemlist.h>
13
14#define LOG_TAG "amthreadpool"
15#include <utils/Log.h>
16
17#include <string.h>
18#include <stdlib.h>
19#include <fcntl.h>
20
21
22static struct itemlist threadpool_list;
23static struct itemlist threadpool_threadlist;
24#define MAX_THREAD_DEPTH 8
25
26#define T_ASSERT_TRUE(x)\
27 do {\
28 if (!(x))\
29 ALOGE("amthreadpool error at %d\n",__LINE__);\
30 } while(0)
31
32#define T_ASSERT_NO_NULL(p) T_ASSERT_TRUE((p)!=NULL)
33
34typedef struct threadpool {
35 pthread_t pid;
36 struct itemlist threadlist;
37} threadpool_t;
38
39typedef struct threadpool_thread_data {
40 pthread_t pid;
41 void * (*start_routine)(void *);
42 void * arg;
43 pthread_t ppid[MAX_THREAD_DEPTH];
44 threadpool_t *pool;
45 pthread_mutex_t pthread_mutex;
46 pthread_cond_t pthread_cond;
47 int on_requred_exit;
48 int thread_inited;
49} threadpool_thread_data_t;
50#define POOL_OF_ITEM(item) ((threadpool_t *)(item)->extdata[0])
51#define THREAD_OF_ITEM(item) ((threadpool_thread_data_t *)(item)->extdata[0])
52
53static int amthreadpool_release(pthread_t pid);
54static threadpool_t * amthreadpool_create_pool(pthread_t pid);
55
56static threadpool_t * amthreadpool_findthead_pool(pthread_t pid)
57{
58 struct item *item;
59 item = itemlist_find_match_item(&threadpool_list, pid);
60 if (item) {
61 return (threadpool_t *)item->extdata[0];
62 }
63 return NULL;
64}
65
66static threadpool_thread_data_t * amthreadpool_findthead_thread_data(pthread_t pid)
67{
68 struct item *item;
69 item = itemlist_find_match_item(&threadpool_threadlist, pid);
70 if (item) {
71 return (threadpool_thread_data_t *)item->extdata[0];
72 }
73 return NULL;
74}
75
76/*creat thread pool for main thread*/
77static threadpool_t * amthreadpool_create_pool(pthread_t pid)
78{
79 struct item *poolitem;
80 threadpool_t *pool;
81 int ret = -1;
82 unsigned long exdata[2];
83 pool = malloc(sizeof(threadpool_t));
84 if (!pool) {
85 ALOGE("malloc pool data failed\n");
86 return NULL;
87 }
88 memset(pool, 0, sizeof(threadpool_t));
89 pool->pid = pid;
90 if (pid == 0) {
91 pool->pid = pthread_self();
92 }
93 pool->threadlist.max_items = 0;
94 pool->threadlist.item_ext_buf_size = 0;
95 pool->threadlist.muti_threads_access = 1;
96 pool->threadlist.reject_same_item_data = 1;
97 itemlist_init(&pool->threadlist);
98 exdata[0] = (unsigned long)pool;
99 itemlist_add_tail_data_ext(&threadpool_list, pool->pid, 1, exdata);
100
101 return pool;
102}
103
104static int amthreadpool_pool_add_thread(threadpool_t *pool, unsigned long pid, threadpool_thread_data_t* thread)
105{
106 int ret;
107 unsigned long exdata[2];
108 exdata[0] = (unsigned long)thread;
109 if (pool) {
110 ret = itemlist_add_tail_data_ext(&pool->threadlist, thread->pid, 1, exdata);
111 } else {
112 pool = amthreadpool_create_pool(pid);
113 thread->pool = pool;
114 }
115 ret |= itemlist_add_tail_data_ext(&threadpool_threadlist, thread->pid, 1, exdata);
116 return ret;
117}
118static int amthreadpool_pool_del_thread(pthread_t pid)
119{
120 threadpool_t *pool;
121 threadpool_thread_data_t* t1, *t2;
122 int ret = 0;
123 struct item *item;
124 item = itemlist_get_match_item(&threadpool_threadlist, pid);
125 if (!item) {
126 return -2; /*freed before*/
127 }
128 t1 = THREAD_OF_ITEM(item);
129 item_free(item);
130 T_ASSERT_NO_NULL(t1);
131 pool = t1->pool;
132 T_ASSERT_NO_NULL(pool);
133 item = itemlist_get_match_item(&pool->threadlist, pid);
134 if (item) {
135 T_ASSERT_NO_NULL(item);
136 t2 = THREAD_OF_ITEM(item);
137 T_ASSERT_NO_NULL(t2);
138 if (t1 != t2) {
139 ALOGE("%d thread data not mached, %p!=%p\n", (int)pid, t1, t2);
140 }
141 item_free(item);
142 }
143 pthread_cond_destroy(&t1->pthread_cond);
144 pthread_mutex_destroy(&t1->pthread_mutex);
145 free(t1);
146 if (pool->pid == pid) {
147 amthreadpool_release(pid);
148 }
149 return ret;
150}
151
152
153static int amthreadpool_thread_wake_t(threadpool_thread_data_t*t, int trycancel)
154{
155 int ret;
156 pthread_mutex_lock(&t->pthread_mutex);
157 t->on_requred_exit = trycancel;
158 ret = pthread_cond_signal(&t->pthread_cond);
159 pthread_mutex_unlock(&t->pthread_mutex);
160 return ret;
161}
162static int64_t amthreadpool_gettime(void)
163{
164 struct timeval tv;
165 gettimeofday(&tv, NULL);
166 return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
167}
168
169int amthreadpool_thread_usleep_in_monotonic(int us)
170{
171 pthread_t pid = pthread_self();
172 struct timespec pthread_ts, tnow;
173 int64_t us64 = us;
174 threadpool_thread_data_t *t = amthreadpool_findthead_thread_data(pid);
175 int ret = 0;
176/* 64bit compiler do not have pthread_cond_timedwait_monotonic_np */
177#ifndef __aarch64__
178 if (!t) {
179 ///ALOGE("%lu thread sleep data not found!!!\n", pid);
180 usleep(us);//for not deadlock.
181 return 0;
182 }
183 if (t->on_requred_exit > 1) {
184 if (us64 < 100 * 1000) {
185 us64 = 100 * 1000;
186 }
187 t->on_requred_exit--; /*if on_requred_exit,do less sleep till 1.*/
188 }
189 clock_gettime(CLOCK_MONOTONIC, &tnow);
190 pthread_ts.tv_sec = tnow.tv_sec + (us64 + tnow.tv_nsec / 1000) / 1000000;
191 pthread_ts.tv_nsec = (us64 * 1000 + tnow.tv_nsec) % 1000000000;
192 pthread_mutex_lock(&t->pthread_mutex);
193 ret = pthread_cond_timedwait_monotonic_np(&t->pthread_cond, &t->pthread_mutex, &pthread_ts);
194
195 pthread_mutex_unlock(&t->pthread_mutex);
196 return ret;
197#else
198 usleep(us);//for not deadlock.
199 return 0;
200#endif
201
202}
203
204
205int amthreadpool_thread_usleep_in(int us)
206{
207 pthread_t pid = pthread_self();
208 struct timespec pthread_ts;
209 struct timeval now;
210 int64_t us64 = us;
211 threadpool_thread_data_t *t = amthreadpool_findthead_thread_data(pid);
212 int ret = 0;
213
214 if (!t) {
215 ///ALOGE("%lu thread sleep data not found!!!\n", pid);
216 usleep(us);//for not deadlock.
217 return 0;
218 }
219 if (t->on_requred_exit > 1) {
220 if (us64 < 100 * 1000) {
221 us64 = 100 * 1000;
222 }
223 t->on_requred_exit--; /*if on_requred_exit,do less sleep till 1.*/
224 }
225 ret = gettimeofday(&now, NULL);
226 pthread_ts.tv_sec = now.tv_sec + (us64 + now.tv_usec) / 1000000;
227 pthread_ts.tv_nsec = ((us64 + now.tv_usec) * 1000) % 1000000000;
228 pthread_mutex_lock(&t->pthread_mutex);
229 ret = pthread_cond_timedwait(&t->pthread_cond, &t->pthread_mutex, &pthread_ts);
230 pthread_mutex_unlock(&t->pthread_mutex);
231 return ret;
232}
233int amthreadpool_thread_usleep_debug(int us, const char *func, int line)
234{
235
236 int64_t starttime = amthreadpool_gettime();
237 int64_t endtime;
238 int ret;
239
240#ifdef AMTHREADPOOL_SLEEP_US_MONOTONIC
241 ret = amthreadpool_thread_usleep_in_monotonic(us);
242#else
243 ret = amthreadpool_thread_usleep_in(us);
244#endif
245 endtime = amthreadpool_gettime();
246 if ((endtime - starttime - us) > 100 * 1000) {
247 ALOGE("***amthreadpool_thread_usleep wast more time wait %d us, real %lld us\n", us, (int64_t)(endtime - starttime));
248 }
249 return ret;
250}
251
252int amthreadpool_thread_wake(pthread_t pid)
253{
254 threadpool_thread_data_t *t = amthreadpool_findthead_thread_data(pid);
255 if (!t) {
256 ALOGE("%lu wake thread data not found!!!\n", pid);
257 return -1;
258 }
259 return amthreadpool_thread_wake_t(t, t->on_requred_exit);
260}
261int amthreadpool_on_requare_exit(pthread_t pid)
262{
263 unsigned long rpid = pid != 0 ? pid : pthread_self();
264 threadpool_thread_data_t *t = amthreadpool_findthead_thread_data(rpid);
265 if (!t) {
266 return 0;
267 }
268 if (t->on_requred_exit) {
269 ///ALOGI("%lu name on try exit.\n", pid);
270 }
271 return !!t->on_requred_exit;
272}
273
274static int amthreadpool_pool_thread_cancel_l1(pthread_t pid, int cancel, int allthreads)
275{
276 struct itemlist *itemlist;
277 threadpool_thread_data_t *t, *t1;
278 struct item *item = NULL;
279 threadpool_t *pool;
280 t = amthreadpool_findthead_thread_data(pid);
281 if (!t) {
282 ALOGE("%lu pool data not found!!!\n", pid);
283 return 0;
284 }
285 pool = t->pool;
286 if (allthreads && pool && pool->pid == pid) {
287 itemlist = &pool->threadlist;
288 FOR_EACH_ITEM_IN_ITEMLIST(itemlist, item)
289 t1 = THREAD_OF_ITEM(item);
290 amthreadpool_thread_wake_t(t1, cancel);
291 FOR_ITEM_END(itemlist);
292 }
293 amthreadpool_thread_wake_t(t, cancel);
294 ///amthreadpool_system_dump_info();
295 return 0;
296}
297
298int amthreadpool_pool_thread_cancel(pthread_t pid)
299{
300 return amthreadpool_pool_thread_cancel_l1(pid, 3, 1);
301}
302
303int amthreadpool_pool_thread_uncancel(pthread_t pid)
304{
305 return amthreadpool_pool_thread_cancel_l1(pid, 0, 1);
306}
307int amthreadpool_thread_cancel(pthread_t pid)
308{
309 return amthreadpool_pool_thread_cancel_l1(pid, 3, 0);
310}
311int amthreadpool_thread_uncancel(pthread_t pid)
312{
313 return amthreadpool_pool_thread_cancel_l1(pid, 0, 0);
314}
315
316static int amthreadpool_release(pthread_t pid)
317{
318 struct item *poolitem;
319 threadpool_t *pool;
320 poolitem = itemlist_get_match_item(&threadpool_list, pid);
321 if (poolitem) {
322 pool = POOL_OF_ITEM(poolitem);
323 itemlist_deinit(&pool->threadlist);
324 free((void *)pool);
325 item_free(poolitem);
326 }
327 return 0;
328}
329
330
331void * amthreadpool_start_thread(void *arg)
332{
333 void *ret;
334 threadpool_thread_data_t *t = (threadpool_thread_data_t *)arg;
335 {
336 threadpool_thread_data_t *thread_p;
337 threadpool_t *pool = NULL;
338 int i;
339 t->pid = pthread_self();
340 thread_p = amthreadpool_findthead_thread_data(t->ppid[0]);
341 if (thread_p) {
342 pool = thread_p->pool;
343 for (i = 0; i < MAX_THREAD_DEPTH - 1; i++) {
344 if (!thread_p->ppid[i]) {
345 break;
346 }
347 t->ppid[i + 1] = thread_p->ppid[i];
348 }
349 t->pool = pool;
350
351 }
352 amthreadpool_pool_add_thread(pool, t->pid, t);
353 }
354 pthread_mutex_lock(&t->pthread_mutex);
355 t->thread_inited = 1;
356 pthread_cond_signal(&t->pthread_cond);
357 pthread_mutex_unlock(&t->pthread_mutex);
358 ret = t->start_routine(t->arg);
359 return ret;
360}
361
362int amthreadpool_pthread_create_name(pthread_t * newthread,
363 __const pthread_attr_t * attr,
364 void * (*start_routine)(void *),
365 void * arg, const char *name)
366{
367 pthread_t pid = pthread_self();
368 pthread_t subpid;
369 int ret;
370
371 threadpool_thread_data_t *t = malloc(sizeof(threadpool_thread_data_t));
372 if (!t) {
373 ALOGE("malloc threadpool_thread_data_t data failed\n");
374 return -100;
375 }
376 memset(t, 0, sizeof(threadpool_thread_data_t));
377 t->start_routine = start_routine;
378 t->arg = arg;
379 t->ppid[0] = pid;
380 t->thread_inited = 0;
381 pthread_mutex_init(&t->pthread_mutex, NULL);
382 pthread_cond_init(&t->pthread_cond, NULL);
383 ret = pthread_create(&subpid, attr, amthreadpool_start_thread, (void *)t);
384 if (ret == 0) {
385 *newthread = subpid;
386 if (name) {
387 pthread_setname_np(pid, name);
388 }
389 pthread_mutex_lock(&t->pthread_mutex);
390 while (t->thread_inited == 0)
391 pthread_cond_wait(&t->pthread_cond, &t->pthread_mutex);
392 pthread_mutex_unlock(&t->pthread_mutex);
393 }
394 return ret;
395}
396
397
398
399int amthreadpool_pthread_create(pthread_t * newthread,
400 __const pthread_attr_t * attr,
401 void * (*start_routine)(void *),
402 void * arg)
403{
404 return amthreadpool_pthread_create_name(newthread, attr, start_routine, arg, NULL);
405}
406
407int amthreadpool_pthread_join(pthread_t thid, void ** ret_val)
408{
409 int ret;
410 ret = pthread_join(thid, ret_val);
411 amthreadpool_pool_del_thread(thid);
412 return ret;
413}
414
415
416
417
418
419/*creat thread pool system init*/
420int amthreadpool_system_init(void)
421{
422 static int inited = 0;
423 if (inited) {
424 return 0;
425 }
426 inited ++;
427 threadpool_list.max_items = 0;
428 threadpool_list.item_ext_buf_size = 0;
429 threadpool_list.muti_threads_access = 1;
430 threadpool_list.reject_same_item_data = 1;
431 itemlist_init(&threadpool_list);
432
433 threadpool_threadlist.max_items = 0;
434 threadpool_threadlist.item_ext_buf_size = 0;
435 threadpool_threadlist.muti_threads_access = 1;
436 threadpool_threadlist.reject_same_item_data = 1;
437 itemlist_init(&threadpool_threadlist);
438 return 0;
439}
440
441
442int amthreadpool_system_dump_info(void)
443{
444 threadpool_thread_data_t *t;
445 threadpool_t *pool;
446 struct item *item = NULL;
447 struct item *item1 = NULL;
448 ALOGI("------------amthreadpool_system_dump_info----------START\n");
449 ALOGI("pool & threads:\n");
450 FOR_EACH_ITEM_IN_ITEMLIST(&threadpool_list, item) {
451 pool = POOL_OF_ITEM(item);
452 ALOGI("pool:%p\n", pool);
453 ALOGI("--tpid:%lu\n", pool->pid);
454 FOR_EACH_ITEM_IN_ITEMLIST(&pool->threadlist, item1) {
455 t = THREAD_OF_ITEM(item1);
456 ALOGI("--tpid:%lu\n", t->pid);
457 //ALOGI("----name=%p\n",amthreadpool_thread_name(t->pid));
458 ALOGI("----ppid=%lu,%lu,%lu,%lu,%lu", t->ppid[0], t->ppid[1], t->ppid[2], t->ppid[3], t->ppid[4]);
459 ALOGI("----pool:%p\n", t->pool);
460 ALOGI("----on_requred_exit:%d\n", t->on_requred_exit);
461 }
462 FOR_ITEM_END(&pool->threadlist);
463 }
464 FOR_ITEM_END(&threadpool_list);
465 ALOGI("all threads:\n");
466 FOR_EACH_ITEM_IN_ITEMLIST(&threadpool_threadlist, item) {
467 t = THREAD_OF_ITEM(item);
468 ALOGI("--tpid:%lu\n", t->pid);
469 //ALOGI("----name=%p\n",amthreadpool_thread_name(t->pid));
470 ALOGI("----ppid=%lu,%lu,%lu,%lu,%lu", t->ppid[0], t->ppid[1], t->ppid[2], t->ppid[3], t->ppid[4]);
471 ALOGI("----pool:%p\n", t->pool);
472 ALOGI("----on_requred_exit:%d\n", t->on_requred_exit);
473 }
474 FOR_ITEM_END(&threadpool_threadlist);
475 ALOGI("------------amthreadpool_system_dump_info----------END\n");
476 return 0;
477}
478