11 #include "thread_map.h"
14 /* Skip "." and ".." directories */
15 static int filter(const struct dirent
*dir
)
17 if (dir
->d_name
[0] == '.')
23 struct thread_map
*thread_map__new_by_pid(pid_t pid
)
25 struct thread_map
*threads
;
28 struct dirent
**namelist
= NULL
;
31 sprintf(name
, "/proc/%d/task", pid
);
32 items
= scandir(name
, &namelist
, filter
, NULL
);
36 threads
= malloc(sizeof(*threads
) + sizeof(pid_t
) * items
);
37 if (threads
!= NULL
) {
38 for (i
= 0; i
< items
; i
++)
39 threads
->map
[i
] = atoi(namelist
[i
]->d_name
);
43 for (i
=0; i
<items
; i
++)
50 struct thread_map
*thread_map__new_by_tid(pid_t tid
)
52 struct thread_map
*threads
= malloc(sizeof(*threads
) + sizeof(pid_t
));
54 if (threads
!= NULL
) {
55 threads
->map
[0] = tid
;
62 struct thread_map
*thread_map__new_by_uid(uid_t uid
)
65 int max_threads
= 32, items
, i
;
67 struct dirent dirent
, *next
, **namelist
= NULL
;
68 struct thread_map
*threads
= malloc(sizeof(*threads
) +
69 max_threads
* sizeof(pid_t
));
73 proc
= opendir("/proc");
75 goto out_free_threads
;
79 while (!readdir_r(proc
, &dirent
, &next
) && next
) {
83 pid_t pid
= strtol(dirent
.d_name
, &end
, 10);
85 if (*end
) /* only interested in proper numerical dirents */
88 snprintf(path
, sizeof(path
), "/proc/%s", dirent
.d_name
);
90 if (stat(path
, &st
) != 0)
96 snprintf(path
, sizeof(path
), "/proc/%d/task", pid
);
97 items
= scandir(path
, &namelist
, filter
, NULL
);
99 goto out_free_closedir
;
101 while (threads
->nr
+ items
>= max_threads
) {
107 struct thread_map
*tmp
;
109 tmp
= realloc(threads
, (sizeof(*threads
) +
110 max_threads
* sizeof(pid_t
)));
112 goto out_free_namelist
;
117 for (i
= 0; i
< items
; i
++)
118 threads
->map
[threads
->nr
+ i
] = atoi(namelist
[i
]->d_name
);
120 for (i
= 0; i
< items
; i
++)
124 threads
->nr
+= items
;
137 for (i
= 0; i
< items
; i
++)
146 struct thread_map
*thread_map__new(pid_t pid
, pid_t tid
, uid_t uid
)
149 return thread_map__new_by_pid(pid
);
151 if (tid
== -1 && uid
!= UINT_MAX
)
152 return thread_map__new_by_uid(uid
);
154 return thread_map__new_by_tid(tid
);
157 static struct thread_map
*thread_map__new_by_pid_str(const char *pid_str
)
159 struct thread_map
*threads
= NULL
, *nt
;
161 int items
, total_tasks
= 0;
162 struct dirent
**namelist
= NULL
;
164 pid_t pid
, prev_pid
= INT_MAX
;
166 struct str_node
*pos
;
167 struct strlist
*slist
= strlist__new(false, pid_str
);
172 strlist__for_each(pos
, slist
) {
173 pid
= strtol(pos
->s
, &end_ptr
, 10);
175 if (pid
== INT_MIN
|| pid
== INT_MAX
||
176 (*end_ptr
!= '\0' && *end_ptr
!= ','))
177 goto out_free_threads
;
182 sprintf(name
, "/proc/%d/task", pid
);
183 items
= scandir(name
, &namelist
, filter
, NULL
);
185 goto out_free_threads
;
187 total_tasks
+= items
;
188 nt
= realloc(threads
, (sizeof(*threads
) +
189 sizeof(pid_t
) * total_tasks
));
191 goto out_free_namelist
;
195 for (i
= 0; i
< items
; i
++) {
196 threads
->map
[j
++] = atoi(namelist
[i
]->d_name
);
199 threads
->nr
= total_tasks
;
204 strlist__delete(slist
);
208 for (i
= 0; i
< items
; i
++)
217 static struct thread_map
*thread_map__new_by_tid_str(const char *tid_str
)
219 struct thread_map
*threads
= NULL
, *nt
;
221 pid_t tid
, prev_tid
= INT_MAX
;
223 struct str_node
*pos
;
224 struct strlist
*slist
;
226 /* perf-stat expects threads to be generated even if tid not given */
228 threads
= malloc(sizeof(*threads
) + sizeof(pid_t
));
229 if (threads
!= NULL
) {
230 threads
->map
[0] = -1;
236 slist
= strlist__new(false, tid_str
);
240 strlist__for_each(pos
, slist
) {
241 tid
= strtol(pos
->s
, &end_ptr
, 10);
243 if (tid
== INT_MIN
|| tid
== INT_MAX
||
244 (*end_ptr
!= '\0' && *end_ptr
!= ','))
245 goto out_free_threads
;
251 nt
= realloc(threads
, sizeof(*threads
) + sizeof(pid_t
) * ntasks
);
254 goto out_free_threads
;
257 threads
->map
[ntasks
- 1] = tid
;
258 threads
->nr
= ntasks
;
268 struct thread_map
*thread_map__new_str(const char *pid
, const char *tid
,
272 return thread_map__new_by_pid_str(pid
);
274 if (!tid
&& uid
!= UINT_MAX
)
275 return thread_map__new_by_uid(uid
);
277 return thread_map__new_by_tid_str(tid
);
280 void thread_map__delete(struct thread_map
*threads
)
285 size_t thread_map__fprintf(struct thread_map
*threads
, FILE *fp
)
288 size_t printed
= fprintf(fp
, "%d thread%s: ",
289 threads
->nr
, threads
->nr
> 1 ? "s" : "");
290 for (i
= 0; i
< threads
->nr
; ++i
)
291 printed
+= fprintf(fp
, "%s%d", i
? ", " : "", threads
->map
[i
]);
293 return printed
+ fprintf(fp
, "\n");