4 * Copyright (c) 2000 - 2011 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>
12 * This library is free software; you can redistribute it and/or modify it under
13 * the terms of the GNU Lesser General Public License as published by the
14 * Free Software Foundation; either version 2.1 of the License, or (at your option)
17 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
18 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
20 * License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this library; if not, write to the Free Software Foundation, Inc., 51
24 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
32 #include <signal.h> // for signal
33 #include <unistd.h> // for ualarm, sleep
34 #include <sys/timerfd.h> // for timerfd
36 #include <errno.h> // for errno
37 #include <string.h> // for memset
38 #include <stdint.h> // for uint64_t
42 #include "probeinfo.h"
48 #define ERR_THREAD_CREATE_FAIL -2001 // thread creation fail
50 #define MAX_TITLE_LENGTH 16
51 #define MAX_CHART_HANDLE 10 // cannot be exceeded 10
52 #define MAX_SERIES_PER_CHART 4 // cannot be exceeded 10
53 // chart handle is from 1 to 9
54 // series handle is from 11 to 99
55 // series handle 32 means that the series is 2nd series in 3rd chart.
56 // zero value handle means error
58 // =====================================================================
60 // =====================================================================
62 typedef struct _chart_interval_callback
64 da_handle chart_handle;
65 da_handle series_handle;
66 da_user_data_2_chart_data callback;
68 struct _chart_interval_callback* next;
69 } chart_interval_callback;
74 pthread_t thread_handle;
75 chart_interval_callback* callback_list;
76 pthread_mutex_t list_mutex;
81 int chart_handle_index;
82 int series_handle_index[MAX_CHART_HANDLE];
83 int interval_for_series[MAX_CHART_HANDLE][MAX_SERIES_PER_CHART];
84 interval_manager interval_10ms;
85 interval_manager interval_100ms;
86 interval_manager interval_1s;
87 } chart_handle_maintainer;
89 chart_handle_maintainer chm;
91 __thread pid_t cur_thread = -1;
94 // =====================================================================
95 // internal macro definition
96 // =====================================================================
98 #define DECLARE_CHART_VARIABLE \
99 da_handle __attribute__((unused)) ret = 0; \
100 probeInfo_t probeInfo; \
103 #define APPEND_LOG_CHART_RESULT(RESULT) \
104 log.length += sprintf(log.data + log.length, "`,%d`,0x%p`,0`,2", \
105 RESULT, CALLER_ADDRESS)
107 #define APPEND_LOG_CHART(HANDLE, TYPE, TEXT, COLOR, VALUE) \
108 log.length += sprintf(log.data + log.length, "`,`,%d`,%d`,%s`,%d`,%.3f", \
109 HANDLE, TYPE, TEXT, COLOR, VALUE)
111 // =====================================================================
112 // timer thread routine for callback
113 // =====================================================================
115 void* _chart_timerThread(void* data)
117 DECLARE_CHART_VARIABLE;
121 chart_interval_callback* cur;
123 sigset_t profsigmask;
124 interval_manager* pmanager = (interval_manager*)data;
128 sigemptyset(&profsigmask);
129 sigaddset(&profsigmask, SIGPROF);
130 pthread_sigmask(SIG_BLOCK, &profsigmask, NULL);
132 while((readsize = read(pmanager->timerfd, &exp, sizeof(uint64_t))) > 0)
134 pthread_mutex_lock(&pmanager->list_mutex);
136 cur = pmanager->callback_list;
139 value = cur->callback(cur->user_data);
142 setProbePoint(&probeInfo);
143 log.length = sprintf(log.data, "%d`,%d`,%s`,%lu`,%d`,%d`,`,`,0x%p`,0`,2`,`,%d`,0`,`,0`,%.3f",
144 LC_CUSTOM, probeInfo.eventIndex, __func__, probeInfo.currentTime, probeInfo.pID,
145 probeInfo.tID, CALLER_ADDRESS, cur->series_handle, value);
146 printLog(&log, MSG_LOG);
149 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "", 0);
150 PACK_COMMON_END(0, 0, 2);
151 PACK_CUSTOM(cur->series_handle, 0, "", 0, value);
157 pthread_mutex_unlock(&pmanager->list_mutex);
167 static int start_callback_thread(chart_interval interval)
170 pthread_t* thread_handle = NULL;
171 interval_manager* pman = NULL;
172 struct itimerspec timevalue;
174 if(interval == CHART_INTERVAL_10MSEC)
176 timerfd = &(chm.interval_10ms.timerfd);
177 thread_handle = &(chm.interval_10ms.thread_handle);
178 pman = &(chm.interval_10ms);
179 timevalue.it_value.tv_sec = 0;
180 timevalue.it_value.tv_nsec = 10000000L;
181 timevalue.it_interval.tv_sec = 0;
182 timevalue.it_interval.tv_nsec = 10000000L;
184 else if(interval == CHART_INTERVAL_100MSEC)
186 timerfd = &(chm.interval_100ms.timerfd);
187 thread_handle = &(chm.interval_100ms.thread_handle);
188 pman = &(chm.interval_100ms);
189 timevalue.it_value.tv_sec = 0;
190 timevalue.it_value.tv_nsec = 100000000L;
191 timevalue.it_interval.tv_sec = 0;
192 timevalue.it_interval.tv_nsec = 100000000L;
194 else if(interval == CHART_INTERVAL_1SEC)
196 timerfd = &(chm.interval_1s.timerfd);
197 thread_handle = &(chm.interval_1s.thread_handle);
198 pman = &(chm.interval_1s);
199 timevalue.it_value.tv_sec = 1;
200 timevalue.it_value.tv_nsec = 0;
201 timevalue.it_interval.tv_sec = 1;
202 timevalue.it_interval.tv_nsec = 0;
206 return ERR_WRONG_PARAMETER;
209 if(*timerfd != -1 || *thread_handle != -1)
210 return 0; // already thread exist
212 *timerfd = timerfd_create(CLOCK_REALTIME, 0);
216 if(timerfd_settime(*timerfd, 0, &timevalue, NULL) == -1)
219 if(pthread_create(thread_handle, NULL, _chart_timerThread, pman) < 0)
220 return ERR_THREAD_CREATE_FAIL;
226 // =====================================================================
227 // internal utility function
228 // =====================================================================
230 static void add_to_callback_list(chart_interval interval, da_handle charthandle, da_handle series_handle,
231 da_user_data_2_chart_data callback, void* user_data)
233 chart_interval_callback* newelem;
235 newelem = (chart_interval_callback*)malloc(sizeof(chart_interval_callback));
236 newelem->chart_handle = charthandle;
237 newelem->series_handle = series_handle;
238 newelem->callback = callback;
239 newelem->user_data = user_data;
241 chm.interval_for_series[charthandle][series_handle % 10] = interval;
245 case CHART_INTERVAL_10MSEC:
246 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
247 newelem->next = chm.interval_10ms.callback_list;
248 chm.interval_10ms.callback_list = newelem;
249 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
250 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
252 case CHART_INTERVAL_100MSEC:
253 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
254 newelem->next = chm.interval_100ms.callback_list;
255 chm.interval_100ms.callback_list = newelem;
256 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
257 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
259 case CHART_INTERVAL_1SEC:
260 pthread_mutex_lock(&chm.interval_1s.list_mutex);
261 newelem->next = chm.interval_1s.callback_list;
262 chm.interval_1s.callback_list = newelem;
263 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
264 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
272 static void remove_all_callback_list()
274 chart_interval_callback* cur;
276 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
277 while(chm.interval_10ms.callback_list != NULL)
279 cur = chm.interval_10ms.callback_list;
280 chm.interval_10ms.callback_list = cur->next;
283 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
285 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
286 while(chm.interval_100ms.callback_list != NULL)
288 cur = chm.interval_100ms.callback_list;
289 chm.interval_100ms.callback_list = cur->next;
292 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
294 pthread_mutex_lock(&chm.interval_1s.list_mutex);
295 while(chm.interval_1s.callback_list != NULL)
297 cur = chm.interval_1s.callback_list;
298 chm.interval_1s.callback_list = cur->next;
301 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
303 memset(&chm.interval_for_series, 0, sizeof(chm.interval_for_series));
304 __sync_and_and_fetch(&(gTraceInfo.custom_chart_callback_count), 0);
307 static void remove_from_callback_list(da_handle charthandle, da_handle series_handle)
309 chart_interval_callback *prev, *cur;
310 chart_interval interval;
312 interval = chm.interval_for_series[charthandle][series_handle % 10];
313 chm.interval_for_series[charthandle][series_handle % 10] = 0;
317 case CHART_INTERVAL_10MSEC:
318 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
321 cur = chm.interval_10ms.callback_list;
324 if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
327 prev->next = cur->next;
329 chm.interval_10ms.callback_list = cur->next;
331 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
340 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
342 case CHART_INTERVAL_100MSEC:
343 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
346 cur = chm.interval_100ms.callback_list;
349 if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
352 prev->next = cur->next;
354 chm.interval_100ms.callback_list = cur->next;
356 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
365 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
367 case CHART_INTERVAL_1SEC:
368 pthread_mutex_lock(&chm.interval_1s.list_mutex);
371 cur = chm.interval_1s.callback_list;
374 if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
377 prev->next = cur->next;
379 chm.interval_1s.callback_list = cur->next;
381 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
390 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
398 // =====================================================================
399 // constructor and destructor functions
400 // =====================================================================
402 void __attribute__((constructor)) _init_lib()
406 memset(&chm, 0, sizeof(chm));
407 chm.interval_10ms.timerfd = -1;
408 chm.interval_100ms.timerfd = -1;
409 chm.interval_1s.timerfd = -1;
410 chm.interval_10ms.thread_handle = -1;
411 chm.interval_100ms.thread_handle = -1;
412 chm.interval_1s.thread_handle = -1;
413 pthread_mutex_init(&chm.interval_10ms.list_mutex, NULL);
414 pthread_mutex_init(&chm.interval_100ms.list_mutex, NULL);
415 pthread_mutex_init(&chm.interval_1s.list_mutex, NULL);
420 void __attribute__((destructor)) _fini_lib()
424 remove_all_callback_list();
425 if(chm.interval_10ms.timerfd != -1)
426 close(chm.interval_10ms.timerfd);
427 if(chm.interval_100ms.timerfd != -1)
428 close(chm.interval_100ms.timerfd);
429 if(chm.interval_1s.timerfd != -1)
430 close(chm.interval_1s.timerfd);
432 if(chm.interval_10ms.thread_handle != -1)
434 pthread_join(chm.interval_10ms.thread_handle, NULL);
436 if(chm.interval_100ms.thread_handle != -1)
438 pthread_join(chm.interval_100ms.thread_handle, NULL);
440 if(chm.interval_1s.thread_handle != -1)
442 pthread_join(chm.interval_1s.thread_handle, NULL);
449 // =====================================================================
451 // =====================================================================
453 void da_mark(chart_color color, char* mark_text)
455 DECLARE_CHART_VARIABLE;
460 setProbePoint(&probeInfo);
461 APPEND_LOG_BASIC(LC_CUSTOM);
462 APPEND_LOG_INPUT("%s", "");
463 APPEND_LOG_CHART_RESULT(0);
464 APPEND_LOG_CHART(0, 0, mark_text, color, 0.0f);
465 printLog(&log, MSG_LOG);
468 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "dp", color, mark_text);
469 PACK_COMMON_END(0, 0, 2);
470 PACK_CUSTOM(0, 0, mark_text, color, 0.0f);
476 da_handle da_create_chart(char* chart_name)
478 DECLARE_CHART_VARIABLE;
480 // check if there is available chart handle slot
481 if(chm.chart_handle_index + 1 >= MAX_CHART_HANDLE)
482 return ERR_MAX_CHART_NUMBER;
484 // check if chart_name is null
485 if(chart_name == NULL)
486 return ERR_WRONG_PARAMETER;
489 ret = ++(chm.chart_handle_index);
492 setProbePoint(&probeInfo);
493 APPEND_LOG_BASIC(LC_CUSTOM);
494 APPEND_LOG_INPUT("%s", "");
495 APPEND_LOG_CHART_RESULT(ret);
496 APPEND_LOG_CHART(0, 0, chart_name, 0, 0.0f);
497 printLog(&log, MSG_LOG);
500 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "p", chart_name);
501 PACK_COMMON_END(ret, 0, 2);
502 PACK_CUSTOM(0, 0, chart_name, 0, 0.0f);
510 da_handle da_create_series(da_handle charthandle, char* seriesname,
511 series_type type, chart_color color)
513 DECLARE_CHART_VARIABLE;
515 // check if charthandle is valid handle or not
516 if(charthandle <= 0 || charthandle > chm.chart_handle_index)
517 return ERR_WRONG_HANDLE;
519 // chech if extra parameter is valid
520 if(seriesname == NULL)
521 return ERR_WRONG_PARAMETER;
523 // check if there is available series spot
524 if(chm.series_handle_index[(int)charthandle] + 1 >= MAX_SERIES_PER_CHART)
525 return ERR_MAX_CHART_NUMBER;
528 ret = ++(chm.series_handle_index[charthandle]);
529 ret += (10 * charthandle);
532 setProbePoint(&probeInfo);
533 APPEND_LOG_BASIC(LC_CUSTOM);
534 APPEND_LOG_INPUT("%s", "");
535 APPEND_LOG_CHART_RESULT(ret);
536 APPEND_LOG_CHART(charthandle, type, seriesname, color, 0.0f);
537 printLog(&log, MSG_LOG);
540 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "dpdd", charthandle, seriesname, type, color);
541 PACK_COMMON_END(ret, 0, 2);
542 PACK_CUSTOM(charthandle, type, seriesname, color, 0.0f);
550 da_handle da_create_default_series(da_handle charthandle, char* seriesname)
552 return da_create_series(charthandle, seriesname,
553 CHART_TYPE_AUTO, CHART_COLOR_AUTO);
556 int da_set_callback(da_handle series_handle, da_user_data_2_chart_data callback,
557 void* data_addr, chart_interval interval)
560 cindex = (int)(series_handle / 10);
561 sindex = series_handle % 10;
563 // check series handle
564 if(cindex <= 0 || cindex > chm.chart_handle_index)
565 return ERR_WRONG_HANDLE;
567 if(sindex > chm.series_handle_index[(int)cindex])
568 return ERR_WRONG_HANDLE;
570 // check rest parameters
571 if(interval == CHART_NO_CYCLE && callback != NULL)
572 return ERR_WRONG_PARAMETER;
576 // remove previously registered callback
577 remove_from_callback_list(cindex, series_handle);
579 // register new callback
582 add_to_callback_list(interval, cindex, series_handle, callback, data_addr);
583 start_callback_thread(interval);
590 void da_log(da_handle series_handle, float uservalue)
592 DECLARE_CHART_VARIABLE;
594 // chech if series handle is valid
596 cindex = (int)(series_handle / 10);
597 sindex = series_handle % 10;
599 if(cindex <= 0 || cindex > chm.chart_handle_index)
602 if(sindex > chm.series_handle_index[(int)cindex])
608 setProbePoint(&probeInfo);
609 APPEND_LOG_BASIC(LC_CUSTOM);
610 APPEND_LOG_INPUT("%s", "");
611 APPEND_LOG_CHART_RESULT(0);
612 APPEND_LOG_CHART(series_handle, 0, "", 0, uservalue);
613 printLog(&log, MSG_LOG);
616 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "dw", series_handle, uservalue);
617 PACK_COMMON_END(0, 0, 2);
618 PACK_CUSTOM(series_handle, 0, "", 0, uservalue);