11 #include "thread_map.h"
14 /* Skip "." and ".." directories */
15 static int filter(const struct dirent *dir)
17 if (dir->d_name[0] == '.')
23 static struct thread_map *thread_map__realloc(struct thread_map *map, int nr)
25 size_t size = sizeof(*map) + sizeof(pid_t) * nr;
27 return realloc(map, size);
30 #define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr)
32 struct thread_map *thread_map__new_by_pid(pid_t pid)
34 struct thread_map *threads;
37 struct dirent **namelist = NULL;
40 sprintf(name, "/proc/%d/task", pid);
41 items = scandir(name, &namelist, filter, NULL);
45 threads = thread_map__alloc(items);
46 if (threads != NULL) {
47 for (i = 0; i < items; i++)
48 threads->map[i] = atoi(namelist[i]->d_name);
52 for (i=0; i<items; i++)
59 struct thread_map *thread_map__new_by_tid(pid_t tid)
61 struct thread_map *threads = thread_map__alloc(1);
63 if (threads != NULL) {
64 threads->map[0] = tid;
71 struct thread_map *thread_map__new_by_uid(uid_t uid)
74 int max_threads = 32, items, i;
76 struct dirent dirent, *next, **namelist = NULL;
77 struct thread_map *threads = thread_map__alloc(max_threads);
82 proc = opendir("/proc");
84 goto out_free_threads;
88 while (!readdir_r(proc, &dirent, &next) && next) {
92 pid_t pid = strtol(dirent.d_name, &end, 10);
94 if (*end) /* only interested in proper numerical dirents */
97 snprintf(path, sizeof(path), "/proc/%s", dirent.d_name);
99 if (stat(path, &st) != 0)
102 if (st.st_uid != uid)
105 snprintf(path, sizeof(path), "/proc/%d/task", pid);
106 items = scandir(path, &namelist, filter, NULL);
108 goto out_free_closedir;
110 while (threads->nr + items >= max_threads) {
116 struct thread_map *tmp;
118 tmp = realloc(threads, (sizeof(*threads) +
119 max_threads * sizeof(pid_t)));
121 goto out_free_namelist;
126 for (i = 0; i < items; i++)
127 threads->map[threads->nr + i] = atoi(namelist[i]->d_name);
129 for (i = 0; i < items; i++)
133 threads->nr += items;
146 for (i = 0; i < items; i++)
155 struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
158 return thread_map__new_by_pid(pid);
160 if (tid == -1 && uid != UINT_MAX)
161 return thread_map__new_by_uid(uid);
163 return thread_map__new_by_tid(tid);
166 static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
168 struct thread_map *threads = NULL, *nt;
170 int items, total_tasks = 0;
171 struct dirent **namelist = NULL;
173 pid_t pid, prev_pid = INT_MAX;
175 struct str_node *pos;
176 struct strlist *slist = strlist__new(false, pid_str);
181 strlist__for_each(pos, slist) {
182 pid = strtol(pos->s, &end_ptr, 10);
184 if (pid == INT_MIN || pid == INT_MAX ||
185 (*end_ptr != '\0' && *end_ptr != ','))
186 goto out_free_threads;
191 sprintf(name, "/proc/%d/task", pid);
192 items = scandir(name, &namelist, filter, NULL);
194 goto out_free_threads;
196 total_tasks += items;
197 nt = thread_map__realloc(threads, total_tasks);
199 goto out_free_namelist;
203 for (i = 0; i < items; i++) {
204 threads->map[j++] = atoi(namelist[i]->d_name);
207 threads->nr = total_tasks;
212 strlist__delete(slist);
216 for (i = 0; i < items; i++)
225 struct thread_map *thread_map__new_dummy(void)
227 struct thread_map *threads = thread_map__alloc(1);
229 if (threads != NULL) {
230 threads->map[0] = -1;
236 static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
238 struct thread_map *threads = NULL, *nt;
240 pid_t tid, prev_tid = INT_MAX;
242 struct str_node *pos;
243 struct strlist *slist;
245 /* perf-stat expects threads to be generated even if tid not given */
247 return thread_map__new_dummy();
249 slist = strlist__new(false, tid_str);
253 strlist__for_each(pos, slist) {
254 tid = strtol(pos->s, &end_ptr, 10);
256 if (tid == INT_MIN || tid == INT_MAX ||
257 (*end_ptr != '\0' && *end_ptr != ','))
258 goto out_free_threads;
264 nt = thread_map__realloc(threads, ntasks);
267 goto out_free_threads;
270 threads->map[ntasks - 1] = tid;
271 threads->nr = ntasks;
281 struct thread_map *thread_map__new_str(const char *pid, const char *tid,
285 return thread_map__new_by_pid_str(pid);
287 if (!tid && uid != UINT_MAX)
288 return thread_map__new_by_uid(uid);
290 return thread_map__new_by_tid_str(tid);
293 void thread_map__delete(struct thread_map *threads)
298 size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
301 size_t printed = fprintf(fp, "%d thread%s: ",
302 threads->nr, threads->nr > 1 ? "s" : "");
303 for (i = 0; i < threads->nr; ++i)
304 printed += fprintf(fp, "%s%d", i ? ", " : "", threads->map[i]);
306 return printed + fprintf(fp, "\n");