xref: /linux/tools/perf/util/thread_map.c (revision 13c230ab6e56c6ae3a968f01f4c6505b794cecad)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2fd78260bSArnaldo Carvalho de Melo #include <dirent.h>
3a43783aeSArnaldo Carvalho de Melo #include <errno.h>
40d37aa34SArnaldo Carvalho de Melo #include <limits.h>
50d37aa34SArnaldo Carvalho de Melo #include <stdbool.h>
6fd78260bSArnaldo Carvalho de Melo #include <stdlib.h>
7fd78260bSArnaldo Carvalho de Melo #include <stdio.h>
80d37aa34SArnaldo Carvalho de Melo #include <sys/types.h>
90d37aa34SArnaldo Carvalho de Melo #include <sys/stat.h>
100d37aa34SArnaldo Carvalho de Melo #include <unistd.h>
11a067558eSArnaldo Carvalho de Melo #include "string2.h"
12b52956c9SDavid Ahern #include "strlist.h"
13b52956c9SDavid Ahern #include <string.h>
14792402fdSJiri Olsa #include <api/fs/fs.h>
15*13c230abSArnaldo Carvalho de Melo #include <linux/string.h>
16186fbb74SJiri Olsa #include "asm/bug.h"
17fd78260bSArnaldo Carvalho de Melo #include "thread_map.h"
1804662523SArnaldo Carvalho de Melo #include "util.h"
19792402fdSJiri Olsa #include "debug.h"
2059660942SJiri Olsa #include "event.h"
21fd78260bSArnaldo Carvalho de Melo 
22fd78260bSArnaldo Carvalho de Melo /* Skip "." and ".." directories */
23fd78260bSArnaldo Carvalho de Melo static int filter(const struct dirent *dir)
24fd78260bSArnaldo Carvalho de Melo {
25fd78260bSArnaldo Carvalho de Melo 	if (dir->d_name[0] == '.')
26fd78260bSArnaldo Carvalho de Melo 		return 0;
27fd78260bSArnaldo Carvalho de Melo 	else
28fd78260bSArnaldo Carvalho de Melo 		return 1;
29fd78260bSArnaldo Carvalho de Melo }
30fd78260bSArnaldo Carvalho de Melo 
3162eea464SJiri Olsa static void thread_map__reset(struct thread_map *map, int start, int nr)
3262eea464SJiri Olsa {
3362eea464SJiri Olsa 	size_t size = (nr - start) * sizeof(map->map[0]);
3462eea464SJiri Olsa 
3562eea464SJiri Olsa 	memset(&map->map[start], 0, size);
36ab6c79b8SJin Yao 	map->err_thread = -1;
3762eea464SJiri Olsa }
3862eea464SJiri Olsa 
399d7e8c3aSJiri Olsa static struct thread_map *thread_map__realloc(struct thread_map *map, int nr)
409d7e8c3aSJiri Olsa {
41060664f3SArnaldo Carvalho de Melo 	size_t size = sizeof(*map) + sizeof(map->map[0]) * nr;
4262eea464SJiri Olsa 	int start = map ? map->nr : 0;
439d7e8c3aSJiri Olsa 
4462eea464SJiri Olsa 	map = realloc(map, size);
4562eea464SJiri Olsa 	/*
4662eea464SJiri Olsa 	 * We only realloc to add more items, let's reset new items.
4762eea464SJiri Olsa 	 */
4862eea464SJiri Olsa 	if (map)
4962eea464SJiri Olsa 		thread_map__reset(map, start, nr);
5062eea464SJiri Olsa 
5162eea464SJiri Olsa 	return map;
529d7e8c3aSJiri Olsa }
539d7e8c3aSJiri Olsa 
549d7e8c3aSJiri Olsa #define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr)
559d7e8c3aSJiri Olsa 
56fd78260bSArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_pid(pid_t pid)
57fd78260bSArnaldo Carvalho de Melo {
58fd78260bSArnaldo Carvalho de Melo 	struct thread_map *threads;
59fd78260bSArnaldo Carvalho de Melo 	char name[256];
60fd78260bSArnaldo Carvalho de Melo 	int items;
61fd78260bSArnaldo Carvalho de Melo 	struct dirent **namelist = NULL;
62fd78260bSArnaldo Carvalho de Melo 	int i;
63fd78260bSArnaldo Carvalho de Melo 
64fd78260bSArnaldo Carvalho de Melo 	sprintf(name, "/proc/%d/task", pid);
65fd78260bSArnaldo Carvalho de Melo 	items = scandir(name, &namelist, filter, NULL);
66fd78260bSArnaldo Carvalho de Melo 	if (items <= 0)
67fd78260bSArnaldo Carvalho de Melo 		return NULL;
68fd78260bSArnaldo Carvalho de Melo 
699d7e8c3aSJiri Olsa 	threads = thread_map__alloc(items);
70fd78260bSArnaldo Carvalho de Melo 	if (threads != NULL) {
71fd78260bSArnaldo Carvalho de Melo 		for (i = 0; i < items; i++)
72e13798c7SJiri Olsa 			thread_map__set_pid(threads, i, atoi(namelist[i]->d_name));
73fd78260bSArnaldo Carvalho de Melo 		threads->nr = items;
74364fed35SElena Reshetova 		refcount_set(&threads->refcnt, 1);
75fd78260bSArnaldo Carvalho de Melo 	}
76fd78260bSArnaldo Carvalho de Melo 
77fd78260bSArnaldo Carvalho de Melo 	for (i=0; i<items; i++)
7874cf249dSArnaldo Carvalho de Melo 		zfree(&namelist[i]);
79fd78260bSArnaldo Carvalho de Melo 	free(namelist);
80fd78260bSArnaldo Carvalho de Melo 
81fd78260bSArnaldo Carvalho de Melo 	return threads;
82fd78260bSArnaldo Carvalho de Melo }
83fd78260bSArnaldo Carvalho de Melo 
84fd78260bSArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_tid(pid_t tid)
85fd78260bSArnaldo Carvalho de Melo {
869d7e8c3aSJiri Olsa 	struct thread_map *threads = thread_map__alloc(1);
87fd78260bSArnaldo Carvalho de Melo 
88fd78260bSArnaldo Carvalho de Melo 	if (threads != NULL) {
89e13798c7SJiri Olsa 		thread_map__set_pid(threads, 0, tid);
90fd78260bSArnaldo Carvalho de Melo 		threads->nr = 1;
91364fed35SElena Reshetova 		refcount_set(&threads->refcnt, 1);
92fd78260bSArnaldo Carvalho de Melo 	}
93fd78260bSArnaldo Carvalho de Melo 
94fd78260bSArnaldo Carvalho de Melo 	return threads;
95fd78260bSArnaldo Carvalho de Melo }
96fd78260bSArnaldo Carvalho de Melo 
978d3cd4c3SArnaldo Carvalho de Melo static struct thread_map *__thread_map__new_all_cpus(uid_t uid)
980d37aa34SArnaldo Carvalho de Melo {
990d37aa34SArnaldo Carvalho de Melo 	DIR *proc;
1000d37aa34SArnaldo Carvalho de Melo 	int max_threads = 32, items, i;
101bdf23a9aSArnaldo Carvalho de Melo 	char path[NAME_MAX + 1 + 6];
1023354cf71SArnaldo Carvalho de Melo 	struct dirent *dirent, **namelist = NULL;
1039d7e8c3aSJiri Olsa 	struct thread_map *threads = thread_map__alloc(max_threads);
1049d7e8c3aSJiri Olsa 
1050d37aa34SArnaldo Carvalho de Melo 	if (threads == NULL)
1060d37aa34SArnaldo Carvalho de Melo 		goto out;
1070d37aa34SArnaldo Carvalho de Melo 
1080d37aa34SArnaldo Carvalho de Melo 	proc = opendir("/proc");
1090d37aa34SArnaldo Carvalho de Melo 	if (proc == NULL)
1100d37aa34SArnaldo Carvalho de Melo 		goto out_free_threads;
1110d37aa34SArnaldo Carvalho de Melo 
1120d37aa34SArnaldo Carvalho de Melo 	threads->nr = 0;
113364fed35SElena Reshetova 	refcount_set(&threads->refcnt, 1);
1140d37aa34SArnaldo Carvalho de Melo 
1153354cf71SArnaldo Carvalho de Melo 	while ((dirent = readdir(proc)) != NULL) {
1160d37aa34SArnaldo Carvalho de Melo 		char *end;
1170d37aa34SArnaldo Carvalho de Melo 		bool grow = false;
1183354cf71SArnaldo Carvalho de Melo 		pid_t pid = strtol(dirent->d_name, &end, 10);
1190d37aa34SArnaldo Carvalho de Melo 
1200d37aa34SArnaldo Carvalho de Melo 		if (*end) /* only interested in proper numerical dirents */
1210d37aa34SArnaldo Carvalho de Melo 			continue;
1220d37aa34SArnaldo Carvalho de Melo 
1233354cf71SArnaldo Carvalho de Melo 		snprintf(path, sizeof(path), "/proc/%s", dirent->d_name);
1240d37aa34SArnaldo Carvalho de Melo 
1258d3cd4c3SArnaldo Carvalho de Melo 		if (uid != UINT_MAX) {
1268d3cd4c3SArnaldo Carvalho de Melo 			struct stat st;
1270d37aa34SArnaldo Carvalho de Melo 
1288d3cd4c3SArnaldo Carvalho de Melo 			if (stat(path, &st) != 0 || st.st_uid != uid)
1290d37aa34SArnaldo Carvalho de Melo 				continue;
1308d3cd4c3SArnaldo Carvalho de Melo 		}
1310d37aa34SArnaldo Carvalho de Melo 
1320d37aa34SArnaldo Carvalho de Melo 		snprintf(path, sizeof(path), "/proc/%d/task", pid);
1330d37aa34SArnaldo Carvalho de Melo 		items = scandir(path, &namelist, filter, NULL);
1340d37aa34SArnaldo Carvalho de Melo 		if (items <= 0)
1350d37aa34SArnaldo Carvalho de Melo 			goto out_free_closedir;
1360d37aa34SArnaldo Carvalho de Melo 
1370d37aa34SArnaldo Carvalho de Melo 		while (threads->nr + items >= max_threads) {
1380d37aa34SArnaldo Carvalho de Melo 			max_threads *= 2;
1390d37aa34SArnaldo Carvalho de Melo 			grow = true;
1400d37aa34SArnaldo Carvalho de Melo 		}
1410d37aa34SArnaldo Carvalho de Melo 
1420d37aa34SArnaldo Carvalho de Melo 		if (grow) {
1430d37aa34SArnaldo Carvalho de Melo 			struct thread_map *tmp;
1440d37aa34SArnaldo Carvalho de Melo 
14508ae217bSArnaldo Carvalho de Melo 			tmp = thread_map__realloc(threads, max_threads);
1460d37aa34SArnaldo Carvalho de Melo 			if (tmp == NULL)
1470d37aa34SArnaldo Carvalho de Melo 				goto out_free_namelist;
1480d37aa34SArnaldo Carvalho de Melo 
1490d37aa34SArnaldo Carvalho de Melo 			threads = tmp;
1500d37aa34SArnaldo Carvalho de Melo 		}
1510d37aa34SArnaldo Carvalho de Melo 
152e13798c7SJiri Olsa 		for (i = 0; i < items; i++) {
153e13798c7SJiri Olsa 			thread_map__set_pid(threads, threads->nr + i,
154e13798c7SJiri Olsa 					    atoi(namelist[i]->d_name));
155e13798c7SJiri Olsa 		}
1560d37aa34SArnaldo Carvalho de Melo 
1570d37aa34SArnaldo Carvalho de Melo 		for (i = 0; i < items; i++)
15874cf249dSArnaldo Carvalho de Melo 			zfree(&namelist[i]);
1590d37aa34SArnaldo Carvalho de Melo 		free(namelist);
1600d37aa34SArnaldo Carvalho de Melo 
1610d37aa34SArnaldo Carvalho de Melo 		threads->nr += items;
1620d37aa34SArnaldo Carvalho de Melo 	}
1630d37aa34SArnaldo Carvalho de Melo 
1640d37aa34SArnaldo Carvalho de Melo out_closedir:
1650d37aa34SArnaldo Carvalho de Melo 	closedir(proc);
1660d37aa34SArnaldo Carvalho de Melo out:
1670d37aa34SArnaldo Carvalho de Melo 	return threads;
1680d37aa34SArnaldo Carvalho de Melo 
1690d37aa34SArnaldo Carvalho de Melo out_free_threads:
1700d37aa34SArnaldo Carvalho de Melo 	free(threads);
1710d37aa34SArnaldo Carvalho de Melo 	return NULL;
1720d37aa34SArnaldo Carvalho de Melo 
1730d37aa34SArnaldo Carvalho de Melo out_free_namelist:
1740d37aa34SArnaldo Carvalho de Melo 	for (i = 0; i < items; i++)
17574cf249dSArnaldo Carvalho de Melo 		zfree(&namelist[i]);
1760d37aa34SArnaldo Carvalho de Melo 	free(namelist);
1770d37aa34SArnaldo Carvalho de Melo 
1780d37aa34SArnaldo Carvalho de Melo out_free_closedir:
17904662523SArnaldo Carvalho de Melo 	zfree(&threads);
1800d37aa34SArnaldo Carvalho de Melo 	goto out_closedir;
1810d37aa34SArnaldo Carvalho de Melo }
1820d37aa34SArnaldo Carvalho de Melo 
1838d3cd4c3SArnaldo Carvalho de Melo struct thread_map *thread_map__new_all_cpus(void)
1848d3cd4c3SArnaldo Carvalho de Melo {
1858d3cd4c3SArnaldo Carvalho de Melo 	return __thread_map__new_all_cpus(UINT_MAX);
1868d3cd4c3SArnaldo Carvalho de Melo }
1878d3cd4c3SArnaldo Carvalho de Melo 
1888d3cd4c3SArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_uid(uid_t uid)
1898d3cd4c3SArnaldo Carvalho de Melo {
1908d3cd4c3SArnaldo Carvalho de Melo 	return __thread_map__new_all_cpus(uid);
1918d3cd4c3SArnaldo Carvalho de Melo }
1928d3cd4c3SArnaldo Carvalho de Melo 
1930d37aa34SArnaldo Carvalho de Melo struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
194fd78260bSArnaldo Carvalho de Melo {
195fd78260bSArnaldo Carvalho de Melo 	if (pid != -1)
196fd78260bSArnaldo Carvalho de Melo 		return thread_map__new_by_pid(pid);
1970d37aa34SArnaldo Carvalho de Melo 
1980d37aa34SArnaldo Carvalho de Melo 	if (tid == -1 && uid != UINT_MAX)
1990d37aa34SArnaldo Carvalho de Melo 		return thread_map__new_by_uid(uid);
2000d37aa34SArnaldo Carvalho de Melo 
201fd78260bSArnaldo Carvalho de Melo 	return thread_map__new_by_tid(tid);
202fd78260bSArnaldo Carvalho de Melo }
203fd78260bSArnaldo Carvalho de Melo 
204b52956c9SDavid Ahern static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
205b52956c9SDavid Ahern {
206b52956c9SDavid Ahern 	struct thread_map *threads = NULL, *nt;
207b52956c9SDavid Ahern 	char name[256];
208b52956c9SDavid Ahern 	int items, total_tasks = 0;
209b52956c9SDavid Ahern 	struct dirent **namelist = NULL;
210b52956c9SDavid Ahern 	int i, j = 0;
211b52956c9SDavid Ahern 	pid_t pid, prev_pid = INT_MAX;
212b52956c9SDavid Ahern 	char *end_ptr;
213b52956c9SDavid Ahern 	struct str_node *pos;
2144a77e218SArnaldo Carvalho de Melo 	struct strlist_config slist_config = { .dont_dupstr = true, };
2154a77e218SArnaldo Carvalho de Melo 	struct strlist *slist = strlist__new(pid_str, &slist_config);
216b52956c9SDavid Ahern 
217b52956c9SDavid Ahern 	if (!slist)
218b52956c9SDavid Ahern 		return NULL;
219b52956c9SDavid Ahern 
220602a1f4dSArnaldo Carvalho de Melo 	strlist__for_each_entry(pos, slist) {
221b52956c9SDavid Ahern 		pid = strtol(pos->s, &end_ptr, 10);
222b52956c9SDavid Ahern 
223b52956c9SDavid Ahern 		if (pid == INT_MIN || pid == INT_MAX ||
224b52956c9SDavid Ahern 		    (*end_ptr != '\0' && *end_ptr != ','))
225b52956c9SDavid Ahern 			goto out_free_threads;
226b52956c9SDavid Ahern 
227b52956c9SDavid Ahern 		if (pid == prev_pid)
228b52956c9SDavid Ahern 			continue;
229b52956c9SDavid Ahern 
230b52956c9SDavid Ahern 		sprintf(name, "/proc/%d/task", pid);
231b52956c9SDavid Ahern 		items = scandir(name, &namelist, filter, NULL);
232b52956c9SDavid Ahern 		if (items <= 0)
233b52956c9SDavid Ahern 			goto out_free_threads;
234b52956c9SDavid Ahern 
235b52956c9SDavid Ahern 		total_tasks += items;
2369d7e8c3aSJiri Olsa 		nt = thread_map__realloc(threads, total_tasks);
237b52956c9SDavid Ahern 		if (nt == NULL)
238e8cdd947SFranck Bui-Huu 			goto out_free_namelist;
239b52956c9SDavid Ahern 
240b52956c9SDavid Ahern 		threads = nt;
241b52956c9SDavid Ahern 
242e8cdd947SFranck Bui-Huu 		for (i = 0; i < items; i++) {
243e13798c7SJiri Olsa 			thread_map__set_pid(threads, j++, atoi(namelist[i]->d_name));
24474cf249dSArnaldo Carvalho de Melo 			zfree(&namelist[i]);
245e8cdd947SFranck Bui-Huu 		}
246e8cdd947SFranck Bui-Huu 		threads->nr = total_tasks;
247b52956c9SDavid Ahern 		free(namelist);
248b52956c9SDavid Ahern 	}
249b52956c9SDavid Ahern 
250b52956c9SDavid Ahern out:
251b52956c9SDavid Ahern 	strlist__delete(slist);
252186fbb74SJiri Olsa 	if (threads)
253364fed35SElena Reshetova 		refcount_set(&threads->refcnt, 1);
254b52956c9SDavid Ahern 	return threads;
255b52956c9SDavid Ahern 
256e8cdd947SFranck Bui-Huu out_free_namelist:
257e8cdd947SFranck Bui-Huu 	for (i = 0; i < items; i++)
25874cf249dSArnaldo Carvalho de Melo 		zfree(&namelist[i]);
259e8cdd947SFranck Bui-Huu 	free(namelist);
260e8cdd947SFranck Bui-Huu 
261b52956c9SDavid Ahern out_free_threads:
26204662523SArnaldo Carvalho de Melo 	zfree(&threads);
263b52956c9SDavid Ahern 	goto out;
264b52956c9SDavid Ahern }
265b52956c9SDavid Ahern 
266641556c9SArnaldo Carvalho de Melo struct thread_map *thread_map__new_dummy(void)
267641556c9SArnaldo Carvalho de Melo {
2689d7e8c3aSJiri Olsa 	struct thread_map *threads = thread_map__alloc(1);
269641556c9SArnaldo Carvalho de Melo 
270641556c9SArnaldo Carvalho de Melo 	if (threads != NULL) {
271e13798c7SJiri Olsa 		thread_map__set_pid(threads, 0, -1);
272641556c9SArnaldo Carvalho de Melo 		threads->nr = 1;
273364fed35SElena Reshetova 		refcount_set(&threads->refcnt, 1);
274641556c9SArnaldo Carvalho de Melo 	}
275641556c9SArnaldo Carvalho de Melo 	return threads;
276641556c9SArnaldo Carvalho de Melo }
277641556c9SArnaldo Carvalho de Melo 
278097be0f5SJiri Olsa struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
279b52956c9SDavid Ahern {
280b52956c9SDavid Ahern 	struct thread_map *threads = NULL, *nt;
281b52956c9SDavid Ahern 	int ntasks = 0;
282b52956c9SDavid Ahern 	pid_t tid, prev_tid = INT_MAX;
283b52956c9SDavid Ahern 	char *end_ptr;
284b52956c9SDavid Ahern 	struct str_node *pos;
2854a77e218SArnaldo Carvalho de Melo 	struct strlist_config slist_config = { .dont_dupstr = true, };
286b52956c9SDavid Ahern 	struct strlist *slist;
287b52956c9SDavid Ahern 
288b52956c9SDavid Ahern 	/* perf-stat expects threads to be generated even if tid not given */
289641556c9SArnaldo Carvalho de Melo 	if (!tid_str)
290641556c9SArnaldo Carvalho de Melo 		return thread_map__new_dummy();
291b52956c9SDavid Ahern 
2924a77e218SArnaldo Carvalho de Melo 	slist = strlist__new(tid_str, &slist_config);
293b52956c9SDavid Ahern 	if (!slist)
294b52956c9SDavid Ahern 		return NULL;
295b52956c9SDavid Ahern 
296602a1f4dSArnaldo Carvalho de Melo 	strlist__for_each_entry(pos, slist) {
297b52956c9SDavid Ahern 		tid = strtol(pos->s, &end_ptr, 10);
298b52956c9SDavid Ahern 
299b52956c9SDavid Ahern 		if (tid == INT_MIN || tid == INT_MAX ||
300b52956c9SDavid Ahern 		    (*end_ptr != '\0' && *end_ptr != ','))
301b52956c9SDavid Ahern 			goto out_free_threads;
302b52956c9SDavid Ahern 
303b52956c9SDavid Ahern 		if (tid == prev_tid)
304b52956c9SDavid Ahern 			continue;
305b52956c9SDavid Ahern 
306b52956c9SDavid Ahern 		ntasks++;
3079d7e8c3aSJiri Olsa 		nt = thread_map__realloc(threads, ntasks);
308b52956c9SDavid Ahern 
309b52956c9SDavid Ahern 		if (nt == NULL)
310b52956c9SDavid Ahern 			goto out_free_threads;
311b52956c9SDavid Ahern 
312b52956c9SDavid Ahern 		threads = nt;
313e13798c7SJiri Olsa 		thread_map__set_pid(threads, ntasks - 1, tid);
314b52956c9SDavid Ahern 		threads->nr = ntasks;
315b52956c9SDavid Ahern 	}
316b52956c9SDavid Ahern out:
317186fbb74SJiri Olsa 	if (threads)
318364fed35SElena Reshetova 		refcount_set(&threads->refcnt, 1);
319b52956c9SDavid Ahern 	return threads;
320b52956c9SDavid Ahern 
321b52956c9SDavid Ahern out_free_threads:
32204662523SArnaldo Carvalho de Melo 	zfree(&threads);
3237ecb48fdSNamhyung Kim 	strlist__delete(slist);
324b52956c9SDavid Ahern 	goto out;
325b52956c9SDavid Ahern }
326b52956c9SDavid Ahern 
327b52956c9SDavid Ahern struct thread_map *thread_map__new_str(const char *pid, const char *tid,
328147c508fSJin Yao 				       uid_t uid, bool all_threads)
329b52956c9SDavid Ahern {
330b52956c9SDavid Ahern 	if (pid)
331b52956c9SDavid Ahern 		return thread_map__new_by_pid_str(pid);
332b52956c9SDavid Ahern 
333b52956c9SDavid Ahern 	if (!tid && uid != UINT_MAX)
334b52956c9SDavid Ahern 		return thread_map__new_by_uid(uid);
335b52956c9SDavid Ahern 
336147c508fSJin Yao 	if (all_threads)
33773c0ca1eSJin Yao 		return thread_map__new_all_cpus();
33873c0ca1eSJin Yao 
339b52956c9SDavid Ahern 	return thread_map__new_by_tid_str(tid);
340b52956c9SDavid Ahern }
341b52956c9SDavid Ahern 
342186fbb74SJiri Olsa static void thread_map__delete(struct thread_map *threads)
343fd78260bSArnaldo Carvalho de Melo {
344186fbb74SJiri Olsa 	if (threads) {
345792402fdSJiri Olsa 		int i;
346792402fdSJiri Olsa 
347364fed35SElena Reshetova 		WARN_ONCE(refcount_read(&threads->refcnt) != 0,
348186fbb74SJiri Olsa 			  "thread map refcnt unbalanced\n");
349792402fdSJiri Olsa 		for (i = 0; i < threads->nr; i++)
350792402fdSJiri Olsa 			free(thread_map__comm(threads, i));
351fd78260bSArnaldo Carvalho de Melo 		free(threads);
352fd78260bSArnaldo Carvalho de Melo 	}
353186fbb74SJiri Olsa }
354186fbb74SJiri Olsa 
355186fbb74SJiri Olsa struct thread_map *thread_map__get(struct thread_map *map)
356186fbb74SJiri Olsa {
357186fbb74SJiri Olsa 	if (map)
358364fed35SElena Reshetova 		refcount_inc(&map->refcnt);
359186fbb74SJiri Olsa 	return map;
360186fbb74SJiri Olsa }
361186fbb74SJiri Olsa 
362186fbb74SJiri Olsa void thread_map__put(struct thread_map *map)
363186fbb74SJiri Olsa {
364364fed35SElena Reshetova 	if (map && refcount_dec_and_test(&map->refcnt))
365186fbb74SJiri Olsa 		thread_map__delete(map);
366186fbb74SJiri Olsa }
3679ae7d335SArnaldo Carvalho de Melo 
3689ae7d335SArnaldo Carvalho de Melo size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
3699ae7d335SArnaldo Carvalho de Melo {
3709ae7d335SArnaldo Carvalho de Melo 	int i;
3719ae7d335SArnaldo Carvalho de Melo 	size_t printed = fprintf(fp, "%d thread%s: ",
3729ae7d335SArnaldo Carvalho de Melo 				 threads->nr, threads->nr > 1 ? "s" : "");
3739ae7d335SArnaldo Carvalho de Melo 	for (i = 0; i < threads->nr; ++i)
374e13798c7SJiri Olsa 		printed += fprintf(fp, "%s%d", i ? ", " : "", thread_map__pid(threads, i));
3759ae7d335SArnaldo Carvalho de Melo 
3769ae7d335SArnaldo Carvalho de Melo 	return printed + fprintf(fp, "\n");
3779ae7d335SArnaldo Carvalho de Melo }
378792402fdSJiri Olsa 
379792402fdSJiri Olsa static int get_comm(char **comm, pid_t pid)
380792402fdSJiri Olsa {
381792402fdSJiri Olsa 	char *path;
382792402fdSJiri Olsa 	size_t size;
383792402fdSJiri Olsa 	int err;
384792402fdSJiri Olsa 
385792402fdSJiri Olsa 	if (asprintf(&path, "%s/%d/comm", procfs__mountpoint(), pid) == -1)
386792402fdSJiri Olsa 		return -ENOMEM;
387792402fdSJiri Olsa 
388792402fdSJiri Olsa 	err = filename__read_str(path, comm, &size);
389792402fdSJiri Olsa 	if (!err) {
390792402fdSJiri Olsa 		/*
391792402fdSJiri Olsa 		 * We're reading 16 bytes, while filename__read_str
392792402fdSJiri Olsa 		 * allocates data per BUFSIZ bytes, so we can safely
393792402fdSJiri Olsa 		 * mark the end of the string.
394792402fdSJiri Olsa 		 */
395792402fdSJiri Olsa 		(*comm)[size] = 0;
396*13c230abSArnaldo Carvalho de Melo 		strim(*comm);
397792402fdSJiri Olsa 	}
398792402fdSJiri Olsa 
399792402fdSJiri Olsa 	free(path);
400792402fdSJiri Olsa 	return err;
401792402fdSJiri Olsa }
402792402fdSJiri Olsa 
403792402fdSJiri Olsa static void comm_init(struct thread_map *map, int i)
404792402fdSJiri Olsa {
405792402fdSJiri Olsa 	pid_t pid = thread_map__pid(map, i);
406792402fdSJiri Olsa 	char *comm = NULL;
407792402fdSJiri Olsa 
408792402fdSJiri Olsa 	/* dummy pid comm initialization */
409792402fdSJiri Olsa 	if (pid == -1) {
410792402fdSJiri Olsa 		map->map[i].comm = strdup("dummy");
411792402fdSJiri Olsa 		return;
412792402fdSJiri Olsa 	}
413792402fdSJiri Olsa 
414792402fdSJiri Olsa 	/*
415792402fdSJiri Olsa 	 * The comm name is like extra bonus ;-),
416792402fdSJiri Olsa 	 * so just warn if we fail for any reason.
417792402fdSJiri Olsa 	 */
418792402fdSJiri Olsa 	if (get_comm(&comm, pid))
419792402fdSJiri Olsa 		pr_warning("Couldn't resolve comm name for pid %d\n", pid);
420792402fdSJiri Olsa 
421792402fdSJiri Olsa 	map->map[i].comm = comm;
422792402fdSJiri Olsa }
423792402fdSJiri Olsa 
424792402fdSJiri Olsa void thread_map__read_comms(struct thread_map *threads)
425792402fdSJiri Olsa {
426792402fdSJiri Olsa 	int i;
427792402fdSJiri Olsa 
428792402fdSJiri Olsa 	for (i = 0; i < threads->nr; ++i)
429792402fdSJiri Olsa 		comm_init(threads, i);
430792402fdSJiri Olsa }
43159660942SJiri Olsa 
43259660942SJiri Olsa static void thread_map__copy_event(struct thread_map *threads,
43359660942SJiri Olsa 				   struct thread_map_event *event)
43459660942SJiri Olsa {
43559660942SJiri Olsa 	unsigned i;
43659660942SJiri Olsa 
43759660942SJiri Olsa 	threads->nr = (int) event->nr;
43859660942SJiri Olsa 
43959660942SJiri Olsa 	for (i = 0; i < event->nr; i++) {
44059660942SJiri Olsa 		thread_map__set_pid(threads, i, (pid_t) event->entries[i].pid);
44159660942SJiri Olsa 		threads->map[i].comm = strndup(event->entries[i].comm, 16);
44259660942SJiri Olsa 	}
44359660942SJiri Olsa 
444364fed35SElena Reshetova 	refcount_set(&threads->refcnt, 1);
44559660942SJiri Olsa }
44659660942SJiri Olsa 
44759660942SJiri Olsa struct thread_map *thread_map__new_event(struct thread_map_event *event)
44859660942SJiri Olsa {
44959660942SJiri Olsa 	struct thread_map *threads;
45059660942SJiri Olsa 
45159660942SJiri Olsa 	threads = thread_map__alloc(event->nr);
45259660942SJiri Olsa 	if (threads)
45359660942SJiri Olsa 		thread_map__copy_event(threads, event);
45459660942SJiri Olsa 
45559660942SJiri Olsa 	return threads;
45659660942SJiri Olsa }
4573407df8bSJiri Olsa 
4583407df8bSJiri Olsa bool thread_map__has(struct thread_map *threads, pid_t pid)
4593407df8bSJiri Olsa {
4603407df8bSJiri Olsa 	int i;
4613407df8bSJiri Olsa 
4623407df8bSJiri Olsa 	for (i = 0; i < threads->nr; ++i) {
4633407df8bSJiri Olsa 		if (threads->map[i].pid == pid)
4643407df8bSJiri Olsa 			return true;
4653407df8bSJiri Olsa 	}
4663407df8bSJiri Olsa 
4673407df8bSJiri Olsa 	return false;
4683407df8bSJiri Olsa }
46938af91f0SJiri Olsa 
47038af91f0SJiri Olsa int thread_map__remove(struct thread_map *threads, int idx)
47138af91f0SJiri Olsa {
47238af91f0SJiri Olsa 	int i;
47338af91f0SJiri Olsa 
47438af91f0SJiri Olsa 	if (threads->nr < 1)
47538af91f0SJiri Olsa 		return -EINVAL;
47638af91f0SJiri Olsa 
47738af91f0SJiri Olsa 	if (idx >= threads->nr)
47838af91f0SJiri Olsa 		return -EINVAL;
47938af91f0SJiri Olsa 
48038af91f0SJiri Olsa 	/*
48138af91f0SJiri Olsa 	 * Free the 'idx' item and shift the rest up.
48238af91f0SJiri Olsa 	 */
48338af91f0SJiri Olsa 	free(threads->map[idx].comm);
48438af91f0SJiri Olsa 
48538af91f0SJiri Olsa 	for (i = idx; i < threads->nr - 1; i++)
48638af91f0SJiri Olsa 		threads->map[i] = threads->map[i + 1];
48738af91f0SJiri Olsa 
48838af91f0SJiri Olsa 	threads->nr--;
48938af91f0SJiri Olsa 	return 0;
49038af91f0SJiri Olsa }
491