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"
49 #include "real_functions.h"
51 #define ERR_THREAD_CREATE_FAIL -2001 // thread creation fail
53 #define MAX_TITLE_LENGTH 16
54 #define MAX_CHART_HANDLE 10 // cannot be exceeded 10
55 #define MAX_SERIES_PER_CHART 4 // cannot be exceeded 10
56 // chart handle is from 1 to 9
57 // series handle is from 11 to 99
58 // series handle 32 means that the series is 2nd series in 3rd chart.
59 // zero value handle means error
61 // =====================================================================
63 // =====================================================================
65 typedef struct _chart_interval_callback
67 da_handle chart_handle;
68 da_handle series_handle;
69 da_user_data_2_chart_data callback;
71 struct _chart_interval_callback* next;
72 } chart_interval_callback;
77 pthread_t thread_handle;
78 chart_interval_callback* callback_list;
79 pthread_mutex_t list_mutex;
84 int chart_handle_index;
85 int series_handle_index[MAX_CHART_HANDLE];
86 int interval_for_series[MAX_CHART_HANDLE][MAX_SERIES_PER_CHART];
87 interval_manager interval_10ms;
88 interval_manager interval_100ms;
89 interval_manager interval_1s;
90 } chart_handle_maintainer;
92 chart_handle_maintainer chm;
94 __thread pid_t cur_thread = -1;
97 // =====================================================================
98 // internal macro definition
99 // =====================================================================
101 #define DECLARE_CHART_VARIABLE \
102 da_handle __attribute__((unused)) ret = 0; \
103 probeInfo_t probeInfo;
105 // =====================================================================
106 // timer thread routine for callback
107 // =====================================================================
109 void* _chart_timerThread(void* data)
111 DECLARE_CHART_VARIABLE;
115 chart_interval_callback* cur;
117 sigset_t profsigmask;
118 interval_manager* pmanager = (interval_manager*)data;
122 sigemptyset(&profsigmask);
123 sigaddset(&profsigmask, SIGPROF);
124 pthread_sigmask(SIG_BLOCK, &profsigmask, NULL);
126 while((readsize = read(pmanager->timerfd, &exp, sizeof(uint64_t))) > 0)
128 pthread_mutex_lock(&pmanager->list_mutex);
130 cur = pmanager->callback_list;
133 value = cur->callback(cur->user_data);
135 setProbePoint(&probeInfo);
138 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
139 API_ID__chart_timerThread,
141 PACK_COMMON_END('p', 0, 0, 2);
142 PACK_CUSTOM(cur->series_handle, 0, "", 0, value);
148 pthread_mutex_unlock(&pmanager->list_mutex);
158 static int start_callback_thread(chart_interval interval)
161 pthread_t* thread_handle = NULL;
162 interval_manager* pman = NULL;
163 struct itimerspec timevalue;
165 if(interval == CHART_INTERVAL_10MSEC)
167 timerfd = &(chm.interval_10ms.timerfd);
168 thread_handle = &(chm.interval_10ms.thread_handle);
169 pman = &(chm.interval_10ms);
170 timevalue.it_value.tv_sec = 0;
171 timevalue.it_value.tv_nsec = 10000000L;
172 timevalue.it_interval.tv_sec = 0;
173 timevalue.it_interval.tv_nsec = 10000000L;
175 else if(interval == CHART_INTERVAL_100MSEC)
177 timerfd = &(chm.interval_100ms.timerfd);
178 thread_handle = &(chm.interval_100ms.thread_handle);
179 pman = &(chm.interval_100ms);
180 timevalue.it_value.tv_sec = 0;
181 timevalue.it_value.tv_nsec = 100000000L;
182 timevalue.it_interval.tv_sec = 0;
183 timevalue.it_interval.tv_nsec = 100000000L;
185 else if(interval == CHART_INTERVAL_1SEC)
187 timerfd = &(chm.interval_1s.timerfd);
188 thread_handle = &(chm.interval_1s.thread_handle);
189 pman = &(chm.interval_1s);
190 timevalue.it_value.tv_sec = 1;
191 timevalue.it_value.tv_nsec = 0;
192 timevalue.it_interval.tv_sec = 1;
193 timevalue.it_interval.tv_nsec = 0;
197 return ERR_WRONG_PARAMETER;
201 * FIXME: Type of pthread_t is undefined.
202 * Comparing it with -1 is *very* bad
204 if (*timerfd != -1 || *thread_handle != (pthread_t) -1)
205 return 0; // already thread exist
207 *timerfd = timerfd_create(CLOCK_REALTIME, 0);
211 if (timerfd_settime(*timerfd, 0, &timevalue, NULL) == -1)
214 if (pthread_create(thread_handle, NULL, _chart_timerThread, pman) < 0)
215 return ERR_THREAD_CREATE_FAIL;
221 // =====================================================================
222 // internal utility function
223 // =====================================================================
225 static void add_to_callback_list(chart_interval interval, da_handle charthandle, da_handle series_handle,
226 da_user_data_2_chart_data callback, void* user_data)
228 chart_interval_callback* newelem;
230 newelem = (chart_interval_callback*)real_malloc(sizeof(chart_interval_callback));
231 newelem->chart_handle = charthandle;
232 newelem->series_handle = series_handle;
233 newelem->callback = callback;
234 newelem->user_data = user_data;
236 chm.interval_for_series[charthandle][series_handle % 10] = interval;
240 case CHART_INTERVAL_10MSEC:
241 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
242 newelem->next = chm.interval_10ms.callback_list;
243 chm.interval_10ms.callback_list = newelem;
244 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
245 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
247 case CHART_INTERVAL_100MSEC:
248 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
249 newelem->next = chm.interval_100ms.callback_list;
250 chm.interval_100ms.callback_list = newelem;
251 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
252 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
254 case CHART_INTERVAL_1SEC:
255 pthread_mutex_lock(&chm.interval_1s.list_mutex);
256 newelem->next = chm.interval_1s.callback_list;
257 chm.interval_1s.callback_list = newelem;
258 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
259 __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
267 static void remove_all_callback_list()
269 chart_interval_callback* cur;
271 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
272 while(chm.interval_10ms.callback_list != NULL)
274 cur = chm.interval_10ms.callback_list;
275 chm.interval_10ms.callback_list = cur->next;
278 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
280 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
281 while(chm.interval_100ms.callback_list != NULL)
283 cur = chm.interval_100ms.callback_list;
284 chm.interval_100ms.callback_list = cur->next;
287 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
289 pthread_mutex_lock(&chm.interval_1s.list_mutex);
290 while(chm.interval_1s.callback_list != NULL)
292 cur = chm.interval_1s.callback_list;
293 chm.interval_1s.callback_list = cur->next;
296 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
298 memset(&chm.interval_for_series, 0, sizeof(chm.interval_for_series));
299 __sync_and_and_fetch(&(gTraceInfo.custom_chart_callback_count), 0);
302 static void remove_from_callback_list(da_handle charthandle, da_handle series_handle)
304 chart_interval_callback *prev, *cur;
305 chart_interval interval;
307 interval = chm.interval_for_series[charthandle][series_handle % 10];
308 chm.interval_for_series[charthandle][series_handle % 10] = 0;
312 case CHART_INTERVAL_10MSEC:
313 pthread_mutex_lock(&chm.interval_10ms.list_mutex);
316 cur = chm.interval_10ms.callback_list;
319 if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
322 prev->next = cur->next;
324 chm.interval_10ms.callback_list = cur->next;
326 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
335 pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
337 case CHART_INTERVAL_100MSEC:
338 pthread_mutex_lock(&chm.interval_100ms.list_mutex);
341 cur = chm.interval_100ms.callback_list;
344 if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
347 prev->next = cur->next;
349 chm.interval_100ms.callback_list = cur->next;
351 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
360 pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
362 case CHART_INTERVAL_1SEC:
363 pthread_mutex_lock(&chm.interval_1s.list_mutex);
366 cur = chm.interval_1s.callback_list;
369 if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
372 prev->next = cur->next;
374 chm.interval_1s.callback_list = cur->next;
376 __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
385 pthread_mutex_unlock(&chm.interval_1s.list_mutex);
393 // =====================================================================
394 // constructor and destructor functions
395 // =====================================================================
397 void __attribute__((constructor)) _init_lib()
401 memset(&chm, 0, sizeof(chm));
402 chm.interval_10ms.timerfd = -1;
403 chm.interval_100ms.timerfd = -1;
404 chm.interval_1s.timerfd = -1;
405 chm.interval_10ms.thread_handle = -1;
406 chm.interval_100ms.thread_handle = -1;
407 chm.interval_1s.thread_handle = -1;
408 pthread_mutex_init(&chm.interval_10ms.list_mutex, NULL);
409 pthread_mutex_init(&chm.interval_100ms.list_mutex, NULL);
410 pthread_mutex_init(&chm.interval_1s.list_mutex, NULL);
415 void __attribute__((destructor)) _fini_lib()
419 remove_all_callback_list();
420 if (chm.interval_10ms.timerfd != -1)
421 close(chm.interval_10ms.timerfd);
422 if (chm.interval_100ms.timerfd != -1)
423 close(chm.interval_100ms.timerfd);
424 if (chm.interval_1s.timerfd != -1)
425 close(chm.interval_1s.timerfd);
426 /*! Bad. Ugly. Unportable */
427 if (chm.interval_10ms.thread_handle != (pthread_t) -1)
428 pthread_join(chm.interval_10ms.thread_handle, NULL);
429 if (chm.interval_100ms.thread_handle != (pthread_t) -1)
430 pthread_join(chm.interval_100ms.thread_handle, NULL);
431 if (chm.interval_1s.thread_handle != (pthread_t) -1)
432 pthread_join(chm.interval_1s.thread_handle, NULL);
438 // =====================================================================
440 // =====================================================================
442 void da_mark(chart_color color, char* mark_text)
444 DECLARE_CHART_VARIABLE;
448 setProbePoint(&probeInfo);
451 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
453 "dp", color, voidp_to_uint64(mark_text));
454 PACK_COMMON_END('v', 0, 0, 2);
455 PACK_CUSTOM(0, 0, mark_text, color, 0.0f);
461 da_handle da_create_chart(char* chart_name)
463 DECLARE_CHART_VARIABLE;
465 // check if there is available chart handle slot
466 if(chm.chart_handle_index + 1 >= MAX_CHART_HANDLE)
467 return ERR_MAX_CHART_NUMBER;
469 // check if chart_name is null
470 if(chart_name == NULL)
471 return ERR_WRONG_PARAMETER;
474 ret = ++(chm.chart_handle_index);
476 setProbePoint(&probeInfo);
479 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
480 API_ID_da_create_chart,
481 "p", voidp_to_uint64(chart_name));
482 PACK_COMMON_END('d', ret, 0, 2);
483 PACK_CUSTOM(0, 0, chart_name, 0, 0.0f);
491 da_handle da_create_series(da_handle charthandle, char* seriesname,
492 series_type type, chart_color color)
494 DECLARE_CHART_VARIABLE;
496 // check if charthandle is valid handle or not
497 if(charthandle <= 0 || charthandle > chm.chart_handle_index)
498 return ERR_WRONG_HANDLE;
500 // chech if extra parameter is valid
501 if(seriesname == NULL)
502 return ERR_WRONG_PARAMETER;
504 // check if there is available series spot
505 if(chm.series_handle_index[(int)charthandle] + 1 >= MAX_SERIES_PER_CHART)
506 return ERR_MAX_CHART_NUMBER;
509 ret = ++(chm.series_handle_index[charthandle]);
510 ret += (10 * charthandle);
512 setProbePoint(&probeInfo);
515 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
516 API_ID_da_create_series,
517 "dpdd", charthandle, voidp_to_uint64(seriesname),
519 PACK_COMMON_END('d', ret, 0, 2);
520 PACK_CUSTOM(charthandle, type, seriesname, color, 0.0f);
528 da_handle da_create_default_series(da_handle charthandle, char* seriesname)
530 return da_create_series(charthandle, seriesname,
531 CHART_TYPE_AUTO, CHART_COLOR_AUTO);
534 int da_set_callback(da_handle series_handle, da_user_data_2_chart_data callback,
535 void* data_addr, chart_interval interval)
538 cindex = (int)(series_handle / 10);
539 sindex = series_handle % 10;
541 // check series handle
542 if(cindex <= 0 || cindex > chm.chart_handle_index)
543 return ERR_WRONG_HANDLE;
545 if(sindex > chm.series_handle_index[(int)cindex])
546 return ERR_WRONG_HANDLE;
548 // check rest parameters
549 if(interval == CHART_NO_CYCLE && callback != NULL)
550 return ERR_WRONG_PARAMETER;
554 // remove previously registered callback
555 remove_from_callback_list(cindex, series_handle);
557 // register new callback
561 add_to_callback_list(interval, cindex, series_handle, callback, data_addr);
562 re = start_callback_thread(interval);
563 PRINTMSG("start callback thread return %d\n", re);
570 void da_log(da_handle series_handle, float uservalue)
572 DECLARE_CHART_VARIABLE;
574 // chech if series handle is valid
576 cindex = (int)(series_handle / 10);
577 sindex = series_handle % 10;
579 if(cindex <= 0 || cindex > chm.chart_handle_index)
582 if(sindex > chm.series_handle_index[(int)cindex])
587 setProbePoint(&probeInfo);
590 PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM,
592 "df", series_handle, uservalue);
593 PACK_COMMON_END('v', 0, 0, 2);
594 PACK_CUSTOM(series_handle, 0, "", 0, uservalue);