set unix line endings instead of windows ones
[platform/core/system/swap-probe.git] / custom_chart / da_chart.c
index be39320..6012c1f 100755 (executable)
-/*\r
- *  DA probe\r
- *\r
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.\r
- *\r
- * Contact: \r
- *\r
- * Jaewon Lim <jaewon81.lim@samsung.com>\r
- * Woojin Jung <woojin2.jung@samsung.com>\r
- * Juyoung Kim <j0.kim@samsung.com>\r
- * \r
- * This library is free software; you can redistribute it and/or modify it under\r
- * the terms of the GNU Lesser General Public License as published by the\r
- * Free Software Foundation; either version 2.1 of the License, or (at your option)\r
- * any later version.\r
- * \r
- * This library is distributed in the hope that it will be useful, but WITHOUT ANY\r
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public\r
- * License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public License\r
- * along with this library; if not, write to the Free Software Foundation, Inc., 51\r
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
- *\r
- * Contributors:\r
- * - S-Core Co., Ltd\r
- * \r
- */\r
-\r
-#include <pthread.h>\r
-#include <signal.h>                    // for signal\r
-#include <unistd.h>                    // for ualarm, sleep\r
-#include <sys/timerfd.h>       // for timerfd\r
-#include <stdio.h>\r
-#include <errno.h>                     // for errno\r
-#include <string.h>                    // for memset\r
-#include <stdint.h>                    // for uint64_t\r
-\r
-#include "daprobe.h"\r
-#include "dahelper.h"\r
-#include "probeinfo.h"\r
-#define _USE_DA_\r
-#include "da_chart.h"\r
-\r
-#include "binproto.h"\r
-\r
-#define ERR_THREAD_CREATE_FAIL -2001   // thread creation fail\r
-\r
-#define MAX_TITLE_LENGTH               16\r
-#define MAX_CHART_HANDLE               10              // cannot be exceeded 10\r
-#define MAX_SERIES_PER_CHART   4               // cannot be exceeded 10\r
-// chart handle is  from 1 to 9\r
-// series handle is from 11 to 99\r
-// series handle 32 means that the series is 2nd series in 3rd chart.\r
-// zero value handle means error\r
-\r
-// =====================================================================\r
-// global variable\r
-// =====================================================================\r
-\r
-typedef struct _chart_interval_callback\r
-{\r
-       da_handle chart_handle;\r
-       da_handle series_handle;\r
-       da_user_data_2_chart_data callback;\r
-       void* user_data;\r
-       struct _chart_interval_callback* next;\r
-} chart_interval_callback;\r
-\r
-typedef struct\r
-{\r
-       int                     timerfd;\r
-       pthread_t       thread_handle;\r
-       chart_interval_callback*        callback_list;\r
-       pthread_mutex_t         list_mutex;\r
-} interval_manager;\r
-\r
-typedef struct\r
-{\r
-       int                     chart_handle_index;\r
-       int                     series_handle_index[MAX_CHART_HANDLE];\r
-       int                     interval_for_series[MAX_CHART_HANDLE][MAX_SERIES_PER_CHART];\r
-       interval_manager        interval_10ms;\r
-       interval_manager        interval_100ms;\r
-       interval_manager        interval_1s;\r
-} chart_handle_maintainer;\r
-\r
-chart_handle_maintainer chm;\r
-\r
-__thread pid_t cur_thread = -1;\r
-\r
-\r
-// =====================================================================\r
-// internal macro definition\r
-// =====================================================================\r
-\r
-#define DECLARE_CHART_VARIABLE                                 \\r
-       da_handle __attribute__((unused)) ret = 0;      \\r
-       probeInfo_t probeInfo;                                          \\r
-       log_t log\r
-\r
-#define APPEND_LOG_CHART_RESULT(RESULT)                                                                        \\r
-       log.length += sprintf(log.data + log.length, "`,%d`,0x%p`,0`,2",        \\r
-                       RESULT, CALLER_ADDRESS)\r
-\r
-#define APPEND_LOG_CHART(HANDLE, TYPE, TEXT, COLOR, VALUE)                                     \\r
-       log.length += sprintf(log.data + log.length, "`,`,%d`,%d`,%s`,%d`,%.3f",        \\r
-                       HANDLE, TYPE, TEXT, COLOR, VALUE)\r
-\r
-// =====================================================================\r
-// timer thread routine for callback\r
-// =====================================================================\r
-\r
-void* _chart_timerThread(void* data)\r
-{\r
-       DECLARE_CHART_VARIABLE;\r
-\r
-       uint64_t exp;\r
-       ssize_t readsize;\r
-       chart_interval_callback* cur;\r
-       float value;\r
-       sigset_t profsigmask;\r
-       interval_manager* pmanager = (interval_manager*)data;\r
-\r
-       probeBlockStart();\r
-\r
-       sigemptyset(&profsigmask);\r
-       sigaddset(&profsigmask, SIGPROF);\r
-       pthread_sigmask(SIG_BLOCK, &profsigmask, NULL);\r
-\r
-       while((readsize = read(pmanager->timerfd, &exp, sizeof(uint64_t))) > 0)\r
-       {\r
-               pthread_mutex_lock(&pmanager->list_mutex);\r
-\r
-               cur = pmanager->callback_list;\r
-               while(cur != NULL)\r
-               {\r
-                       value = cur->callback(cur->user_data);\r
-\r
-                       INIT_LOG;\r
-                       setProbePoint(&probeInfo);\r
-                       log.length = sprintf(log.data, "%d`,%d`,%s`,%lu`,%d`,%d`,`,`,0x%p`,0`,2`,`,%d`,0`,`,0`,%.3f",\r
-                                       LC_CUSTOM, probeInfo.eventIndex, __func__, probeInfo.currentTime, probeInfo.pID,\r
-                                       probeInfo.tID, CALLER_ADDRESS, cur->series_handle, value);\r
-                       printLog(&log, MSG_LOG);\r
-\r
-                       PREPARE_LOCAL_BUF();\r
-                       PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "", 0);\r
-                       PACK_COMMON_END(0, 0, 2);\r
-                       PACK_CUSTOM(cur->series_handle, 0, "", 0, value);\r
-                       FLUSH_LOCAL_BUF();\r
-\r
-                       cur = cur->next;\r
-               }\r
-\r
-               pthread_mutex_unlock(&pmanager->list_mutex);\r
-\r
-               sleep(0);\r
-       }\r
-\r
-       probeBlockEnd();\r
-\r
-       return NULL;\r
-}\r
-\r
-static int start_callback_thread(chart_interval interval)\r
-{\r
-       int* timerfd = NULL;\r
-       pthread_t* thread_handle = NULL;\r
-       interval_manager* pman = NULL;\r
-       struct itimerspec timevalue;\r
-\r
-       if(interval == CHART_INTERVAL_10MSEC)\r
-       {\r
-               timerfd = &(chm.interval_10ms.timerfd);\r
-               thread_handle = &(chm.interval_10ms.thread_handle);\r
-               pman = &(chm.interval_10ms);\r
-               timevalue.it_value.tv_sec = 0;\r
-               timevalue.it_value.tv_nsec = 10000000L;\r
-               timevalue.it_interval.tv_sec = 0;\r
-               timevalue.it_interval.tv_nsec = 10000000L;\r
-       }\r
-       else if(interval == CHART_INTERVAL_100MSEC)\r
-       {\r
-               timerfd = &(chm.interval_100ms.timerfd);\r
-               thread_handle = &(chm.interval_100ms.thread_handle);\r
-               pman = &(chm.interval_100ms);\r
-               timevalue.it_value.tv_sec = 0;\r
-               timevalue.it_value.tv_nsec = 100000000L;\r
-               timevalue.it_interval.tv_sec = 0;\r
-               timevalue.it_interval.tv_nsec = 100000000L;\r
-       }\r
-       else if(interval == CHART_INTERVAL_1SEC)\r
-       {\r
-               timerfd = &(chm.interval_1s.timerfd);\r
-               thread_handle = &(chm.interval_1s.thread_handle);\r
-               pman = &(chm.interval_1s);\r
-               timevalue.it_value.tv_sec = 1;\r
-               timevalue.it_value.tv_nsec = 0;\r
-               timevalue.it_interval.tv_sec = 1;\r
-               timevalue.it_interval.tv_nsec = 0;\r
-       }\r
-       else\r
-       {\r
-               return ERR_WRONG_PARAMETER;\r
-       }\r
-\r
-       if(*timerfd != -1 || *thread_handle != -1)\r
-               return 0;               // already thread exist\r
-\r
-       *timerfd = timerfd_create(CLOCK_REALTIME, 0);\r
-       if(*timerfd == -1)\r
-               return errno;\r
-\r
-       if(timerfd_settime(*timerfd, 0, &timevalue, NULL) == -1)\r
-               return errno;\r
-\r
-       if(pthread_create(thread_handle, NULL, _chart_timerThread, pman) < 0)\r
-               return ERR_THREAD_CREATE_FAIL;\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-// =====================================================================\r
-// internal utility function\r
-// =====================================================================\r
-\r
-static void add_to_callback_list(chart_interval interval, da_handle charthandle, da_handle series_handle,\r
-               da_user_data_2_chart_data callback, void* user_data)\r
-{\r
-       chart_interval_callback* newelem;\r
-       \r
-       newelem = (chart_interval_callback*)malloc(sizeof(chart_interval_callback));\r
-       newelem->chart_handle = charthandle;\r
-       newelem->series_handle = series_handle;\r
-       newelem->callback = callback;\r
-       newelem->user_data = user_data;\r
-\r
-       chm.interval_for_series[charthandle][series_handle % 10] = interval;\r
-       \r
-       switch(interval)\r
-       {\r
-       case CHART_INTERVAL_10MSEC:\r
-               pthread_mutex_lock(&chm.interval_10ms.list_mutex);\r
-               newelem->next = chm.interval_10ms.callback_list;\r
-               chm.interval_10ms.callback_list = newelem;\r
-               pthread_mutex_unlock(&chm.interval_10ms.list_mutex);\r
-               __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);\r
-               break;\r
-       case CHART_INTERVAL_100MSEC:\r
-               pthread_mutex_lock(&chm.interval_100ms.list_mutex);\r
-               newelem->next = chm.interval_100ms.callback_list;\r
-               chm.interval_100ms.callback_list = newelem;\r
-               pthread_mutex_unlock(&chm.interval_100ms.list_mutex);\r
-               __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);\r
-               break;\r
-       case CHART_INTERVAL_1SEC:\r
-               pthread_mutex_lock(&chm.interval_1s.list_mutex);\r
-               newelem->next = chm.interval_1s.callback_list;\r
-               chm.interval_1s.callback_list = newelem;\r
-               pthread_mutex_unlock(&chm.interval_1s.list_mutex);\r
-               __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);\r
-               break;\r
-       default:\r
-               free(newelem);\r
-               break;\r
-       }\r
-}\r
-\r
-static void remove_all_callback_list()\r
-{\r
-       chart_interval_callback* cur;\r
-       \r
-       pthread_mutex_lock(&chm.interval_10ms.list_mutex);\r
-       while(chm.interval_10ms.callback_list != NULL)\r
-       {\r
-               cur = chm.interval_10ms.callback_list;\r
-               chm.interval_10ms.callback_list = cur->next;\r
-               free(cur);\r
-       }\r
-       pthread_mutex_unlock(&chm.interval_10ms.list_mutex);\r
-\r
-       pthread_mutex_lock(&chm.interval_100ms.list_mutex);\r
-       while(chm.interval_100ms.callback_list != NULL)\r
-       {\r
-               cur = chm.interval_100ms.callback_list;\r
-               chm.interval_100ms.callback_list = cur->next;\r
-               free(cur);\r
-       }\r
-       pthread_mutex_unlock(&chm.interval_100ms.list_mutex);\r
-\r
-       pthread_mutex_lock(&chm.interval_1s.list_mutex);\r
-       while(chm.interval_1s.callback_list != NULL)\r
-       {\r
-               cur = chm.interval_1s.callback_list;\r
-               chm.interval_1s.callback_list = cur->next;\r
-               free(cur);\r
-       }\r
-       pthread_mutex_unlock(&chm.interval_1s.list_mutex);\r
-\r
-       memset(&chm.interval_for_series, 0, sizeof(chm.interval_for_series));\r
-       __sync_and_and_fetch(&(gTraceInfo.custom_chart_callback_count), 0);\r
-}\r
-\r
-static void remove_from_callback_list(da_handle charthandle, da_handle series_handle)\r
-{\r
-       chart_interval_callback *prev, *cur;\r
-       chart_interval interval;\r
-\r
-       interval = chm.interval_for_series[charthandle][series_handle % 10];\r
-       chm.interval_for_series[charthandle][series_handle % 10] = 0;\r
-\r
-       switch(interval)\r
-       {\r
-       case CHART_INTERVAL_10MSEC:\r
-               pthread_mutex_lock(&chm.interval_10ms.list_mutex);\r
-\r
-               prev = NULL;\r
-               cur = chm.interval_10ms.callback_list;\r
-               while(cur != NULL)\r
-               {\r
-                       if(cur->chart_handle == charthandle && cur->series_handle == series_handle)\r
-                       {\r
-                               if(prev)\r
-                                       prev->next = cur->next;\r
-                               else\r
-                                       chm.interval_10ms.callback_list = cur->next;\r
-\r
-                               __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);\r
-                               free(cur);\r
-                               break;\r
-                       }\r
-\r
-                       prev = cur;\r
-                       cur = cur->next;\r
-               }\r
-\r
-               pthread_mutex_unlock(&chm.interval_10ms.list_mutex);\r
-               break;\r
-       case CHART_INTERVAL_100MSEC:\r
-               pthread_mutex_lock(&chm.interval_100ms.list_mutex);\r
-\r
-               prev = NULL;\r
-               cur = chm.interval_100ms.callback_list;\r
-               while(cur != NULL)\r
-               {\r
-                       if(cur->chart_handle == charthandle && cur->series_handle == series_handle)\r
-                       {\r
-                               if(prev)\r
-                                       prev->next = cur->next;\r
-                               else\r
-                                       chm.interval_100ms.callback_list = cur->next;\r
-\r
-                               __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);\r
-                               free(cur);\r
-                               break;\r
-                       }\r
-\r
-                       prev = cur;\r
-                       cur = cur->next;\r
-               }\r
-\r
-               pthread_mutex_unlock(&chm.interval_100ms.list_mutex);\r
-               break;\r
-       case CHART_INTERVAL_1SEC:\r
-               pthread_mutex_lock(&chm.interval_1s.list_mutex);\r
-\r
-               prev = NULL;\r
-               cur = chm.interval_1s.callback_list;\r
-               while(cur != NULL)\r
-               {\r
-                       if(cur->chart_handle == charthandle && cur->series_handle == series_handle)\r
-                       {\r
-                               if(prev)\r
-                                       prev->next = cur->next;\r
-                               else\r
-                                       chm.interval_1s.callback_list = cur->next;\r
-\r
-                               __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);\r
-                               free(cur);\r
-                               break;\r
-                       }\r
-\r
-                       prev = cur;\r
-                       cur = cur->next;\r
-               }\r
-\r
-               pthread_mutex_unlock(&chm.interval_1s.list_mutex);\r
-               break;\r
-       default:\r
-               break;\r
-       }\r
-}\r
-\r
-\r
-// =====================================================================\r
-// constructor and destructor functions\r
-// =====================================================================\r
-\r
-void __attribute__((constructor)) _init_lib()\r
-{\r
-       probeBlockStart();\r
-\r
-       memset(&chm, 0, sizeof(chm));\r
-       chm.interval_10ms.timerfd = -1;\r
-       chm.interval_100ms.timerfd = -1;\r
-       chm.interval_1s.timerfd = -1;\r
-       chm.interval_10ms.thread_handle = -1;\r
-       chm.interval_100ms.thread_handle = -1;\r
-       chm.interval_1s.thread_handle = -1;\r
-       pthread_mutex_init(&chm.interval_10ms.list_mutex, NULL);\r
-       pthread_mutex_init(&chm.interval_100ms.list_mutex, NULL);\r
-       pthread_mutex_init(&chm.interval_1s.list_mutex, NULL);\r
-\r
-       probeBlockEnd();\r
-}\r
-\r
-void __attribute__((destructor)) _fini_lib()\r
-{\r
-       probeBlockStart();\r
-\r
-       remove_all_callback_list();\r
-       if(chm.interval_10ms.timerfd != -1)\r
-               close(chm.interval_10ms.timerfd);\r
-       if(chm.interval_100ms.timerfd != -1)\r
-               close(chm.interval_100ms.timerfd);\r
-       if(chm.interval_1s.timerfd != -1)\r
-               close(chm.interval_1s.timerfd);\r
-\r
-       if(chm.interval_10ms.thread_handle != -1)\r
-       {\r
-               pthread_join(chm.interval_10ms.thread_handle, NULL);\r
-       }\r
-       if(chm.interval_100ms.thread_handle != -1)\r
-       {\r
-               pthread_join(chm.interval_100ms.thread_handle, NULL);\r
-       }\r
-       if(chm.interval_1s.thread_handle != -1)\r
-       {\r
-               pthread_join(chm.interval_1s.thread_handle, NULL);\r
-       }\r
-\r
-       probeBlockEnd();\r
-}\r
-\r
-\r
-// =====================================================================\r
-// api definition\r
-// =====================================================================\r
-\r
-void da_mark(chart_color color, char* mark_text)\r
-{\r
-       DECLARE_CHART_VARIABLE;\r
-       \r
-       probeBlockStart();\r
-       \r
-       INIT_LOG;\r
-       setProbePoint(&probeInfo);\r
-       APPEND_LOG_BASIC(LC_CUSTOM);\r
-       APPEND_LOG_INPUT("%s", "");\r
-       APPEND_LOG_CHART_RESULT(0);\r
-       APPEND_LOG_CHART(0, 0, mark_text, color, 0.0f);\r
-       printLog(&log, MSG_LOG);\r
-\r
-       PREPARE_LOCAL_BUF();\r
-       PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "dp", color, mark_text);\r
-       PACK_COMMON_END(0, 0, 2);\r
-       PACK_CUSTOM(0, 0, mark_text, color, 0.0f);\r
-       FLUSH_LOCAL_BUF();\r
-\r
-       probeBlockEnd();\r
-}\r
-\r
-da_handle da_create_chart(char* chart_name)\r
-{\r
-       DECLARE_CHART_VARIABLE;\r
-\r
-       // check if there is available chart handle slot\r
-       if(chm.chart_handle_index + 1 >= MAX_CHART_HANDLE)\r
-               return ERR_MAX_CHART_NUMBER;\r
-               \r
-       // check if chart_name is null\r
-       if(chart_name == NULL)\r
-               return ERR_WRONG_PARAMETER;\r
-               \r
-       probeBlockStart();\r
-       ret = ++(chm.chart_handle_index);\r
-\r
-       INIT_LOG;\r
-       setProbePoint(&probeInfo);\r
-       APPEND_LOG_BASIC(LC_CUSTOM);\r
-       APPEND_LOG_INPUT("%s", "");\r
-       APPEND_LOG_CHART_RESULT(ret);\r
-       APPEND_LOG_CHART(0, 0, chart_name, 0, 0.0f);\r
-       printLog(&log, MSG_LOG);\r
-\r
-       PREPARE_LOCAL_BUF();\r
-       PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "p", chart_name);\r
-       PACK_COMMON_END(ret, 0, 2);\r
-       PACK_CUSTOM(0, 0, chart_name, 0, 0.0f);\r
-       FLUSH_LOCAL_BUF();\r
-       \r
-       probeBlockEnd();\r
-       \r
-       return ret;\r
-}\r
-\r
-da_handle da_create_series(da_handle charthandle, char* seriesname,\r
-               series_type type, chart_color color)\r
-{\r
-       DECLARE_CHART_VARIABLE;\r
-       \r
-       // check if charthandle is valid handle or not\r
-       if(charthandle <= 0 || charthandle > chm.chart_handle_index)\r
-               return ERR_WRONG_HANDLE;\r
-               \r
-       // chech if extra parameter is valid\r
-       if(seriesname == NULL)\r
-               return ERR_WRONG_PARAMETER;\r
-\r
-       // check if there is available series spot\r
-       if(chm.series_handle_index[(int)charthandle] + 1 >= MAX_SERIES_PER_CHART)\r
-               return ERR_MAX_CHART_NUMBER;\r
-       \r
-       probeBlockStart();\r
-       ret = ++(chm.series_handle_index[charthandle]);\r
-       ret += (10 * charthandle);\r
-       \r
-       INIT_LOG;\r
-       setProbePoint(&probeInfo);\r
-       APPEND_LOG_BASIC(LC_CUSTOM);\r
-       APPEND_LOG_INPUT("%s", "");\r
-       APPEND_LOG_CHART_RESULT(ret);\r
-       APPEND_LOG_CHART(charthandle, type, seriesname, color, 0.0f);\r
-       printLog(&log, MSG_LOG);\r
-\r
-       PREPARE_LOCAL_BUF();\r
-       PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "dpdd",  charthandle, seriesname, type, color);\r
-       PACK_COMMON_END(ret, 0, 2);\r
-       PACK_CUSTOM(charthandle, type, seriesname, color, 0.0f);\r
-       FLUSH_LOCAL_BUF();\r
-\r
-       probeBlockEnd();\r
-       \r
-       return ret;\r
-}\r
-               \r
-da_handle da_create_default_series(da_handle charthandle, char* seriesname)\r
-{\r
-       return da_create_series(charthandle, seriesname,\r
-                       CHART_TYPE_AUTO, CHART_COLOR_AUTO);\r
-}\r
-\r
-int da_set_callback(da_handle series_handle, da_user_data_2_chart_data callback,\r
-               void* data_addr, chart_interval interval)\r
-{\r
-       int cindex, sindex;\r
-       cindex = (int)(series_handle / 10);\r
-       sindex = series_handle % 10;\r
-       \r
-       // check series handle\r
-       if(cindex <= 0 || cindex > chm.chart_handle_index)\r
-               return ERR_WRONG_HANDLE;\r
-       \r
-       if(sindex > chm.series_handle_index[(int)cindex])\r
-               return ERR_WRONG_HANDLE;\r
-       \r
-       // check rest parameters\r
-       if(interval == CHART_NO_CYCLE && callback != NULL)\r
-               return ERR_WRONG_PARAMETER;\r
-\r
-       probeBlockStart();\r
-\r
-       // remove previously registered callback\r
-       remove_from_callback_list(cindex, series_handle);\r
-\r
-       // register new callback\r
-       if(callback != NULL)\r
-       {\r
-               add_to_callback_list(interval, cindex, series_handle, callback, data_addr);\r
-               start_callback_thread(interval);\r
-       }\r
-       probeBlockEnd();\r
-\r
-       return 0;\r
-}\r
-\r
-void da_log(da_handle series_handle, float uservalue)\r
-{\r
-       DECLARE_CHART_VARIABLE;\r
-       \r
-       // chech if series handle is valid\r
-       int cindex, sindex;\r
-       cindex = (int)(series_handle / 10);\r
-       sindex = series_handle % 10;\r
-       \r
-       if(cindex <= 0 || cindex > chm.chart_handle_index)\r
-               return;\r
-       \r
-       if(sindex > chm.series_handle_index[(int)cindex])\r
-               return;\r
-       \r
-       probeBlockStart();\r
-       \r
-       INIT_LOG;\r
-       setProbePoint(&probeInfo);\r
-       APPEND_LOG_BASIC(LC_CUSTOM);\r
-       APPEND_LOG_INPUT("%s", "");\r
-       APPEND_LOG_CHART_RESULT(0);\r
-       APPEND_LOG_CHART(series_handle, 0, "", 0, uservalue);\r
-       printLog(&log, MSG_LOG);\r
-\r
-       PREPARE_LOCAL_BUF();\r
-       PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "dw", series_handle, uservalue);\r
-       PACK_COMMON_END(0, 0, 2);\r
-       PACK_CUSTOM(series_handle, 0, "", 0, uservalue);\r
-       FLUSH_LOCAL_BUF();\r
-       \r
-       probeBlockEnd();\r
-}\r
+/*
+ *  DA probe
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ *
+ * Jaewon Lim <jaewon81.lim@samsung.com>
+ * Woojin Jung <woojin2.jung@samsung.com>
+ * Juyoung Kim <j0.kim@samsung.com>
+ * 
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
+ * 
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ * 
+ */
+
+#include <pthread.h>
+#include <signal.h>                    // for signal
+#include <unistd.h>                    // for ualarm, sleep
+#include <sys/timerfd.h>       // for timerfd
+#include <stdio.h>
+#include <errno.h>                     // for errno
+#include <string.h>                    // for memset
+#include <stdint.h>                    // for uint64_t
+
+#include "daprobe.h"
+#include "dahelper.h"
+#include "probeinfo.h"
+#define _USE_DA_
+#include "da_chart.h"
+
+#include "binproto.h"
+
+#define ERR_THREAD_CREATE_FAIL -2001   // thread creation fail
+
+#define MAX_TITLE_LENGTH               16
+#define MAX_CHART_HANDLE               10              // cannot be exceeded 10
+#define MAX_SERIES_PER_CHART   4               // cannot be exceeded 10
+// chart handle is  from 1 to 9
+// series handle is from 11 to 99
+// series handle 32 means that the series is 2nd series in 3rd chart.
+// zero value handle means error
+
+// =====================================================================
+// global variable
+// =====================================================================
+
+typedef struct _chart_interval_callback
+{
+       da_handle chart_handle;
+       da_handle series_handle;
+       da_user_data_2_chart_data callback;
+       void* user_data;
+       struct _chart_interval_callback* next;
+} chart_interval_callback;
+
+typedef struct
+{
+       int                     timerfd;
+       pthread_t       thread_handle;
+       chart_interval_callback*        callback_list;
+       pthread_mutex_t         list_mutex;
+} interval_manager;
+
+typedef struct
+{
+       int                     chart_handle_index;
+       int                     series_handle_index[MAX_CHART_HANDLE];
+       int                     interval_for_series[MAX_CHART_HANDLE][MAX_SERIES_PER_CHART];
+       interval_manager        interval_10ms;
+       interval_manager        interval_100ms;
+       interval_manager        interval_1s;
+} chart_handle_maintainer;
+
+chart_handle_maintainer chm;
+
+__thread pid_t cur_thread = -1;
+
+
+// =====================================================================
+// internal macro definition
+// =====================================================================
+
+#define DECLARE_CHART_VARIABLE                                 \
+       da_handle __attribute__((unused)) ret = 0;      \
+       probeInfo_t probeInfo;                                          \
+       log_t log
+
+#define APPEND_LOG_CHART_RESULT(RESULT)                                                                        \
+       log.length += sprintf(log.data + log.length, "`,%d`,0x%p`,0`,2",        \
+                       RESULT, CALLER_ADDRESS)
+
+#define APPEND_LOG_CHART(HANDLE, TYPE, TEXT, COLOR, VALUE)                                     \
+       log.length += sprintf(log.data + log.length, "`,`,%d`,%d`,%s`,%d`,%.3f",        \
+                       HANDLE, TYPE, TEXT, COLOR, VALUE)
+
+// =====================================================================
+// timer thread routine for callback
+// =====================================================================
+
+void* _chart_timerThread(void* data)
+{
+       DECLARE_CHART_VARIABLE;
+
+       uint64_t exp;
+       ssize_t readsize;
+       chart_interval_callback* cur;
+       float value;
+       sigset_t profsigmask;
+       interval_manager* pmanager = (interval_manager*)data;
+
+       probeBlockStart();
+
+       sigemptyset(&profsigmask);
+       sigaddset(&profsigmask, SIGPROF);
+       pthread_sigmask(SIG_BLOCK, &profsigmask, NULL);
+
+       while((readsize = read(pmanager->timerfd, &exp, sizeof(uint64_t))) > 0)
+       {
+               pthread_mutex_lock(&pmanager->list_mutex);
+
+               cur = pmanager->callback_list;
+               while(cur != NULL)
+               {
+                       value = cur->callback(cur->user_data);
+
+                       INIT_LOG;
+                       setProbePoint(&probeInfo);
+                       log.length = sprintf(log.data, "%d`,%d`,%s`,%lu`,%d`,%d`,`,`,0x%p`,0`,2`,`,%d`,0`,`,0`,%.3f",
+                                       LC_CUSTOM, probeInfo.eventIndex, __func__, probeInfo.currentTime, probeInfo.pID,
+                                       probeInfo.tID, CALLER_ADDRESS, cur->series_handle, value);
+                       printLog(&log, MSG_LOG);
+
+                       PREPARE_LOCAL_BUF();
+                       PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "", 0);
+                       PACK_COMMON_END(0, 0, 2);
+                       PACK_CUSTOM(cur->series_handle, 0, "", 0, value);
+                       FLUSH_LOCAL_BUF();
+
+                       cur = cur->next;
+               }
+
+               pthread_mutex_unlock(&pmanager->list_mutex);
+
+               sleep(0);
+       }
+
+       probeBlockEnd();
+
+       return NULL;
+}
+
+static int start_callback_thread(chart_interval interval)
+{
+       int* timerfd = NULL;
+       pthread_t* thread_handle = NULL;
+       interval_manager* pman = NULL;
+       struct itimerspec timevalue;
+
+       if(interval == CHART_INTERVAL_10MSEC)
+       {
+               timerfd = &(chm.interval_10ms.timerfd);
+               thread_handle = &(chm.interval_10ms.thread_handle);
+               pman = &(chm.interval_10ms);
+               timevalue.it_value.tv_sec = 0;
+               timevalue.it_value.tv_nsec = 10000000L;
+               timevalue.it_interval.tv_sec = 0;
+               timevalue.it_interval.tv_nsec = 10000000L;
+       }
+       else if(interval == CHART_INTERVAL_100MSEC)
+       {
+               timerfd = &(chm.interval_100ms.timerfd);
+               thread_handle = &(chm.interval_100ms.thread_handle);
+               pman = &(chm.interval_100ms);
+               timevalue.it_value.tv_sec = 0;
+               timevalue.it_value.tv_nsec = 100000000L;
+               timevalue.it_interval.tv_sec = 0;
+               timevalue.it_interval.tv_nsec = 100000000L;
+       }
+       else if(interval == CHART_INTERVAL_1SEC)
+       {
+               timerfd = &(chm.interval_1s.timerfd);
+               thread_handle = &(chm.interval_1s.thread_handle);
+               pman = &(chm.interval_1s);
+               timevalue.it_value.tv_sec = 1;
+               timevalue.it_value.tv_nsec = 0;
+               timevalue.it_interval.tv_sec = 1;
+               timevalue.it_interval.tv_nsec = 0;
+       }
+       else
+       {
+               return ERR_WRONG_PARAMETER;
+       }
+
+       if(*timerfd != -1 || *thread_handle != -1)
+               return 0;               // already thread exist
+
+       *timerfd = timerfd_create(CLOCK_REALTIME, 0);
+       if(*timerfd == -1)
+               return errno;
+
+       if(timerfd_settime(*timerfd, 0, &timevalue, NULL) == -1)
+               return errno;
+
+       if(pthread_create(thread_handle, NULL, _chart_timerThread, pman) < 0)
+               return ERR_THREAD_CREATE_FAIL;
+
+       return 0;
+}
+
+
+// =====================================================================
+// internal utility function
+// =====================================================================
+
+static void add_to_callback_list(chart_interval interval, da_handle charthandle, da_handle series_handle,
+               da_user_data_2_chart_data callback, void* user_data)
+{
+       chart_interval_callback* newelem;
+       
+       newelem = (chart_interval_callback*)malloc(sizeof(chart_interval_callback));
+       newelem->chart_handle = charthandle;
+       newelem->series_handle = series_handle;
+       newelem->callback = callback;
+       newelem->user_data = user_data;
+
+       chm.interval_for_series[charthandle][series_handle % 10] = interval;
+       
+       switch(interval)
+       {
+       case CHART_INTERVAL_10MSEC:
+               pthread_mutex_lock(&chm.interval_10ms.list_mutex);
+               newelem->next = chm.interval_10ms.callback_list;
+               chm.interval_10ms.callback_list = newelem;
+               pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
+               __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
+               break;
+       case CHART_INTERVAL_100MSEC:
+               pthread_mutex_lock(&chm.interval_100ms.list_mutex);
+               newelem->next = chm.interval_100ms.callback_list;
+               chm.interval_100ms.callback_list = newelem;
+               pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
+               __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
+               break;
+       case CHART_INTERVAL_1SEC:
+               pthread_mutex_lock(&chm.interval_1s.list_mutex);
+               newelem->next = chm.interval_1s.callback_list;
+               chm.interval_1s.callback_list = newelem;
+               pthread_mutex_unlock(&chm.interval_1s.list_mutex);
+               __sync_add_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
+               break;
+       default:
+               free(newelem);
+               break;
+       }
+}
+
+static void remove_all_callback_list()
+{
+       chart_interval_callback* cur;
+       
+       pthread_mutex_lock(&chm.interval_10ms.list_mutex);
+       while(chm.interval_10ms.callback_list != NULL)
+       {
+               cur = chm.interval_10ms.callback_list;
+               chm.interval_10ms.callback_list = cur->next;
+               free(cur);
+       }
+       pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
+
+       pthread_mutex_lock(&chm.interval_100ms.list_mutex);
+       while(chm.interval_100ms.callback_list != NULL)
+       {
+               cur = chm.interval_100ms.callback_list;
+               chm.interval_100ms.callback_list = cur->next;
+               free(cur);
+       }
+       pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
+
+       pthread_mutex_lock(&chm.interval_1s.list_mutex);
+       while(chm.interval_1s.callback_list != NULL)
+       {
+               cur = chm.interval_1s.callback_list;
+               chm.interval_1s.callback_list = cur->next;
+               free(cur);
+       }
+       pthread_mutex_unlock(&chm.interval_1s.list_mutex);
+
+       memset(&chm.interval_for_series, 0, sizeof(chm.interval_for_series));
+       __sync_and_and_fetch(&(gTraceInfo.custom_chart_callback_count), 0);
+}
+
+static void remove_from_callback_list(da_handle charthandle, da_handle series_handle)
+{
+       chart_interval_callback *prev, *cur;
+       chart_interval interval;
+
+       interval = chm.interval_for_series[charthandle][series_handle % 10];
+       chm.interval_for_series[charthandle][series_handle % 10] = 0;
+
+       switch(interval)
+       {
+       case CHART_INTERVAL_10MSEC:
+               pthread_mutex_lock(&chm.interval_10ms.list_mutex);
+
+               prev = NULL;
+               cur = chm.interval_10ms.callback_list;
+               while(cur != NULL)
+               {
+                       if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
+                       {
+                               if(prev)
+                                       prev->next = cur->next;
+                               else
+                                       chm.interval_10ms.callback_list = cur->next;
+
+                               __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
+                               free(cur);
+                               break;
+                       }
+
+                       prev = cur;
+                       cur = cur->next;
+               }
+
+               pthread_mutex_unlock(&chm.interval_10ms.list_mutex);
+               break;
+       case CHART_INTERVAL_100MSEC:
+               pthread_mutex_lock(&chm.interval_100ms.list_mutex);
+
+               prev = NULL;
+               cur = chm.interval_100ms.callback_list;
+               while(cur != NULL)
+               {
+                       if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
+                       {
+                               if(prev)
+                                       prev->next = cur->next;
+                               else
+                                       chm.interval_100ms.callback_list = cur->next;
+
+                               __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
+                               free(cur);
+                               break;
+                       }
+
+                       prev = cur;
+                       cur = cur->next;
+               }
+
+               pthread_mutex_unlock(&chm.interval_100ms.list_mutex);
+               break;
+       case CHART_INTERVAL_1SEC:
+               pthread_mutex_lock(&chm.interval_1s.list_mutex);
+
+               prev = NULL;
+               cur = chm.interval_1s.callback_list;
+               while(cur != NULL)
+               {
+                       if(cur->chart_handle == charthandle && cur->series_handle == series_handle)
+                       {
+                               if(prev)
+                                       prev->next = cur->next;
+                               else
+                                       chm.interval_1s.callback_list = cur->next;
+
+                               __sync_sub_and_fetch(&(gTraceInfo.custom_chart_callback_count), 1);
+                               free(cur);
+                               break;
+                       }
+
+                       prev = cur;
+                       cur = cur->next;
+               }
+
+               pthread_mutex_unlock(&chm.interval_1s.list_mutex);
+               break;
+       default:
+               break;
+       }
+}
+
+
+// =====================================================================
+// constructor and destructor functions
+// =====================================================================
+
+void __attribute__((constructor)) _init_lib()
+{
+       probeBlockStart();
+
+       memset(&chm, 0, sizeof(chm));
+       chm.interval_10ms.timerfd = -1;
+       chm.interval_100ms.timerfd = -1;
+       chm.interval_1s.timerfd = -1;
+       chm.interval_10ms.thread_handle = -1;
+       chm.interval_100ms.thread_handle = -1;
+       chm.interval_1s.thread_handle = -1;
+       pthread_mutex_init(&chm.interval_10ms.list_mutex, NULL);
+       pthread_mutex_init(&chm.interval_100ms.list_mutex, NULL);
+       pthread_mutex_init(&chm.interval_1s.list_mutex, NULL);
+
+       probeBlockEnd();
+}
+
+void __attribute__((destructor)) _fini_lib()
+{
+       probeBlockStart();
+
+       remove_all_callback_list();
+       if(chm.interval_10ms.timerfd != -1)
+               close(chm.interval_10ms.timerfd);
+       if(chm.interval_100ms.timerfd != -1)
+               close(chm.interval_100ms.timerfd);
+       if(chm.interval_1s.timerfd != -1)
+               close(chm.interval_1s.timerfd);
+
+       if(chm.interval_10ms.thread_handle != -1)
+       {
+               pthread_join(chm.interval_10ms.thread_handle, NULL);
+       }
+       if(chm.interval_100ms.thread_handle != -1)
+       {
+               pthread_join(chm.interval_100ms.thread_handle, NULL);
+       }
+       if(chm.interval_1s.thread_handle != -1)
+       {
+               pthread_join(chm.interval_1s.thread_handle, NULL);
+       }
+
+       probeBlockEnd();
+}
+
+
+// =====================================================================
+// api definition
+// =====================================================================
+
+void da_mark(chart_color color, char* mark_text)
+{
+       DECLARE_CHART_VARIABLE;
+       
+       probeBlockStart();
+       
+       INIT_LOG;
+       setProbePoint(&probeInfo);
+       APPEND_LOG_BASIC(LC_CUSTOM);
+       APPEND_LOG_INPUT("%s", "");
+       APPEND_LOG_CHART_RESULT(0);
+       APPEND_LOG_CHART(0, 0, mark_text, color, 0.0f);
+       printLog(&log, MSG_LOG);
+
+       PREPARE_LOCAL_BUF();
+       PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "dp", color, mark_text);
+       PACK_COMMON_END(0, 0, 2);
+       PACK_CUSTOM(0, 0, mark_text, color, 0.0f);
+       FLUSH_LOCAL_BUF();
+
+       probeBlockEnd();
+}
+
+da_handle da_create_chart(char* chart_name)
+{
+       DECLARE_CHART_VARIABLE;
+
+       // check if there is available chart handle slot
+       if(chm.chart_handle_index + 1 >= MAX_CHART_HANDLE)
+               return ERR_MAX_CHART_NUMBER;
+               
+       // check if chart_name is null
+       if(chart_name == NULL)
+               return ERR_WRONG_PARAMETER;
+               
+       probeBlockStart();
+       ret = ++(chm.chart_handle_index);
+
+       INIT_LOG;
+       setProbePoint(&probeInfo);
+       APPEND_LOG_BASIC(LC_CUSTOM);
+       APPEND_LOG_INPUT("%s", "");
+       APPEND_LOG_CHART_RESULT(ret);
+       APPEND_LOG_CHART(0, 0, chart_name, 0, 0.0f);
+       printLog(&log, MSG_LOG);
+
+       PREPARE_LOCAL_BUF();
+       PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "p", chart_name);
+       PACK_COMMON_END(ret, 0, 2);
+       PACK_CUSTOM(0, 0, chart_name, 0, 0.0f);
+       FLUSH_LOCAL_BUF();
+       
+       probeBlockEnd();
+       
+       return ret;
+}
+
+da_handle da_create_series(da_handle charthandle, char* seriesname,
+               series_type type, chart_color color)
+{
+       DECLARE_CHART_VARIABLE;
+       
+       // check if charthandle is valid handle or not
+       if(charthandle <= 0 || charthandle > chm.chart_handle_index)
+               return ERR_WRONG_HANDLE;
+               
+       // chech if extra parameter is valid
+       if(seriesname == NULL)
+               return ERR_WRONG_PARAMETER;
+
+       // check if there is available series spot
+       if(chm.series_handle_index[(int)charthandle] + 1 >= MAX_SERIES_PER_CHART)
+               return ERR_MAX_CHART_NUMBER;
+       
+       probeBlockStart();
+       ret = ++(chm.series_handle_index[charthandle]);
+       ret += (10 * charthandle);
+       
+       INIT_LOG;
+       setProbePoint(&probeInfo);
+       APPEND_LOG_BASIC(LC_CUSTOM);
+       APPEND_LOG_INPUT("%s", "");
+       APPEND_LOG_CHART_RESULT(ret);
+       APPEND_LOG_CHART(charthandle, type, seriesname, color, 0.0f);
+       printLog(&log, MSG_LOG);
+
+       PREPARE_LOCAL_BUF();
+       PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "dpdd",  charthandle, seriesname, type, color);
+       PACK_COMMON_END(ret, 0, 2);
+       PACK_CUSTOM(charthandle, type, seriesname, color, 0.0f);
+       FLUSH_LOCAL_BUF();
+
+       probeBlockEnd();
+       
+       return ret;
+}
+               
+da_handle da_create_default_series(da_handle charthandle, char* seriesname)
+{
+       return da_create_series(charthandle, seriesname,
+                       CHART_TYPE_AUTO, CHART_COLOR_AUTO);
+}
+
+int da_set_callback(da_handle series_handle, da_user_data_2_chart_data callback,
+               void* data_addr, chart_interval interval)
+{
+       int cindex, sindex;
+       cindex = (int)(series_handle / 10);
+       sindex = series_handle % 10;
+       
+       // check series handle
+       if(cindex <= 0 || cindex > chm.chart_handle_index)
+               return ERR_WRONG_HANDLE;
+       
+       if(sindex > chm.series_handle_index[(int)cindex])
+               return ERR_WRONG_HANDLE;
+       
+       // check rest parameters
+       if(interval == CHART_NO_CYCLE && callback != NULL)
+               return ERR_WRONG_PARAMETER;
+
+       probeBlockStart();
+
+       // remove previously registered callback
+       remove_from_callback_list(cindex, series_handle);
+
+       // register new callback
+       if(callback != NULL)
+       {
+               add_to_callback_list(interval, cindex, series_handle, callback, data_addr);
+               start_callback_thread(interval);
+       }
+       probeBlockEnd();
+
+       return 0;
+}
+
+void da_log(da_handle series_handle, float uservalue)
+{
+       DECLARE_CHART_VARIABLE;
+       
+       // chech if series handle is valid
+       int cindex, sindex;
+       cindex = (int)(series_handle / 10);
+       sindex = series_handle % 10;
+       
+       if(cindex <= 0 || cindex > chm.chart_handle_index)
+               return;
+       
+       if(sindex > chm.series_handle_index[(int)cindex])
+               return;
+       
+       probeBlockStart();
+       
+       INIT_LOG;
+       setProbePoint(&probeInfo);
+       APPEND_LOG_BASIC(LC_CUSTOM);
+       APPEND_LOG_INPUT("%s", "");
+       APPEND_LOG_CHART_RESULT(0);
+       APPEND_LOG_CHART(series_handle, 0, "", 0, uservalue);
+       printLog(&log, MSG_LOG);
+
+       PREPARE_LOCAL_BUF();
+       PACK_COMMON_BEGIN(MSG_PROBE_CUSTOM, LC_CUSTOM, "dw", series_handle, uservalue);
+       PACK_COMMON_END(0, 0, 2);
+       PACK_CUSTOM(series_handle, 0, "", 0, uservalue);
+       FLUSH_LOCAL_BUF();
+       
+       probeBlockEnd();
+}