4 * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
8 * Jaewon Lim <jaewon81.lim@samsung.com>
9 * Woojin Jung <woojin2.jung@samsung.com>
10 * Juyoung Kim <j0.kim@samsung.com>
11 * Anastasia Lyupa <a.lyupa@samsung.com>
13 * This library is free software; you can redistribute it and/or modify it under
14 * the terms of the GNU Lesser General Public License as published by the
15 * Free Software Foundation; either version 2.1 of the License, or (at your option)
18 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
19 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
21 * License for more details.
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this library; if not, write to the Free Software Foundation, Inc., 51
25 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 * - Samsung RnD Institute Russia
34 #include <signal.h> // for signal
35 #include <unistd.h> // for ualarm, sleep
36 #include <sys/timerfd.h> // for timerfd
38 #include <errno.h> // for errno
39 #include <string.h> // for memset
40 #include <stdint.h> // for uint64_t
44 #include "probeinfo.h"
50 #define ERR_THREAD_CREATE_FAIL -2001 // thread creation fail
52 #define MAX_TITLE_LENGTH 16
53 #define MAX_CHART_HANDLE 10 // cannot be exceeded 10
54 #define MAX_SERIES_PER_CHART 4 // cannot be exceeded 10
55 // chart handle is from 1 to 9
56 // series handle is from 11 to 99
57 // series handle 32 means that the series is 2nd series in 3rd chart.
58 // zero value handle means error
60 // =====================================================================
62 // =====================================================================
64 typedef struct _chart_interval_callback
66 da_handle chart_handle;
67 da_handle series_handle;
68 da_user_data_2_chart_data callback;
70 struct _chart_interval_callback* next;
71 } chart_interval_callback;
76 pthread_t thread_handle;
77 chart_interval_callback* callback_list;
78 pthread_mutex_t list_mutex;
83 int chart_handle_index;
84 int series_handle_index[MAX_CHART_HANDLE];
85 int interval_for_series[MAX_CHART_HANDLE][MAX_SERIES_PER_CHART];
86 interval_manager interval_10ms;
87 interval_manager interval_100ms;
88 interval_manager interval_1s;
89 } chart_handle_maintainer;
91 chart_handle_maintainer chm;
93 __thread pid_t cur_thread = -1;
96 // =====================================================================
97 // internal macro definition
98 // =====================================================================
100 #define DECLARE_CHART_VARIABLE \
101 da_handle __attribute__((unused)) ret = 0; \
102 probeInfo_t probeInfo;
104 // =====================================================================
105 // timer thread routine for callback
106 // =====================================================================
108 void* _chart_timerThread(void* data)
110 DECLARE_CHART_VARIABLE;
114 chart_interval_callback* cur;
116 sigset_t profsigmask;
117 interval_manager* pmanager = (interval_manager*)data;
121 sigemptyset(&profsigmask);
122 sigaddset(&profsigmask, SIGPROF);
123 pthread_sigmask(SIG_BLOCK, &profsigmask, NULL);
125 while((readsize = read(pmanager->timerfd, &exp, sizeof(uint64_t))) > 0)
127 pthread_mutex_lock(&pmanager->list_mutex);
129 cur = pmanager->callback_list;
132 value = cur->callback(cur->user_data);
134 setProbePoint(&probeInfo);
137 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
138 API_ID__chart_timerThread,
140 PACK_COMMON_END(0, 0, 2);
141 PACK_CUSTOM(cur->series_handle, 0, "", 0, value);
147 pthread_mutex_unlock(&pmanager->list_mutex);
157 static int start_callback_thread(chart_interval interval)
160 pthread_t* thread_handle = NULL;
161 interval_manager* pman = NULL;
162 struct itimerspec timevalue;
164 if(interval == CHART_INTERVAL_10MSEC)
166 timerfd = &(chm.interval_10ms.timerfd);
167 thread_handle = &(chm.interval_10ms.thread_handle);
168 pman = &(chm.interval_10ms);
169 timevalue.it_value.tv_sec = 0;
170 timevalue.it_value.tv_nsec = 10000000L;
171 timevalue.it_interval.tv_sec = 0;
172 timevalue.it_interval.tv_nsec = 10000000L;
174 else if(interval == CHART_INTERVAL_100MSEC)
176 timerfd = &(chm.interval_100ms.timerfd);
177 thread_handle = &(chm.interval_100ms.thread_handle);
178 pman = &(chm.interval_100ms);
179 timevalue.it_value.tv_sec = 0;
180 timevalue.it_value.tv_nsec = 100000000L;
181 timevalue.it_interval.tv_sec = 0;
182 timevalue.it_interval.tv_nsec = 100000000L;
184 else if(interval == CHART_INTERVAL_1SEC)
186 timerfd = &(chm.interval_1s.timerfd);
187 thread_handle = &(chm.interval_1s.thread_handle);
188 pman = &(chm.interval_1s);
189 timevalue.it_value.tv_sec = 1;
190 timevalue.it_value.tv_nsec = 0;
191 timevalue.it_interval.tv_sec = 1;
192 timevalue.it_interval.tv_nsec = 0;
196 return ERR_WRONG_PARAMETER;
200 * FIXME: Type of pthread_t is undefined.
201 * Comparing it with -1 is *very* bad
203 if (*timerfd != -1 || *thread_handle != (pthread_t) -1)
204 return 0; // already thread exist
206 *timerfd = timerfd_create(CLOCK_REALTIME, 0);
210 if (timerfd_settime(*timerfd, 0, &timevalue, NULL) == -1)
213 if (pthread_create(thread_handle, NULL, _chart_timerThread, pman) < 0)
214 return ERR_THREAD_CREATE_FAIL;
220 // =====================================================================
221 // internal utility function
222 // =====================================================================
224 static void add_to_callback_list(chart_interval interval, da_handle charthandle, da_handle series_handle,
225 da_user_data_2_chart_data callback, void* user_data)
227 chart_interval_callback* newelem;
229 newelem = (chart_interval_callback*)malloc(sizeof(chart_interval_callback));
230 newelem->chart_handle = charthandle;
231 newelem->series_handle = series_handle;
232 newelem->callback = callback;
233 newelem->user_data = user_data;
235 chm.interval_for_series[charthandle][series_handle % 10] = interval;
239 case CHART_INTERVAL_10MSEC:
240 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
241 newelem->next = chm.interval_10ms.callback_list;
242 chm.interval_10ms.callback_list = newelem;
243 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
244 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
246 case CHART_INTERVAL_100MSEC:
247 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
248 newelem->next = chm.interval_100ms.callback_list;
249 chm.interval_100ms.callback_list = newelem;
250 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
251 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
253 case CHART_INTERVAL_1SEC:
254 pthread_mutex_lock(&chm.interval_1s.list_mutex);
255 newelem->next = chm.interval_1s.callback_list;
256 chm.interval_1s.callback_list = newelem;
257 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
258 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
266 static void remove_all_callback_list()
268 chart_interval_callback* cur;
270 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
271 while(chm.interval_10ms.callback_list != NULL)
273 cur = chm.interval_10ms.callback_list;
274 chm.interval_10ms.callback_list = cur->next;
277 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
279 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
280 while(chm.interval_100ms.callback_list != NULL)
282 cur = chm.interval_100ms.callback_list;
283 chm.interval_100ms.callback_list = cur->next;
286 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
288 pthread_mutex_lock(&chm.interval_1s.list_mutex);
289 while(chm.interval_1s.callback_list != NULL)
291 cur = chm.interval_1s.callback_list;
292 chm.interval_1s.callback_list = cur->next;
295 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
297 memset(&chm.interval_for_series, 0, sizeof(chm.interval_for_series));
298 __sync_and_and_fetch(&(gTraceInfo.custom_chart_callback_count), 0);
301 static void remove_from_callback_list(da_handle charthandle, da_handle series_handle)
303 chart_interval_callback *prev, *cur;
304 chart_interval interval;
306 interval = chm.interval_for_series[charthandle][series_handle % 10];
307 chm.interval_for_series[charthandle][series_handle % 10] = 0;
311 case CHART_INTERVAL_10MSEC:
312 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
315 cur = chm.interval_10ms.callback_list;
318 if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
321 prev->next = cur->next;
323 chm.interval_10ms.callback_list = cur->next;
325 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
334 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
336 case CHART_INTERVAL_100MSEC:
337 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
340 cur = chm.interval_100ms.callback_list;
343 if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
346 prev->next = cur->next;
348 chm.interval_100ms.callback_list = cur->next;
350 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
359 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
361 case CHART_INTERVAL_1SEC:
362 pthread_mutex_lock(&chm.interval_1s.list_mutex);
365 cur = chm.interval_1s.callback_list;
368 if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
371 prev->next = cur->next;
373 chm.interval_1s.callback_list = cur->next;
375 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
384 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
392 // =====================================================================
393 // constructor and destructor functions
394 // =====================================================================
396 void __attribute__((constructor)) _init_lib()
400 memset(&chm, 0, sizeof(chm));
401 chm.interval_10ms.timerfd = -1;
402 chm.interval_100ms.timerfd = -1;
403 chm.interval_1s.timerfd = -1;
404 chm.interval_10ms.thread_handle = -1;
405 chm.interval_100ms.thread_handle = -1;
406 chm.interval_1s.thread_handle = -1;
407 pthread_mutex_init(&chm.interval_10ms.list_mutex, NULL);
408 pthread_mutex_init(&chm.interval_100ms.list_mutex, NULL);
409 pthread_mutex_init(&chm.interval_1s.list_mutex, NULL);
414 void __attribute__((destructor)) _fini_lib()
418 remove_all_callback_list();
419 if (chm.interval_10ms.timerfd != -1)
420 close(chm.interval_10ms.timerfd);
421 if (chm.interval_100ms.timerfd != -1)
422 close(chm.interval_100ms.timerfd);
423 if (chm.interval_1s.timerfd != -1)
424 close(chm.interval_1s.timerfd);
425 /*! Bad. Ugly. Unportable */
426 if (chm.interval_10ms.thread_handle != (pthread_t) -1)
427 pthread_join(chm.interval_10ms.thread_handle, NULL);
428 if (chm.interval_100ms.thread_handle != (pthread_t) -1)
429 pthread_join(chm.interval_100ms.thread_handle, NULL);
430 if (chm.interval_1s.thread_handle != (pthread_t) -1)
431 pthread_join(chm.interval_1s.thread_handle, NULL);
437 // =====================================================================
439 // =====================================================================
441 void da_mark(chart_color color, char* mark_text)
443 DECLARE_CHART_VARIABLE;
447 setProbePoint(&probeInfo);
450 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
452 "dp", color, mark_text);
453 PACK_COMMON_END(0, 0, 2);
454 PACK_CUSTOM(0, 0, mark_text, color, 0.0f);
460 da_handle da_create_chart(char* chart_name)
462 DECLARE_CHART_VARIABLE;
464 // check if there is available chart handle slot
465 if(chm.chart_handle_index + 1 >= MAX_CHART_HANDLE)
466 return ERR_MAX_CHART_NUMBER;
468 // check if chart_name is null
469 if(chart_name == NULL)
470 return ERR_WRONG_PARAMETER;
473 ret = ++(chm.chart_handle_index);
475 setProbePoint(&probeInfo);
478 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
479 API_ID_da_create_chart,
481 PACK_COMMON_END(ret, 0, 2);
482 PACK_CUSTOM(0, 0, chart_name, 0, 0.0f);
490 da_handle da_create_series(da_handle charthandle, char* seriesname,
491 series_type type, chart_color color)
493 DECLARE_CHART_VARIABLE;
495 // check if charthandle is valid handle or not
496 if(charthandle <= 0 || charthandle > chm.chart_handle_index)
497 return ERR_WRONG_HANDLE;
499 // chech if extra parameter is valid
500 if(seriesname == NULL)
501 return ERR_WRONG_PARAMETER;
503 // check if there is available series spot
504 if(chm.series_handle_index[(int)charthandle] + 1 >= MAX_SERIES_PER_CHART)
505 return ERR_MAX_CHART_NUMBER;
508 ret = ++(chm.series_handle_index[charthandle]);
509 ret += (10 * charthandle);
511 setProbePoint(&probeInfo);
514 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
515 API_ID_da_create_series,
516 "dpdd", charthandle, seriesname, type, color);
517 PACK_COMMON_END(ret, 0, 2);
518 PACK_CUSTOM(charthandle, type, seriesname, color, 0.0f);
526 da_handle da_create_default_series(da_handle charthandle, char* seriesname)
528 return da_create_series(charthandle, seriesname,
529 CHART_TYPE_AUTO, CHART_COLOR_AUTO);
532 int da_set_callback(da_handle series_handle, da_user_data_2_chart_data callback,
533 void* data_addr, chart_interval interval)
536 cindex = (int)(series_handle / 10);
537 sindex = series_handle % 10;
539 // check series handle
540 if(cindex <= 0 || cindex > chm.chart_handle_index)
541 return ERR_WRONG_HANDLE;
543 if(sindex > chm.series_handle_index[(int)cindex])
544 return ERR_WRONG_HANDLE;
546 // check rest parameters
547 if(interval == CHART_NO_CYCLE && callback != NULL)
548 return ERR_WRONG_PARAMETER;
552 // remove previously registered callback
553 remove_from_callback_list(cindex, series_handle);
555 // register new callback
559 add_to_callback_list(interval, cindex, series_handle, callback, data_addr);
560 re = start_callback_thread(interval);
561 LOG("start callback thread return %d\n", re);
568 void da_log(da_handle series_handle, float uservalue)
570 DECLARE_CHART_VARIABLE;
572 // chech if series handle is valid
574 cindex = (int)(series_handle / 10);
575 sindex = series_handle % 10;
577 if(cindex <= 0 || cindex > chm.chart_handle_index)
580 if(sindex > chm.series_handle_index[(int)cindex])
585 setProbePoint(&probeInfo);
588 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
590 "dw", series_handle, uservalue);
591 PACK_COMMON_END(0, 0, 2);
592 PACK_CUSTOM(series_handle, 0, "", 0, uservalue);