11 #include "thread_map.h"
13 /* Skip "." and ".." directories */
14 static int filter(const struct dirent
*dir
)
16 if (dir
->d_name
[0] == '.')
22 struct thread_map
*thread_map__new_by_pid(pid_t pid
)
24 struct thread_map
*threads
;
27 struct dirent
**namelist
= NULL
;
30 sprintf(name
, "/proc/%d/task", pid
);
31 items
= scandir(name
, &namelist
, filter
, NULL
);
35 threads
= malloc(sizeof(*threads
) + sizeof(pid_t
) * items
);
36 if (threads
!= NULL
) {
37 for (i
= 0; i
< items
; i
++)
38 threads
->map
[i
] = atoi(namelist
[i
]->d_name
);
42 for (i
=0; i
<items
; i
++)
49 struct thread_map
*thread_map__new_by_tid(pid_t tid
)
51 struct thread_map
*threads
= malloc(sizeof(*threads
) + sizeof(pid_t
));
53 if (threads
!= NULL
) {
54 threads
->map
[0] = tid
;
61 struct thread_map
*thread_map__new_by_uid(uid_t uid
)
64 int max_threads
= 32, items
, i
;
66 struct dirent dirent
, *next
, **namelist
= NULL
;
67 struct thread_map
*threads
= malloc(sizeof(*threads
) +
68 max_threads
* sizeof(pid_t
));
72 proc
= opendir("/proc");
74 goto out_free_threads
;
78 while (!readdir_r(proc
, &dirent
, &next
) && next
) {
82 pid_t pid
= strtol(dirent
.d_name
, &end
, 10);
84 if (*end
) /* only interested in proper numerical dirents */
87 snprintf(path
, sizeof(path
), "/proc/%s", dirent
.d_name
);
89 if (stat(path
, &st
) != 0)
95 snprintf(path
, sizeof(path
), "/proc/%d/task", pid
);
96 items
= scandir(path
, &namelist
, filter
, NULL
);
98 goto out_free_closedir
;
100 while (threads
->nr
+ items
>= max_threads
) {
106 struct thread_map
*tmp
;
108 tmp
= realloc(threads
, (sizeof(*threads
) +
109 max_threads
* sizeof(pid_t
)));
111 goto out_free_namelist
;
116 for (i
= 0; i
< items
; i
++)
117 threads
->map
[threads
->nr
+ i
] = atoi(namelist
[i
]->d_name
);
119 for (i
= 0; i
< items
; i
++)
123 threads
->nr
+= items
;
136 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
++)
218 static struct thread_map
*thread_map__new_by_tid_str(const char *tid_str
)
220 struct thread_map
*threads
= NULL
, *nt
;
222 pid_t tid
, prev_tid
= INT_MAX
;
224 struct str_node
*pos
;
225 struct strlist
*slist
;
227 /* perf-stat expects threads to be generated even if tid not given */
229 threads
= malloc(sizeof(*threads
) + sizeof(pid_t
));
230 if (threads
!= NULL
) {
231 threads
->map
[0] = -1;
237 slist
= strlist__new(false, tid_str
);
241 strlist__for_each(pos
, slist
) {
242 tid
= strtol(pos
->s
, &end_ptr
, 10);
244 if (tid
== INT_MIN
|| tid
== INT_MAX
||
245 (*end_ptr
!= '\0' && *end_ptr
!= ','))
246 goto out_free_threads
;
252 nt
= realloc(threads
, sizeof(*threads
) + sizeof(pid_t
) * ntasks
);
255 goto out_free_threads
;
258 threads
->map
[ntasks
- 1] = tid
;
259 threads
->nr
= ntasks
;
270 struct thread_map
*thread_map__new_str(const char *pid
, const char *tid
,
274 return thread_map__new_by_pid_str(pid
);
276 if (!tid
&& uid
!= UINT_MAX
)
277 return thread_map__new_by_uid(uid
);
279 return thread_map__new_by_tid_str(tid
);
282 void thread_map__delete(struct thread_map
*threads
)
287 size_t thread_map__fprintf(struct thread_map
*threads
, FILE *fp
)
290 size_t printed
= fprintf(fp
, "%d thread%s: ",
291 threads
->nr
, threads
->nr
> 1 ? "s" : "");
292 for (i
= 0; i
< threads
->nr
; ++i
)
293 printed
+= fprintf(fp
, "%s%d", i
? ", " : "", threads
->map
[i
]);
295 return printed
+ fprintf(fp
, "\n");