1fd78260bSArnaldo Carvalho de Melo #include <dirent.h> 20d37aa34SArnaldo Carvalho de Melo #include <limits.h> 30d37aa34SArnaldo Carvalho de Melo #include <stdbool.h> 4fd78260bSArnaldo Carvalho de Melo #include <stdlib.h> 5fd78260bSArnaldo Carvalho de Melo #include <stdio.h> 60d37aa34SArnaldo Carvalho de Melo #include <sys/types.h> 70d37aa34SArnaldo Carvalho de Melo #include <sys/stat.h> 80d37aa34SArnaldo Carvalho de Melo #include <unistd.h> 9b52956c9SDavid Ahern #include "strlist.h" 10b52956c9SDavid Ahern #include <string.h> 11fd78260bSArnaldo Carvalho de Melo #include "thread_map.h" 1204662523SArnaldo Carvalho de Melo #include "util.h" 13fd78260bSArnaldo Carvalho de Melo 14fd78260bSArnaldo Carvalho de Melo /* Skip "." and ".." directories */ 15fd78260bSArnaldo Carvalho de Melo static int filter(const struct dirent *dir) 16fd78260bSArnaldo Carvalho de Melo { 17fd78260bSArnaldo Carvalho de Melo if (dir->d_name[0] == '.') 18fd78260bSArnaldo Carvalho de Melo return 0; 19fd78260bSArnaldo Carvalho de Melo else 20fd78260bSArnaldo Carvalho de Melo return 1; 21fd78260bSArnaldo Carvalho de Melo } 22fd78260bSArnaldo Carvalho de Melo 23fd78260bSArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_pid(pid_t pid) 24fd78260bSArnaldo Carvalho de Melo { 25fd78260bSArnaldo Carvalho de Melo struct thread_map *threads; 26fd78260bSArnaldo Carvalho de Melo char name[256]; 27fd78260bSArnaldo Carvalho de Melo int items; 28fd78260bSArnaldo Carvalho de Melo struct dirent **namelist = NULL; 29fd78260bSArnaldo Carvalho de Melo int i; 30fd78260bSArnaldo Carvalho de Melo 31fd78260bSArnaldo Carvalho de Melo sprintf(name, "/proc/%d/task", pid); 32fd78260bSArnaldo Carvalho de Melo items = scandir(name, &namelist, filter, NULL); 33fd78260bSArnaldo Carvalho de Melo if (items <= 0) 34fd78260bSArnaldo Carvalho de Melo return NULL; 35fd78260bSArnaldo Carvalho de Melo 36fd78260bSArnaldo Carvalho de Melo threads = malloc(sizeof(*threads) + sizeof(pid_t) * items); 37fd78260bSArnaldo Carvalho de Melo if (threads != NULL) { 38fd78260bSArnaldo Carvalho de Melo for (i = 0; i < items; i++) 39fd78260bSArnaldo Carvalho de Melo threads->map[i] = atoi(namelist[i]->d_name); 40fd78260bSArnaldo Carvalho de Melo threads->nr = items; 41fd78260bSArnaldo Carvalho de Melo } 42fd78260bSArnaldo Carvalho de Melo 43fd78260bSArnaldo Carvalho de Melo for (i=0; i<items; i++) 4474cf249dSArnaldo Carvalho de Melo zfree(&namelist[i]); 45fd78260bSArnaldo Carvalho de Melo free(namelist); 46fd78260bSArnaldo Carvalho de Melo 47fd78260bSArnaldo Carvalho de Melo return threads; 48fd78260bSArnaldo Carvalho de Melo } 49fd78260bSArnaldo Carvalho de Melo 50fd78260bSArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_tid(pid_t tid) 51fd78260bSArnaldo Carvalho de Melo { 52fd78260bSArnaldo Carvalho de Melo struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t)); 53fd78260bSArnaldo Carvalho de Melo 54fd78260bSArnaldo Carvalho de Melo if (threads != NULL) { 55fd78260bSArnaldo Carvalho de Melo threads->map[0] = tid; 56fd78260bSArnaldo Carvalho de Melo threads->nr = 1; 57fd78260bSArnaldo Carvalho de Melo } 58fd78260bSArnaldo Carvalho de Melo 59fd78260bSArnaldo Carvalho de Melo return threads; 60fd78260bSArnaldo Carvalho de Melo } 61fd78260bSArnaldo Carvalho de Melo 620d37aa34SArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_uid(uid_t uid) 630d37aa34SArnaldo Carvalho de Melo { 640d37aa34SArnaldo Carvalho de Melo DIR *proc; 650d37aa34SArnaldo Carvalho de Melo int max_threads = 32, items, i; 660d37aa34SArnaldo Carvalho de Melo char path[256]; 670d37aa34SArnaldo Carvalho de Melo struct dirent dirent, *next, **namelist = NULL; 680d37aa34SArnaldo Carvalho de Melo struct thread_map *threads = malloc(sizeof(*threads) + 690d37aa34SArnaldo Carvalho de Melo max_threads * sizeof(pid_t)); 700d37aa34SArnaldo Carvalho de Melo if (threads == NULL) 710d37aa34SArnaldo Carvalho de Melo goto out; 720d37aa34SArnaldo Carvalho de Melo 730d37aa34SArnaldo Carvalho de Melo proc = opendir("/proc"); 740d37aa34SArnaldo Carvalho de Melo if (proc == NULL) 750d37aa34SArnaldo Carvalho de Melo goto out_free_threads; 760d37aa34SArnaldo Carvalho de Melo 770d37aa34SArnaldo Carvalho de Melo threads->nr = 0; 780d37aa34SArnaldo Carvalho de Melo 790d37aa34SArnaldo Carvalho de Melo while (!readdir_r(proc, &dirent, &next) && next) { 800d37aa34SArnaldo Carvalho de Melo char *end; 810d37aa34SArnaldo Carvalho de Melo bool grow = false; 820d37aa34SArnaldo Carvalho de Melo struct stat st; 830d37aa34SArnaldo Carvalho de Melo pid_t pid = strtol(dirent.d_name, &end, 10); 840d37aa34SArnaldo Carvalho de Melo 850d37aa34SArnaldo Carvalho de Melo if (*end) /* only interested in proper numerical dirents */ 860d37aa34SArnaldo Carvalho de Melo continue; 870d37aa34SArnaldo Carvalho de Melo 880d37aa34SArnaldo Carvalho de Melo snprintf(path, sizeof(path), "/proc/%s", dirent.d_name); 890d37aa34SArnaldo Carvalho de Melo 900d37aa34SArnaldo Carvalho de Melo if (stat(path, &st) != 0) 910d37aa34SArnaldo Carvalho de Melo continue; 920d37aa34SArnaldo Carvalho de Melo 930d37aa34SArnaldo Carvalho de Melo if (st.st_uid != uid) 940d37aa34SArnaldo Carvalho de Melo continue; 950d37aa34SArnaldo Carvalho de Melo 960d37aa34SArnaldo Carvalho de Melo snprintf(path, sizeof(path), "/proc/%d/task", pid); 970d37aa34SArnaldo Carvalho de Melo items = scandir(path, &namelist, filter, NULL); 980d37aa34SArnaldo Carvalho de Melo if (items <= 0) 990d37aa34SArnaldo Carvalho de Melo goto out_free_closedir; 1000d37aa34SArnaldo Carvalho de Melo 1010d37aa34SArnaldo Carvalho de Melo while (threads->nr + items >= max_threads) { 1020d37aa34SArnaldo Carvalho de Melo max_threads *= 2; 1030d37aa34SArnaldo Carvalho de Melo grow = true; 1040d37aa34SArnaldo Carvalho de Melo } 1050d37aa34SArnaldo Carvalho de Melo 1060d37aa34SArnaldo Carvalho de Melo if (grow) { 1070d37aa34SArnaldo Carvalho de Melo struct thread_map *tmp; 1080d37aa34SArnaldo Carvalho de Melo 1090d37aa34SArnaldo Carvalho de Melo tmp = realloc(threads, (sizeof(*threads) + 1100d37aa34SArnaldo Carvalho de Melo max_threads * sizeof(pid_t))); 1110d37aa34SArnaldo Carvalho de Melo if (tmp == NULL) 1120d37aa34SArnaldo Carvalho de Melo goto out_free_namelist; 1130d37aa34SArnaldo Carvalho de Melo 1140d37aa34SArnaldo Carvalho de Melo threads = tmp; 1150d37aa34SArnaldo Carvalho de Melo } 1160d37aa34SArnaldo Carvalho de Melo 1170d37aa34SArnaldo Carvalho de Melo for (i = 0; i < items; i++) 1180d37aa34SArnaldo Carvalho de Melo threads->map[threads->nr + i] = atoi(namelist[i]->d_name); 1190d37aa34SArnaldo Carvalho de Melo 1200d37aa34SArnaldo Carvalho de Melo for (i = 0; i < items; i++) 12174cf249dSArnaldo Carvalho de Melo zfree(&namelist[i]); 1220d37aa34SArnaldo Carvalho de Melo free(namelist); 1230d37aa34SArnaldo Carvalho de Melo 1240d37aa34SArnaldo Carvalho de Melo threads->nr += items; 1250d37aa34SArnaldo Carvalho de Melo } 1260d37aa34SArnaldo Carvalho de Melo 1270d37aa34SArnaldo Carvalho de Melo out_closedir: 1280d37aa34SArnaldo Carvalho de Melo closedir(proc); 1290d37aa34SArnaldo Carvalho de Melo out: 1300d37aa34SArnaldo Carvalho de Melo return threads; 1310d37aa34SArnaldo Carvalho de Melo 1320d37aa34SArnaldo Carvalho de Melo out_free_threads: 1330d37aa34SArnaldo Carvalho de Melo free(threads); 1340d37aa34SArnaldo Carvalho de Melo return NULL; 1350d37aa34SArnaldo Carvalho de Melo 1360d37aa34SArnaldo Carvalho de Melo out_free_namelist: 1370d37aa34SArnaldo Carvalho de Melo for (i = 0; i < items; i++) 13874cf249dSArnaldo Carvalho de Melo zfree(&namelist[i]); 1390d37aa34SArnaldo Carvalho de Melo free(namelist); 1400d37aa34SArnaldo Carvalho de Melo 1410d37aa34SArnaldo Carvalho de Melo out_free_closedir: 14204662523SArnaldo Carvalho de Melo zfree(&threads); 1430d37aa34SArnaldo Carvalho de Melo goto out_closedir; 1440d37aa34SArnaldo Carvalho de Melo } 1450d37aa34SArnaldo Carvalho de Melo 1460d37aa34SArnaldo Carvalho de Melo struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid) 147fd78260bSArnaldo Carvalho de Melo { 148fd78260bSArnaldo Carvalho de Melo if (pid != -1) 149fd78260bSArnaldo Carvalho de Melo return thread_map__new_by_pid(pid); 1500d37aa34SArnaldo Carvalho de Melo 1510d37aa34SArnaldo Carvalho de Melo if (tid == -1 && uid != UINT_MAX) 1520d37aa34SArnaldo Carvalho de Melo return thread_map__new_by_uid(uid); 1530d37aa34SArnaldo Carvalho de Melo 154fd78260bSArnaldo Carvalho de Melo return thread_map__new_by_tid(tid); 155fd78260bSArnaldo Carvalho de Melo } 156fd78260bSArnaldo Carvalho de Melo 157b52956c9SDavid Ahern static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) 158b52956c9SDavid Ahern { 159b52956c9SDavid Ahern struct thread_map *threads = NULL, *nt; 160b52956c9SDavid Ahern char name[256]; 161b52956c9SDavid Ahern int items, total_tasks = 0; 162b52956c9SDavid Ahern struct dirent **namelist = NULL; 163b52956c9SDavid Ahern int i, j = 0; 164b52956c9SDavid Ahern pid_t pid, prev_pid = INT_MAX; 165b52956c9SDavid Ahern char *end_ptr; 166b52956c9SDavid Ahern struct str_node *pos; 167b52956c9SDavid Ahern struct strlist *slist = strlist__new(false, pid_str); 168b52956c9SDavid Ahern 169b52956c9SDavid Ahern if (!slist) 170b52956c9SDavid Ahern return NULL; 171b52956c9SDavid Ahern 172b52956c9SDavid Ahern strlist__for_each(pos, slist) { 173b52956c9SDavid Ahern pid = strtol(pos->s, &end_ptr, 10); 174b52956c9SDavid Ahern 175b52956c9SDavid Ahern if (pid == INT_MIN || pid == INT_MAX || 176b52956c9SDavid Ahern (*end_ptr != '\0' && *end_ptr != ',')) 177b52956c9SDavid Ahern goto out_free_threads; 178b52956c9SDavid Ahern 179b52956c9SDavid Ahern if (pid == prev_pid) 180b52956c9SDavid Ahern continue; 181b52956c9SDavid Ahern 182b52956c9SDavid Ahern sprintf(name, "/proc/%d/task", pid); 183b52956c9SDavid Ahern items = scandir(name, &namelist, filter, NULL); 184b52956c9SDavid Ahern if (items <= 0) 185b52956c9SDavid Ahern goto out_free_threads; 186b52956c9SDavid Ahern 187b52956c9SDavid Ahern total_tasks += items; 188b52956c9SDavid Ahern nt = realloc(threads, (sizeof(*threads) + 189b52956c9SDavid Ahern sizeof(pid_t) * total_tasks)); 190b52956c9SDavid Ahern if (nt == NULL) 191e8cdd947SFranck Bui-Huu goto out_free_namelist; 192b52956c9SDavid Ahern 193b52956c9SDavid Ahern threads = nt; 194b52956c9SDavid Ahern 195e8cdd947SFranck Bui-Huu for (i = 0; i < items; i++) { 196b52956c9SDavid Ahern threads->map[j++] = atoi(namelist[i]->d_name); 19774cf249dSArnaldo Carvalho de Melo zfree(&namelist[i]); 198e8cdd947SFranck Bui-Huu } 199e8cdd947SFranck Bui-Huu threads->nr = total_tasks; 200b52956c9SDavid Ahern free(namelist); 201b52956c9SDavid Ahern } 202b52956c9SDavid Ahern 203b52956c9SDavid Ahern out: 204b52956c9SDavid Ahern strlist__delete(slist); 205b52956c9SDavid Ahern return threads; 206b52956c9SDavid Ahern 207e8cdd947SFranck Bui-Huu out_free_namelist: 208e8cdd947SFranck Bui-Huu for (i = 0; i < items; i++) 20974cf249dSArnaldo Carvalho de Melo zfree(&namelist[i]); 210e8cdd947SFranck Bui-Huu free(namelist); 211e8cdd947SFranck Bui-Huu 212b52956c9SDavid Ahern out_free_threads: 21304662523SArnaldo Carvalho de Melo zfree(&threads); 214b52956c9SDavid Ahern goto out; 215b52956c9SDavid Ahern } 216b52956c9SDavid Ahern 217*641556c9SArnaldo Carvalho de Melo struct thread_map *thread_map__new_dummy(void) 218*641556c9SArnaldo Carvalho de Melo { 219*641556c9SArnaldo Carvalho de Melo struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t)); 220*641556c9SArnaldo Carvalho de Melo 221*641556c9SArnaldo Carvalho de Melo if (threads != NULL) { 222*641556c9SArnaldo Carvalho de Melo threads->map[0] = -1; 223*641556c9SArnaldo Carvalho de Melo threads->nr = 1; 224*641556c9SArnaldo Carvalho de Melo } 225*641556c9SArnaldo Carvalho de Melo return threads; 226*641556c9SArnaldo Carvalho de Melo } 227*641556c9SArnaldo Carvalho de Melo 228b52956c9SDavid Ahern static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) 229b52956c9SDavid Ahern { 230b52956c9SDavid Ahern struct thread_map *threads = NULL, *nt; 231b52956c9SDavid Ahern int ntasks = 0; 232b52956c9SDavid Ahern pid_t tid, prev_tid = INT_MAX; 233b52956c9SDavid Ahern char *end_ptr; 234b52956c9SDavid Ahern struct str_node *pos; 235b52956c9SDavid Ahern struct strlist *slist; 236b52956c9SDavid Ahern 237b52956c9SDavid Ahern /* perf-stat expects threads to be generated even if tid not given */ 238*641556c9SArnaldo Carvalho de Melo if (!tid_str) 239*641556c9SArnaldo Carvalho de Melo return thread_map__new_dummy(); 240b52956c9SDavid Ahern 241b52956c9SDavid Ahern slist = strlist__new(false, tid_str); 242b52956c9SDavid Ahern if (!slist) 243b52956c9SDavid Ahern return NULL; 244b52956c9SDavid Ahern 245b52956c9SDavid Ahern strlist__for_each(pos, slist) { 246b52956c9SDavid Ahern tid = strtol(pos->s, &end_ptr, 10); 247b52956c9SDavid Ahern 248b52956c9SDavid Ahern if (tid == INT_MIN || tid == INT_MAX || 249b52956c9SDavid Ahern (*end_ptr != '\0' && *end_ptr != ',')) 250b52956c9SDavid Ahern goto out_free_threads; 251b52956c9SDavid Ahern 252b52956c9SDavid Ahern if (tid == prev_tid) 253b52956c9SDavid Ahern continue; 254b52956c9SDavid Ahern 255b52956c9SDavid Ahern ntasks++; 256b52956c9SDavid Ahern nt = realloc(threads, sizeof(*threads) + sizeof(pid_t) * ntasks); 257b52956c9SDavid Ahern 258b52956c9SDavid Ahern if (nt == NULL) 259b52956c9SDavid Ahern goto out_free_threads; 260b52956c9SDavid Ahern 261b52956c9SDavid Ahern threads = nt; 262b52956c9SDavid Ahern threads->map[ntasks - 1] = tid; 263b52956c9SDavid Ahern threads->nr = ntasks; 264b52956c9SDavid Ahern } 265b52956c9SDavid Ahern out: 266b52956c9SDavid Ahern return threads; 267b52956c9SDavid Ahern 268b52956c9SDavid Ahern out_free_threads: 26904662523SArnaldo Carvalho de Melo zfree(&threads); 270b52956c9SDavid Ahern goto out; 271b52956c9SDavid Ahern } 272b52956c9SDavid Ahern 273b52956c9SDavid Ahern struct thread_map *thread_map__new_str(const char *pid, const char *tid, 274b52956c9SDavid Ahern uid_t uid) 275b52956c9SDavid Ahern { 276b52956c9SDavid Ahern if (pid) 277b52956c9SDavid Ahern return thread_map__new_by_pid_str(pid); 278b52956c9SDavid Ahern 279b52956c9SDavid Ahern if (!tid && uid != UINT_MAX) 280b52956c9SDavid Ahern return thread_map__new_by_uid(uid); 281b52956c9SDavid Ahern 282b52956c9SDavid Ahern return thread_map__new_by_tid_str(tid); 283b52956c9SDavid Ahern } 284b52956c9SDavid Ahern 285fd78260bSArnaldo Carvalho de Melo void thread_map__delete(struct thread_map *threads) 286fd78260bSArnaldo Carvalho de Melo { 287fd78260bSArnaldo Carvalho de Melo free(threads); 288fd78260bSArnaldo Carvalho de Melo } 2899ae7d335SArnaldo Carvalho de Melo 2909ae7d335SArnaldo Carvalho de Melo size_t thread_map__fprintf(struct thread_map *threads, FILE *fp) 2919ae7d335SArnaldo Carvalho de Melo { 2929ae7d335SArnaldo Carvalho de Melo int i; 2939ae7d335SArnaldo Carvalho de Melo size_t printed = fprintf(fp, "%d thread%s: ", 2949ae7d335SArnaldo Carvalho de Melo threads->nr, threads->nr > 1 ? "s" : ""); 2959ae7d335SArnaldo Carvalho de Melo for (i = 0; i < threads->nr; ++i) 2969ae7d335SArnaldo Carvalho de Melo printed += fprintf(fp, "%s%d", i ? ", " : "", threads->map[i]); 2979ae7d335SArnaldo Carvalho de Melo 2989ae7d335SArnaldo Carvalho de Melo return printed + fprintf(fp, "\n"); 2999ae7d335SArnaldo Carvalho de Melo } 300