xref: /linux/tools/perf/util/thread_map.c (revision 364fed351369e0193244fa2c78df855724cdddb9)
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"
1659660942SJiri Olsa #include "event.h"
17fd78260bSArnaldo Carvalho de Melo 
18fd78260bSArnaldo Carvalho de Melo /* Skip "." and ".." directories */
19fd78260bSArnaldo Carvalho de Melo static int filter(const struct dirent *dir)
20fd78260bSArnaldo Carvalho de Melo {
21fd78260bSArnaldo Carvalho de Melo 	if (dir->d_name[0] == '.')
22fd78260bSArnaldo Carvalho de Melo 		return 0;
23fd78260bSArnaldo Carvalho de Melo 	else
24fd78260bSArnaldo Carvalho de Melo 		return 1;
25fd78260bSArnaldo Carvalho de Melo }
26fd78260bSArnaldo Carvalho de Melo 
2762eea464SJiri Olsa static void thread_map__reset(struct thread_map *map, int start, int nr)
2862eea464SJiri Olsa {
2962eea464SJiri Olsa 	size_t size = (nr - start) * sizeof(map->map[0]);
3062eea464SJiri Olsa 
3162eea464SJiri Olsa 	memset(&map->map[start], 0, size);
3262eea464SJiri Olsa }
3362eea464SJiri Olsa 
349d7e8c3aSJiri Olsa static struct thread_map *thread_map__realloc(struct thread_map *map, int nr)
359d7e8c3aSJiri Olsa {
36060664f3SArnaldo Carvalho de Melo 	size_t size = sizeof(*map) + sizeof(map->map[0]) * nr;
3762eea464SJiri Olsa 	int start = map ? map->nr : 0;
389d7e8c3aSJiri Olsa 
3962eea464SJiri Olsa 	map = realloc(map, size);
4062eea464SJiri Olsa 	/*
4162eea464SJiri Olsa 	 * We only realloc to add more items, let's reset new items.
4262eea464SJiri Olsa 	 */
4362eea464SJiri Olsa 	if (map)
4462eea464SJiri Olsa 		thread_map__reset(map, start, nr);
4562eea464SJiri Olsa 
4662eea464SJiri Olsa 	return map;
479d7e8c3aSJiri Olsa }
489d7e8c3aSJiri Olsa 
499d7e8c3aSJiri Olsa #define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr)
509d7e8c3aSJiri Olsa 
51fd78260bSArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_pid(pid_t pid)
52fd78260bSArnaldo Carvalho de Melo {
53fd78260bSArnaldo Carvalho de Melo 	struct thread_map *threads;
54fd78260bSArnaldo Carvalho de Melo 	char name[256];
55fd78260bSArnaldo Carvalho de Melo 	int items;
56fd78260bSArnaldo Carvalho de Melo 	struct dirent **namelist = NULL;
57fd78260bSArnaldo Carvalho de Melo 	int i;
58fd78260bSArnaldo Carvalho de Melo 
59fd78260bSArnaldo Carvalho de Melo 	sprintf(name, "/proc/%d/task", pid);
60fd78260bSArnaldo Carvalho de Melo 	items = scandir(name, &namelist, filter, NULL);
61fd78260bSArnaldo Carvalho de Melo 	if (items <= 0)
62fd78260bSArnaldo Carvalho de Melo 		return NULL;
63fd78260bSArnaldo Carvalho de Melo 
649d7e8c3aSJiri Olsa 	threads = thread_map__alloc(items);
65fd78260bSArnaldo Carvalho de Melo 	if (threads != NULL) {
66fd78260bSArnaldo Carvalho de Melo 		for (i = 0; i < items; i++)
67e13798c7SJiri Olsa 			thread_map__set_pid(threads, i, atoi(namelist[i]->d_name));
68fd78260bSArnaldo Carvalho de Melo 		threads->nr = items;
69*364fed35SElena Reshetova 		refcount_set(&threads->refcnt, 1);
70fd78260bSArnaldo Carvalho de Melo 	}
71fd78260bSArnaldo Carvalho de Melo 
72fd78260bSArnaldo Carvalho de Melo 	for (i=0; i<items; i++)
7374cf249dSArnaldo Carvalho de Melo 		zfree(&namelist[i]);
74fd78260bSArnaldo Carvalho de Melo 	free(namelist);
75fd78260bSArnaldo Carvalho de Melo 
76fd78260bSArnaldo Carvalho de Melo 	return threads;
77fd78260bSArnaldo Carvalho de Melo }
78fd78260bSArnaldo Carvalho de Melo 
79fd78260bSArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_tid(pid_t tid)
80fd78260bSArnaldo Carvalho de Melo {
819d7e8c3aSJiri Olsa 	struct thread_map *threads = thread_map__alloc(1);
82fd78260bSArnaldo Carvalho de Melo 
83fd78260bSArnaldo Carvalho de Melo 	if (threads != NULL) {
84e13798c7SJiri Olsa 		thread_map__set_pid(threads, 0, tid);
85fd78260bSArnaldo Carvalho de Melo 		threads->nr = 1;
86*364fed35SElena Reshetova 		refcount_set(&threads->refcnt, 1);
87fd78260bSArnaldo Carvalho de Melo 	}
88fd78260bSArnaldo Carvalho de Melo 
89fd78260bSArnaldo Carvalho de Melo 	return threads;
90fd78260bSArnaldo Carvalho de Melo }
91fd78260bSArnaldo Carvalho de Melo 
920d37aa34SArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_uid(uid_t uid)
930d37aa34SArnaldo Carvalho de Melo {
940d37aa34SArnaldo Carvalho de Melo 	DIR *proc;
950d37aa34SArnaldo Carvalho de Melo 	int max_threads = 32, items, i;
96bdf23a9aSArnaldo Carvalho de Melo 	char path[NAME_MAX + 1 + 6];
973354cf71SArnaldo Carvalho de Melo 	struct dirent *dirent, **namelist = NULL;
989d7e8c3aSJiri Olsa 	struct thread_map *threads = thread_map__alloc(max_threads);
999d7e8c3aSJiri Olsa 
1000d37aa34SArnaldo Carvalho de Melo 	if (threads == NULL)
1010d37aa34SArnaldo Carvalho de Melo 		goto out;
1020d37aa34SArnaldo Carvalho de Melo 
1030d37aa34SArnaldo Carvalho de Melo 	proc = opendir("/proc");
1040d37aa34SArnaldo Carvalho de Melo 	if (proc == NULL)
1050d37aa34SArnaldo Carvalho de Melo 		goto out_free_threads;
1060d37aa34SArnaldo Carvalho de Melo 
1070d37aa34SArnaldo Carvalho de Melo 	threads->nr = 0;
108*364fed35SElena Reshetova 	refcount_set(&threads->refcnt, 1);
1090d37aa34SArnaldo Carvalho de Melo 
1103354cf71SArnaldo Carvalho de Melo 	while ((dirent = readdir(proc)) != NULL) {
1110d37aa34SArnaldo Carvalho de Melo 		char *end;
1120d37aa34SArnaldo Carvalho de Melo 		bool grow = false;
1130d37aa34SArnaldo Carvalho de Melo 		struct stat st;
1143354cf71SArnaldo Carvalho de Melo 		pid_t pid = strtol(dirent->d_name, &end, 10);
1150d37aa34SArnaldo Carvalho de Melo 
1160d37aa34SArnaldo Carvalho de Melo 		if (*end) /* only interested in proper numerical dirents */
1170d37aa34SArnaldo Carvalho de Melo 			continue;
1180d37aa34SArnaldo Carvalho de Melo 
1193354cf71SArnaldo Carvalho de Melo 		snprintf(path, sizeof(path), "/proc/%s", dirent->d_name);
1200d37aa34SArnaldo Carvalho de Melo 
1210d37aa34SArnaldo Carvalho de Melo 		if (stat(path, &st) != 0)
1220d37aa34SArnaldo Carvalho de Melo 			continue;
1230d37aa34SArnaldo Carvalho de Melo 
1240d37aa34SArnaldo Carvalho de Melo 		if (st.st_uid != uid)
1250d37aa34SArnaldo Carvalho de Melo 			continue;
1260d37aa34SArnaldo Carvalho de Melo 
1270d37aa34SArnaldo Carvalho de Melo 		snprintf(path, sizeof(path), "/proc/%d/task", pid);
1280d37aa34SArnaldo Carvalho de Melo 		items = scandir(path, &namelist, filter, NULL);
1290d37aa34SArnaldo Carvalho de Melo 		if (items <= 0)
1300d37aa34SArnaldo Carvalho de Melo 			goto out_free_closedir;
1310d37aa34SArnaldo Carvalho de Melo 
1320d37aa34SArnaldo Carvalho de Melo 		while (threads->nr + items >= max_threads) {
1330d37aa34SArnaldo Carvalho de Melo 			max_threads *= 2;
1340d37aa34SArnaldo Carvalho de Melo 			grow = true;
1350d37aa34SArnaldo Carvalho de Melo 		}
1360d37aa34SArnaldo Carvalho de Melo 
1370d37aa34SArnaldo Carvalho de Melo 		if (grow) {
1380d37aa34SArnaldo Carvalho de Melo 			struct thread_map *tmp;
1390d37aa34SArnaldo Carvalho de Melo 
14008ae217bSArnaldo Carvalho de Melo 			tmp = thread_map__realloc(threads, max_threads);
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;
1994a77e218SArnaldo Carvalho de Melo 	struct strlist_config slist_config = { .dont_dupstr = true, };
2004a77e218SArnaldo Carvalho de Melo 	struct strlist *slist = strlist__new(pid_str, &slist_config);
201b52956c9SDavid Ahern 
202b52956c9SDavid Ahern 	if (!slist)
203b52956c9SDavid Ahern 		return NULL;
204b52956c9SDavid Ahern 
205602a1f4dSArnaldo Carvalho de Melo 	strlist__for_each_entry(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)
238*364fed35SElena Reshetova 		refcount_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;
258*364fed35SElena Reshetova 		refcount_set(&threads->refcnt, 1);
259641556c9SArnaldo Carvalho de Melo 	}
260641556c9SArnaldo Carvalho de Melo 	return threads;
261641556c9SArnaldo Carvalho de Melo }
262641556c9SArnaldo Carvalho de Melo 
263097be0f5SJiri Olsa 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;
2704a77e218SArnaldo 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 
2774a77e218SArnaldo Carvalho de Melo 	slist = strlist__new(tid_str, &slist_config);
278b52956c9SDavid Ahern 	if (!slist)
279b52956c9SDavid Ahern 		return NULL;
280b52956c9SDavid Ahern 
281602a1f4dSArnaldo Carvalho de Melo 	strlist__for_each_entry(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)
303*364fed35SElena Reshetova 		refcount_set(&threads->refcnt, 1);
304b52956c9SDavid Ahern 	return threads;
305b52956c9SDavid Ahern 
306b52956c9SDavid Ahern out_free_threads:
30704662523SArnaldo Carvalho de Melo 	zfree(&threads);
3087ecb48fdSNamhyung Kim 	strlist__delete(slist);
309b52956c9SDavid Ahern 	goto out;
310b52956c9SDavid Ahern }
311b52956c9SDavid Ahern 
312b52956c9SDavid Ahern struct thread_map *thread_map__new_str(const char *pid, const char *tid,
313b52956c9SDavid Ahern 				       uid_t uid)
314b52956c9SDavid Ahern {
315b52956c9SDavid Ahern 	if (pid)
316b52956c9SDavid Ahern 		return thread_map__new_by_pid_str(pid);
317b52956c9SDavid Ahern 
318b52956c9SDavid Ahern 	if (!tid && uid != UINT_MAX)
319b52956c9SDavid Ahern 		return thread_map__new_by_uid(uid);
320b52956c9SDavid Ahern 
321b52956c9SDavid Ahern 	return thread_map__new_by_tid_str(tid);
322b52956c9SDavid Ahern }
323b52956c9SDavid Ahern 
324186fbb74SJiri Olsa static void thread_map__delete(struct thread_map *threads)
325fd78260bSArnaldo Carvalho de Melo {
326186fbb74SJiri Olsa 	if (threads) {
327792402fdSJiri Olsa 		int i;
328792402fdSJiri Olsa 
329*364fed35SElena Reshetova 		WARN_ONCE(refcount_read(&threads->refcnt) != 0,
330186fbb74SJiri Olsa 			  "thread map refcnt unbalanced\n");
331792402fdSJiri Olsa 		for (i = 0; i < threads->nr; i++)
332792402fdSJiri Olsa 			free(thread_map__comm(threads, i));
333fd78260bSArnaldo Carvalho de Melo 		free(threads);
334fd78260bSArnaldo Carvalho de Melo 	}
335186fbb74SJiri Olsa }
336186fbb74SJiri Olsa 
337186fbb74SJiri Olsa struct thread_map *thread_map__get(struct thread_map *map)
338186fbb74SJiri Olsa {
339186fbb74SJiri Olsa 	if (map)
340*364fed35SElena Reshetova 		refcount_inc(&map->refcnt);
341186fbb74SJiri Olsa 	return map;
342186fbb74SJiri Olsa }
343186fbb74SJiri Olsa 
344186fbb74SJiri Olsa void thread_map__put(struct thread_map *map)
345186fbb74SJiri Olsa {
346*364fed35SElena Reshetova 	if (map && refcount_dec_and_test(&map->refcnt))
347186fbb74SJiri Olsa 		thread_map__delete(map);
348186fbb74SJiri Olsa }
3499ae7d335SArnaldo Carvalho de Melo 
3509ae7d335SArnaldo Carvalho de Melo size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
3519ae7d335SArnaldo Carvalho de Melo {
3529ae7d335SArnaldo Carvalho de Melo 	int i;
3539ae7d335SArnaldo Carvalho de Melo 	size_t printed = fprintf(fp, "%d thread%s: ",
3549ae7d335SArnaldo Carvalho de Melo 				 threads->nr, threads->nr > 1 ? "s" : "");
3559ae7d335SArnaldo Carvalho de Melo 	for (i = 0; i < threads->nr; ++i)
356e13798c7SJiri Olsa 		printed += fprintf(fp, "%s%d", i ? ", " : "", thread_map__pid(threads, i));
3579ae7d335SArnaldo Carvalho de Melo 
3589ae7d335SArnaldo Carvalho de Melo 	return printed + fprintf(fp, "\n");
3599ae7d335SArnaldo Carvalho de Melo }
360792402fdSJiri Olsa 
361792402fdSJiri Olsa static int get_comm(char **comm, pid_t pid)
362792402fdSJiri Olsa {
363792402fdSJiri Olsa 	char *path;
364792402fdSJiri Olsa 	size_t size;
365792402fdSJiri Olsa 	int err;
366792402fdSJiri Olsa 
367792402fdSJiri Olsa 	if (asprintf(&path, "%s/%d/comm", procfs__mountpoint(), pid) == -1)
368792402fdSJiri Olsa 		return -ENOMEM;
369792402fdSJiri Olsa 
370792402fdSJiri Olsa 	err = filename__read_str(path, comm, &size);
371792402fdSJiri Olsa 	if (!err) {
372792402fdSJiri Olsa 		/*
373792402fdSJiri Olsa 		 * We're reading 16 bytes, while filename__read_str
374792402fdSJiri Olsa 		 * allocates data per BUFSIZ bytes, so we can safely
375792402fdSJiri Olsa 		 * mark the end of the string.
376792402fdSJiri Olsa 		 */
377792402fdSJiri Olsa 		(*comm)[size] = 0;
378792402fdSJiri Olsa 		rtrim(*comm);
379792402fdSJiri Olsa 	}
380792402fdSJiri Olsa 
381792402fdSJiri Olsa 	free(path);
382792402fdSJiri Olsa 	return err;
383792402fdSJiri Olsa }
384792402fdSJiri Olsa 
385792402fdSJiri Olsa static void comm_init(struct thread_map *map, int i)
386792402fdSJiri Olsa {
387792402fdSJiri Olsa 	pid_t pid = thread_map__pid(map, i);
388792402fdSJiri Olsa 	char *comm = NULL;
389792402fdSJiri Olsa 
390792402fdSJiri Olsa 	/* dummy pid comm initialization */
391792402fdSJiri Olsa 	if (pid == -1) {
392792402fdSJiri Olsa 		map->map[i].comm = strdup("dummy");
393792402fdSJiri Olsa 		return;
394792402fdSJiri Olsa 	}
395792402fdSJiri Olsa 
396792402fdSJiri Olsa 	/*
397792402fdSJiri Olsa 	 * The comm name is like extra bonus ;-),
398792402fdSJiri Olsa 	 * so just warn if we fail for any reason.
399792402fdSJiri Olsa 	 */
400792402fdSJiri Olsa 	if (get_comm(&comm, pid))
401792402fdSJiri Olsa 		pr_warning("Couldn't resolve comm name for pid %d\n", pid);
402792402fdSJiri Olsa 
403792402fdSJiri Olsa 	map->map[i].comm = comm;
404792402fdSJiri Olsa }
405792402fdSJiri Olsa 
406792402fdSJiri Olsa void thread_map__read_comms(struct thread_map *threads)
407792402fdSJiri Olsa {
408792402fdSJiri Olsa 	int i;
409792402fdSJiri Olsa 
410792402fdSJiri Olsa 	for (i = 0; i < threads->nr; ++i)
411792402fdSJiri Olsa 		comm_init(threads, i);
412792402fdSJiri Olsa }
41359660942SJiri Olsa 
41459660942SJiri Olsa static void thread_map__copy_event(struct thread_map *threads,
41559660942SJiri Olsa 				   struct thread_map_event *event)
41659660942SJiri Olsa {
41759660942SJiri Olsa 	unsigned i;
41859660942SJiri Olsa 
41959660942SJiri Olsa 	threads->nr = (int) event->nr;
42059660942SJiri Olsa 
42159660942SJiri Olsa 	for (i = 0; i < event->nr; i++) {
42259660942SJiri Olsa 		thread_map__set_pid(threads, i, (pid_t) event->entries[i].pid);
42359660942SJiri Olsa 		threads->map[i].comm = strndup(event->entries[i].comm, 16);
42459660942SJiri Olsa 	}
42559660942SJiri Olsa 
426*364fed35SElena Reshetova 	refcount_set(&threads->refcnt, 1);
42759660942SJiri Olsa }
42859660942SJiri Olsa 
42959660942SJiri Olsa struct thread_map *thread_map__new_event(struct thread_map_event *event)
43059660942SJiri Olsa {
43159660942SJiri Olsa 	struct thread_map *threads;
43259660942SJiri Olsa 
43359660942SJiri Olsa 	threads = thread_map__alloc(event->nr);
43459660942SJiri Olsa 	if (threads)
43559660942SJiri Olsa 		thread_map__copy_event(threads, event);
43659660942SJiri Olsa 
43759660942SJiri Olsa 	return threads;
43859660942SJiri Olsa }
4393407df8bSJiri Olsa 
4403407df8bSJiri Olsa bool thread_map__has(struct thread_map *threads, pid_t pid)
4413407df8bSJiri Olsa {
4423407df8bSJiri Olsa 	int i;
4433407df8bSJiri Olsa 
4443407df8bSJiri Olsa 	for (i = 0; i < threads->nr; ++i) {
4453407df8bSJiri Olsa 		if (threads->map[i].pid == pid)
4463407df8bSJiri Olsa 			return true;
4473407df8bSJiri Olsa 	}
4483407df8bSJiri Olsa 
4493407df8bSJiri Olsa 	return false;
4503407df8bSJiri Olsa }
45138af91f0SJiri Olsa 
45238af91f0SJiri Olsa int thread_map__remove(struct thread_map *threads, int idx)
45338af91f0SJiri Olsa {
45438af91f0SJiri Olsa 	int i;
45538af91f0SJiri Olsa 
45638af91f0SJiri Olsa 	if (threads->nr < 1)
45738af91f0SJiri Olsa 		return -EINVAL;
45838af91f0SJiri Olsa 
45938af91f0SJiri Olsa 	if (idx >= threads->nr)
46038af91f0SJiri Olsa 		return -EINVAL;
46138af91f0SJiri Olsa 
46238af91f0SJiri Olsa 	/*
46338af91f0SJiri Olsa 	 * Free the 'idx' item and shift the rest up.
46438af91f0SJiri Olsa 	 */
46538af91f0SJiri Olsa 	free(threads->map[idx].comm);
46638af91f0SJiri Olsa 
46738af91f0SJiri Olsa 	for (i = idx; i < threads->nr - 1; i++)
46838af91f0SJiri Olsa 		threads->map[i] = threads->map[i + 1];
46938af91f0SJiri Olsa 
47038af91f0SJiri Olsa 	threads->nr--;
47138af91f0SJiri Olsa 	return 0;
47238af91f0SJiri Olsa }
473