1 #include "../perf.h" 2 #include <stdlib.h> 3 #include <stdio.h> 4 #include <string.h> 5 #include "thread.h" 6 #include "util.h" 7 #include "debug.h" 8 9 static struct thread *thread__new(pid_t pid) 10 { 11 struct thread *self = calloc(1, sizeof(*self)); 12 13 if (self != NULL) { 14 self->pid = pid; 15 self->comm = malloc(32); 16 if (self->comm) 17 snprintf(self->comm, 32, ":%d", self->pid); 18 INIT_LIST_HEAD(&self->maps); 19 } 20 21 return self; 22 } 23 24 int thread__set_comm(struct thread *self, const char *comm) 25 { 26 if (self->comm) 27 free(self->comm); 28 self->comm = strdup(comm); 29 return self->comm ? 0 : -ENOMEM; 30 } 31 32 static size_t thread__fprintf(struct thread *self, FILE *fp) 33 { 34 struct map *pos; 35 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 36 37 list_for_each_entry(pos, &self->maps, node) 38 ret += map__fprintf(pos, fp); 39 40 return ret; 41 } 42 43 struct thread * 44 threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) 45 { 46 struct rb_node **p = &threads->rb_node; 47 struct rb_node *parent = NULL; 48 struct thread *th; 49 50 /* 51 * Font-end cache - PID lookups come in blocks, 52 * so most of the time we dont have to look up 53 * the full rbtree: 54 */ 55 if (*last_match && (*last_match)->pid == pid) 56 return *last_match; 57 58 while (*p != NULL) { 59 parent = *p; 60 th = rb_entry(parent, struct thread, rb_node); 61 62 if (th->pid == pid) { 63 *last_match = th; 64 return th; 65 } 66 67 if (pid < th->pid) 68 p = &(*p)->rb_left; 69 else 70 p = &(*p)->rb_right; 71 } 72 73 th = thread__new(pid); 74 if (th != NULL) { 75 rb_link_node(&th->rb_node, parent, p); 76 rb_insert_color(&th->rb_node, threads); 77 *last_match = th; 78 } 79 80 return th; 81 } 82 83 struct thread * 84 register_idle_thread(struct rb_root *threads, struct thread **last_match) 85 { 86 struct thread *thread = threads__findnew(0, threads, last_match); 87 88 if (!thread || thread__set_comm(thread, "swapper")) { 89 fprintf(stderr, "problem inserting idle task.\n"); 90 exit(-1); 91 } 92 93 return thread; 94 } 95 96 void thread__insert_map(struct thread *self, struct map *map) 97 { 98 struct map *pos, *tmp; 99 100 list_for_each_entry_safe(pos, tmp, &self->maps, node) { 101 if (map__overlap(pos, map)) { 102 if (verbose >= 2) { 103 printf("overlapping maps:\n"); 104 map__fprintf(map, stdout); 105 map__fprintf(pos, stdout); 106 } 107 108 if (map->start <= pos->start && map->end > pos->start) 109 pos->start = map->end; 110 111 if (map->end >= pos->end && map->start < pos->end) 112 pos->end = map->start; 113 114 if (verbose >= 2) { 115 printf("after collision:\n"); 116 map__fprintf(pos, stdout); 117 } 118 119 if (pos->start >= pos->end) { 120 list_del_init(&pos->node); 121 free(pos); 122 } 123 } 124 } 125 126 list_add_tail(&map->node, &self->maps); 127 } 128 129 int thread__fork(struct thread *self, struct thread *parent) 130 { 131 struct map *map; 132 133 if (self->comm) 134 free(self->comm); 135 self->comm = strdup(parent->comm); 136 if (!self->comm) 137 return -ENOMEM; 138 139 list_for_each_entry(map, &parent->maps, node) { 140 struct map *new = map__clone(map); 141 if (!new) 142 return -ENOMEM; 143 thread__insert_map(self, new); 144 } 145 146 return 0; 147 } 148 149 struct map *thread__find_map(struct thread *self, u64 ip) 150 { 151 struct map *pos; 152 153 if (self == NULL) 154 return NULL; 155 156 list_for_each_entry(pos, &self->maps, node) 157 if (ip >= pos->start && ip <= pos->end) 158 return pos; 159 160 return NULL; 161 } 162 163 size_t threads__fprintf(FILE *fp, struct rb_root *threads) 164 { 165 size_t ret = 0; 166 struct rb_node *nd; 167 168 for (nd = rb_first(threads); nd; nd = rb_next(nd)) { 169 struct thread *pos = rb_entry(nd, struct thread, rb_node); 170 171 ret += thread__fprintf(pos, fp); 172 } 173 174 return ret; 175 } 176