1#include "../perf.h"
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5#include "session.h"
6#include "thread.h"
7#include "thread-stack.h"
8#include "util.h"
9#include "debug.h"
10#include "comm.h"
11#include "unwind.h"
12
13int thread__init_map_groups(struct thread *thread, struct machine *machine)
14{
15	struct thread *leader;
16	pid_t pid = thread->pid_;
17
18	if (pid == thread->tid || pid == -1) {
19		thread->mg = map_groups__new(machine);
20	} else {
21		leader = machine__findnew_thread(machine, pid, pid);
22		if (leader)
23			thread->mg = map_groups__get(leader->mg);
24	}
25
26	return thread->mg ? 0 : -1;
27}
28
29struct thread *thread__new(pid_t pid, pid_t tid)
30{
31	char *comm_str;
32	struct comm *comm;
33	struct thread *thread = zalloc(sizeof(*thread));
34
35	if (thread != NULL) {
36		thread->pid_ = pid;
37		thread->tid = tid;
38		thread->ppid = -1;
39		thread->cpu = -1;
40		INIT_LIST_HEAD(&thread->comm_list);
41
42		if (unwind__prepare_access(thread) < 0)
43			goto err_thread;
44
45		comm_str = malloc(32);
46		if (!comm_str)
47			goto err_thread;
48
49		snprintf(comm_str, 32, ":%d", tid);
50		comm = comm__new(comm_str, 0, false);
51		free(comm_str);
52		if (!comm)
53			goto err_thread;
54
55		list_add(&comm->list, &thread->comm_list);
56
57	}
58
59	return thread;
60
61err_thread:
62	free(thread);
63	return NULL;
64}
65
66void thread__delete(struct thread *thread)
67{
68	struct comm *comm, *tmp;
69
70	thread_stack__free(thread);
71
72	if (thread->mg) {
73		map_groups__put(thread->mg);
74		thread->mg = NULL;
75	}
76	list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
77		list_del(&comm->list);
78		comm__free(comm);
79	}
80	unwind__finish_access(thread);
81
82	free(thread);
83}
84
85struct thread *thread__get(struct thread *thread)
86{
87	++thread->refcnt;
88	return thread;
89}
90
91void thread__put(struct thread *thread)
92{
93	if (thread && --thread->refcnt == 0) {
94		list_del_init(&thread->node);
95		thread__delete(thread);
96	}
97}
98
99struct comm *thread__comm(const struct thread *thread)
100{
101	if (list_empty(&thread->comm_list))
102		return NULL;
103
104	return list_first_entry(&thread->comm_list, struct comm, list);
105}
106
107struct comm *thread__exec_comm(const struct thread *thread)
108{
109	struct comm *comm, *last = NULL;
110
111	list_for_each_entry(comm, &thread->comm_list, list) {
112		if (comm->exec)
113			return comm;
114		last = comm;
115	}
116
117	return last;
118}
119
120int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
121		       bool exec)
122{
123	struct comm *new, *curr = thread__comm(thread);
124	int err;
125
126	/* Override the default :tid entry */
127	if (!thread->comm_set) {
128		err = comm__override(curr, str, timestamp, exec);
129		if (err)
130			return err;
131	} else {
132		new = comm__new(str, timestamp, exec);
133		if (!new)
134			return -ENOMEM;
135		list_add(&new->list, &thread->comm_list);
136
137		if (exec)
138			unwind__flush_access(thread);
139	}
140
141	thread->comm_set = true;
142
143	return 0;
144}
145
146const char *thread__comm_str(const struct thread *thread)
147{
148	const struct comm *comm = thread__comm(thread);
149
150	if (!comm)
151		return NULL;
152
153	return comm__str(comm);
154}
155
156/* CHECKME: it should probably better return the max comm len from its comm list */
157int thread__comm_len(struct thread *thread)
158{
159	if (!thread->comm_len) {
160		const char *comm = thread__comm_str(thread);
161		if (!comm)
162			return 0;
163		thread->comm_len = strlen(comm);
164	}
165
166	return thread->comm_len;
167}
168
169size_t thread__fprintf(struct thread *thread, FILE *fp)
170{
171	return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
172	       map_groups__fprintf(thread->mg, fp);
173}
174
175void thread__insert_map(struct thread *thread, struct map *map)
176{
177	map_groups__fixup_overlappings(thread->mg, map, stderr);
178	map_groups__insert(thread->mg, map);
179}
180
181static int thread__clone_map_groups(struct thread *thread,
182				    struct thread *parent)
183{
184	int i;
185
186	/* This is new thread, we share map groups for process. */
187	if (thread->pid_ == parent->pid_)
188		return 0;
189
190	/* But this one is new process, copy maps. */
191	for (i = 0; i < MAP__NR_TYPES; ++i)
192		if (map_groups__clone(thread->mg, parent->mg, i) < 0)
193			return -ENOMEM;
194
195	return 0;
196}
197
198int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
199{
200	int err;
201
202	if (parent->comm_set) {
203		const char *comm = thread__comm_str(parent);
204		if (!comm)
205			return -ENOMEM;
206		err = thread__set_comm(thread, comm, timestamp);
207		if (err)
208			return err;
209	}
210
211	thread->ppid = parent->tid;
212	return thread__clone_map_groups(thread, parent);
213}
214
215void thread__find_cpumode_addr_location(struct thread *thread,
216					enum map_type type, u64 addr,
217					struct addr_location *al)
218{
219	size_t i;
220	const u8 const cpumodes[] = {
221		PERF_RECORD_MISC_USER,
222		PERF_RECORD_MISC_KERNEL,
223		PERF_RECORD_MISC_GUEST_USER,
224		PERF_RECORD_MISC_GUEST_KERNEL
225	};
226
227	for (i = 0; i < ARRAY_SIZE(cpumodes); i++) {
228		thread__find_addr_location(thread, cpumodes[i], type, addr, al);
229		if (al->map)
230			break;
231	}
232}
233