]>
Commit | Line | Data |
---|---|---|
6baa0a5a FW |
1 | #include "../perf.h" |
2 | #include <stdlib.h> | |
3 | #include <stdio.h> | |
4 | #include <string.h> | |
5 | #include "thread.h" | |
6 | #include "util.h" | |
6e086437 | 7 | #include "debug.h" |
6baa0a5a FW |
8 | |
9 | static struct thread *thread__new(pid_t pid) | |
10 | { | |
0ec04e16 | 11 | struct thread *self = calloc(1, sizeof(*self)); |
6baa0a5a FW |
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 | ||
5b447a6a FW |
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 | ||
80ed0987 | 88 | if (!thread || thread__set_comm(thread, "swapper")) { |
5b447a6a FW |
89 | fprintf(stderr, "problem inserting idle task.\n"); |
90 | exit(-1); | |
91 | } | |
92 | ||
93 | return thread; | |
94 | } | |
95 | ||
6baa0a5a FW |
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)) { | |
6e086437 FW |
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 | } | |
6baa0a5a FW |
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 | } |