blob: 3d4b6c5931b924bace8f8dc03700292bbf22b0bf [file] [log] [blame]
Arnaldo Carvalho de Melofd782602011-01-18 15:15:24 -02001#include <dirent.h>
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02002#include <limits.h>
3#include <stdbool.h>
Arnaldo Carvalho de Melofd782602011-01-18 15:15:24 -02004#include <stdlib.h>
5#include <stdio.h>
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -02006#include <sys/types.h>
7#include <sys/stat.h>
8#include <unistd.h>
Arnaldo Carvalho de Melofd782602011-01-18 15:15:24 -02009#include "thread_map.h"
10
11/* Skip "." and ".." directories */
12static int filter(const struct dirent *dir)
13{
14 if (dir->d_name[0] == '.')
15 return 0;
16 else
17 return 1;
18}
19
20struct thread_map *thread_map__new_by_pid(pid_t pid)
21{
22 struct thread_map *threads;
23 char name[256];
24 int items;
25 struct dirent **namelist = NULL;
26 int i;
27
28 sprintf(name, "/proc/%d/task", pid);
29 items = scandir(name, &namelist, filter, NULL);
30 if (items <= 0)
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -020031 return NULL;
Arnaldo Carvalho de Melofd782602011-01-18 15:15:24 -020032
33 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
34 if (threads != NULL) {
35 for (i = 0; i < items; i++)
36 threads->map[i] = atoi(namelist[i]->d_name);
37 threads->nr = items;
38 }
39
40 for (i=0; i<items; i++)
41 free(namelist[i]);
42 free(namelist);
43
44 return threads;
45}
46
47struct thread_map *thread_map__new_by_tid(pid_t tid)
48{
49 struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t));
50
51 if (threads != NULL) {
52 threads->map[0] = tid;
53 threads->nr = 1;
54 }
55
56 return threads;
57}
58
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -020059struct thread_map *thread_map__new_by_uid(uid_t uid)
60{
61 DIR *proc;
62 int max_threads = 32, items, i;
63 char path[256];
64 struct dirent dirent, *next, **namelist = NULL;
65 struct thread_map *threads = malloc(sizeof(*threads) +
66 max_threads * sizeof(pid_t));
67 if (threads == NULL)
68 goto out;
69
70 proc = opendir("/proc");
71 if (proc == NULL)
72 goto out_free_threads;
73
74 threads->nr = 0;
75
76 while (!readdir_r(proc, &dirent, &next) && next) {
77 char *end;
78 bool grow = false;
79 struct stat st;
80 pid_t pid = strtol(dirent.d_name, &end, 10);
81
82 if (*end) /* only interested in proper numerical dirents */
83 continue;
84
85 snprintf(path, sizeof(path), "/proc/%s", dirent.d_name);
86
87 if (stat(path, &st) != 0)
88 continue;
89
90 if (st.st_uid != uid)
91 continue;
92
93 snprintf(path, sizeof(path), "/proc/%d/task", pid);
94 items = scandir(path, &namelist, filter, NULL);
95 if (items <= 0)
96 goto out_free_closedir;
97
98 while (threads->nr + items >= max_threads) {
99 max_threads *= 2;
100 grow = true;
101 }
102
103 if (grow) {
104 struct thread_map *tmp;
105
106 tmp = realloc(threads, (sizeof(*threads) +
107 max_threads * sizeof(pid_t)));
108 if (tmp == NULL)
109 goto out_free_namelist;
110
111 threads = tmp;
112 }
113
114 for (i = 0; i < items; i++)
115 threads->map[threads->nr + i] = atoi(namelist[i]->d_name);
116
117 for (i = 0; i < items; i++)
118 free(namelist[i]);
119 free(namelist);
120
121 threads->nr += items;
122 }
123
124out_closedir:
125 closedir(proc);
126out:
127 return threads;
128
129out_free_threads:
130 free(threads);
131 return NULL;
132
133out_free_namelist:
134 for (i = 0; i < items; i++)
135 free(namelist[i]);
136 free(namelist);
137
138out_free_closedir:
139 free(threads);
140 threads = NULL;
141 goto out_closedir;
142}
143
144struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
Arnaldo Carvalho de Melofd782602011-01-18 15:15:24 -0200145{
146 if (pid != -1)
147 return thread_map__new_by_pid(pid);
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -0200148
149 if (tid == -1 && uid != UINT_MAX)
150 return thread_map__new_by_uid(uid);
151
Arnaldo Carvalho de Melofd782602011-01-18 15:15:24 -0200152 return thread_map__new_by_tid(tid);
153}
154
155void thread_map__delete(struct thread_map *threads)
156{
157 free(threads);
158}
Arnaldo Carvalho de Melo9ae7d332012-01-19 14:07:23 -0200159
160size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
161{
162 int i;
163 size_t printed = fprintf(fp, "%d thread%s: ",
164 threads->nr, threads->nr > 1 ? "s" : "");
165 for (i = 0; i < threads->nr; ++i)
166 printed += fprintf(fp, "%s%d", i ? ", " : "", threads->map[i]);
167
168 return printed + fprintf(fp, "\n");
169}