automotive-dlt
dlt-kpi.c
Go to the documentation of this file.
1 /*
2  * @licence app begin@
3  * SPDX license identifier: MPL-2.0
4  *
5  * Copyright (C) 2011-2015, BMW AG
6  *
7  * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
8  *
9  * This Source Code Form is subject to the terms of the
10  * Mozilla Public License (MPL), v. 2.0.
11  * If a copy of the MPL was not distributed with this file,
12  * You can obtain one at http://mozilla.org/MPL/2.0/.
13  *
14  * For further information see http://www.genivi.org/.
15  * @licence end@
16  */
17 
27 #include "dlt-kpi.h"
28 
29 #include <signal.h>
30 #include <dirent.h>
31 #include <time.h>
32 #include <unistd.h>
33 #include <pthread.h>
34 
35 DLT_DECLARE_CONTEXT(kpi_ctx);
36 
38 
39 static volatile sig_atomic_t stop_loop = 0;
41 static struct timespec _tmp_time;
42 static pthread_mutex_t process_list_mutex;
43 
44 void dlt_kpi_stop_loops(int sig);
50 DltReturnValue dlt_kpi_update_process_list(DltKpiProcessList *list, unsigned long int time_dif_ms);
56 
57 unsigned long int timespec_to_millis(struct timespec *time)
58 {
59  return (time->tv_sec) * 1000 + (time->tv_nsec / 1000000);
60 }
61 
62 unsigned long int get_millis()
63 {
64  clock_gettime(CLOCK_REALTIME, &_tmp_time);
66 }
67 
68 int main(int argc, char **argv)
69 {
70  printf("Launching dlt-kpi...\n");
71 
72  if(dlt_kpi_init(argc, argv, &config) < DLT_RETURN_OK)
73  {
74  fprintf(stderr, "Initialization error!\n");
75  return -1;
76  }
77 
79 
81  {
82  fprintf(stderr, "Error occurred initializing process lists\n");
83  return -1;
84  }
85 
86  if(pthread_mutex_init(&process_list_mutex, NULL) < 0)
87  {
88  fprintf(stderr, "Error occurred initializing mutex\n");
89  return -1;
90  }
91 
92  DLT_REGISTER_APP("PROC", "/proc/-filesystem logger application");
93  DLT_REGISTER_CONTEXT_LL_TS(kpi_ctx, "PROC", "/proc/-filesystem logger context", config.log_level, 1);
94 
95  pthread_t process_thread;
96  pthread_t irq_thread;
97  pthread_t check_thread;
98 
99  if(pthread_create(&process_thread, NULL, &dlt_kpi_start_process_thread, NULL) != 0)
100  {
101  fprintf(stderr, "Could not create thread\n");
102  return -1;
103  }
104  if(pthread_create(&irq_thread, NULL, &dlt_kpi_start_irq_thread, NULL) != 0)
105  {
106  fprintf(stderr, "Could not create thread\n");
107  return -1;
108  }
109  if(pthread_create(&check_thread, NULL, &dlt_kpi_start_check_thread, NULL) != 0)
110  {
111  fprintf(stderr, "Could not create thread\n");
112  return -1;
113  }
114 
115  pthread_join(process_thread, NULL);
116  pthread_join(irq_thread, NULL);
117  pthread_join(check_thread, NULL);
118 
119  DLT_UNREGISTER_CONTEXT(kpi_ctx);
121 
122  pthread_mutex_destroy(&process_list_mutex);
123 
125 
126  printf("Done.\n");
127 
128  return 0;
129 }
130 
132 {
133  struct sigaction action;
134  memset(&action, 0, sizeof(struct sigaction));
135  action.sa_handler = dlt_kpi_stop_loops;
136 
137  sigaction(SIGTERM, &action, NULL);
138 }
139 
140 void dlt_kpi_stop_loops(int sig)
141 {
142  if(sig > -1)
143  fprintf(stderr, "dlt-kpi is now terminating due to signal %d...\n", sig);
144  else
145  fprintf(stderr, "dlt-kpi is now terminating due to an error...\n");
146 
147  stop_loop = 1;
148 }
149 
151 {
152  if((list = dlt_kpi_create_process_list()) == NULL) return DLT_RETURN_ERROR;
153  if((new_process_list = dlt_kpi_create_process_list()) == NULL) return DLT_RETURN_ERROR;
154  if((stopped_process_list = dlt_kpi_create_process_list()) == NULL) return DLT_RETURN_ERROR;
155  if((update_process_list = dlt_kpi_create_process_list()) == NULL) return DLT_RETURN_ERROR;
156 
157  return DLT_RETURN_OK;
158 }
159 
161 {
163 
165  ret = DLT_RETURN_ERROR;
166 
167  if(dlt_kpi_free_process_list(new_process_list) < DLT_RETURN_OK)
168  ret = DLT_RETURN_ERROR;
169 
170  if(dlt_kpi_free_process_list(stopped_process_list) < DLT_RETURN_OK)
171  ret = DLT_RETURN_ERROR;
172 
173  if(dlt_kpi_free_process_list(update_process_list) < DLT_RETURN_OK)
174  ret = DLT_RETURN_ERROR;
175 
176  return ret;
177 }
178 
180 {
182  dlt_kpi_stop_loops(-1);
183 
184  return NULL;
185 }
186 
188 {
189  static unsigned long int old_millis, sleep_millis, dif_millis;
190 
191  old_millis = get_millis();
192 
193  while(!stop_loop)
194  {
195  /*DltReturnValue ret = */ dlt_kpi_update_process_list(list, config.process_log_interval);
196  //if(ret < DLT_RETURN_OK)
197  // return ret;
198 
199  dif_millis = get_millis() - old_millis;
200 
201  if(dif_millis >= (unsigned long)(config.process_log_interval))
202  sleep_millis = 0;
203  else
204  sleep_millis = config.process_log_interval - dif_millis;
205 
206  usleep(sleep_millis * 1000);
207 
208  old_millis = get_millis();
209  }
210 
211  return DLT_RETURN_OK;
212 }
213 
214 DltReturnValue dlt_kpi_log_list(DltKpiProcessList *list, DltReturnValue(*process_callback)(DltKpiProcess*, char*, int), char *title, int delete_elements)
215 {
216  if(list == NULL || process_callback == NULL || title == NULL)
217  {
218  fprintf(stderr, "%s: Invalid Parameter (NULL)\n", __func__);
220  }
221 
222  dlt_kpi_reset_cursor(list);
223  if(list->cursor == NULL)
224  return DLT_RETURN_OK; // list empty; nothing to do
225 
226  // Synchronization message
227  DLT_LOG(kpi_ctx, config.log_level, DLT_STRING(title), DLT_STRING("BEG"));
228 
229  DltReturnValue ret;
231 
232  char buffer[BUFFER_SIZE];
233  buffer[0] = '\0';
234 
235  if((ret = dlt_user_log_write_start(&kpi_ctx, &data, config.log_level)) < DLT_RETURN_OK)
236  {
237  fprintf(stderr, "%s: dlt_user_log_write_start() returned error.\n", __func__);
238  return ret;
239  }
240 
241  if((ret = dlt_user_log_write_string(&data, title)) < DLT_RETURN_OK)
242  {
243  fprintf(stderr, "%s: dlt_user_log_write_string() returned error.\n", __func__);
244  return ret;
245  }
246 
247  do
248  {
249  if((ret = (*process_callback)(list->cursor, buffer, sizeof(buffer) - 1)) < DLT_RETURN_OK)
250  return ret;
251 
252  if((ret = dlt_user_log_write_string(&data, buffer)) < DLT_RETURN_OK)
253  {
254  /* Log buffer full => Write log and start new one*/
255  if((ret = dlt_user_log_write_finish(&data)) < DLT_RETURN_OK)
256  {
257  fprintf(stderr, "%s: dlt_user_log_write_finish() returned error.\n",__func__);
258  return ret;
259  }
260 
261  if((ret = dlt_user_log_write_start(&kpi_ctx, &data, config.log_level)) < DLT_RETURN_OK)
262  {
263  fprintf(stderr, "%s: dlt_user_log_write_start() returned error.\n",__func__);
264  return ret;
265  }
266 
267  if((ret = dlt_user_log_write_string(&data, title)) < DLT_RETURN_OK)
268  {
269  fprintf(stderr, "%s: dlt_user_log_write_string() returned error.\n",__func__);
270  return ret;
271  }
272  }
273  else if(delete_elements)
274  {
276  return ret;
277  }
278  else
279  {
280  list->cursor = list->cursor->next;
281  }
282  }
283  while(list->cursor != NULL);
284 
285  if((ret = dlt_user_log_write_finish(&data)) < DLT_RETURN_OK)
286  {
287  fprintf(stderr, "%s: dlt_user_log_write_finish() returned error.\n",__func__);
288  return ret;
289  }
290 
291  // Synchronization message
292  DLT_LOG(kpi_ctx, config.log_level, DLT_STRING(title), DLT_STRING("END"));
293 
294  return DLT_RETURN_OK;
295 }
296 
297 DltReturnValue dlt_kpi_update_process_list(DltKpiProcessList *list, unsigned long int time_dif_ms)
298 {
299  static char *strchk;
300  static DltReturnValue tmp_ret;
301  static struct dirent *current_dir;
302  static pid_t current_dir_pid;
303 
304  if(list == NULL)
305  {
306  fprintf(stderr, "dlt_kpi_update_process_list(): Nullpointer parameter");
308  }
309 
310  DIR *proc_dir = opendir("/proc");
311  if(proc_dir == NULL)
312  {
313  dlt_log(LOG_ERR, "Could not open /proc/ !\n");
314  return DLT_RETURN_ERROR;
315  }
316 
317  current_dir = readdir(proc_dir);
318  dlt_kpi_reset_cursor(list);
319 
320  int debug_process_count = 0;
321 
322  if(pthread_mutex_lock(&process_list_mutex) < 0)
323  {
324  fprintf(stderr, "Can't lock mutex\n");
325  return DLT_RETURN_ERROR;
326  }
327 
328  while(1)
329  {
330  if(current_dir == NULL)
331  {
332  /* no more active processes.. delete all remaining processes in the list */
333  if(list->cursor != NULL)
334  while(list->cursor != NULL)
335  {
336  if((tmp_ret = dlt_kpi_add_process_after_cursor(stopped_process_list, dlt_kpi_clone_process(list->cursor))) < DLT_RETURN_OK)
337  return tmp_ret;
338 
340  }
341 
342  break;
343  }
344 
345  current_dir_pid = strtol(current_dir->d_name, &strchk, 10);
346  if(*strchk != '\0' || current_dir_pid <= 0)
347  {
348  /* no valid PID */
349  current_dir = readdir(proc_dir); // next process in proc-fs
350  continue;
351  }
352 
353  /* compare the /proc/-filesystem with our process-list */
354  if(list->cursor == NULL || current_dir_pid < list->cursor->pid) // New Process
355  {
356  DltKpiProcess *new_process = dlt_kpi_create_process(current_dir_pid);
357  if(new_process == NULL)
358  {
359  fprintf(stderr, "Error: Could not create process (out of memory?)\n");
360  return DLT_RETURN_ERROR;
361  }
362 
363  if((tmp_ret = dlt_kpi_add_process_before_cursor(list, new_process)) < DLT_RETURN_OK)
364  return tmp_ret;
365 
366  if((tmp_ret = dlt_kpi_add_process_before_cursor(new_process_list, dlt_kpi_clone_process(new_process))) < DLT_RETURN_OK)
367  return tmp_ret;
368 
369  current_dir = readdir(proc_dir); // next process in proc-fs
370  debug_process_count++;
371  }
372  else if(current_dir_pid > list->cursor->pid) // Process ended
373  {
374  if((tmp_ret = dlt_kpi_add_process_after_cursor(stopped_process_list, dlt_kpi_clone_process(list->cursor))) < DLT_RETURN_OK)
375  return tmp_ret;
376 
377  if((tmp_ret = dlt_kpi_remove_process_at_cursor(list)) < DLT_RETURN_OK)
378  return tmp_ret;
379  }
380  else if(current_dir_pid == list->cursor->pid) // Staying process
381  {
382  /* update data */
383  if((tmp_ret = dlt_kpi_update_process(list->cursor, time_dif_ms)) < DLT_RETURN_OK)
384  return tmp_ret;
385 
386  if(list->cursor->cpu_time > 0) // only log active processes
387  if((tmp_ret = dlt_kpi_add_process_after_cursor(update_process_list, dlt_kpi_clone_process(list->cursor))) < DLT_RETURN_OK)
388  {
389  fprintf(stderr, "dlt_kpi_update_process_list: Can't add process to list updateProcessList\n");
390  return tmp_ret;
391  }
392 
393  if((tmp_ret = dlt_kpi_increment_cursor(list)) < DLT_RETURN_OK) // next process in list
394  return tmp_ret;
395 
396  current_dir = readdir(proc_dir); // next process in proc-fs
397  debug_process_count++;
398  }
399  }
400 
401  if(pthread_mutex_unlock(&process_list_mutex) < 0)
402  {
403  fprintf(stderr, "Can't unlock mutex\n");
404  return DLT_RETURN_ERROR;
405  }
406 
407  /* Log new processes */
408  if((tmp_ret = dlt_kpi_log_list(new_process_list, &dlt_kpi_get_msg_process_new, "NEW", 1)) < DLT_RETURN_OK)
409  return tmp_ret;
410 
411  /* Log stopped processes */
412  if((tmp_ret = dlt_kpi_log_list(stopped_process_list, &dlt_kpi_get_msg_process_stop, "STP", 1)) < DLT_RETURN_OK)
413  return tmp_ret;
414 
415  /* Log active processes */
416  if((tmp_ret = dlt_kpi_log_list(update_process_list, &dlt_kpi_get_msg_process_update, "ACT", 1)) < DLT_RETURN_OK)
417  return tmp_ret;
418 
419  if(closedir(proc_dir) < 0)
420  fprintf(stderr, "Could not close /proc/ directory\n");
421 
422  return DLT_RETURN_OK;
423 }
424 
426 {
428  dlt_kpi_stop_loops(-1);
429 
430  return NULL;
431 }
432 
434 {
435  static unsigned long int old_millis, sleep_millis, dif_millis;
436 
437  old_millis = get_millis();
438 
439  while(!stop_loop)
440  {
441  /*DltReturnValue ret = */ dlt_kpi_log_interrupts(&kpi_ctx, config.log_level);
442  //if(ret < DLT_RETURN_OK)
443  // return ret;
444 
445  dif_millis = get_millis() - old_millis;
446 
447  if(dif_millis >= (unsigned long)(config.irq_log_interval))
448  sleep_millis = 0;
449  else
450  sleep_millis = config.irq_log_interval - dif_millis;
451 
452  usleep(sleep_millis * 1000);
453 
454  old_millis = get_millis();
455  }
456 
457  return DLT_RETURN_OK;
458 }
459 
461 {
463  dlt_kpi_stop_loops(-1);
464 
465  return NULL;
466 }
467 
469 {
470  static unsigned long int old_millis, sleep_millis, dif_millis;
471 
472  old_millis = get_millis();
473 
474  while(!stop_loop)
475  {
476  /*DltReturnValue ret = */ dlt_kpi_log_check_commandlines();
477  //if(ret < DLT_RETURN_OK)
478  // return ret;
479 
480  dif_millis = get_millis() - old_millis;
481 
482  if(dif_millis >= (unsigned long)(config.check_log_interval))
483  sleep_millis = 0;
484  else
485  sleep_millis = config.check_log_interval - dif_millis;
486 
487  usleep(sleep_millis * 1000);
488 
489  old_millis = get_millis();
490  }
491 
492  return DLT_RETURN_OK;
493 }
494 
496 {
497  if(pthread_mutex_lock(&process_list_mutex) < 0)
498  {
499  fprintf(stderr, "Can't lock mutex\n");
500  return DLT_RETURN_ERROR;
501  }
502 
504 
505  if(pthread_mutex_unlock(&process_list_mutex) < 0)
506  {
507  fprintf(stderr, "Can't unlock mutex\n");
508  return DLT_RETURN_ERROR;
509  }
510 
511  return ret;
512 }
void dlt_kpi_stop_loops(int sig)
Definition: dlt-kpi.c:140
DltReturnValue dlt_kpi_log_list(DltKpiProcessList *list, DltReturnValue(*process_callback)(DltKpiProcess *, char *, int), char *title, int delete_elements)
Definition: dlt-kpi.c:214
static DltKpiProcessList * new_process_list
Definition: dlt-kpi.c:40
DltReturnValue dlt_kpi_update_process_list(DltKpiProcessList *list, unsigned long int time_dif_ms)
Definition: dlt-kpi.c:297
DltReturnValue dlt_kpi_init(int argc, char **argv, DltKpiConfig *config)
DltKpiProcess * dlt_kpi_create_process(int pid)
DltReturnValue dlt_user_log_write_string(DltContextData *log, const char *text)
Definition: dlt_user.c:2280
#define DLT_UNREGISTER_APP()
DltReturnValue dlt_kpi_remove_process_at_cursor(DltKpiProcessList *list)
struct DltKpiProcess * cursor
DltReturnValue
Definition: dlt_types.h:86
DltKpiConfig config
Definition: dlt-kpi.c:37
DLT_DECLARE_CONTEXT(kpi_ctx)
static DltKpiProcessList * list
Definition: dlt-kpi.c:40
unsigned long int get_millis()
Definition: dlt-kpi.c:62
DltReturnValue dlt_log(int prio, char *s)
Definition: dlt_common.c:2029
DltReturnValue dlt_kpi_irq_loop()
Definition: dlt-kpi.c:433
DltReturnValue dlt_kpi_get_msg_process_update(DltKpiProcess *process, char *buffer, int maxlen)
int check_log_interval
Definition: dlt-kpi.h:52
DltKpiProcessList * dlt_kpi_create_process_list()
DltReturnValue dlt_kpi_get_msg_process_stop(DltKpiProcess *process, char *buffer, int maxlen)
DltReturnValue dlt_kpi_process_loop()
Definition: dlt-kpi.c:187
int irq_log_interval
Definition: dlt-kpi.h:52
int main(int argc, char **argv)
Definition: dlt-kpi.c:68
static char data[kDataSize]
Definition: city-test.cc:40
void * dlt_kpi_start_check_thread()
Definition: dlt-kpi.c:460
DltKpiProcess * dlt_kpi_clone_process(DltKpiProcess *original)
unsigned long int timespec_to_millis(struct timespec *time)
Definition: dlt-kpi.c:57
static DltKpiProcessList * update_process_list
Definition: dlt-kpi.c:40
struct DltKpiProcess * next
DltReturnValue dlt_kpi_add_process_before_cursor(DltKpiProcessList *list, DltKpiProcess *process)
DltReturnValue dlt_kpi_free_process_list(DltKpiProcessList *list)
#define DLT_REGISTER_APP(APPID, DESCRIPTION)
DltLogLevelType log_level
Definition: dlt-kpi.h:53
DltReturnValue dlt_kpi_free_process_lists()
Definition: dlt-kpi.c:160
#define DLT_STRING(TEXT)
unsigned char buffer[BUFFER_SIZE]
Buffer for dlt file transfer. The size is defined by BUFFER_SIZE.
void * dlt_kpi_start_irq_thread()
Definition: dlt-kpi.c:425
#define BUFFER_SIZE
static pthread_mutex_t process_list_mutex
Definition: dlt-kpi.c:42
DltReturnValue dlt_kpi_increment_cursor(DltKpiProcessList *list)
static struct timespec _tmp_time
Definition: dlt-kpi.c:41
DltReturnValue dlt_kpi_add_process_after_cursor(DltKpiProcessList *list, DltKpiProcess *process)
unsigned long int cpu_time
#define DLT_UNREGISTER_CONTEXT(CONTEXT)
DltReturnValue dlt_kpi_update_process(DltKpiProcess *process, unsigned long int time_dif_ms)
#define DLT_REGISTER_CONTEXT_LL_TS(CONTEXT, CONTEXTID, DESCRIPTION, LOGLEVEL, TRACESTATUS)
int process_log_interval
Definition: dlt-kpi.h:52
static volatile sig_atomic_t stop_loop
Definition: dlt-kpi.c:39
DltReturnValue dlt_kpi_init_process_lists()
Definition: dlt-kpi.c:150
#define DLT_LOG(CONTEXT, LOGLEVEL, ARGS...)
DltReturnValue dlt_kpi_log_check_commandlines()
Definition: dlt-kpi.c:495
static DltKpiProcessList * stopped_process_list
Definition: dlt-kpi.c:40
DltReturnValue dlt_kpi_log_interrupts(DltContext *ctx, DltLogLevelType log_level)
DltReturnValue dlt_kpi_reset_cursor(DltKpiProcessList *list)
DltReturnValue dlt_kpi_check_loop()
Definition: dlt-kpi.c:468
DltReturnValue dlt_kpi_get_msg_process_new(DltKpiProcess *process, char *buffer, int maxlen)
DltReturnValue dlt_kpi_get_msg_process_commandline(DltKpiProcess *process, char *buffer, int maxlen)
void dlt_kpi_init_sigterm_handler()
Definition: dlt-kpi.c:131
void * dlt_kpi_start_process_thread()
Definition: dlt-kpi.c:179
DltReturnValue dlt_user_log_write_finish(DltContextData *log)
Definition: dlt_user.c:1482
#define NULL
Definition: dlt_common.h:232
DltReturnValue dlt_user_log_write_start(DltContext *handle, DltContextData *log, DltLogLevelType loglevel)
Definition: dlt_user.c:1428