thread.c 7.5 KB
Newer Older
1
#include "../perf.h"
2
#include <errno.h>
3 4 5
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
6
#include <linux/kernel.h>
7
#include "session.h"
8
#include "thread.h"
9
#include "thread-stack.h"
10
#include "util.h"
11
#include "debug.h"
12
#include "namespaces.h"
13
#include "comm.h"
14
#include "unwind.h"
15

16 17
#include <api/fs/fs.h>

18 19 20 21
int thread__init_map_groups(struct thread *thread, struct machine *machine)
{
	pid_t pid = thread->pid_;

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

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

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

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

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

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

		list_add(&comm->list, &thread->comm_list);
60
		refcount_set(&thread->refcnt, 1);
61
		RB_CLEAR_NODE(&thread->rb_node);
62 63
		/* Thread holds first ref to nsdata. */
		thread->nsinfo = nsinfo__new(pid);
64 65
	}

66
	return thread;
67 68 69 70

err_thread:
	free(thread);
	return NULL;
71 72
}

73
void thread__delete(struct thread *thread)
74
{
75 76
	struct namespaces *namespaces, *tmp_namespaces;
	struct comm *comm, *tmp_comm;
77

78 79
	BUG_ON(!RB_EMPTY_NODE(&thread->rb_node));

80 81
	thread_stack__free(thread);

82 83 84 85
	if (thread->mg) {
		map_groups__put(thread->mg);
		thread->mg = NULL;
	}
86 87 88 89 90 91
	list_for_each_entry_safe(namespaces, tmp_namespaces,
				 &thread->namespaces_list, list) {
		list_del(&namespaces->list);
		namespaces__free(namespaces);
	}
	list_for_each_entry_safe(comm, tmp_comm, &thread->comm_list, list) {
92 93 94
		list_del(&comm->list);
		comm__free(comm);
	}
95
	unwind__finish_access(thread);
96
	nsinfo__zput(thread->nsinfo);
97

98
	free(thread);
99 100
}

101 102
struct thread *thread__get(struct thread *thread)
{
103
	if (thread)
104
		refcount_inc(&thread->refcnt);
105 106 107 108 109
	return thread;
}

void thread__put(struct thread *thread)
{
110
	if (thread && refcount_dec_and_test(&thread->refcnt)) {
111 112 113 114
		/*
		 * Remove it from the dead_threads list, as last reference
		 * is gone.
		 */
115 116 117 118 119
		list_del_init(&thread->node);
		thread__delete(thread);
	}
}

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
struct namespaces *thread__namespaces(const struct thread *thread)
{
	if (list_empty(&thread->namespaces_list))
		return NULL;

	return list_first_entry(&thread->namespaces_list, struct namespaces, list);
}

int thread__set_namespaces(struct thread *thread, u64 timestamp,
			   struct namespaces_event *event)
{
	struct namespaces *new, *curr = thread__namespaces(thread);

	new = namespaces__new(event);
	if (!new)
		return -ENOMEM;

	list_add(&new->list, &thread->namespaces_list);

	if (timestamp && curr) {
		/*
		 * setns syscall must have changed few or all the namespaces
		 * of this thread. Update end time for the namespaces
		 * previously used.
		 */
		curr = list_next_entry(new, list);
		curr->end_time = timestamp;
	}

	return 0;
}

152
struct comm *thread__comm(const struct thread *thread)
153
{
154 155
	if (list_empty(&thread->comm_list))
		return NULL;
156

157 158 159
	return list_first_entry(&thread->comm_list, struct comm, list);
}

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
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)
175 176 177
{
	struct comm *new, *curr = thread__comm(thread);

178 179
	/* Override the default :tid entry */
	if (!thread->comm_set) {
180
		int err = comm__override(curr, str, timestamp, exec);
181 182
		if (err)
			return err;
183
	} else {
184
		new = comm__new(str, timestamp, exec);
185 186 187
		if (!new)
			return -ENOMEM;
		list_add(&new->list, &thread->comm_list);
188 189 190

		if (exec)
			unwind__flush_access(thread);
191
	}
192 193 194 195

	thread->comm_set = true;

	return 0;
196 197
}

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
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;
}

215 216
const char *thread__comm_str(const struct thread *thread)
{
217 218 219 220 221 222
	const struct comm *comm = thread__comm(thread);

	if (!comm)
		return NULL;

	return comm__str(comm);
223 224
}

225
/* CHECKME: it should probably better return the max comm len from its comm list */
226
int thread__comm_len(struct thread *thread)
227
{
228
	if (!thread->comm_len) {
229 230
		const char *comm = thread__comm_str(thread);
		if (!comm)
231
			return 0;
232
		thread->comm_len = strlen(comm);
233 234
	}

235
	return thread->comm_len;
236 237
}

238
size_t thread__fprintf(struct thread *thread, FILE *fp)
239
{
240
	return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
241
	       map_groups__fprintf(thread->mg, fp);
242 243
}

244
int thread__insert_map(struct thread *thread, struct map *map)
245
{
246 247
	int ret;

248
	ret = unwind__prepare_access(thread, map, NULL);
249 250 251
	if (ret)
		return ret;

252
	map_groups__fixup_overlappings(thread->mg, map, stderr);
253
	map_groups__insert(thread->mg, map);
254 255

	return 0;
256 257
}

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
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;
}

291 292 293 294 295 296 297
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_)
298
		return thread__prepare_access(thread);
299

300 301 302 303 304 305
	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;
	}

306 307
	/* But this one is new process, copy maps. */
	for (i = 0; i < MAP__NR_TYPES; ++i)
308
		if (map_groups__clone(thread, parent->mg, i) < 0)
309 310 311 312 313
			return -ENOMEM;

	return 0;
}

314
int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
315
{
316
	if (parent->comm_set) {
317
		const char *comm = thread__comm_str(parent);
318
		int err;
319
		if (!comm)
320
			return -ENOMEM;
321
		err = thread__set_comm(thread, comm, timestamp);
322
		if (err)
323
			return err;
324
	}
325

326
	thread->ppid = parent->tid;
327
	return thread__clone_map_groups(thread, parent);
328
}
329 330 331 332 333 334

void thread__find_cpumode_addr_location(struct thread *thread,
					enum map_type type, u64 addr,
					struct addr_location *al)
{
	size_t i;
335
	const u8 cpumodes[] = {
336 337 338 339 340 341 342
		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++) {
343
		thread__find_addr_location(thread, cpumodes[i], type, addr, al);
344 345 346 347
		if (al->map)
			break;
	}
}
348 349 350 351 352 353 354 355 356 357 358

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_);
}