From 0c22e8b31651caf12a2b4d4acef5bc65d486e570 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 2 Nov 2012 15:46:56 -0700 Subject: [PATCH] dumpstate: dump all threads in show_wchan for_each_pid only finds processes and not their threads. Add for_each_tid and call it for show_wchan so we can see where all threads are blocked in the kernel. Change-Id: Iffb59f7c2933cecf51cdd358a36e19932c2f24c7 --- cmds/dumpstate/dumpstate.c | 2 +- cmds/dumpstate/dumpstate.h | 11 +++++- cmds/dumpstate/utils.c | 77 +++++++++++++++++++++++++++++++++++--- 3 files changed, 81 insertions(+), 9 deletions(-) diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index f3fcca05a..1aae99e3e 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -102,7 +102,7 @@ static void dumpstate() { run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL); for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES"); - for_each_pid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS"); + for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS"); // dump_file("EVENT LOG TAGS", "/etc/event-log-tags"); run_command("SYSTEM LOG", 20, "logcat", "-v", "threadtime", "-d", "*:v", NULL); diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 45247cd28..67bbd7e2a 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -19,10 +19,14 @@ #include #include +#include #include #define SU_PATH "/system/xbin/su" +typedef void (for_each_pid_func)(int, const char *); +typedef void (for_each_tid_func)(int, int, const char *); + /* prints the contents of a file */ int dump_file(const char *title, const char* path); @@ -42,10 +46,13 @@ pid_t redirect_to_file(FILE *redirect, char *path, int gzip_level); const char *dump_traces(); /* for each process in the system, run the specified function */ -void for_each_pid(void (*func)(int, const char *), const char *header); +void for_each_pid(for_each_pid_func func, const char *header); + +/* for each thread in the system, run the specified function */ +void for_each_tid(for_each_tid_func func, const char *header); /* Displays a blocked processes in-kernel wait channel */ -void show_wchan(int pid, const char *name); +void show_wchan(int pid, int tid, const char *name); /* Runs "showmap" for a process */ void do_showmap(int pid, const char *name); diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c index 8f132d5f4..c85690d98 100644 --- a/cmds/dumpstate/utils.c +++ b/cmds/dumpstate/utils.c @@ -48,7 +48,7 @@ static const char* native_processes_to_dump[] = { NULL, }; -void for_each_pid(void (*func)(int, const char *), const char *header) { +static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) { DIR *d; struct dirent *de; @@ -73,23 +73,85 @@ void for_each_pid(void (*func)(int, const char *), const char *header) { if ((fd = open(cmdpath, O_RDONLY)) < 0) { strcpy(cmdline, "N/A"); } else { - read(fd, cmdline, sizeof(cmdline)); + read(fd, cmdline, sizeof(cmdline) - 1); close(fd); } - func(pid, cmdline); + helper(pid, cmdline, arg); } closedir(d); } -void show_wchan(int pid, const char *name) { +static void for_each_pid_helper(int pid, const char *cmdline, void *arg) { + for_each_pid_func *func = arg; + func(pid, cmdline); +} + +void for_each_pid(for_each_pid_func func, const char *header) { + __for_each_pid(for_each_pid_helper, header, func); +} + +static void for_each_tid_helper(int pid, const char *cmdline, void *arg) { + DIR *d; + struct dirent *de; + char taskpath[255]; + for_each_tid_func *func = arg; + + sprintf(taskpath, "/proc/%d/task", pid); + + if (!(d = opendir(taskpath))) { + printf("Failed to open %s (%s)\n", taskpath, strerror(errno)); + return; + } + + func(pid, pid, cmdline); + + while ((de = readdir(d))) { + int tid; + int fd; + char commpath[255]; + char comm[255]; + + if (!(tid = atoi(de->d_name))) { + continue; + } + + if (tid == pid) + continue; + + sprintf(commpath,"/proc/%d/comm", tid); + memset(comm, 0, sizeof(cmdline)); + if ((fd = open(commpath, O_RDONLY)) < 0) { + strcpy(comm, "N/A"); + } else { + char *c; + read(fd, comm, sizeof(comm) - 1); + close(fd); + + c = strrchr(comm, '\n'); + if (c) { + *c = '\0'; + } + } + func(pid, tid, comm); + } + + closedir(d); +} + +void for_each_tid(for_each_tid_func func, const char *header) { + __for_each_pid(for_each_tid_helper, header, func); +} + +void show_wchan(int pid, int tid, const char *name) { char path[255]; char buffer[255]; int fd; + char name_buffer[255]; memset(buffer, 0, sizeof(buffer)); - sprintf(path, "/proc/%d/wchan", pid); + sprintf(path, "/proc/%d/wchan", tid); if ((fd = open(path, O_RDONLY)) < 0) { printf("Failed to open '%s' (%s)\n", path, strerror(errno)); return; @@ -100,7 +162,10 @@ void show_wchan(int pid, const char *name) { goto out_close; } - printf("%-7d %-32s %s\n", pid, name, buffer); + snprintf(name_buffer, sizeof(name_buffer), "%*s%s", + pid == tid ? 0 : 3, "", name); + + printf("%-7d %-32s %s\n", tid, name_buffer, buffer); out_close: close(fd);