Convert LTTngTop to C++ and state system
[lttngtop.git] / src / iostreamtop.cpp
diff --git a/src/iostreamtop.cpp b/src/iostreamtop.cpp
new file mode 100644 (file)
index 0000000..3e96c60
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2011-2012 Mathieu Bain <mathieu.bain@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+extern "C"
+{
+#include <babeltrace/babeltrace.h>
+}
+
+#include "lttngtoptypes.h"
+#include "common.h"
+#include "iostreamtop.h"
+
+void add_file(Quark proc_quark, Quark file, int fd,
+                       unsigned long timestamp)
+{
+       Quark parent;
+       Quark file_pointer;
+       Quark old_file;
+       std::string filename;
+       std::string old_filename;
+       std::string path;
+       int flag;
+
+       if (state_system->attributeExists(proc_quark, "threadparent")) {
+               parent = state_system->getQuark(proc_quark, "threadparent");
+               insert_file(parent, fd, timestamp);
+       }
+
+       path = path_name_from_fd(fd);
+       if (state_system->attributeExists(proc_quark, path + "/file")) {
+               file_pointer = state_system->getQuark(proc_quark, path);
+               get_current_attribute_value_quark(&file_pointer, "file",
+                                                 old_file);
+               get_current_attribute_value_string(&old_file, "name",
+                                                  old_filename);
+               get_current_attribute_value_string(&file, "name", filename);
+               if (old_filename != filename) {
+                       /* Different file with same fd, we overwrite the
+                          file pointer */
+                       modify_attribute(timestamp, &file_pointer, "file",
+                                        file);
+               } else {
+                       modify_attribute(timestamp, &old_file, "flag",
+                                        __NR_open);
+               }
+       } else {
+               file_pointer = state_system->getQuark(proc_quark, path);
+               modify_attribute(timestamp, &file_pointer, "file", file);
+
+       }
+        /* To easily retrieve file pointer from files_history */
+       modify_attribute(timestamp, &file, "fd", fd);
+
+       /* The file may have been created in the parent */
+       get_current_attribute_value_int(&file, "flag", flag);
+       if (flag == -1) {
+               modify_attribute(timestamp, &file, "fd", fd);
+               modify_attribute(timestamp, &file, "flag", __NR_open);
+               increment_attribute(timestamp, NULL, "nbfiles");
+               increment_attribute(timestamp, NULL, "nbnewfiles");
+       }
+}
+
+/*
+ * Edit the file
+ * Called by handled_statedump_filename
+ */
+void edit_file(unsigned long timestamp, Quark proc, Quark file, int fd)
+{
+       std::string path;
+
+       path = path_name_from_fd(fd);
+       if (!state_system->attributeExists(proc, path)) {
+               add_file(proc, file, fd, timestamp);
+       }
+}
+
+Quark create_file(Quark proc, std::string file_name, unsigned long timestamp)
+{
+       Quark file_history;
+       Quark old_newest;
+       bool has_old;
+       std::string current_path;
+       int index;
+       std::stringstream ss;
+
+       if (!get_current_attribute_value_quark(&proc, "files_history/current",
+                                             file_history)) {
+               /* First file for process */
+               file_history = state_system->getQuark(
+                       proc, "files_history/file_0");
+       } else {
+
+               current_path = state_system->getFullAttributeName(file_history);
+               index = atoi(current_path.substr(current_path.find_last_of('_')
+                       + 1).c_str());
+               ss << "files_history/file_" << index + 1;
+               current_path = ss.str();
+               file_history = state_system->getQuark(
+                       proc, current_path);
+       }
+
+       has_old = get_current_attribute_value_quark(
+               &proc,"files_history/current", old_newest);
+       modify_attribute(timestamp, &proc, "files_history/current",
+               file_history);
+       modify_attribute(timestamp, &file_history, "file/name", file_name);
+       modify_attribute(timestamp, &file_history, "file/read", 0);
+       modify_attribute(timestamp, &file_history, "file/write", 0);
+       modify_attribute(timestamp, &file_history, "file/flag", -1);
+       modify_attribute(timestamp, &file_history, "file/fd", -1);
+       modify_attribute(timestamp, &file_history, "file/birth", timestamp);
+       if (has_old)
+               modify_attribute(timestamp, &file_history, "next", old_newest);
+       else
+              nullify_attribute(timestamp, &file_history, "next");
+
+       return state_system->getQuark(file_history, "file");
+}
+
+void insert_file(Quark proc, int fd, unsigned long timestamp)
+{
+       Quark file;
+       Quark parent;
+       Quark parent_file;
+       bool parent_has_file;
+       std::string name;
+
+       if (fd < 0)
+               return;
+
+       if (get_file(proc, fd, file)) {
+               if (state_system->attributeExists(proc, "threadparent")) {
+                       parent = state_system->getQuark(proc, "threadparent");
+                       parent_has_file = get_file(parent, fd,
+                                                  parent_file);
+                       if (parent_has_file) {
+                               get_current_attribute_value_string(&parent_file,
+                                                                  "name",
+                                                                  name);
+                               modify_attribute(timestamp, &file, "name",
+                                                name);
+                       }
+               }
+       } else {
+               file = create_file(proc, "Unknown", timestamp);
+               add_file(proc, file, fd, timestamp);
+       }
+}
+
+void close_file(unsigned long timestamp, Quark proc, int fd)
+{
+       Quark file;
+       bool file_found;
+
+       file_found = get_current_attribute_value_quark(&proc,
+                                                      path_name_from_fd(fd),
+                                                      file);
+       if (file_found) {
+               modify_attribute(timestamp, &file, "flag", __NR_close);
+               decrement_attribute(timestamp, NULL, "nbfiles");
+       }
+       increment_attribute(timestamp, NULL, "nbdeadfiles");
+}
+
+bool get_file(Quark proc_quark, int fd, Quark &file_quark)
+{
+       std::string path = path_name_from_fd(fd);
+       Quark file_pointer;
+       if (state_system->attributeExists(proc_quark, path)) {
+               file_pointer = state_system->getQuark(proc_quark, path);
+               return get_current_attribute_value_quark(&file_pointer, "file",
+                                                        file_quark);
+       } else {
+               return false;
+       }
+}
+
+void show_history(Quark proc)
+{
+       Quark file;
+       int fd;
+       std::string name;
+
+       if (get_current_attribute_value_quark(&proc, "files_history", file)) {
+               do {
+                       fd = -1;
+                       name = "";
+                       get_current_attribute_value_int(&file, "file/fd", fd);
+                       get_current_attribute_value_string(
+                               &file, "file/name", name);
+                       fprintf(stderr, "fd = %d, name = %s\n", fd,
+                               name.c_str());
+               } while (get_current_attribute_value_quark(
+                                &file, "next", file));
+       }
+
+}
+
+int update_iostream_ret(int tid, char *comm, unsigned long timestamp,
+                                 uint64_t cpu_id, int ret)
+{
+       Quark proc_quark;
+       Quark syscall_info_quark;
+       Quark file_quark;
+       Quark file_history_quark;
+       bool file_found;
+       int syscall_type;
+       int fd;
+       int err = 0;
+
+       proc_quark = get_proc(tid, comm, timestamp);
+
+       if (state_system->attributeExists(proc_quark, "syscall_info")) {
+               syscall_info_quark = state_system->getQuark(proc_quark,
+                                                           "syscall_info");
+               get_current_attribute_value_int(&syscall_info_quark, "type",
+                                               syscall_type);
+               if (syscall_type == __NR_read && ret > 0) {
+                       increase_attribute(timestamp, &proc_quark,
+                                          "totalfileread", ret);
+                       increase_attribute(timestamp, &proc_quark,
+                                          "fileread", ret);
+                       get_current_attribute_value_int(&syscall_info_quark,
+                                                       "fd", fd);
+                       file_found = get_file(proc_quark, fd,
+                                                       file_quark);
+                       if (file_found)
+                               increase_attribute(timestamp, &file_quark,
+                                                  "read", ret);
+               } else if (syscall_type == __NR_write && ret > 0) {
+
+                       increase_attribute(timestamp, &proc_quark,
+                                          "totalfilewrite", ret);
+                       increase_attribute(timestamp, &proc_quark,
+                                          "filewrite", ret);
+                       get_current_attribute_value_int(&syscall_info_quark,
+                                                       "fd", fd);
+                       file_found = get_file(proc_quark, fd,
+                                                       file_quark);
+                       if (file_found)
+                               increase_attribute(timestamp, &file_quark,
+                                                  "write", ret);
+               } else if (syscall_type == __NR_open && ret > 0) {
+                       file_history_quark = state_system->getQuark(proc_quark,
+                                                                   "files_history");
+                       file_quark = state_system->getQuark(file_history_quark,
+                                                           "current/file");
+                       add_file(proc_quark, file_quark, ret,
+                                          timestamp);
+                       modify_attribute(timestamp, &file_quark, "fd", fd);
+               } else {
+                       err = -1;
+               }
+       }
+       return err;
+}
+
+void update_syscall_info(unsigned long timestamp, int type, int cpu_id,
+       Quark proc, int fd)
+{
+       int tid;
+
+       get_current_attribute_value_int(&proc, "tid", tid);
+       modify_attribute(timestamp, &proc, "syscall_info/type", type);
+       modify_attribute(timestamp, &proc, "syscall_info/cpu_id", cpu_id);
+       modify_attribute(timestamp, &proc, "syscall_info/tid", tid);
+       modify_attribute(timestamp, &proc, "syscall_info/fd", fd);
+}
+
+enum bt_cb_ret handle_exit_syscall(struct bt_ctf_event *call_data,
+                                            void *private_data)
+{
+       const struct definition *scope;
+       unsigned long timestamp;
+       char *comm;
+       uint64_t ret, tid;
+       uint64_t cpu_id;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       comm = get_context_comm(call_data);
+       tid = get_context_tid(call_data);
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       ret = bt_ctf_get_int64(bt_ctf_get_field(call_data,
+                                               scope, "_ret"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing ret context info\n");
+               goto error;
+       }
+
+       cpu_id = get_cpu_id(call_data);
+
+       /*
+        * if we encounter an exit_syscall and
+        * it is not for a syscall read or write
+        * we just abort the execution of this callback
+        */
+       if (update_iostream_ret(
+                   tid, comm, timestamp, cpu_id, ret) < 0)
+               return BT_CB_ERROR_CONTINUE;
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
+enum bt_cb_ret handle_sys_write(struct bt_ctf_event *call_data,
+                                         void *private_data)
+{
+       const struct definition *scope;
+       Quark proc;
+       unsigned long timestamp;
+       int cpu_id;
+       int tid;
+       char *procname;
+       int fd;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       tid = get_context_tid(call_data);
+       cpu_id = get_cpu_id(call_data);
+
+       procname = get_context_comm(call_data);
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
+                                               scope, "_fd"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing fd context info\n");
+               goto error;
+       }
+
+       proc = get_proc(tid, procname, timestamp);
+       update_syscall_info(timestamp, __NR_write, cpu_id, proc, fd);
+
+       insert_file(proc, fd, timestamp);
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
+enum bt_cb_ret handle_sys_read(struct bt_ctf_event *call_data,
+                                        void *private_data)
+{
+       const struct definition *scope;
+       Quark proc;
+       unsigned long timestamp;
+       uint64_t cpu_id;
+       int64_t tid;
+       char *procname;
+       int fd;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       tid = get_context_tid(call_data);
+       cpu_id = get_cpu_id(call_data);
+
+       procname = get_context_comm(call_data);
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
+                                               scope, "_fd"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing fd context info\n");
+               goto error;
+       }
+
+       proc = get_proc(tid, procname, timestamp);
+       update_syscall_info(timestamp, __NR_read, cpu_id, proc, fd);
+
+       insert_file(proc, fd, timestamp);
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
+enum bt_cb_ret handle_sys_open(struct bt_ctf_event *call_data,
+                                        void *private_data)
+{
+       Quark proc;
+       const struct definition *scope;
+       unsigned long timestamp;
+       uint64_t cpu_id;
+       int64_t tid;
+       char *procname;
+       char *file;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       tid = get_context_tid(call_data);
+       cpu_id = get_cpu_id(call_data);
+
+       procname = get_context_comm(call_data);
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       file = bt_ctf_get_string(bt_ctf_get_field(call_data,
+                                                 scope, "_filename"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing file name context info\n");
+               goto error;
+       }
+
+       proc = get_proc(tid, procname, timestamp);
+       update_syscall_info(timestamp, __NR_open, cpu_id, proc, -1);
+
+       create_file(proc, file, timestamp);
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
+enum bt_cb_ret handle_sys_close(struct bt_ctf_event *call_data,
+                                         void *private_data)
+{
+       const struct definition *scope;
+       Quark proc;
+       unsigned long timestamp;
+       int64_t tid;
+       char *procname;
+       int fd;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       tid = get_context_tid(call_data);
+
+       procname = get_context_comm(call_data);
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       fd = bt_ctf_get_uint64(bt_ctf_get_field(call_data,
+                                               scope, "_fd"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing fd context info\n");
+               goto error;
+       }
+
+       proc = get_proc(tid, procname, timestamp);
+
+       close_file(timestamp, proc, fd);
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
+
+enum bt_cb_ret handle_statedump_file_descriptor(
+       struct bt_ctf_event *call_data, void *private_data)
+{
+       const struct definition *scope;
+       Quark parent;
+       Quark file;
+       unsigned long timestamp;
+       int64_t pid;
+       char *file_name;
+       int fd;
+
+       timestamp = bt_ctf_get_timestamp(call_data);
+       if (timestamp == -1ULL)
+               goto error;
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       pid = bt_ctf_get_int64(bt_ctf_get_field(call_data,
+                                               scope, "_pid"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing tid context info\n");
+               goto error;
+       }
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       fd = bt_ctf_get_int64(bt_ctf_get_field(call_data,
+                                              scope, "_fd"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing fd context info\n");
+               goto error;
+       }
+
+       scope = bt_ctf_get_top_level_scope(call_data,
+                                          BT_EVENT_FIELDS);
+       file_name = bt_ctf_get_string(bt_ctf_get_field(call_data,
+                                                      scope, "_filename"));
+       if (bt_ctf_field_get_error()) {
+               fprintf(stderr, "Missing file name context info\n");
+               goto error;
+       }
+
+       parent = get_proc_pid(pid, pid, timestamp);
+       create_file(parent, file_name, timestamp);
+       file = state_system->getQuark(parent, "files_history/current/file");
+       edit_file(timestamp, parent, file, fd);
+
+       return BT_CB_OK;
+
+error:
+       return BT_CB_ERROR_STOP;
+}
This page took 0.027098 seconds and 4 git commands to generate.