xref: /linux/tools/perf/util/thread_map.c (revision 4a77e2183fc0260c0efc7adeccf933fef893ad5f)
1fd78260bSArnaldo Carvalho de Melo #include <dirent.h>
20d37aa34SArnaldo Carvalho de Melo #include <limits.h>
30d37aa34SArnaldo Carvalho de Melo #include <stdbool.h>
4fd78260bSArnaldo Carvalho de Melo #include <stdlib.h>
5fd78260bSArnaldo Carvalho de Melo #include <stdio.h>
60d37aa34SArnaldo Carvalho de Melo #include <sys/types.h>
70d37aa34SArnaldo Carvalho de Melo #include <sys/stat.h>
80d37aa34SArnaldo Carvalho de Melo #include <unistd.h>
9b52956c9SDavid Ahern #include "strlist.h"
10b52956c9SDavid Ahern #include <string.h>
11792402fdSJiri Olsa #include <api/fs/fs.h>
12186fbb74SJiri Olsa #include "asm/bug.h"
13fd78260bSArnaldo Carvalho de Melo #include "thread_map.h"
1404662523SArnaldo Carvalho de Melo #include "util.h"
15792402fdSJiri Olsa #include "debug.h"
16fd78260bSArnaldo Carvalho de Melo 
17fd78260bSArnaldo Carvalho de Melo /* Skip "." and ".." directories */
18fd78260bSArnaldo Carvalho de Melo static int filter(const struct dirent *dir)
19fd78260bSArnaldo Carvalho de Melo {
20fd78260bSArnaldo Carvalho de Melo 	if (dir->d_name[0] == '.')
21fd78260bSArnaldo Carvalho de Melo 		return 0;
22fd78260bSArnaldo Carvalho de Melo 	else
23fd78260bSArnaldo Carvalho de Melo 		return 1;
24fd78260bSArnaldo Carvalho de Melo }
25fd78260bSArnaldo Carvalho de Melo 
2662eea464SJiri Olsa static void thread_map__reset(struct thread_map *map, int start, int nr)
2762eea464SJiri Olsa {
2862eea464SJiri Olsa 	size_t size = (nr - start) * sizeof(map->map[0]);
2962eea464SJiri Olsa 
3062eea464SJiri Olsa 	memset(&map->map[start], 0, size);
3162eea464SJiri Olsa }
3262eea464SJiri Olsa 
339d7e8c3aSJiri Olsa static struct thread_map *thread_map__realloc(struct thread_map *map, int nr)
349d7e8c3aSJiri Olsa {
35060664f3SArnaldo Carvalho de Melo 	size_t size = sizeof(*map) + sizeof(map->map[0]) * nr;
3662eea464SJiri Olsa 	int start = map ? map->nr : 0;
379d7e8c3aSJiri Olsa 
3862eea464SJiri Olsa 	map = realloc(map, size);
3962eea464SJiri Olsa 	/*
4062eea464SJiri Olsa 	 * We only realloc to add more items, let's reset new items.
4162eea464SJiri Olsa 	 */
4262eea464SJiri Olsa 	if (map)
4362eea464SJiri Olsa 		thread_map__reset(map, start, nr);
4462eea464SJiri Olsa 
4562eea464SJiri Olsa 	return map;
469d7e8c3aSJiri Olsa }
479d7e8c3aSJiri Olsa 
489d7e8c3aSJiri Olsa #define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr)
499d7e8c3aSJiri Olsa 
50fd78260bSArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_pid(pid_t pid)
51fd78260bSArnaldo Carvalho de Melo {
52fd78260bSArnaldo Carvalho de Melo 	struct thread_map *threads;
53fd78260bSArnaldo Carvalho de Melo 	char name[256];
54fd78260bSArnaldo Carvalho de Melo 	int items;
55fd78260bSArnaldo Carvalho de Melo 	struct dirent **namelist = NULL;
56fd78260bSArnaldo Carvalho de Melo 	int i;
57fd78260bSArnaldo Carvalho de Melo 
58fd78260bSArnaldo Carvalho de Melo 	sprintf(name, "/proc/%d/task", pid);
59fd78260bSArnaldo Carvalho de Melo 	items = scandir(name, &namelist, filter, NULL);
60fd78260bSArnaldo Carvalho de Melo 	if (items <= 0)
61fd78260bSArnaldo Carvalho de Melo 		return NULL;
62fd78260bSArnaldo Carvalho de Melo 
639d7e8c3aSJiri Olsa 	threads = thread_map__alloc(items);
64fd78260bSArnaldo Carvalho de Melo 	if (threads != NULL) {
65fd78260bSArnaldo Carvalho de Melo 		for (i = 0; i < items; i++)
66e13798c7SJiri Olsa 			thread_map__set_pid(threads, i, atoi(namelist[i]->d_name));
67fd78260bSArnaldo Carvalho de Melo 		threads->nr = items;
68186fbb74SJiri Olsa 		atomic_set(&threads->refcnt, 1);
69fd78260bSArnaldo Carvalho de Melo 	}
70fd78260bSArnaldo Carvalho de Melo 
71fd78260bSArnaldo Carvalho de Melo 	for (i=0; i<items; i++)
7274cf249dSArnaldo Carvalho de Melo 		zfree(&namelist[i]);
73fd78260bSArnaldo Carvalho de Melo 	free(namelist);
74fd78260bSArnaldo Carvalho de Melo 
75fd78260bSArnaldo Carvalho de Melo 	return threads;
76fd78260bSArnaldo Carvalho de Melo }
77fd78260bSArnaldo Carvalho de Melo 
78fd78260bSArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_tid(pid_t tid)
79fd78260bSArnaldo Carvalho de Melo {
809d7e8c3aSJiri Olsa 	struct thread_map *threads = thread_map__alloc(1);
81fd78260bSArnaldo Carvalho de Melo 
82fd78260bSArnaldo Carvalho de Melo 	if (threads != NULL) {
83e13798c7SJiri Olsa 		thread_map__set_pid(threads, 0, tid);
84fd78260bSArnaldo Carvalho de Melo 		threads->nr = 1;
85186fbb74SJiri Olsa 		atomic_set(&threads->refcnt, 1);
86fd78260bSArnaldo Carvalho de Melo 	}
87fd78260bSArnaldo Carvalho de Melo 
88fd78260bSArnaldo Carvalho de Melo 	return threads;
89fd78260bSArnaldo Carvalho de Melo }
90fd78260bSArnaldo Carvalho de Melo 
910d37aa34SArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_uid(uid_t uid)
920d37aa34SArnaldo Carvalho de Melo {
930d37aa34SArnaldo Carvalho de Melo 	DIR *proc;
940d37aa34SArnaldo Carvalho de Melo 	int max_threads = 32, items, i;
950d37aa34SArnaldo Carvalho de Melo 	char path[256];
960d37aa34SArnaldo Carvalho de Melo 	struct dirent dirent, *next, **namelist = NULL;
979d7e8c3aSJiri Olsa 	struct thread_map *threads = thread_map__alloc(max_threads);
989d7e8c3aSJiri Olsa 
990d37aa34SArnaldo Carvalho de Melo 	if (threads == NULL)
1000d37aa34SArnaldo Carvalho de Melo 		goto out;
1010d37aa34SArnaldo Carvalho de Melo 
1020d37aa34SArnaldo Carvalho de Melo 	proc = opendir("/proc");
1030d37aa34SArnaldo Carvalho de Melo 	if (proc == NULL)
1040d37aa34SArnaldo Carvalho de Melo 		goto out_free_threads;
1050d37aa34SArnaldo Carvalho de Melo 
1060d37aa34SArnaldo Carvalho de Melo 	threads->nr = 0;
107186fbb74SJiri Olsa 	atomic_set(&threads->refcnt, 1);
1080d37aa34SArnaldo Carvalho de Melo 
1090d37aa34SArnaldo Carvalho de Melo 	while (!readdir_r(proc, &dirent, &next) && next) {
1100d37aa34SArnaldo Carvalho de Melo 		char *end;
1110d37aa34SArnaldo Carvalho de Melo 		bool grow = false;
1120d37aa34SArnaldo Carvalho de Melo 		struct stat st;
1130d37aa34SArnaldo Carvalho de Melo 		pid_t pid = strtol(dirent.d_name, &end, 10);
1140d37aa34SArnaldo Carvalho de Melo 
1150d37aa34SArnaldo Carvalho de Melo 		if (*end) /* only interested in proper numerical dirents */
1160d37aa34SArnaldo Carvalho de Melo 			continue;
1170d37aa34SArnaldo Carvalho de Melo 
1180d37aa34SArnaldo Carvalho de Melo 		snprintf(path, sizeof(path), "/proc/%s", dirent.d_name);
1190d37aa34SArnaldo Carvalho de Melo 
1200d37aa34SArnaldo Carvalho de Melo 		if (stat(path, &st) != 0)
1210d37aa34SArnaldo Carvalho de Melo 			continue;
1220d37aa34SArnaldo Carvalho de Melo 
1230d37aa34SArnaldo Carvalho de Melo 		if (st.st_uid != uid)
1240d37aa34SArnaldo Carvalho de Melo 			continue;
1250d37aa34SArnaldo Carvalho de Melo 
1260d37aa34SArnaldo Carvalho de Melo 		snprintf(path, sizeof(path), "/proc/%d/task", pid);
1270d37aa34SArnaldo Carvalho de Melo 		items = scandir(path, &namelist, filter, NULL);
1280d37aa34SArnaldo Carvalho de Melo 		if (items <= 0)
1290d37aa34SArnaldo Carvalho de Melo 			goto out_free_closedir;
1300d37aa34SArnaldo Carvalho de Melo 
1310d37aa34SArnaldo Carvalho de Melo 		while (threads->nr + items >= max_threads) {
1320d37aa34SArnaldo Carvalho de Melo 			max_threads *= 2;
1330d37aa34SArnaldo Carvalho de Melo 			grow = true;
1340d37aa34SArnaldo Carvalho de Melo 		}
1350d37aa34SArnaldo Carvalho de Melo 
1360d37aa34SArnaldo Carvalho de Melo 		if (grow) {
1370d37aa34SArnaldo Carvalho de Melo 			struct thread_map *tmp;
1380d37aa34SArnaldo Carvalho de Melo 
1390d37aa34SArnaldo Carvalho de Melo 			tmp = realloc(threads, (sizeof(*threads) +
1400d37aa34SArnaldo Carvalho de Melo 						max_threads * sizeof(pid_t)));
1410d37aa34SArnaldo Carvalho de Melo 			if (tmp == NULL)
1420d37aa34SArnaldo Carvalho de Melo 				goto out_free_namelist;
1430d37aa34SArnaldo Carvalho de Melo 
1440d37aa34SArnaldo Carvalho de Melo 			threads = tmp;
1450d37aa34SArnaldo Carvalho de Melo 		}
1460d37aa34SArnaldo Carvalho de Melo 
147e13798c7SJiri Olsa 		for (i = 0; i < items; i++) {
148e13798c7SJiri Olsa 			thread_map__set_pid(threads, threads->nr + i,
149e13798c7SJiri Olsa 					    atoi(namelist[i]->d_name));
150e13798c7SJiri Olsa 		}
1510d37aa34SArnaldo Carvalho de Melo 
1520d37aa34SArnaldo Carvalho de Melo 		for (i = 0; i < items; i++)
15374cf249dSArnaldo Carvalho de Melo 			zfree(&namelist[i]);
1540d37aa34SArnaldo Carvalho de Melo 		free(namelist);
1550d37aa34SArnaldo Carvalho de Melo 
1560d37aa34SArnaldo Carvalho de Melo 		threads->nr += items;
1570d37aa34SArnaldo Carvalho de Melo 	}
1580d37aa34SArnaldo Carvalho de Melo 
1590d37aa34SArnaldo Carvalho de Melo out_closedir:
1600d37aa34SArnaldo Carvalho de Melo 	closedir(proc);
1610d37aa34SArnaldo Carvalho de Melo out:
1620d37aa34SArnaldo Carvalho de Melo 	return threads;
1630d37aa34SArnaldo Carvalho de Melo 
1640d37aa34SArnaldo Carvalho de Melo out_free_threads:
1650d37aa34SArnaldo Carvalho de Melo 	free(threads);
1660d37aa34SArnaldo Carvalho de Melo 	return NULL;
1670d37aa34SArnaldo Carvalho de Melo 
1680d37aa34SArnaldo Carvalho de Melo out_free_namelist:
1690d37aa34SArnaldo Carvalho de Melo 	for (i = 0; i < items; i++)
17074cf249dSArnaldo Carvalho de Melo 		zfree(&namelist[i]);
1710d37aa34SArnaldo Carvalho de Melo 	free(namelist);
1720d37aa34SArnaldo Carvalho de Melo 
1730d37aa34SArnaldo Carvalho de Melo out_free_closedir:
17404662523SArnaldo Carvalho de Melo 	zfree(&threads);
1750d37aa34SArnaldo Carvalho de Melo 	goto out_closedir;
1760d37aa34SArnaldo Carvalho de Melo }
1770d37aa34SArnaldo Carvalho de Melo 
1780d37aa34SArnaldo Carvalho de Melo struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
179fd78260bSArnaldo Carvalho de Melo {
180fd78260bSArnaldo Carvalho de Melo 	if (pid != -1)
181fd78260bSArnaldo Carvalho de Melo 		return thread_map__new_by_pid(pid);
1820d37aa34SArnaldo Carvalho de Melo 
1830d37aa34SArnaldo Carvalho de Melo 	if (tid == -1 && uid != UINT_MAX)
1840d37aa34SArnaldo Carvalho de Melo 		return thread_map__new_by_uid(uid);
1850d37aa34SArnaldo Carvalho de Melo 
186fd78260bSArnaldo Carvalho de Melo 	return thread_map__new_by_tid(tid);
187fd78260bSArnaldo Carvalho de Melo }
188fd78260bSArnaldo Carvalho de Melo 
189b52956c9SDavid Ahern static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
190b52956c9SDavid Ahern {
191b52956c9SDavid Ahern 	struct thread_map *threads = NULL, *nt;
192b52956c9SDavid Ahern 	char name[256];
193b52956c9SDavid Ahern 	int items, total_tasks = 0;
194b52956c9SDavid Ahern 	struct dirent **namelist = NULL;
195b52956c9SDavid Ahern 	int i, j = 0;
196b52956c9SDavid Ahern 	pid_t pid, prev_pid = INT_MAX;
197b52956c9SDavid Ahern 	char *end_ptr;
198b52956c9SDavid Ahern 	struct str_node *pos;
199*4a77e218SArnaldo Carvalho de Melo 	struct strlist_config slist_config = { .dont_dupstr = true, };
200*4a77e218SArnaldo Carvalho de Melo 	struct strlist *slist = strlist__new(pid_str, &slist_config);
201b52956c9SDavid Ahern 
202b52956c9SDavid Ahern 	if (!slist)
203b52956c9SDavid Ahern 		return NULL;
204b52956c9SDavid Ahern 
205b52956c9SDavid Ahern 	strlist__for_each(pos, slist) {
206b52956c9SDavid Ahern 		pid = strtol(pos->s, &end_ptr, 10);
207b52956c9SDavid Ahern 
208b52956c9SDavid Ahern 		if (pid == INT_MIN || pid == INT_MAX ||
209b52956c9SDavid Ahern 		    (*end_ptr != '\0' && *end_ptr != ','))
210b52956c9SDavid Ahern 			goto out_free_threads;
211b52956c9SDavid Ahern 
212b52956c9SDavid Ahern 		if (pid == prev_pid)
213b52956c9SDavid Ahern 			continue;
214b52956c9SDavid Ahern 
215b52956c9SDavid Ahern 		sprintf(name, "/proc/%d/task", pid);
216b52956c9SDavid Ahern 		items = scandir(name, &namelist, filter, NULL);
217b52956c9SDavid Ahern 		if (items <= 0)
218b52956c9SDavid Ahern 			goto out_free_threads;
219b52956c9SDavid Ahern 
220b52956c9SDavid Ahern 		total_tasks += items;
2219d7e8c3aSJiri Olsa 		nt = thread_map__realloc(threads, total_tasks);
222b52956c9SDavid Ahern 		if (nt == NULL)
223e8cdd947SFranck Bui-Huu 			goto out_free_namelist;
224b52956c9SDavid Ahern 
225b52956c9SDavid Ahern 		threads = nt;
226b52956c9SDavid Ahern 
227e8cdd947SFranck Bui-Huu 		for (i = 0; i < items; i++) {
228e13798c7SJiri Olsa 			thread_map__set_pid(threads, j++, atoi(namelist[i]->d_name));
22974cf249dSArnaldo Carvalho de Melo 			zfree(&namelist[i]);
230e8cdd947SFranck Bui-Huu 		}
231e8cdd947SFranck Bui-Huu 		threads->nr = total_tasks;
232b52956c9SDavid Ahern 		free(namelist);
233b52956c9SDavid Ahern 	}
234b52956c9SDavid Ahern 
235b52956c9SDavid Ahern out:
236b52956c9SDavid Ahern 	strlist__delete(slist);
237186fbb74SJiri Olsa 	if (threads)
238186fbb74SJiri Olsa 		atomic_set(&threads->refcnt, 1);
239b52956c9SDavid Ahern 	return threads;
240b52956c9SDavid Ahern 
241e8cdd947SFranck Bui-Huu out_free_namelist:
242e8cdd947SFranck Bui-Huu 	for (i = 0; i < items; i++)
24374cf249dSArnaldo Carvalho de Melo 		zfree(&namelist[i]);
244e8cdd947SFranck Bui-Huu 	free(namelist);
245e8cdd947SFranck Bui-Huu 
246b52956c9SDavid Ahern out_free_threads:
24704662523SArnaldo Carvalho de Melo 	zfree(&threads);
248b52956c9SDavid Ahern 	goto out;
249b52956c9SDavid Ahern }
250b52956c9SDavid Ahern 
251641556c9SArnaldo Carvalho de Melo struct thread_map *thread_map__new_dummy(void)
252641556c9SArnaldo Carvalho de Melo {
2539d7e8c3aSJiri Olsa 	struct thread_map *threads = thread_map__alloc(1);
254641556c9SArnaldo Carvalho de Melo 
255641556c9SArnaldo Carvalho de Melo 	if (threads != NULL) {
256e13798c7SJiri Olsa 		thread_map__set_pid(threads, 0, -1);
257641556c9SArnaldo Carvalho de Melo 		threads->nr = 1;
258186fbb74SJiri Olsa 		atomic_set(&threads->refcnt, 1);
259641556c9SArnaldo Carvalho de Melo 	}
260641556c9SArnaldo Carvalho de Melo 	return threads;
261641556c9SArnaldo Carvalho de Melo }
262641556c9SArnaldo Carvalho de Melo 
263b52956c9SDavid Ahern static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
264b52956c9SDavid Ahern {
265b52956c9SDavid Ahern 	struct thread_map *threads = NULL, *nt;
266b52956c9SDavid Ahern 	int ntasks = 0;
267b52956c9SDavid Ahern 	pid_t tid, prev_tid = INT_MAX;
268b52956c9SDavid Ahern 	char *end_ptr;
269b52956c9SDavid Ahern 	struct str_node *pos;
270*4a77e218SArnaldo Carvalho de Melo 	struct strlist_config slist_config = { .dont_dupstr = true, };
271b52956c9SDavid Ahern 	struct strlist *slist;
272b52956c9SDavid Ahern 
273b52956c9SDavid Ahern 	/* perf-stat expects threads to be generated even if tid not given */
274641556c9SArnaldo Carvalho de Melo 	if (!tid_str)
275641556c9SArnaldo Carvalho de Melo 		return thread_map__new_dummy();
276b52956c9SDavid Ahern 
277*4a77e218SArnaldo Carvalho de Melo 	slist = strlist__new(tid_str, &slist_config);
278b52956c9SDavid Ahern 	if (!slist)
279b52956c9SDavid Ahern 		return NULL;
280b52956c9SDavid Ahern 
281b52956c9SDavid Ahern 	strlist__for_each(pos, slist) {
282b52956c9SDavid Ahern 		tid = strtol(pos->s, &end_ptr, 10);
283b52956c9SDavid Ahern 
284b52956c9SDavid Ahern 		if (tid == INT_MIN || tid == INT_MAX ||
285b52956c9SDavid Ahern 		    (*end_ptr != '\0' && *end_ptr != ','))
286b52956c9SDavid Ahern 			goto out_free_threads;
287b52956c9SDavid Ahern 
288b52956c9SDavid Ahern 		if (tid == prev_tid)
289b52956c9SDavid Ahern 			continue;
290b52956c9SDavid Ahern 
291b52956c9SDavid Ahern 		ntasks++;
2929d7e8c3aSJiri Olsa 		nt = thread_map__realloc(threads, ntasks);
293b52956c9SDavid Ahern 
294b52956c9SDavid Ahern 		if (nt == NULL)
295b52956c9SDavid Ahern 			goto out_free_threads;
296b52956c9SDavid Ahern 
297b52956c9SDavid Ahern 		threads = nt;
298e13798c7SJiri Olsa 		thread_map__set_pid(threads, ntasks - 1, tid);
299b52956c9SDavid Ahern 		threads->nr = ntasks;
300b52956c9SDavid Ahern 	}
301b52956c9SDavid Ahern out:
302186fbb74SJiri Olsa 	if (threads)
303186fbb74SJiri Olsa 		atomic_set(&threads->refcnt, 1);
304b52956c9SDavid Ahern 	return threads;
305b52956c9SDavid Ahern 
306b52956c9SDavid Ahern out_free_threads:
30704662523SArnaldo Carvalho de Melo 	zfree(&threads);
308b52956c9SDavid Ahern 	goto out;
309b52956c9SDavid Ahern }
310b52956c9SDavid Ahern 
311b52956c9SDavid Ahern struct thread_map *thread_map__new_str(const char *pid, const char *tid,
312b52956c9SDavid Ahern 				       uid_t uid)
313b52956c9SDavid Ahern {
314b52956c9SDavid Ahern 	if (pid)
315b52956c9SDavid Ahern 		return thread_map__new_by_pid_str(pid);
316b52956c9SDavid Ahern 
317b52956c9SDavid Ahern 	if (!tid && uid != UINT_MAX)
318b52956c9SDavid Ahern 		return thread_map__new_by_uid(uid);
319b52956c9SDavid Ahern 
320b52956c9SDavid Ahern 	return thread_map__new_by_tid_str(tid);
321b52956c9SDavid Ahern }
322b52956c9SDavid Ahern 
323186fbb74SJiri Olsa static void thread_map__delete(struct thread_map *threads)
324fd78260bSArnaldo Carvalho de Melo {
325186fbb74SJiri Olsa 	if (threads) {
326792402fdSJiri Olsa 		int i;
327792402fdSJiri Olsa 
328186fbb74SJiri Olsa 		WARN_ONCE(atomic_read(&threads->refcnt) != 0,
329186fbb74SJiri Olsa 			  "thread map refcnt unbalanced\n");
330792402fdSJiri Olsa 		for (i = 0; i < threads->nr; i++)
331792402fdSJiri Olsa 			free(thread_map__comm(threads, i));
332fd78260bSArnaldo Carvalho de Melo 		free(threads);
333fd78260bSArnaldo Carvalho de Melo 	}
334186fbb74SJiri Olsa }
335186fbb74SJiri Olsa 
336186fbb74SJiri Olsa struct thread_map *thread_map__get(struct thread_map *map)
337186fbb74SJiri Olsa {
338186fbb74SJiri Olsa 	if (map)
339186fbb74SJiri Olsa 		atomic_inc(&map->refcnt);
340186fbb74SJiri Olsa 	return map;
341186fbb74SJiri Olsa }
342186fbb74SJiri Olsa 
343186fbb74SJiri Olsa void thread_map__put(struct thread_map *map)
344186fbb74SJiri Olsa {
345186fbb74SJiri Olsa 	if (map && atomic_dec_and_test(&map->refcnt))
346186fbb74SJiri Olsa 		thread_map__delete(map);
347186fbb74SJiri Olsa }
3489ae7d335SArnaldo Carvalho de Melo 
3499ae7d335SArnaldo Carvalho de Melo size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
3509ae7d335SArnaldo Carvalho de Melo {
3519ae7d335SArnaldo Carvalho de Melo 	int i;
3529ae7d335SArnaldo Carvalho de Melo 	size_t printed = fprintf(fp, "%d thread%s: ",
3539ae7d335SArnaldo Carvalho de Melo 				 threads->nr, threads->nr > 1 ? "s" : "");
3549ae7d335SArnaldo Carvalho de Melo 	for (i = 0; i < threads->nr; ++i)
355e13798c7SJiri Olsa 		printed += fprintf(fp, "%s%d", i ? ", " : "", thread_map__pid(threads, i));
3569ae7d335SArnaldo Carvalho de Melo 
3579ae7d335SArnaldo Carvalho de Melo 	return printed + fprintf(fp, "\n");
3589ae7d335SArnaldo Carvalho de Melo }
359792402fdSJiri Olsa 
360792402fdSJiri Olsa static int get_comm(char **comm, pid_t pid)
361792402fdSJiri Olsa {
362792402fdSJiri Olsa 	char *path;
363792402fdSJiri Olsa 	size_t size;
364792402fdSJiri Olsa 	int err;
365792402fdSJiri Olsa 
366792402fdSJiri Olsa 	if (asprintf(&path, "%s/%d/comm", procfs__mountpoint(), pid) == -1)
367792402fdSJiri Olsa 		return -ENOMEM;
368792402fdSJiri Olsa 
369792402fdSJiri Olsa 	err = filename__read_str(path, comm, &size);
370792402fdSJiri Olsa 	if (!err) {
371792402fdSJiri Olsa 		/*
372792402fdSJiri Olsa 		 * We're reading 16 bytes, while filename__read_str
373792402fdSJiri Olsa 		 * allocates data per BUFSIZ bytes, so we can safely
374792402fdSJiri Olsa 		 * mark the end of the string.
375792402fdSJiri Olsa 		 */
376792402fdSJiri Olsa 		(*comm)[size] = 0;
377792402fdSJiri Olsa 		rtrim(*comm);
378792402fdSJiri Olsa 	}
379792402fdSJiri Olsa 
380792402fdSJiri Olsa 	free(path);
381792402fdSJiri Olsa 	return err;
382792402fdSJiri Olsa }
383792402fdSJiri Olsa 
384792402fdSJiri Olsa static void comm_init(struct thread_map *map, int i)
385792402fdSJiri Olsa {
386792402fdSJiri Olsa 	pid_t pid = thread_map__pid(map, i);
387792402fdSJiri Olsa 	char *comm = NULL;
388792402fdSJiri Olsa 
389792402fdSJiri Olsa 	/* dummy pid comm initialization */
390792402fdSJiri Olsa 	if (pid == -1) {
391792402fdSJiri Olsa 		map->map[i].comm = strdup("dummy");
392792402fdSJiri Olsa 		return;
393792402fdSJiri Olsa 	}
394792402fdSJiri Olsa 
395792402fdSJiri Olsa 	/*
396792402fdSJiri Olsa 	 * The comm name is like extra bonus ;-),
397792402fdSJiri Olsa 	 * so just warn if we fail for any reason.
398792402fdSJiri Olsa 	 */
399792402fdSJiri Olsa 	if (get_comm(&comm, pid))
400792402fdSJiri Olsa 		pr_warning("Couldn't resolve comm name for pid %d\n", pid);
401792402fdSJiri Olsa 
402792402fdSJiri Olsa 	map->map[i].comm = comm;
403792402fdSJiri Olsa }
404792402fdSJiri Olsa 
405792402fdSJiri Olsa void thread_map__read_comms(struct thread_map *threads)
406792402fdSJiri Olsa {
407792402fdSJiri Olsa 	int i;
408792402fdSJiri Olsa 
409792402fdSJiri Olsa 	for (i = 0; i < threads->nr; ++i)
410792402fdSJiri Olsa 		comm_init(threads, i);
411792402fdSJiri Olsa }
412