1e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <dirent.h>
2e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <limits.h>
3e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <stdbool.h>
4e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <stdlib.h>
5e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <stdio.h>
6e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <sys/types.h>
7e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <sys/stat.h>
8e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <unistd.h>
9e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "strlist.h"
10e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <string.h>
11e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "thread_map.h"
12e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
13e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* Skip "." and ".." directories */
14e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int filter(const struct dirent *dir)
15e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
16e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (dir->d_name[0] == '.')
17e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 0;
18e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	else
19e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return 1;
20e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
21e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
22e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct thread_map *thread_map__new_by_pid(pid_t pid)
23e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
24e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct thread_map *threads;
25e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char name[256];
26e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int items;
27e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct dirent **namelist = NULL;
28e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int i;
29e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
30e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sprintf(name, "/proc/%d/task", pid);
31e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	items = scandir(name, &namelist, filter, NULL);
32e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (items <= 0)
33e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return NULL;
34e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
35e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
36e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (threads != NULL) {
37e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		for (i = 0; i < items; i++)
38e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			threads->map[i] = atoi(namelist[i]->d_name);
39e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		threads->nr = items;
40e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
41e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
42e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i=0; i<items; i++)
43e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		free(namelist[i]);
44e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free(namelist);
45e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
46e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return threads;
47e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
48e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
49e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct thread_map *thread_map__new_by_tid(pid_t tid)
50e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
51e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t));
52e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
53e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (threads != NULL) {
54e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		threads->map[0] = tid;
55e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		threads->nr	= 1;
56e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
57e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
58e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return threads;
59e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
60e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
61e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct thread_map *thread_map__new_by_uid(uid_t uid)
62e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
63e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	DIR *proc;
64e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int max_threads = 32, items, i;
65e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char path[256];
66e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct dirent dirent, *next, **namelist = NULL;
67e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct thread_map *threads = malloc(sizeof(*threads) +
68e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					    max_threads * sizeof(pid_t));
69e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (threads == NULL)
70e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		goto out;
71e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
72e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	proc = opendir("/proc");
73e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (proc == NULL)
74e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		goto out_free_threads;
75e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
76e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	threads->nr = 0;
77e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
78e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (!readdir_r(proc, &dirent, &next) && next) {
79e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		char *end;
80e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		bool grow = false;
81e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct stat st;
82e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pid_t pid = strtol(dirent.d_name, &end, 10);
83e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
84e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (*end) /* only interested in proper numerical dirents */
85e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
86e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
87e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		snprintf(path, sizeof(path), "/proc/%s", dirent.d_name);
88e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
89e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (stat(path, &st) != 0)
90e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
91e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
92e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (st.st_uid != uid)
93e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
94e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
95e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		snprintf(path, sizeof(path), "/proc/%d/task", pid);
96e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		items = scandir(path, &namelist, filter, NULL);
97e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (items <= 0)
98e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out_free_closedir;
99e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		while (threads->nr + items >= max_threads) {
101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			max_threads *= 2;
102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			grow = true;
103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (grow) {
106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			struct thread_map *tmp;
107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			tmp = realloc(threads, (sizeof(*threads) +
109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng						max_threads * sizeof(pid_t)));
110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (tmp == NULL)
111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				goto out_free_namelist;
112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			threads = tmp;
114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		for (i = 0; i < items; i++)
117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			threads->map[threads->nr + i] = atoi(namelist[i]->d_name);
118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		for (i = 0; i < items; i++)
120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			free(namelist[i]);
121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		free(namelist);
122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		threads->nr += items;
124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_closedir:
127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	closedir(proc);
128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout:
129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return threads;
130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_free_threads:
132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free(threads);
133e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return NULL;
134e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
135e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_free_namelist:
136e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < items; i++)
137e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		free(namelist[i]);
138e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free(namelist);
139e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
140e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_free_closedir:
141e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free(threads);
142e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	threads = NULL;
143e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	goto out_closedir;
144e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
145e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
146e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
147e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
148e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (pid != -1)
149e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return thread_map__new_by_pid(pid);
150e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
151e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (tid == -1 && uid != UINT_MAX)
152e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return thread_map__new_by_uid(uid);
153e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
154e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return thread_map__new_by_tid(tid);
155e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
156e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
157e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
158e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
159e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct thread_map *threads = NULL, *nt;
160e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char name[256];
161e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int items, total_tasks = 0;
162e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct dirent **namelist = NULL;
163e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int i, j = 0;
164e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pid_t pid, prev_pid = INT_MAX;
165e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char *end_ptr;
166e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct str_node *pos;
167e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct strlist *slist = strlist__new(false, pid_str);
168e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
169e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!slist)
170e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return NULL;
171e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
172e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	strlist__for_each(pos, slist) {
173e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pid = strtol(pos->s, &end_ptr, 10);
174e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
175e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (pid == INT_MIN || pid == INT_MAX ||
176e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    (*end_ptr != '\0' && *end_ptr != ','))
177e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out_free_threads;
178e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
179e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (pid == prev_pid)
180e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
181e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
182e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sprintf(name, "/proc/%d/task", pid);
183e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		items = scandir(name, &namelist, filter, NULL);
184e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (items <= 0)
185e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out_free_threads;
186e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
187e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		total_tasks += items;
188e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		nt = realloc(threads, (sizeof(*threads) +
189e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				       sizeof(pid_t) * total_tasks));
190e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (nt == NULL)
191e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out_free_namelist;
192e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
193e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		threads = nt;
194e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
195e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		for (i = 0; i < items; i++) {
196e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			threads->map[j++] = atoi(namelist[i]->d_name);
197e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			free(namelist[i]);
198e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
199e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		threads->nr = total_tasks;
200e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		free(namelist);
201e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
202e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
203e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout:
204e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	strlist__delete(slist);
205e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return threads;
206e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
207e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_free_namelist:
208e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < items; i++)
209e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		free(namelist[i]);
210e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free(namelist);
211e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
212e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_free_threads:
213e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free(threads);
214e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	threads = NULL;
215e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	goto out;
216e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
217e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
218e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
219e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
220e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct thread_map *threads = NULL, *nt;
221e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int ntasks = 0;
222e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pid_t tid, prev_tid = INT_MAX;
223e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char *end_ptr;
224e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct str_node *pos;
225e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct strlist *slist;
226e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
227e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* perf-stat expects threads to be generated even if tid not given */
228e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!tid_str) {
229e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		threads = malloc(sizeof(*threads) + sizeof(pid_t));
230e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (threads != NULL) {
231e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			threads->map[0] = -1;
232e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			threads->nr	= 1;
233e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
234e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return threads;
235e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
236e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
237e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	slist = strlist__new(false, tid_str);
238e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!slist)
239e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return NULL;
240e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
241e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	strlist__for_each(pos, slist) {
242e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		tid = strtol(pos->s, &end_ptr, 10);
243e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
244e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (tid == INT_MIN || tid == INT_MAX ||
245e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		    (*end_ptr != '\0' && *end_ptr != ','))
246e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out_free_threads;
247e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
248e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (tid == prev_tid)
249e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			continue;
250e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
251e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ntasks++;
252e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		nt = realloc(threads, sizeof(*threads) + sizeof(pid_t) * ntasks);
253e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
254e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (nt == NULL)
255e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			goto out_free_threads;
256e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
257e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		threads = nt;
258e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		threads->map[ntasks - 1] = tid;
259e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		threads->nr		 = ntasks;
260e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
261e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout:
262e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return threads;
263e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
264e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_free_threads:
265e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free(threads);
266e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	threads = NULL;
267e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	goto out;
268e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
269e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
270e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct thread_map *thread_map__new_str(const char *pid, const char *tid,
271e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				       uid_t uid)
272e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
273e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (pid)
274e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return thread_map__new_by_pid_str(pid);
275e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
276e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (!tid && uid != UINT_MAX)
277e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return thread_map__new_by_uid(uid);
278e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
279e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return thread_map__new_by_tid_str(tid);
280e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
281e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
282e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid thread_map__delete(struct thread_map *threads)
283e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
284e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	free(threads);
285e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
286e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
287e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengsize_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
288e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
289e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int i;
290e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	size_t printed = fprintf(fp, "%d thread%s: ",
291e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				 threads->nr, threads->nr > 1 ? "s" : "");
292e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < threads->nr; ++i)
293e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		printed += fprintf(fp, "%s%d", i ? ", " : "", threads->map[i]);
294e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
295e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return printed + fprintf(fp, "\n");
296e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
297