thread.c 7.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 "namespaces.h"
11
#include "comm.h"
12
#include "unwind.h"
13

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

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

20
	if (pid == thread->tid || pid == -1) {
21
		thread->mg = map_groups__new(machine);
22
	} else {
23
		struct thread *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
		INIT_LIST_HEAD(&thread->namespaces_list);
45 46 47 48 49 50 51
		INIT_LIST_HEAD(&thread->comm_list);

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

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

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

62
	return thread;
63 64 65 66

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

69
void thread__delete(struct thread *thread)
70
{
71 72
	struct namespaces *namespaces, *tmp_namespaces;
	struct comm *comm, *tmp_comm;
73

74 75
	BUG_ON(!RB_EMPTY_NODE(&thread->rb_node));

76 77
	thread_stack__free(thread);

78 79 80 81
	if (thread->mg) {
		map_groups__put(thread->mg);
		thread->mg = NULL;
	}
82 83 84 85 86 87
	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) {
88 89 90
		list_del(&comm->list);
		comm__free(comm);
	}
91
	unwind__finish_access(thread);
92

93
	free(thread);
94 95
}

96 97
struct thread *thread__get(struct thread *thread)
{
98
	if (thread)
99
		refcount_inc(&thread->refcnt);
100 101 102 103 104
	return thread;
}

void thread__put(struct thread *thread)
{
105
	if (thread && refcount_dec_and_test(&thread->refcnt)) {
106 107 108 109
		/*
		 * Remove it from the dead_threads list, as last reference
		 * is gone.
		 */
110 111 112 113 114
		list_del_init(&thread->node);
		thread__delete(thread);
	}
}

115 116 117 118 119 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
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;
}

147
struct comm *thread__comm(const struct thread *thread)
148
{
149 150
	if (list_empty(&thread->comm_list))
		return NULL;
151

152 153 154
	return list_first_entry(&thread->comm_list, struct comm, list);
}

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
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)
170 171 172
{
	struct comm *new, *curr = thread__comm(thread);

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

		if (exec)
			unwind__flush_access(thread);
186
	}
187 188 189 190

	thread->comm_set = true;

	return 0;
191 192
}

193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
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;
}

210 211
const char *thread__comm_str(const struct thread *thread)
{
212 213 214 215 216 217
	const struct comm *comm = thread__comm(thread);

	if (!comm)
		return NULL;

	return comm__str(comm);
218 219
}

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

230
	return thread->comm_len;
231 232
}

233
size_t thread__fprintf(struct thread *thread, FILE *fp)
234
{
235
	return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
236
	       map_groups__fprintf(thread->mg, fp);
237 238
}

239
int thread__insert_map(struct thread *thread, struct map *map)
240
{
241 242
	int ret;

243
	ret = unwind__prepare_access(thread, map, NULL);
244 245 246
	if (ret)
		return ret;

247
	map_groups__fixup_overlappings(thread->mg, map, stderr);
248
	map_groups__insert(thread->mg, map);
249 250

	return 0;
251 252
}

253 254 255 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
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;
}

286 287 288 289 290 291 292
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_)
293
		return thread__prepare_access(thread);
294

295 296 297 298 299 300
	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;
	}

301 302
	/* But this one is new process, copy maps. */
	for (i = 0; i < MAP__NR_TYPES; ++i)
303
		if (map_groups__clone(thread, parent->mg, i) < 0)
304 305 306 307 308
			return -ENOMEM;

	return 0;
}

309
int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
310
{
311
	if (parent->comm_set) {
312
		const char *comm = thread__comm_str(parent);
313
		int err;
314
		if (!comm)
315
			return -ENOMEM;
316
		err = thread__set_comm(thread, comm, timestamp);
317
		if (err)
318
			return err;
319
	}
320

321
	thread->ppid = parent->tid;
322
	return thread__clone_map_groups(thread, parent);
323
}
324 325 326 327 328 329

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

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