From 77400754611a8e7982a7ee3c4816ee5f070c0dca Mon Sep 17 00:00:00 2001 From: Sven Hassler Date: Wed, 25 Nov 2015 14:26:06 +0100 Subject: Renamed "procfs" to "kpi", added sync-messages --- src/kpi/dlt-kpi.c | 510 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 510 insertions(+) create mode 100644 src/kpi/dlt-kpi.c (limited to 'src/kpi/dlt-kpi.c') diff --git a/src/kpi/dlt-kpi.c b/src/kpi/dlt-kpi.c new file mode 100644 index 0000000..f315058 --- /dev/null +++ b/src/kpi/dlt-kpi.c @@ -0,0 +1,510 @@ +/* + * @licence app begin@ + * SPDX license identifier: MPL-2.0 + * + * Copyright (C) 2011-2015, BMW AG + * + * This file is part of GENIVI Project DLT - Diagnostic Log and Trace. + * + * This Source Code Form is subject to the terms of the + * Mozilla Public License (MPL), v. 2.0. + * If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +/*! + * \author Sven Hassler + * + * \copyright Copyright © 2011-2015 BMW AG. \n + * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/. + * + * \file dlt-kpi.c + */ + +#include "dlt-kpi.h" + +#include +#include +#include +#include +#include + +DLT_DECLARE_CONTEXT(kpi_ctx); + +DltKpiConfig config; + +static volatile sig_atomic_t stop_loop = 0; +static DltKpiProcessList *list, *new_process_list, *stopped_process_list, *update_process_list; +static struct timespec _tmp_time; +static pthread_mutex_t process_list_mutex; + +void dlt_kpi_stop_loops(int sig); +void dlt_kpi_init_sigterm_handler(); +DltReturnValue dlt_kpi_init_process_lists(); +DltReturnValue dlt_kpi_free_process_lists(); +void *dlt_kpi_start_process_thread(); +DltReturnValue dlt_kpi_process_loop(); +DltReturnValue dlt_kpi_update_process_list(DltKpiProcessList *list, unsigned long int time_dif_ms); +void *dlt_kpi_start_irq_thread(); +DltReturnValue dlt_kpi_irq_loop(); +void *dlt_kpi_start_check_thread(); +DltReturnValue dlt_kpi_check_loop(); +DltReturnValue dlt_kpi_log_check_commandlines(); + +unsigned long int timespec_to_millis(struct timespec *time) +{ + return (time->tv_sec) * 1000 + (time->tv_nsec / 1000000); +} + +unsigned long int get_millis() +{ + clock_gettime(CLOCK_REALTIME, &_tmp_time); + return timespec_to_millis(&_tmp_time); +} + +int main(int argc, char **argv) +{ + printf("Launching dlt-kpi...\n"); + + if(dlt_kpi_init(argc, argv, &config) < DLT_RETURN_OK) + { + fprintf(stderr, "Initialization error!\n"); + return -1; + } + + dlt_kpi_init_sigterm_handler(); + + if(dlt_kpi_init_process_lists() < DLT_RETURN_OK) + { + fprintf(stderr, "Error occurred initializing process lists\n"); + return -1; + } + + if(pthread_mutex_init(&process_list_mutex, NULL) < 0) + { + fprintf(stderr, "Error occurred initializing mutex\n"); + return -1; + } + + DLT_REGISTER_APP("PROC", "/proc/-filesystem logger application"); + DLT_REGISTER_CONTEXT_LL_TS(kpi_ctx, "PROC", "/proc/-filesystem logger context", config.log_level, 1); + + pthread_t process_thread; + pthread_t irq_thread; + pthread_t check_thread; + + if(pthread_create(&process_thread, NULL, &dlt_kpi_start_process_thread, NULL) != 0) + { + fprintf(stderr, "Could not create thread\n"); + return -1; + } + if(pthread_create(&irq_thread, NULL, &dlt_kpi_start_irq_thread, NULL) != 0) + { + fprintf(stderr, "Could not create thread\n"); + return -1; + } + if(pthread_create(&check_thread, NULL, &dlt_kpi_start_check_thread, NULL) != 0) + { + fprintf(stderr, "Could not create thread\n"); + return -1; + } + + pthread_join(process_thread, NULL); + pthread_join(irq_thread, NULL); + pthread_join(check_thread, NULL); + + DLT_UNREGISTER_CONTEXT(kpi_ctx); + DLT_UNREGISTER_APP(); + + pthread_mutex_destroy(&process_list_mutex); + + dlt_kpi_free_process_lists(); + + printf("Done.\n"); +} + +void dlt_kpi_init_sigterm_handler() +{ + struct sigaction action; + memset(&action, 0, sizeof(struct sigaction)); + action.sa_handler = dlt_kpi_stop_loops; + + sigaction(SIGTERM, &action, NULL); +} + +void dlt_kpi_stop_loops(int sig) +{ + if(sig > -1) + fprintf(stderr, "dlt-kpi is now terminating due to signal %d...\n", sig); + else + fprintf(stderr, "dlt-kpi is now terminating due to an error...\n"); + + stop_loop = 1; +} + +DltReturnValue dlt_kpi_init_process_lists() +{ + if((list = dlt_kpi_create_process_list()) == NULL) return DLT_RETURN_ERROR; + if((new_process_list = dlt_kpi_create_process_list()) == NULL) return DLT_RETURN_ERROR; + if((stopped_process_list = dlt_kpi_create_process_list()) == NULL) return DLT_RETURN_ERROR; + if((update_process_list = dlt_kpi_create_process_list()) == NULL) return DLT_RETURN_ERROR; + + return DLT_RETURN_OK; +} + +DltReturnValue dlt_kpi_free_process_lists() +{ + DltReturnValue ret = DLT_RETURN_OK; + + if(dlt_kpi_free_process_list(list) < DLT_RETURN_OK) + ret = DLT_RETURN_ERROR; + + if(dlt_kpi_free_process_list(new_process_list) < DLT_RETURN_OK) + ret = DLT_RETURN_ERROR; + + if(dlt_kpi_free_process_list(stopped_process_list) < DLT_RETURN_OK) + ret = DLT_RETURN_ERROR; + + if(dlt_kpi_free_process_list(update_process_list) < DLT_RETURN_OK) + ret = DLT_RETURN_ERROR; + + return ret; +} + +void *dlt_kpi_start_process_thread() +{ + if(dlt_kpi_process_loop() < DLT_RETURN_OK) + dlt_kpi_stop_loops(-1); + + return NULL; +} + +DltReturnValue dlt_kpi_process_loop() +{ + static unsigned long int old_millis, sleep_millis, dif_millis; + + old_millis = get_millis(); + + while(!stop_loop) + { + /*DltReturnValue ret = */ dlt_kpi_update_process_list(list, config.process_log_interval); + //if(ret < DLT_RETURN_OK) + // return ret; + + dif_millis = get_millis() - old_millis; + + if(dif_millis >= (unsigned long)(config.process_log_interval)) + sleep_millis = 0; + else + sleep_millis = config.process_log_interval - dif_millis; + + usleep(sleep_millis * 1000); + + old_millis = get_millis(); + } + + return DLT_RETURN_OK; +} + +DltReturnValue dlt_kpi_log_list(DltKpiProcessList *list, DltReturnValue(*process_callback)(DltKpiProcess*, char*, int), char *title, int delete_elements) +{ + if(list == NULL || process_callback == NULL || title == NULL) + { + fprintf(stderr, "dlt_kpi_log_list(): Nullpointer parameter\n"); + return DLT_RETURN_WRONG_PARAMETER; + } + + dlt_kpi_reset_cursor(list); + if(list->cursor == NULL) + return DLT_RETURN_OK; // list empty; nothing to do + + // Synchronization message + DLT_LOG(kpi_ctx, config.log_level, DLT_STRING(title), DLT_STRING("BEG")); + + DltReturnValue ret; + DltContextData data; + + char buffer[BUFFER_SIZE]; + buffer[0] = '\0'; + + if((ret = dlt_user_log_write_start(&kpi_ctx, &data, config.log_level)) < DLT_RETURN_OK) + { + fprintf(stderr, "dlt_kpi_log_list(): dlt_user_log_write_start() returned error.\n"); + return ret; + } + + if((ret = dlt_user_log_write_string(&data, title)) < DLT_RETURN_OK) + { + fprintf(stderr, "dlt_kpi_log_list(): dlt_user_log_write_string() returned error.\n"); + return ret; + } + + do + { + if((ret = (*process_callback)(list->cursor, buffer, sizeof(buffer) - 1)) < DLT_RETURN_OK) + return ret; + + if((ret = dlt_user_log_write_string(&data, buffer)) < DLT_RETURN_OK) + { + /* Log buffer full => Write log and start new one*/ + if((ret = dlt_user_log_write_finish(&data)) < DLT_RETURN_OK) + { + fprintf(stderr, "dlt_kpi_log_list(): dlt_user_log_write_finish() returned error.\n"); + return ret; + } + + if((ret = dlt_user_log_write_start(&kpi_ctx, &data, config.log_level)) < DLT_RETURN_OK) + { + fprintf(stderr, "dlt_kpi_log_list(): dlt_user_log_write_start() returned error.\n"); + return ret; + } + + if((ret = dlt_user_log_write_string(&data, title)) < DLT_RETURN_OK) + { + fprintf(stderr, "dlt_kpi_log_list(): dlt_user_log_write_string() returned error.\n"); + return ret; + } + } + else if(delete_elements) + { + if((ret = dlt_kpi_remove_process_at_cursor(list)) < DLT_RETURN_OK) + return ret; + } + else + { + list->cursor = list->cursor->next; + } + } + while(list->cursor != NULL); + + if((ret = dlt_user_log_write_finish(&data)) < DLT_RETURN_OK) + { + fprintf(stderr, "dlt_kpi_log_list(): dlt_user_log_write_finish() returned error.\n"); + return ret; + } + + // Synchronization message + DLT_LOG(kpi_ctx, config.log_level, DLT_STRING(title), DLT_STRING("END")); + + return DLT_RETURN_OK; +} + +DltReturnValue dlt_kpi_update_process_list(DltKpiProcessList *list, unsigned long int time_dif_ms) +{ + static char *strchk; + static DltReturnValue tmp_ret; + static struct dirent *current_dir; + static pid_t current_dir_pid; + + if(list == NULL) + { + fprintf(stderr, "dlt_kpi_update_process_list(): Nullpointer parameter"); + return DLT_RETURN_WRONG_PARAMETER; + } + + DIR *proc_dir = opendir("/proc"); + if(proc_dir == NULL) + { + dlt_log(LOG_ERR, "Could not open /proc/ !\n"); + return DLT_RETURN_ERROR; + } + + current_dir = readdir(proc_dir); + dlt_kpi_reset_cursor(list); + + int debug_process_count = 0; + + if(pthread_mutex_lock(&process_list_mutex) < 0) + { + fprintf(stderr, "Can't lock mutex\n"); + return DLT_RETURN_ERROR; + } + + while(1) + { + if(current_dir == NULL) + { + /* no more active processes.. delete all remaining processes in the list */ + if(list->cursor != NULL) + while(list->cursor != NULL) + { + if((tmp_ret = dlt_kpi_add_process_after_cursor(stopped_process_list, dlt_kpi_clone_process(list->cursor))) < DLT_RETURN_OK) + return tmp_ret; + + dlt_kpi_remove_process_at_cursor(list); + } + + break; + } + + current_dir_pid = strtol(current_dir->d_name, &strchk, 10); + if(*strchk != '\0' || current_dir_pid <= 0) + { + /* no valid PID */ + current_dir = readdir(proc_dir); // next process in proc-fs + continue; + } + + /* compare the /proc/-filesystem with our process-list */ + if(list->cursor == NULL || current_dir_pid < list->cursor->pid) // New Process + { + DltKpiProcess *new_process = dlt_kpi_create_process(current_dir_pid); + if(new_process == NULL) + { + fprintf(stderr, "Error: Could not create process (out of memory?)\n"); + return DLT_RETURN_ERROR; + } + + if((tmp_ret = dlt_kpi_add_process_before_cursor(list, new_process)) < DLT_RETURN_OK) + return tmp_ret; + + if((tmp_ret = dlt_kpi_add_process_before_cursor(new_process_list, dlt_kpi_clone_process(new_process))) < DLT_RETURN_OK) + return tmp_ret; + + current_dir = readdir(proc_dir); // next process in proc-fs + debug_process_count++; + } + else if(current_dir_pid > list->cursor->pid) // Process ended + { + if((tmp_ret = dlt_kpi_add_process_after_cursor(stopped_process_list, dlt_kpi_clone_process(list->cursor))) < DLT_RETURN_OK) + return tmp_ret; + + if((tmp_ret = dlt_kpi_remove_process_at_cursor(list)) < DLT_RETURN_OK) + return tmp_ret; + } + else if(current_dir_pid == list->cursor->pid) // Staying process + { + /* update data */ + if((tmp_ret = dlt_kpi_update_process(list->cursor, time_dif_ms)) < DLT_RETURN_OK) + return tmp_ret; + + if(list->cursor->cpu_time > 0) // only log active processes + if((tmp_ret = dlt_kpi_add_process_after_cursor(update_process_list, dlt_kpi_clone_process(list->cursor))) < DLT_RETURN_OK) + { + fprintf(stderr, "dlt_kpi_update_process_list: Can't add process to list updateProcessList\n"); + return tmp_ret; + } + + if((tmp_ret = dlt_kpi_increment_cursor(list)) < DLT_RETURN_OK) // next process in list + return tmp_ret; + + current_dir = readdir(proc_dir); // next process in proc-fs + debug_process_count++; + } + } + + if(pthread_mutex_unlock(&process_list_mutex) < 0) + { + fprintf(stderr, "Can't unlock mutex\n"); + return DLT_RETURN_ERROR; + } + + /* Log new processes */ + if((tmp_ret = dlt_kpi_log_list(new_process_list, &dlt_kpi_get_msg_process_new, "NEW", 1)) < DLT_RETURN_OK) + return tmp_ret; + + /* Log stopped processes */ + if((tmp_ret = dlt_kpi_log_list(stopped_process_list, &dlt_kpi_get_msg_process_stop, "STP", 1)) < DLT_RETURN_OK) + return tmp_ret; + + /* Log active processes */ + if((tmp_ret = dlt_kpi_log_list(update_process_list, &dlt_kpi_get_msg_process_update, "ACT", 1)) < DLT_RETURN_OK) + return tmp_ret; + + if(closedir(proc_dir) < 0) + fprintf(stderr, "Could not close /proc/ directory\n"); + + return DLT_RETURN_OK; +} + +void *dlt_kpi_start_irq_thread() +{ + if(dlt_kpi_irq_loop() < DLT_RETURN_OK) + dlt_kpi_stop_loops(-1); + + return NULL; +} + +DltReturnValue dlt_kpi_irq_loop() +{ + static unsigned long int old_millis, sleep_millis, dif_millis; + + old_millis = get_millis(); + + while(!stop_loop) + { + /*DltReturnValue ret = */ dlt_kpi_log_interrupts(&kpi_ctx, config.log_level); + //if(ret < DLT_RETURN_OK) + // return ret; + + dif_millis = get_millis() - old_millis; + + if(dif_millis >= (unsigned long)(config.irq_log_interval)) + sleep_millis = 0; + else + sleep_millis = config.irq_log_interval - dif_millis; + + usleep(sleep_millis * 1000); + + old_millis = get_millis(); + } + + return DLT_RETURN_OK; +} + +void *dlt_kpi_start_check_thread() +{ + if(dlt_kpi_check_loop() < DLT_RETURN_OK) + dlt_kpi_stop_loops(-1); + + return NULL; +} + +DltReturnValue dlt_kpi_check_loop() +{ + static unsigned long int old_millis, sleep_millis, dif_millis; + + old_millis = get_millis(); + + while(!stop_loop) + { + /*DltReturnValue ret = */ dlt_kpi_log_check_commandlines(); + //if(ret < DLT_RETURN_OK) + // return ret; + + dif_millis = get_millis() - old_millis; + + if(dif_millis >= (unsigned long)(config.check_log_interval)) + sleep_millis = 0; + else + sleep_millis = config.check_log_interval - dif_millis; + + usleep(sleep_millis * 1000); + + old_millis = get_millis(); + } + + return DLT_RETURN_OK; +} + +DltReturnValue dlt_kpi_log_check_commandlines() +{ + if(pthread_mutex_lock(&process_list_mutex) < 0) + { + fprintf(stderr, "Can't lock mutex\n"); + return DLT_RETURN_ERROR; + } + + DltReturnValue ret = dlt_kpi_log_list(list, dlt_kpi_get_msg_process_commandline, "CHK", 0); + + if(pthread_mutex_unlock(&process_list_mutex) < 0) + { + fprintf(stderr, "Can't unlock mutex\n"); + return DLT_RETURN_ERROR; + } + + return ret; +} -- cgit v1.2.1