thread.c 6.4 KB
Newer Older
1 2 3 4
#include "../perf.h"
#include <stdlib.h>
#include <stdio.h>
#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

13 14
#include <api/fs/fs.h>

15 16 17 18 19
int thread__init_map_groups(struct thread *thread, struct machine *machine)
{
	struct thread *leader;
	pid_t pid = thread->pid_;

20
	if (pid == thread->tid || pid == -1) {
21
		thread->mg = map_groups__new(machine);
22
	} else {
23
		leader = __machine__findnew_thread(machine, pid, pid);
24
		if (leader) {
25
			thread->mg = map_groups__get(leader->mg);
26 27
			thread__put(leader);
		}
28 29 30 31 32
	}

	return thread->mg ? 0 : -1;
}

33
struct thread *thread__new(pid_t pid, pid_t tid)
34
{
35 36
	char *comm_str;
	struct comm *comm;
37
	struct thread *thread = zalloc(sizeof(*thread));
38

39 40 41 42
	if (thread != NULL) {
		thread->pid_ = pid;
		thread->tid = tid;
		thread->ppid = -1;
43
		thread->cpu = -1;
44 45 46 47 48 49 50
		INIT_LIST_HEAD(&thread->comm_list);

		comm_str = malloc(32);
		if (!comm_str)
			goto err_thread;

		snprintf(comm_str, 32, ":%d", tid);
51
		comm = comm__new(comm_str, 0, false);
52 53 54 55 56
		free(comm_str);
		if (!comm)
			goto err_thread;

		list_add(&comm->list, &thread->comm_list);
57
		atomic_set(&thread->refcnt, 1);
58
		RB_CLEAR_NODE(&thread->rb_node);
59 60
	}

61
	return thread;
62 63 64 65

err_thread:
	free(thread);
	return NULL;
66 67
}

68
void thread__delete(struct thread *thread)
69
{
70 71
	struct comm *comm, *tmp;

72 73
	BUG_ON(!RB_EMPTY_NODE(&thread->rb_node));

74 75
	thread_stack__free(thread);

76 77 78 79
	if (thread->mg) {
		map_groups__put(thread->mg);
		thread->mg = NULL;
	}
80 81 82 83
	list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
		list_del(&comm->list);
		comm__free(comm);
	}
84
	unwind__finish_access(thread);
85

86
	free(thread);
87 88
}

89 90
struct thread *thread__get(struct thread *thread)
{
91 92
	if (thread)
		atomic_inc(&thread->refcnt);
93 94 95 96 97
	return thread;
}

void thread__put(struct thread *thread)
{
98
	if (thread && atomic_dec_and_test(&thread->refcnt)) {
99 100 101 102
		/*
		 * Remove it from the dead_threads list, as last reference
		 * is gone.
		 */
103 104 105 106 107
		list_del_init(&thread->node);
		thread__delete(thread);
	}
}

108
struct comm *thread__comm(const struct thread *thread)
109
{
110 111
	if (list_empty(&thread->comm_list))
		return NULL;
112

113 114 115
	return list_first_entry(&thread->comm_list, struct comm, list);
}

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
struct comm *thread__exec_comm(const struct thread *thread)
{
	struct comm *comm, *last = NULL;

	list_for_each_entry(comm, &thread->comm_list, list) {
		if (comm->exec)
			return comm;
		last = comm;
	}

	return last;
}

int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
		       bool exec)
131 132
{
	struct comm *new, *curr = thread__comm(thread);
133
	int err;
134

135 136
	/* Override the default :tid entry */
	if (!thread->comm_set) {
137
		err = comm__override(curr, str, timestamp, exec);
138 139
		if (err)
			return err;
140
	} else {
141
		new = comm__new(str, timestamp, exec);
142 143 144
		if (!new)
			return -ENOMEM;
		list_add(&new->list, &thread->comm_list);
145 146 147

		if (exec)
			unwind__flush_access(thread);
148
	}
149 150 151 152

	thread->comm_set = true;

	return 0;
153 154
}

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
int thread__set_comm_from_proc(struct thread *thread)
{
	char path[64];
	char *comm = NULL;
	size_t sz;
	int err = -1;

	if (!(snprintf(path, sizeof(path), "%d/task/%d/comm",
		       thread->pid_, thread->tid) >= (int)sizeof(path)) &&
	    procfs__read_str(path, &comm, &sz) == 0) {
		comm[sz - 1] = '\0';
		err = thread__set_comm(thread, comm, 0);
	}

	return err;
}

172 173
const char *thread__comm_str(const struct thread *thread)
{
174 175 176 177 178 179
	const struct comm *comm = thread__comm(thread);

	if (!comm)
		return NULL;

	return comm__str(comm);
180 181
}

182
/* CHECKME: it should probably better return the max comm len from its comm list */
183
int thread__comm_len(struct thread *thread)
184
{
185
	if (!thread->comm_len) {
186 187
		const char *comm = thread__comm_str(thread);
		if (!comm)
188
			return 0;
189
		thread->comm_len = strlen(comm);
190 191
	}

192
	return thread->comm_len;
193 194
}

195
size_t thread__fprintf(struct thread *thread, FILE *fp)
196
{
197
	return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
198
	       map_groups__fprintf(thread->mg, fp);
199 200
}

201
int thread__insert_map(struct thread *thread, struct map *map)
202
{
203 204
	int ret;

205
	ret = unwind__prepare_access(thread, map, NULL);
206 207 208
	if (ret)
		return ret;

209
	map_groups__fixup_overlappings(thread->mg, map, stderr);
210
	map_groups__insert(thread->mg, map);
211 212

	return 0;
213 214
}

215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
static int __thread__prepare_access(struct thread *thread)
{
	bool initialized = false;
	int i, err = 0;

	for (i = 0; i < MAP__NR_TYPES; ++i) {
		struct maps *maps = &thread->mg->maps[i];
		struct map *map;

		pthread_rwlock_rdlock(&maps->lock);

		for (map = maps__first(maps); map; map = map__next(map)) {
			err = unwind__prepare_access(thread, map, &initialized);
			if (err || initialized)
				break;
		}

		pthread_rwlock_unlock(&maps->lock);
	}

	return err;
}

static int thread__prepare_access(struct thread *thread)
{
	int err = 0;

	if (symbol_conf.use_callchain)
		err = __thread__prepare_access(thread);

	return err;
}

248 249 250 251 252 253 254
static int thread__clone_map_groups(struct thread *thread,
				    struct thread *parent)
{
	int i;

	/* This is new thread, we share map groups for process. */
	if (thread->pid_ == parent->pid_)
255
		return thread__prepare_access(thread);
256

257 258 259 260 261 262
	if (thread->mg == parent->mg) {
		pr_debug("broken map groups on thread %d/%d parent %d/%d\n",
			 thread->pid_, thread->tid, parent->pid_, parent->tid);
		return 0;
	}

263 264
	/* But this one is new process, copy maps. */
	for (i = 0; i < MAP__NR_TYPES; ++i)
265
		if (map_groups__clone(thread, parent->mg, i) < 0)
266 267 268 269 270
			return -ENOMEM;

	return 0;
}

271
int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
272
{
273
	int err;
274

275
	if (parent->comm_set) {
276 277
		const char *comm = thread__comm_str(parent);
		if (!comm)
278
			return -ENOMEM;
279
		err = thread__set_comm(thread, comm, timestamp);
280
		if (err)
281
			return err;
282
	}
283

284
	thread->ppid = parent->tid;
285
	return thread__clone_map_groups(thread, parent);
286
}
287 288 289 290 291 292

void thread__find_cpumode_addr_location(struct thread *thread,
					enum map_type type, u64 addr,
					struct addr_location *al)
{
	size_t i;
293
	const u8 cpumodes[] = {
294 295 296 297 298 299 300
		PERF_RECORD_MISC_USER,
		PERF_RECORD_MISC_KERNEL,
		PERF_RECORD_MISC_GUEST_USER,
		PERF_RECORD_MISC_GUEST_KERNEL
	};

	for (i = 0; i < ARRAY_SIZE(cpumodes); i++) {
301
		thread__find_addr_location(thread, cpumodes[i], type, addr, al);
302 303 304 305
		if (al->map)
			break;
	}
}
306 307 308 309 310 311 312 313 314 315 316

struct thread *thread__main_thread(struct machine *machine, struct thread *thread)
{
	if (thread->pid_ == thread->tid)
		return thread__get(thread);

	if (thread->pid_ == -1)
		return NULL;

	return machine__find_thread(machine, thread->pid_, thread->pid_);
}