]> Git Repo - linux.git/blob - tools/perf/util/thread.c
powerpc/vdso64: Fix CLOCK_MONOTONIC inconsistencies across Y2038
[linux.git] / tools / perf / util / thread.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include "../perf.h"
3 #include <errno.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <linux/kernel.h>
8 #include "session.h"
9 #include "thread.h"
10 #include "thread-stack.h"
11 #include "util.h"
12 #include "debug.h"
13 #include "namespaces.h"
14 #include "comm.h"
15 #include "map.h"
16 #include "symbol.h"
17 #include "unwind.h"
18
19 #include <api/fs/fs.h>
20
21 int thread__init_map_groups(struct thread *thread, struct machine *machine)
22 {
23         pid_t pid = thread->pid_;
24
25         if (pid == thread->tid || pid == -1) {
26                 thread->mg = map_groups__new(machine);
27         } else {
28                 struct thread *leader = __machine__findnew_thread(machine, pid, pid);
29                 if (leader) {
30                         thread->mg = map_groups__get(leader->mg);
31                         thread__put(leader);
32                 }
33         }
34
35         return thread->mg ? 0 : -1;
36 }
37
38 struct thread *thread__new(pid_t pid, pid_t tid)
39 {
40         char *comm_str;
41         struct comm *comm;
42         struct thread *thread = zalloc(sizeof(*thread));
43
44         if (thread != NULL) {
45                 thread->pid_ = pid;
46                 thread->tid = tid;
47                 thread->ppid = -1;
48                 thread->cpu = -1;
49                 INIT_LIST_HEAD(&thread->namespaces_list);
50                 INIT_LIST_HEAD(&thread->comm_list);
51                 init_rwsem(&thread->namespaces_lock);
52                 init_rwsem(&thread->comm_lock);
53
54                 comm_str = malloc(32);
55                 if (!comm_str)
56                         goto err_thread;
57
58                 snprintf(comm_str, 32, ":%d", tid);
59                 comm = comm__new(comm_str, 0, false);
60                 free(comm_str);
61                 if (!comm)
62                         goto err_thread;
63
64                 list_add(&comm->list, &thread->comm_list);
65                 refcount_set(&thread->refcnt, 1);
66                 RB_CLEAR_NODE(&thread->rb_node);
67                 /* Thread holds first ref to nsdata. */
68                 thread->nsinfo = nsinfo__new(pid);
69                 srccode_state_init(&thread->srccode_state);
70         }
71
72         return thread;
73
74 err_thread:
75         free(thread);
76         return NULL;
77 }
78
79 void thread__delete(struct thread *thread)
80 {
81         struct namespaces *namespaces, *tmp_namespaces;
82         struct comm *comm, *tmp_comm;
83
84         BUG_ON(!RB_EMPTY_NODE(&thread->rb_node));
85
86         thread_stack__free(thread);
87
88         if (thread->mg) {
89                 map_groups__put(thread->mg);
90                 thread->mg = NULL;
91         }
92         down_write(&thread->namespaces_lock);
93         list_for_each_entry_safe(namespaces, tmp_namespaces,
94                                  &thread->namespaces_list, list) {
95                 list_del(&namespaces->list);
96                 namespaces__free(namespaces);
97         }
98         up_write(&thread->namespaces_lock);
99
100         down_write(&thread->comm_lock);
101         list_for_each_entry_safe(comm, tmp_comm, &thread->comm_list, list) {
102                 list_del(&comm->list);
103                 comm__free(comm);
104         }
105         up_write(&thread->comm_lock);
106
107         unwind__finish_access(thread);
108         nsinfo__zput(thread->nsinfo);
109         srccode_state_free(&thread->srccode_state);
110
111         exit_rwsem(&thread->namespaces_lock);
112         exit_rwsem(&thread->comm_lock);
113         free(thread);
114 }
115
116 struct thread *thread__get(struct thread *thread)
117 {
118         if (thread)
119                 refcount_inc(&thread->refcnt);
120         return thread;
121 }
122
123 void thread__put(struct thread *thread)
124 {
125         if (thread && refcount_dec_and_test(&thread->refcnt)) {
126                 /*
127                  * Remove it from the dead_threads list, as last reference
128                  * is gone.
129                  */
130                 list_del_init(&thread->node);
131                 thread__delete(thread);
132         }
133 }
134
135 struct namespaces *thread__namespaces(const struct thread *thread)
136 {
137         if (list_empty(&thread->namespaces_list))
138                 return NULL;
139
140         return list_first_entry(&thread->namespaces_list, struct namespaces, list);
141 }
142
143 static int __thread__set_namespaces(struct thread *thread, u64 timestamp,
144                                     struct namespaces_event *event)
145 {
146         struct namespaces *new, *curr = thread__namespaces(thread);
147
148         new = namespaces__new(event);
149         if (!new)
150                 return -ENOMEM;
151
152         list_add(&new->list, &thread->namespaces_list);
153
154         if (timestamp && curr) {
155                 /*
156                  * setns syscall must have changed few or all the namespaces
157                  * of this thread. Update end time for the namespaces
158                  * previously used.
159                  */
160                 curr = list_next_entry(new, list);
161                 curr->end_time = timestamp;
162         }
163
164         return 0;
165 }
166
167 int thread__set_namespaces(struct thread *thread, u64 timestamp,
168                            struct namespaces_event *event)
169 {
170         int ret;
171
172         down_write(&thread->namespaces_lock);
173         ret = __thread__set_namespaces(thread, timestamp, event);
174         up_write(&thread->namespaces_lock);
175         return ret;
176 }
177
178 struct comm *thread__comm(const struct thread *thread)
179 {
180         if (list_empty(&thread->comm_list))
181                 return NULL;
182
183         return list_first_entry(&thread->comm_list, struct comm, list);
184 }
185
186 struct comm *thread__exec_comm(const struct thread *thread)
187 {
188         struct comm *comm, *last = NULL;
189
190         list_for_each_entry(comm, &thread->comm_list, list) {
191                 if (comm->exec)
192                         return comm;
193                 last = comm;
194         }
195
196         return last;
197 }
198
199 static int ____thread__set_comm(struct thread *thread, const char *str,
200                                 u64 timestamp, bool exec)
201 {
202         struct comm *new, *curr = thread__comm(thread);
203
204         /* Override the default :tid entry */
205         if (!thread->comm_set) {
206                 int err = comm__override(curr, str, timestamp, exec);
207                 if (err)
208                         return err;
209         } else {
210                 new = comm__new(str, timestamp, exec);
211                 if (!new)
212                         return -ENOMEM;
213                 list_add(&new->list, &thread->comm_list);
214
215                 if (exec)
216                         unwind__flush_access(thread);
217         }
218
219         thread->comm_set = true;
220
221         return 0;
222 }
223
224 int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
225                        bool exec)
226 {
227         int ret;
228
229         down_write(&thread->comm_lock);
230         ret = ____thread__set_comm(thread, str, timestamp, exec);
231         up_write(&thread->comm_lock);
232         return ret;
233 }
234
235 int thread__set_comm_from_proc(struct thread *thread)
236 {
237         char path[64];
238         char *comm = NULL;
239         size_t sz;
240         int err = -1;
241
242         if (!(snprintf(path, sizeof(path), "%d/task/%d/comm",
243                        thread->pid_, thread->tid) >= (int)sizeof(path)) &&
244             procfs__read_str(path, &comm, &sz) == 0) {
245                 comm[sz - 1] = '\0';
246                 err = thread__set_comm(thread, comm, 0);
247         }
248
249         return err;
250 }
251
252 static const char *__thread__comm_str(const struct thread *thread)
253 {
254         const struct comm *comm = thread__comm(thread);
255
256         if (!comm)
257                 return NULL;
258
259         return comm__str(comm);
260 }
261
262 const char *thread__comm_str(const struct thread *thread)
263 {
264         const char *str;
265
266         down_read((struct rw_semaphore *)&thread->comm_lock);
267         str = __thread__comm_str(thread);
268         up_read((struct rw_semaphore *)&thread->comm_lock);
269
270         return str;
271 }
272
273 /* CHECKME: it should probably better return the max comm len from its comm list */
274 int thread__comm_len(struct thread *thread)
275 {
276         if (!thread->comm_len) {
277                 const char *comm = thread__comm_str(thread);
278                 if (!comm)
279                         return 0;
280                 thread->comm_len = strlen(comm);
281         }
282
283         return thread->comm_len;
284 }
285
286 size_t thread__fprintf(struct thread *thread, FILE *fp)
287 {
288         return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
289                map_groups__fprintf(thread->mg, fp);
290 }
291
292 int thread__insert_map(struct thread *thread, struct map *map)
293 {
294         int ret;
295
296         ret = unwind__prepare_access(thread, map, NULL);
297         if (ret)
298                 return ret;
299
300         map_groups__fixup_overlappings(thread->mg, map, stderr);
301         map_groups__insert(thread->mg, map);
302
303         return 0;
304 }
305
306 static int __thread__prepare_access(struct thread *thread)
307 {
308         bool initialized = false;
309         int err = 0;
310         struct maps *maps = &thread->mg->maps;
311         struct map *map;
312
313         down_read(&maps->lock);
314
315         for (map = maps__first(maps); map; map = map__next(map)) {
316                 err = unwind__prepare_access(thread, map, &initialized);
317                 if (err || initialized)
318                         break;
319         }
320
321         up_read(&maps->lock);
322
323         return err;
324 }
325
326 static int thread__prepare_access(struct thread *thread)
327 {
328         int err = 0;
329
330         if (symbol_conf.use_callchain)
331                 err = __thread__prepare_access(thread);
332
333         return err;
334 }
335
336 static int thread__clone_map_groups(struct thread *thread,
337                                     struct thread *parent,
338                                     bool do_maps_clone)
339 {
340         /* This is new thread, we share map groups for process. */
341         if (thread->pid_ == parent->pid_)
342                 return thread__prepare_access(thread);
343
344         if (thread->mg == parent->mg) {
345                 pr_debug("broken map groups on thread %d/%d parent %d/%d\n",
346                          thread->pid_, thread->tid, parent->pid_, parent->tid);
347                 return 0;
348         }
349         /* But this one is new process, copy maps. */
350         return do_maps_clone ? map_groups__clone(thread, parent->mg) : 0;
351 }
352
353 int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bool do_maps_clone)
354 {
355         if (parent->comm_set) {
356                 const char *comm = thread__comm_str(parent);
357                 int err;
358                 if (!comm)
359                         return -ENOMEM;
360                 err = thread__set_comm(thread, comm, timestamp);
361                 if (err)
362                         return err;
363         }
364
365         thread->ppid = parent->tid;
366         return thread__clone_map_groups(thread, parent, do_maps_clone);
367 }
368
369 void thread__find_cpumode_addr_location(struct thread *thread, u64 addr,
370                                         struct addr_location *al)
371 {
372         size_t i;
373         const u8 cpumodes[] = {
374                 PERF_RECORD_MISC_USER,
375                 PERF_RECORD_MISC_KERNEL,
376                 PERF_RECORD_MISC_GUEST_USER,
377                 PERF_RECORD_MISC_GUEST_KERNEL
378         };
379
380         for (i = 0; i < ARRAY_SIZE(cpumodes); i++) {
381                 thread__find_symbol(thread, cpumodes[i], addr, al);
382                 if (al->map)
383                         break;
384         }
385 }
386
387 struct thread *thread__main_thread(struct machine *machine, struct thread *thread)
388 {
389         if (thread->pid_ == thread->tid)
390                 return thread__get(thread);
391
392         if (thread->pid_ == -1)
393                 return NULL;
394
395         return machine__find_thread(machine, thread->pid_, thread->pid_);
396 }
397
398 int thread__memcpy(struct thread *thread, struct machine *machine,
399                    void *buf, u64 ip, int len, bool *is64bit)
400 {
401        u8 cpumode = PERF_RECORD_MISC_USER;
402        struct addr_location al;
403        long offset;
404
405        if (machine__kernel_ip(machine, ip))
406                cpumode = PERF_RECORD_MISC_KERNEL;
407
408        if (!thread__find_map(thread, cpumode, ip, &al) || !al.map->dso ||
409            al.map->dso->data.status == DSO_DATA_STATUS_ERROR ||
410            map__load(al.map) < 0)
411                return -1;
412
413        offset = al.map->map_ip(al.map, ip);
414        if (is64bit)
415                *is64bit = al.map->dso->is_64_bit;
416
417        return dso__data_read_offset(al.map->dso, machine, offset, buf, len);
418 }
This page took 0.055431 seconds and 4 git commands to generate.