4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
\r
8 * Jaewon Lim <jaewon81.lim@samsung.com>
\r
9 * Woojin Jung <woojin2.jung@samsung.com>
\r
10 * Juyoung Kim <j0.kim@samsung.com>
\r
12 * This library is free software; you can redistribute it and/or modify it under
\r
13 * the terms of the GNU Lesser General Public License as published by the
\r
14 * Free Software Foundation; either version 2.1 of the License, or (at your option)
\r
15 * any later version.
\r
17 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
\r
18 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
\r
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
\r
20 * License for more details.
\r
22 * You should have received a copy of the GNU Lesser General Public License
\r
23 * along with this library; if not, write to the Free Software Foundation, Inc., 51
\r
24 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
\r
31 #include <pthread.h>
\r
32 #include <signal.h> // for signal
\r
33 #include <unistd.h> // for ualarm, sleep
\r
34 #include <sys/timerfd.h> // for timerfd
\r
36 #include <errno.h> // for errno
\r
37 #include <string.h> // for memset
\r
38 #include <stdint.h> // for uint64_t
\r
40 #include "daprobe.h"
\r
41 #include "dahelper.h"
\r
42 #include "probeinfo.h"
\r
44 #include "da_chart.h"
\r
46 #define ERR_THREAD_CREATE_FAIL -2001 // thread creation fail
\r
48 #define MAX_TITLE_LENGTH 16
\r
49 #define MAX_CHART_HANDLE 10 // cannot be exceeded 10
\r
50 #define MAX_SERIES_PER_CHART 4 // cannot be exceeded 10
\r
51 // chart handle is from 1 to 9
\r
52 // series handle is from 11 to 99
\r
53 // series handle 32 means that the series is 2nd series in 3rd chart.
\r
54 // zero value handle means error
\r
56 // =====================================================================
\r
58 // =====================================================================
\r
60 typedef struct _chart_interval_callback
\r
62 da_handle chart_handle;
\r
63 da_handle series_handle;
\r
64 da_user_data_2_chart_data callback;
\r
66 struct _chart_interval_callback* next;
\r
67 } chart_interval_callback;
\r
72 pthread_t thread_handle;
\r
73 chart_interval_callback* callback_list;
\r
74 pthread_mutex_t list_mutex;
\r
79 int chart_handle_index;
\r
80 int series_handle_index[MAX_CHART_HANDLE];
\r
81 int interval_for_series[MAX_CHART_HANDLE][MAX_SERIES_PER_CHART];
\r
82 interval_manager interval_10ms;
\r
83 interval_manager interval_100ms;
\r
84 interval_manager interval_1s;
\r
85 } chart_handle_maintainer;
\r
87 chart_handle_maintainer chm;
\r
89 __thread pid_t cur_thread = -1;
\r
92 // =====================================================================
\r
93 // internal macro definition
\r
94 // =====================================================================
\r
96 #define DECLARE_CHART_VARIABLE \
\r
97 da_handle __attribute__((unused)) ret = 0; \
\r
98 probeInfo_t probeInfo; \
\r
101 #define APPEND_LOG_CHART_RESULT(RESULT) \
\r
102 log.length += sprintf(log.data + log.length, "`,%d`,0x%p`,0`,2", \
\r
103 RESULT, CALLER_ADDRESS)
\r
105 #define APPEND_LOG_CHART(HANDLE, TYPE, TEXT, COLOR, VALUE) \
\r
106 log.length += sprintf(log.data + log.length, "`,`,%d`,%d`,%s`,%d`,%.3f", \
\r
107 HANDLE, TYPE, TEXT, COLOR, VALUE)
\r
109 // =====================================================================
\r
110 // timer thread routine for callback
\r
111 // =====================================================================
\r
113 void* _chart_timerThread(void* data)
\r
115 DECLARE_CHART_VARIABLE;
\r
119 chart_interval_callback* cur;
\r
121 sigset_t profsigmask;
\r
122 interval_manager* pmanager = (interval_manager*)data;
\r
126 sigemptyset(&profsigmask);
\r
127 sigaddset(&profsigmask, SIGPROF);
\r
128 pthread_sigmask(SIG_BLOCK, &profsigmask, NULL);
\r
130 while((readsize = read(pmanager->timerfd, &exp, sizeof(uint64_t))) > 0)
\r
132 pthread_mutex_lock(&pmanager->list_mutex);
\r
134 cur = pmanager->callback_list;
\r
137 value = cur->callback(cur->user_data);
\r
140 setProbePoint(&probeInfo);
\r
141 log.length = sprintf(log.data, "%d`,%d`,%s`,%lu`,%d`,%d`,`,`,0x%p`,0`,2`,`,%d`,0`,`,0`,%.3f",
\r
142 LC_CUSTOM, probeInfo.eventIndex, __func__, probeInfo.currentTime, probeInfo.pID,
\r
143 probeInfo.tID, CALLER_ADDRESS, cur->series_handle, value);
\r
144 printLog(&log, MSG_LOG);
\r
149 pthread_mutex_unlock(&pmanager->list_mutex);
\r
159 static int start_callback_thread(chart_interval interval)
\r
161 int* timerfd = NULL;
\r
162 pthread_t* thread_handle = NULL;
\r
163 interval_manager* pman = NULL;
\r
164 struct itimerspec timevalue;
\r
166 if(interval == CHART_INTERVAL_10MSEC)
\r
168 timerfd = &(chm.interval_10ms.timerfd);
\r
169 thread_handle = &(chm.interval_10ms.thread_handle);
\r
170 pman = &(chm.interval_10ms);
\r
171 timevalue.it_value.tv_sec = 0;
\r
172 timevalue.it_value.tv_nsec = 10000000L;
\r
173 timevalue.it_interval.tv_sec = 0;
\r
174 timevalue.it_interval.tv_nsec = 10000000L;
\r
176 else if(interval == CHART_INTERVAL_100MSEC)
\r
178 timerfd = &(chm.interval_100ms.timerfd);
\r
179 thread_handle = &(chm.interval_100ms.thread_handle);
\r
180 pman = &(chm.interval_100ms);
\r
181 timevalue.it_value.tv_sec = 0;
\r
182 timevalue.it_value.tv_nsec = 100000000L;
\r
183 timevalue.it_interval.tv_sec = 0;
\r
184 timevalue.it_interval.tv_nsec = 100000000L;
\r
186 else if(interval == CHART_INTERVAL_1SEC)
\r
188 timerfd = &(chm.interval_1s.timerfd);
\r
189 thread_handle = &(chm.interval_1s.thread_handle);
\r
190 pman = &(chm.interval_1s);
\r
191 timevalue.it_value.tv_sec = 1;
\r
192 timevalue.it_value.tv_nsec = 0;
\r
193 timevalue.it_interval.tv_sec = 1;
\r
194 timevalue.it_interval.tv_nsec = 0;
\r
198 return ERR_WRONG_PARAMETER;
\r
201 if(*timerfd != -1 || *thread_handle != -1)
\r
202 return 0; // already thread exist
\r
204 *timerfd = timerfd_create(CLOCK_REALTIME, 0);
\r
208 if(timerfd_settime(*timerfd, 0, &timevalue, NULL) == -1)
\r
211 if(pthread_create(thread_handle, NULL, _chart_timerThread, pman) < 0)
\r
212 return ERR_THREAD_CREATE_FAIL;
\r
218 // =====================================================================
\r
219 // internal utility function
\r
220 // =====================================================================
\r
222 static void add_to_callback_list(chart_interval interval, da_handle charthandle, da_handle series_handle,
\r
223 da_user_data_2_chart_data callback, void* user_data)
\r
225 chart_interval_callback* newelem;
\r
227 newelem = (chart_interval_callback*)malloc(sizeof(chart_interval_callback));
\r
228 newelem->chart_handle = charthandle;
\r
229 newelem->series_handle = series_handle;
\r
230 newelem->callback = callback;
\r
231 newelem->user_data = user_data;
\r
233 chm.interval_for_series[charthandle][series_handle % 10] = interval;
\r
237 case CHART_INTERVAL_10MSEC:
\r
238 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
\r
239 newelem->next = chm.interval_10ms.callback_list;
\r
240 chm.interval_10ms.callback_list = newelem;
\r
241 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
\r
242 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
\r
244 case CHART_INTERVAL_100MSEC:
\r
245 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
\r
246 newelem->next = chm.interval_100ms.callback_list;
\r
247 chm.interval_100ms.callback_list = newelem;
\r
248 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
\r
249 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
\r
251 case CHART_INTERVAL_1SEC:
\r
252 pthread_mutex_lock(&chm.interval_1s.list_mutex);
\r
253 newelem->next = chm.interval_1s.callback_list;
\r
254 chm.interval_1s.callback_list = newelem;
\r
255 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
\r
256 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
\r
264 static void remove_all_callback_list()
\r
266 chart_interval_callback* cur;
\r
268 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
\r
269 while(chm.interval_10ms.callback_list != NULL)
\r
271 cur = chm.interval_10ms.callback_list;
\r
272 chm.interval_10ms.callback_list = cur->next;
\r
275 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
\r
277 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
\r
278 while(chm.interval_100ms.callback_list != NULL)
\r
280 cur = chm.interval_100ms.callback_list;
\r
281 chm.interval_100ms.callback_list = cur->next;
\r
284 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
\r
286 pthread_mutex_lock(&chm.interval_1s.list_mutex);
\r
287 while(chm.interval_1s.callback_list != NULL)
\r
289 cur = chm.interval_1s.callback_list;
\r
290 chm.interval_1s.callback_list = cur->next;
\r
293 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
\r
295 memset(&chm.interval_for_series, 0, sizeof(chm.interval_for_series));
\r
296 __sync_and_and_fetch(&(gTraceInfo.custom_chart_callback_count), 0);
\r
299 static void remove_from_callback_list(da_handle charthandle, da_handle series_handle)
\r
301 chart_interval_callback *prev, *cur;
\r
302 chart_interval interval;
\r
304 interval = chm.interval_for_series[charthandle][series_handle % 10];
\r
305 chm.interval_for_series[charthandle][series_handle % 10] = 0;
\r
309 case CHART_INTERVAL_10MSEC:
\r
310 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
\r
313 cur = chm.interval_10ms.callback_list;
\r
316 if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
\r
319 prev->next = cur->next;
\r
321 chm.interval_10ms.callback_list = cur->next;
\r
323 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
\r
332 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
\r
334 case CHART_INTERVAL_100MSEC:
\r
335 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
\r
338 cur = chm.interval_100ms.callback_list;
\r
341 if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
\r
344 prev->next = cur->next;
\r
346 chm.interval_100ms.callback_list = cur->next;
\r
348 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
\r
357 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
\r
359 case CHART_INTERVAL_1SEC:
\r
360 pthread_mutex_lock(&chm.interval_1s.list_mutex);
\r
363 cur = chm.interval_1s.callback_list;
\r
366 if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
\r
369 prev->next = cur->next;
\r
371 chm.interval_1s.callback_list = cur->next;
\r
373 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
\r
382 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
\r
390 // =====================================================================
\r
391 // constructor and destructor functions
\r
392 // =====================================================================
\r
394 void __attribute__((constructor)) _init_lib()
\r
398 memset(&chm, 0, sizeof(chm));
\r
399 chm.interval_10ms.timerfd = -1;
\r
400 chm.interval_100ms.timerfd = -1;
\r
401 chm.interval_1s.timerfd = -1;
\r
402 chm.interval_10ms.thread_handle = -1;
\r
403 chm.interval_100ms.thread_handle = -1;
\r
404 chm.interval_1s.thread_handle = -1;
\r
405 pthread_mutex_init(&chm.interval_10ms.list_mutex, NULL);
\r
406 pthread_mutex_init(&chm.interval_100ms.list_mutex, NULL);
\r
407 pthread_mutex_init(&chm.interval_1s.list_mutex, NULL);
\r
412 void __attribute__((destructor)) _fini_lib()
\r
416 remove_all_callback_list();
\r
417 if(chm.interval_10ms.timerfd != -1)
\r
418 close(chm.interval_10ms.timerfd);
\r
419 if(chm.interval_100ms.timerfd != -1)
\r
420 close(chm.interval_100ms.timerfd);
\r
421 if(chm.interval_1s.timerfd != -1)
\r
422 close(chm.interval_1s.timerfd);
\r
424 if(chm.interval_10ms.thread_handle != -1)
\r
426 pthread_join(chm.interval_10ms.thread_handle, NULL);
\r
428 if(chm.interval_100ms.thread_handle != -1)
\r
430 pthread_join(chm.interval_100ms.thread_handle, NULL);
\r
432 if(chm.interval_1s.thread_handle != -1)
\r
434 pthread_join(chm.interval_1s.thread_handle, NULL);
\r
441 // =====================================================================
\r
443 // =====================================================================
\r
445 void da_mark(chart_color color, char* mark_text)
\r
447 DECLARE_CHART_VARIABLE;
\r
452 setProbePoint(&probeInfo);
\r
453 APPEND_LOG_BASIC(LC_CUSTOM);
\r
454 APPEND_LOG_INPUT("%s", "");
\r
455 APPEND_LOG_CHART_RESULT(0);
\r
456 APPEND_LOG_CHART(0, 0, mark_text, color, 0.0f);
\r
457 printLog(&log, MSG_LOG);
\r
462 da_handle da_create_chart(char* chart_name)
\r
464 DECLARE_CHART_VARIABLE;
\r
466 // check if there is available chart handle slot
\r
467 if(chm.chart_handle_index + 1 >= MAX_CHART_HANDLE)
\r
468 return ERR_MAX_CHART_NUMBER;
\r
470 // check if chart_name is null
\r
471 if(chart_name == NULL)
\r
472 return ERR_WRONG_PARAMETER;
\r
475 ret = ++(chm.chart_handle_index);
\r
478 setProbePoint(&probeInfo);
\r
479 APPEND_LOG_BASIC(LC_CUSTOM);
\r
480 APPEND_LOG_INPUT("%s", "");
\r
481 APPEND_LOG_CHART_RESULT(ret);
\r
482 APPEND_LOG_CHART(0, 0, chart_name, 0, 0.0f);
\r
483 printLog(&log, MSG_LOG);
\r
490 da_handle da_create_series(da_handle charthandle, char* seriesname,
\r
491 series_type type, chart_color color)
\r
493 DECLARE_CHART_VARIABLE;
\r
495 // check if charthandle is valid handle or not
\r
496 if(charthandle <= 0 || charthandle > chm.chart_handle_index)
\r
497 return ERR_WRONG_HANDLE;
\r
499 // chech if extra parameter is valid
\r
500 if(seriesname == NULL)
\r
501 return ERR_WRONG_PARAMETER;
\r
503 // check if there is available series spot
\r
504 if(chm.series_handle_index[(int)charthandle] + 1 >= MAX_SERIES_PER_CHART)
\r
505 return ERR_MAX_CHART_NUMBER;
\r
508 ret = ++(chm.series_handle_index[charthandle]);
\r
509 ret += (10 * charthandle);
\r
512 setProbePoint(&probeInfo);
\r
513 APPEND_LOG_BASIC(LC_CUSTOM);
\r
514 APPEND_LOG_INPUT("%s", "");
\r
515 APPEND_LOG_CHART_RESULT(ret);
\r
516 APPEND_LOG_CHART(charthandle, type, seriesname, color, 0.0f);
\r
517 printLog(&log, MSG_LOG);
\r
524 da_handle da_create_default_series(da_handle charthandle, char* seriesname)
\r
526 return da_create_series(charthandle, seriesname,
\r
527 CHART_TYPE_AUTO, CHART_COLOR_AUTO);
\r
530 int da_set_callback(da_handle series_handle, da_user_data_2_chart_data callback,
\r
531 void* data_addr, chart_interval interval)
\r
533 int cindex, sindex;
\r
534 cindex = (int)(series_handle / 10);
\r
535 sindex = series_handle % 10;
\r
537 // check series handle
\r
538 if(cindex <= 0 || cindex > chm.chart_handle_index)
\r
539 return ERR_WRONG_HANDLE;
\r
541 if(sindex > chm.series_handle_index[(int)cindex])
\r
542 return ERR_WRONG_HANDLE;
\r
544 // check rest parameters
\r
545 if(interval == CHART_NO_CYCLE && callback != NULL)
\r
546 return ERR_WRONG_PARAMETER;
\r
550 // remove previously registered callback
\r
551 remove_from_callback_list(cindex, series_handle);
\r
553 // register new callback
\r
554 if(callback != NULL)
\r
556 add_to_callback_list(interval, cindex, series_handle, callback, data_addr);
\r
557 start_callback_thread(interval);
\r
564 void da_log(da_handle series_handle, float uservalue)
\r
566 DECLARE_CHART_VARIABLE;
\r
568 // chech if series handle is valid
\r
569 int cindex, sindex;
\r
570 cindex = (int)(series_handle / 10);
\r
571 sindex = series_handle % 10;
\r
573 if(cindex <= 0 || cindex > chm.chart_handle_index)
\r
576 if(sindex > chm.series_handle_index[(int)cindex])
\r
582 setProbePoint(&probeInfo);
\r
583 APPEND_LOG_BASIC(LC_CUSTOM);
\r
584 APPEND_LOG_INPUT("%s", "");
\r
585 APPEND_LOG_CHART_RESULT(0);
\r
586 APPEND_LOG_CHART(series_handle, 0, "", 0, uservalue);
\r
587 printLog(&log, MSG_LOG);
\r