thread.c 4.2 KB
Newer Older
1 2 3 4 5 6
#include "../perf.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "thread.h"
#include "util.h"
7
#include "debug.h"
8

9 10 11
static struct rb_root threads;
static struct thread *last_match;

12
static struct thread *thread__new(pid_t pid)
13
{
14
	struct thread *self = calloc(1, sizeof(*self));
15 16 17

	if (self != NULL) {
		self->pid = pid;
18 19 20
		self->comm = malloc(32);
		if (self->comm)
			snprintf(self->comm, 32, ":%d", self->pid);
21
		self->maps = RB_ROOT;
22
		INIT_LIST_HEAD(&self->removed_maps);
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
	}

	return self;
}

int thread__set_comm(struct thread *self, const char *comm)
{
	if (self->comm)
		free(self->comm);
	self->comm = strdup(comm);
	return self->comm ? 0 : -ENOMEM;
}

static size_t thread__fprintf(struct thread *self, FILE *fp)
{
38
	struct rb_node *nd;
39 40 41
	struct map *pos;
	size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n",
			     self->pid, self->comm);
42

43
	for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) {
44
		pos = rb_entry(nd, struct map, rb_node);
45
		ret += map__fprintf(pos, fp);
46
	}
47

48 49 50 51 52
	ret = fprintf(fp, "Removed maps:\n");

	list_for_each_entry(pos, &self->removed_maps, node)
		ret += map__fprintf(pos, fp);

53 54 55
	return ret;
}

56
struct thread *threads__findnew(pid_t pid)
57
{
58
	struct rb_node **p = &threads.rb_node;
59 60 61 62 63 64 65 66
	struct rb_node *parent = NULL;
	struct thread *th;

	/*
	 * Font-end cache - PID lookups come in blocks,
	 * so most of the time we dont have to look up
	 * the full rbtree:
	 */
67 68
	if (last_match && last_match->pid == pid)
		return last_match;
69 70 71 72 73 74

	while (*p != NULL) {
		parent = *p;
		th = rb_entry(parent, struct thread, rb_node);

		if (th->pid == pid) {
75
			last_match = th;
76 77 78 79 80 81 82 83 84
			return th;
		}

		if (pid < th->pid)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

85
	th = thread__new(pid);
86 87
	if (th != NULL) {
		rb_link_node(&th->rb_node, parent, p);
88 89
		rb_insert_color(&th->rb_node, &threads);
		last_match = th;
90 91 92 93 94
	}

	return th;
}

95
struct thread *register_idle_thread(void)
96
{
97
	struct thread *thread = threads__findnew(0);
98

99
	if (!thread || thread__set_comm(thread, "swapper")) {
100 101 102 103 104 105 106
		fprintf(stderr, "problem inserting idle task.\n");
		exit(-1);
	}

	return thread;
}

107
static void thread__remove_overlappings(struct thread *self, struct map *map)
108
{
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
	struct rb_node *next = rb_first(&self->maps);

	while (next) {
		struct map *pos = rb_entry(next, struct map, rb_node);
		next = rb_next(&pos->rb_node);

		if (!map__overlap(pos, map))
			continue;

		if (verbose >= 2) {
			printf("overlapping maps:\n");
			map__fprintf(map, stdout);
			map__fprintf(pos, stdout);
		}

124 125 126 127 128 129 130
		rb_erase(&pos->rb_node, &self->maps);
		/*
		 * We may have references to this map, for instance in some
		 * hist_entry instances, so just move them to a separate
		 * list.
		 */
		list_add_tail(&pos->node, &self->removed_maps);
131
	}
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
}

void maps__insert(struct rb_root *maps, struct map *map)
{
	struct rb_node **p = &maps->rb_node;
	struct rb_node *parent = NULL;
	const u64 ip = map->start;
	struct map *m;

	while (*p != NULL) {
		parent = *p;
		m = rb_entry(parent, struct map, rb_node);
		if (ip < m->start)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

	rb_link_node(&map->rb_node, parent, p);
	rb_insert_color(&map->rb_node, maps);
}

struct map *maps__find(struct rb_root *maps, u64 ip)
{
	struct rb_node **p = &maps->rb_node;
	struct rb_node *parent = NULL;
	struct map *m;

	while (*p != NULL) {
		parent = *p;
		m = rb_entry(parent, struct map, rb_node);
		if (ip < m->start)
			p = &(*p)->rb_left;
		else if (ip > m->end)
			p = &(*p)->rb_right;
		else
			return m;
	}

	return NULL;
}
173

174 175 176 177
void thread__insert_map(struct thread *self, struct map *map)
{
	thread__remove_overlappings(self, map);
	maps__insert(&self->maps, map);
178 179 180 181
}

int thread__fork(struct thread *self, struct thread *parent)
{
182
	struct rb_node *nd;
183 184 185 186 187 188 189

	if (self->comm)
		free(self->comm);
	self->comm = strdup(parent->comm);
	if (!self->comm)
		return -ENOMEM;

190 191
	for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) {
		struct map *map = rb_entry(nd, struct map, rb_node);
192 193 194 195 196 197 198 199 200
		struct map *new = map__clone(map);
		if (!new)
			return -ENOMEM;
		thread__insert_map(self, new);
	}

	return 0;
}

201
size_t threads__fprintf(FILE *fp)
202 203 204 205
{
	size_t ret = 0;
	struct rb_node *nd;

206
	for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
207 208 209 210 211 212 213
		struct thread *pos = rb_entry(nd, struct thread, rb_node);

		ret += thread__fprintf(pos, fp);
	}

	return ret;
}