1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2fd78260bSArnaldo Carvalho de Melo #include <dirent.h> 3a43783aeSArnaldo Carvalho de Melo #include <errno.h> 40d37aa34SArnaldo Carvalho de Melo #include <limits.h> 50d37aa34SArnaldo Carvalho de Melo #include <stdbool.h> 6fd78260bSArnaldo Carvalho de Melo #include <stdlib.h> 7fd78260bSArnaldo Carvalho de Melo #include <stdio.h> 80d37aa34SArnaldo Carvalho de Melo #include <sys/types.h> 90d37aa34SArnaldo Carvalho de Melo #include <sys/stat.h> 100d37aa34SArnaldo Carvalho de Melo #include <unistd.h> 11a067558eSArnaldo Carvalho de Melo #include "string2.h" 12b52956c9SDavid Ahern #include "strlist.h" 13b52956c9SDavid Ahern #include <string.h> 14792402fdSJiri Olsa #include <api/fs/fs.h> 15*13c230abSArnaldo Carvalho de Melo #include <linux/string.h> 16186fbb74SJiri Olsa #include "asm/bug.h" 17fd78260bSArnaldo Carvalho de Melo #include "thread_map.h" 1804662523SArnaldo Carvalho de Melo #include "util.h" 19792402fdSJiri Olsa #include "debug.h" 2059660942SJiri Olsa #include "event.h" 21fd78260bSArnaldo Carvalho de Melo 22fd78260bSArnaldo Carvalho de Melo /* Skip "." and ".." directories */ 23fd78260bSArnaldo Carvalho de Melo static int filter(const struct dirent *dir) 24fd78260bSArnaldo Carvalho de Melo { 25fd78260bSArnaldo Carvalho de Melo if (dir->d_name[0] == '.') 26fd78260bSArnaldo Carvalho de Melo return 0; 27fd78260bSArnaldo Carvalho de Melo else 28fd78260bSArnaldo Carvalho de Melo return 1; 29fd78260bSArnaldo Carvalho de Melo } 30fd78260bSArnaldo Carvalho de Melo 3162eea464SJiri Olsa static void thread_map__reset(struct thread_map *map, int start, int nr) 3262eea464SJiri Olsa { 3362eea464SJiri Olsa size_t size = (nr - start) * sizeof(map->map[0]); 3462eea464SJiri Olsa 3562eea464SJiri Olsa memset(&map->map[start], 0, size); 36ab6c79b8SJin Yao map->err_thread = -1; 3762eea464SJiri Olsa } 3862eea464SJiri Olsa 399d7e8c3aSJiri Olsa static struct thread_map *thread_map__realloc(struct thread_map *map, int nr) 409d7e8c3aSJiri Olsa { 41060664f3SArnaldo Carvalho de Melo size_t size = sizeof(*map) + sizeof(map->map[0]) * nr; 4262eea464SJiri Olsa int start = map ? map->nr : 0; 439d7e8c3aSJiri Olsa 4462eea464SJiri Olsa map = realloc(map, size); 4562eea464SJiri Olsa /* 4662eea464SJiri Olsa * We only realloc to add more items, let's reset new items. 4762eea464SJiri Olsa */ 4862eea464SJiri Olsa if (map) 4962eea464SJiri Olsa thread_map__reset(map, start, nr); 5062eea464SJiri Olsa 5162eea464SJiri Olsa return map; 529d7e8c3aSJiri Olsa } 539d7e8c3aSJiri Olsa 549d7e8c3aSJiri Olsa #define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr) 559d7e8c3aSJiri Olsa 56fd78260bSArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_pid(pid_t pid) 57fd78260bSArnaldo Carvalho de Melo { 58fd78260bSArnaldo Carvalho de Melo struct thread_map *threads; 59fd78260bSArnaldo Carvalho de Melo char name[256]; 60fd78260bSArnaldo Carvalho de Melo int items; 61fd78260bSArnaldo Carvalho de Melo struct dirent **namelist = NULL; 62fd78260bSArnaldo Carvalho de Melo int i; 63fd78260bSArnaldo Carvalho de Melo 64fd78260bSArnaldo Carvalho de Melo sprintf(name, "/proc/%d/task", pid); 65fd78260bSArnaldo Carvalho de Melo items = scandir(name, &namelist, filter, NULL); 66fd78260bSArnaldo Carvalho de Melo if (items <= 0) 67fd78260bSArnaldo Carvalho de Melo return NULL; 68fd78260bSArnaldo Carvalho de Melo 699d7e8c3aSJiri Olsa threads = thread_map__alloc(items); 70fd78260bSArnaldo Carvalho de Melo if (threads != NULL) { 71fd78260bSArnaldo Carvalho de Melo for (i = 0; i < items; i++) 72e13798c7SJiri Olsa thread_map__set_pid(threads, i, atoi(namelist[i]->d_name)); 73fd78260bSArnaldo Carvalho de Melo threads->nr = items; 74364fed35SElena Reshetova refcount_set(&threads->refcnt, 1); 75fd78260bSArnaldo Carvalho de Melo } 76fd78260bSArnaldo Carvalho de Melo 77fd78260bSArnaldo Carvalho de Melo for (i=0; i<items; i++) 7874cf249dSArnaldo Carvalho de Melo zfree(&namelist[i]); 79fd78260bSArnaldo Carvalho de Melo free(namelist); 80fd78260bSArnaldo Carvalho de Melo 81fd78260bSArnaldo Carvalho de Melo return threads; 82fd78260bSArnaldo Carvalho de Melo } 83fd78260bSArnaldo Carvalho de Melo 84fd78260bSArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_tid(pid_t tid) 85fd78260bSArnaldo Carvalho de Melo { 869d7e8c3aSJiri Olsa struct thread_map *threads = thread_map__alloc(1); 87fd78260bSArnaldo Carvalho de Melo 88fd78260bSArnaldo Carvalho de Melo if (threads != NULL) { 89e13798c7SJiri Olsa thread_map__set_pid(threads, 0, tid); 90fd78260bSArnaldo Carvalho de Melo threads->nr = 1; 91364fed35SElena Reshetova refcount_set(&threads->refcnt, 1); 92fd78260bSArnaldo Carvalho de Melo } 93fd78260bSArnaldo Carvalho de Melo 94fd78260bSArnaldo Carvalho de Melo return threads; 95fd78260bSArnaldo Carvalho de Melo } 96fd78260bSArnaldo Carvalho de Melo 978d3cd4c3SArnaldo Carvalho de Melo static struct thread_map *__thread_map__new_all_cpus(uid_t uid) 980d37aa34SArnaldo Carvalho de Melo { 990d37aa34SArnaldo Carvalho de Melo DIR *proc; 1000d37aa34SArnaldo Carvalho de Melo int max_threads = 32, items, i; 101bdf23a9aSArnaldo Carvalho de Melo char path[NAME_MAX + 1 + 6]; 1023354cf71SArnaldo Carvalho de Melo struct dirent *dirent, **namelist = NULL; 1039d7e8c3aSJiri Olsa struct thread_map *threads = thread_map__alloc(max_threads); 1049d7e8c3aSJiri Olsa 1050d37aa34SArnaldo Carvalho de Melo if (threads == NULL) 1060d37aa34SArnaldo Carvalho de Melo goto out; 1070d37aa34SArnaldo Carvalho de Melo 1080d37aa34SArnaldo Carvalho de Melo proc = opendir("/proc"); 1090d37aa34SArnaldo Carvalho de Melo if (proc == NULL) 1100d37aa34SArnaldo Carvalho de Melo goto out_free_threads; 1110d37aa34SArnaldo Carvalho de Melo 1120d37aa34SArnaldo Carvalho de Melo threads->nr = 0; 113364fed35SElena Reshetova refcount_set(&threads->refcnt, 1); 1140d37aa34SArnaldo Carvalho de Melo 1153354cf71SArnaldo Carvalho de Melo while ((dirent = readdir(proc)) != NULL) { 1160d37aa34SArnaldo Carvalho de Melo char *end; 1170d37aa34SArnaldo Carvalho de Melo bool grow = false; 1183354cf71SArnaldo Carvalho de Melo pid_t pid = strtol(dirent->d_name, &end, 10); 1190d37aa34SArnaldo Carvalho de Melo 1200d37aa34SArnaldo Carvalho de Melo if (*end) /* only interested in proper numerical dirents */ 1210d37aa34SArnaldo Carvalho de Melo continue; 1220d37aa34SArnaldo Carvalho de Melo 1233354cf71SArnaldo Carvalho de Melo snprintf(path, sizeof(path), "/proc/%s", dirent->d_name); 1240d37aa34SArnaldo Carvalho de Melo 1258d3cd4c3SArnaldo Carvalho de Melo if (uid != UINT_MAX) { 1268d3cd4c3SArnaldo Carvalho de Melo struct stat st; 1270d37aa34SArnaldo Carvalho de Melo 1288d3cd4c3SArnaldo Carvalho de Melo if (stat(path, &st) != 0 || st.st_uid != uid) 1290d37aa34SArnaldo Carvalho de Melo continue; 1308d3cd4c3SArnaldo Carvalho de Melo } 1310d37aa34SArnaldo Carvalho de Melo 1320d37aa34SArnaldo Carvalho de Melo snprintf(path, sizeof(path), "/proc/%d/task", pid); 1330d37aa34SArnaldo Carvalho de Melo items = scandir(path, &namelist, filter, NULL); 1340d37aa34SArnaldo Carvalho de Melo if (items <= 0) 1350d37aa34SArnaldo Carvalho de Melo goto out_free_closedir; 1360d37aa34SArnaldo Carvalho de Melo 1370d37aa34SArnaldo Carvalho de Melo while (threads->nr + items >= max_threads) { 1380d37aa34SArnaldo Carvalho de Melo max_threads *= 2; 1390d37aa34SArnaldo Carvalho de Melo grow = true; 1400d37aa34SArnaldo Carvalho de Melo } 1410d37aa34SArnaldo Carvalho de Melo 1420d37aa34SArnaldo Carvalho de Melo if (grow) { 1430d37aa34SArnaldo Carvalho de Melo struct thread_map *tmp; 1440d37aa34SArnaldo Carvalho de Melo 14508ae217bSArnaldo Carvalho de Melo tmp = thread_map__realloc(threads, max_threads); 1460d37aa34SArnaldo Carvalho de Melo if (tmp == NULL) 1470d37aa34SArnaldo Carvalho de Melo goto out_free_namelist; 1480d37aa34SArnaldo Carvalho de Melo 1490d37aa34SArnaldo Carvalho de Melo threads = tmp; 1500d37aa34SArnaldo Carvalho de Melo } 1510d37aa34SArnaldo Carvalho de Melo 152e13798c7SJiri Olsa for (i = 0; i < items; i++) { 153e13798c7SJiri Olsa thread_map__set_pid(threads, threads->nr + i, 154e13798c7SJiri Olsa atoi(namelist[i]->d_name)); 155e13798c7SJiri Olsa } 1560d37aa34SArnaldo Carvalho de Melo 1570d37aa34SArnaldo Carvalho de Melo for (i = 0; i < items; i++) 15874cf249dSArnaldo Carvalho de Melo zfree(&namelist[i]); 1590d37aa34SArnaldo Carvalho de Melo free(namelist); 1600d37aa34SArnaldo Carvalho de Melo 1610d37aa34SArnaldo Carvalho de Melo threads->nr += items; 1620d37aa34SArnaldo Carvalho de Melo } 1630d37aa34SArnaldo Carvalho de Melo 1640d37aa34SArnaldo Carvalho de Melo out_closedir: 1650d37aa34SArnaldo Carvalho de Melo closedir(proc); 1660d37aa34SArnaldo Carvalho de Melo out: 1670d37aa34SArnaldo Carvalho de Melo return threads; 1680d37aa34SArnaldo Carvalho de Melo 1690d37aa34SArnaldo Carvalho de Melo out_free_threads: 1700d37aa34SArnaldo Carvalho de Melo free(threads); 1710d37aa34SArnaldo Carvalho de Melo return NULL; 1720d37aa34SArnaldo Carvalho de Melo 1730d37aa34SArnaldo Carvalho de Melo out_free_namelist: 1740d37aa34SArnaldo Carvalho de Melo for (i = 0; i < items; i++) 17574cf249dSArnaldo Carvalho de Melo zfree(&namelist[i]); 1760d37aa34SArnaldo Carvalho de Melo free(namelist); 1770d37aa34SArnaldo Carvalho de Melo 1780d37aa34SArnaldo Carvalho de Melo out_free_closedir: 17904662523SArnaldo Carvalho de Melo zfree(&threads); 1800d37aa34SArnaldo Carvalho de Melo goto out_closedir; 1810d37aa34SArnaldo Carvalho de Melo } 1820d37aa34SArnaldo Carvalho de Melo 1838d3cd4c3SArnaldo Carvalho de Melo struct thread_map *thread_map__new_all_cpus(void) 1848d3cd4c3SArnaldo Carvalho de Melo { 1858d3cd4c3SArnaldo Carvalho de Melo return __thread_map__new_all_cpus(UINT_MAX); 1868d3cd4c3SArnaldo Carvalho de Melo } 1878d3cd4c3SArnaldo Carvalho de Melo 1888d3cd4c3SArnaldo Carvalho de Melo struct thread_map *thread_map__new_by_uid(uid_t uid) 1898d3cd4c3SArnaldo Carvalho de Melo { 1908d3cd4c3SArnaldo Carvalho de Melo return __thread_map__new_all_cpus(uid); 1918d3cd4c3SArnaldo Carvalho de Melo } 1928d3cd4c3SArnaldo Carvalho de Melo 1930d37aa34SArnaldo Carvalho de Melo struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid) 194fd78260bSArnaldo Carvalho de Melo { 195fd78260bSArnaldo Carvalho de Melo if (pid != -1) 196fd78260bSArnaldo Carvalho de Melo return thread_map__new_by_pid(pid); 1970d37aa34SArnaldo Carvalho de Melo 1980d37aa34SArnaldo Carvalho de Melo if (tid == -1 && uid != UINT_MAX) 1990d37aa34SArnaldo Carvalho de Melo return thread_map__new_by_uid(uid); 2000d37aa34SArnaldo Carvalho de Melo 201fd78260bSArnaldo Carvalho de Melo return thread_map__new_by_tid(tid); 202fd78260bSArnaldo Carvalho de Melo } 203fd78260bSArnaldo Carvalho de Melo 204b52956c9SDavid Ahern static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) 205b52956c9SDavid Ahern { 206b52956c9SDavid Ahern struct thread_map *threads = NULL, *nt; 207b52956c9SDavid Ahern char name[256]; 208b52956c9SDavid Ahern int items, total_tasks = 0; 209b52956c9SDavid Ahern struct dirent **namelist = NULL; 210b52956c9SDavid Ahern int i, j = 0; 211b52956c9SDavid Ahern pid_t pid, prev_pid = INT_MAX; 212b52956c9SDavid Ahern char *end_ptr; 213b52956c9SDavid Ahern struct str_node *pos; 2144a77e218SArnaldo Carvalho de Melo struct strlist_config slist_config = { .dont_dupstr = true, }; 2154a77e218SArnaldo Carvalho de Melo struct strlist *slist = strlist__new(pid_str, &slist_config); 216b52956c9SDavid Ahern 217b52956c9SDavid Ahern if (!slist) 218b52956c9SDavid Ahern return NULL; 219b52956c9SDavid Ahern 220602a1f4dSArnaldo Carvalho de Melo strlist__for_each_entry(pos, slist) { 221b52956c9SDavid Ahern pid = strtol(pos->s, &end_ptr, 10); 222b52956c9SDavid Ahern 223b52956c9SDavid Ahern if (pid == INT_MIN || pid == INT_MAX || 224b52956c9SDavid Ahern (*end_ptr != '\0' && *end_ptr != ',')) 225b52956c9SDavid Ahern goto out_free_threads; 226b52956c9SDavid Ahern 227b52956c9SDavid Ahern if (pid == prev_pid) 228b52956c9SDavid Ahern continue; 229b52956c9SDavid Ahern 230b52956c9SDavid Ahern sprintf(name, "/proc/%d/task", pid); 231b52956c9SDavid Ahern items = scandir(name, &namelist, filter, NULL); 232b52956c9SDavid Ahern if (items <= 0) 233b52956c9SDavid Ahern goto out_free_threads; 234b52956c9SDavid Ahern 235b52956c9SDavid Ahern total_tasks += items; 2369d7e8c3aSJiri Olsa nt = thread_map__realloc(threads, total_tasks); 237b52956c9SDavid Ahern if (nt == NULL) 238e8cdd947SFranck Bui-Huu goto out_free_namelist; 239b52956c9SDavid Ahern 240b52956c9SDavid Ahern threads = nt; 241b52956c9SDavid Ahern 242e8cdd947SFranck Bui-Huu for (i = 0; i < items; i++) { 243e13798c7SJiri Olsa thread_map__set_pid(threads, j++, atoi(namelist[i]->d_name)); 24474cf249dSArnaldo Carvalho de Melo zfree(&namelist[i]); 245e8cdd947SFranck Bui-Huu } 246e8cdd947SFranck Bui-Huu threads->nr = total_tasks; 247b52956c9SDavid Ahern free(namelist); 248b52956c9SDavid Ahern } 249b52956c9SDavid Ahern 250b52956c9SDavid Ahern out: 251b52956c9SDavid Ahern strlist__delete(slist); 252186fbb74SJiri Olsa if (threads) 253364fed35SElena Reshetova refcount_set(&threads->refcnt, 1); 254b52956c9SDavid Ahern return threads; 255b52956c9SDavid Ahern 256e8cdd947SFranck Bui-Huu out_free_namelist: 257e8cdd947SFranck Bui-Huu for (i = 0; i < items; i++) 25874cf249dSArnaldo Carvalho de Melo zfree(&namelist[i]); 259e8cdd947SFranck Bui-Huu free(namelist); 260e8cdd947SFranck Bui-Huu 261b52956c9SDavid Ahern out_free_threads: 26204662523SArnaldo Carvalho de Melo zfree(&threads); 263b52956c9SDavid Ahern goto out; 264b52956c9SDavid Ahern } 265b52956c9SDavid Ahern 266641556c9SArnaldo Carvalho de Melo struct thread_map *thread_map__new_dummy(void) 267641556c9SArnaldo Carvalho de Melo { 2689d7e8c3aSJiri Olsa struct thread_map *threads = thread_map__alloc(1); 269641556c9SArnaldo Carvalho de Melo 270641556c9SArnaldo Carvalho de Melo if (threads != NULL) { 271e13798c7SJiri Olsa thread_map__set_pid(threads, 0, -1); 272641556c9SArnaldo Carvalho de Melo threads->nr = 1; 273364fed35SElena Reshetova refcount_set(&threads->refcnt, 1); 274641556c9SArnaldo Carvalho de Melo } 275641556c9SArnaldo Carvalho de Melo return threads; 276641556c9SArnaldo Carvalho de Melo } 277641556c9SArnaldo Carvalho de Melo 278097be0f5SJiri Olsa struct thread_map *thread_map__new_by_tid_str(const char *tid_str) 279b52956c9SDavid Ahern { 280b52956c9SDavid Ahern struct thread_map *threads = NULL, *nt; 281b52956c9SDavid Ahern int ntasks = 0; 282b52956c9SDavid Ahern pid_t tid, prev_tid = INT_MAX; 283b52956c9SDavid Ahern char *end_ptr; 284b52956c9SDavid Ahern struct str_node *pos; 2854a77e218SArnaldo Carvalho de Melo struct strlist_config slist_config = { .dont_dupstr = true, }; 286b52956c9SDavid Ahern struct strlist *slist; 287b52956c9SDavid Ahern 288b52956c9SDavid Ahern /* perf-stat expects threads to be generated even if tid not given */ 289641556c9SArnaldo Carvalho de Melo if (!tid_str) 290641556c9SArnaldo Carvalho de Melo return thread_map__new_dummy(); 291b52956c9SDavid Ahern 2924a77e218SArnaldo Carvalho de Melo slist = strlist__new(tid_str, &slist_config); 293b52956c9SDavid Ahern if (!slist) 294b52956c9SDavid Ahern return NULL; 295b52956c9SDavid Ahern 296602a1f4dSArnaldo Carvalho de Melo strlist__for_each_entry(pos, slist) { 297b52956c9SDavid Ahern tid = strtol(pos->s, &end_ptr, 10); 298b52956c9SDavid Ahern 299b52956c9SDavid Ahern if (tid == INT_MIN || tid == INT_MAX || 300b52956c9SDavid Ahern (*end_ptr != '\0' && *end_ptr != ',')) 301b52956c9SDavid Ahern goto out_free_threads; 302b52956c9SDavid Ahern 303b52956c9SDavid Ahern if (tid == prev_tid) 304b52956c9SDavid Ahern continue; 305b52956c9SDavid Ahern 306b52956c9SDavid Ahern ntasks++; 3079d7e8c3aSJiri Olsa nt = thread_map__realloc(threads, ntasks); 308b52956c9SDavid Ahern 309b52956c9SDavid Ahern if (nt == NULL) 310b52956c9SDavid Ahern goto out_free_threads; 311b52956c9SDavid Ahern 312b52956c9SDavid Ahern threads = nt; 313e13798c7SJiri Olsa thread_map__set_pid(threads, ntasks - 1, tid); 314b52956c9SDavid Ahern threads->nr = ntasks; 315b52956c9SDavid Ahern } 316b52956c9SDavid Ahern out: 317186fbb74SJiri Olsa if (threads) 318364fed35SElena Reshetova refcount_set(&threads->refcnt, 1); 319b52956c9SDavid Ahern return threads; 320b52956c9SDavid Ahern 321b52956c9SDavid Ahern out_free_threads: 32204662523SArnaldo Carvalho de Melo zfree(&threads); 3237ecb48fdSNamhyung Kim strlist__delete(slist); 324b52956c9SDavid Ahern goto out; 325b52956c9SDavid Ahern } 326b52956c9SDavid Ahern 327b52956c9SDavid Ahern struct thread_map *thread_map__new_str(const char *pid, const char *tid, 328147c508fSJin Yao uid_t uid, bool all_threads) 329b52956c9SDavid Ahern { 330b52956c9SDavid Ahern if (pid) 331b52956c9SDavid Ahern return thread_map__new_by_pid_str(pid); 332b52956c9SDavid Ahern 333b52956c9SDavid Ahern if (!tid && uid != UINT_MAX) 334b52956c9SDavid Ahern return thread_map__new_by_uid(uid); 335b52956c9SDavid Ahern 336147c508fSJin Yao if (all_threads) 33773c0ca1eSJin Yao return thread_map__new_all_cpus(); 33873c0ca1eSJin Yao 339b52956c9SDavid Ahern return thread_map__new_by_tid_str(tid); 340b52956c9SDavid Ahern } 341b52956c9SDavid Ahern 342186fbb74SJiri Olsa static void thread_map__delete(struct thread_map *threads) 343fd78260bSArnaldo Carvalho de Melo { 344186fbb74SJiri Olsa if (threads) { 345792402fdSJiri Olsa int i; 346792402fdSJiri Olsa 347364fed35SElena Reshetova WARN_ONCE(refcount_read(&threads->refcnt) != 0, 348186fbb74SJiri Olsa "thread map refcnt unbalanced\n"); 349792402fdSJiri Olsa for (i = 0; i < threads->nr; i++) 350792402fdSJiri Olsa free(thread_map__comm(threads, i)); 351fd78260bSArnaldo Carvalho de Melo free(threads); 352fd78260bSArnaldo Carvalho de Melo } 353186fbb74SJiri Olsa } 354186fbb74SJiri Olsa 355186fbb74SJiri Olsa struct thread_map *thread_map__get(struct thread_map *map) 356186fbb74SJiri Olsa { 357186fbb74SJiri Olsa if (map) 358364fed35SElena Reshetova refcount_inc(&map->refcnt); 359186fbb74SJiri Olsa return map; 360186fbb74SJiri Olsa } 361186fbb74SJiri Olsa 362186fbb74SJiri Olsa void thread_map__put(struct thread_map *map) 363186fbb74SJiri Olsa { 364364fed35SElena Reshetova if (map && refcount_dec_and_test(&map->refcnt)) 365186fbb74SJiri Olsa thread_map__delete(map); 366186fbb74SJiri Olsa } 3679ae7d335SArnaldo Carvalho de Melo 3689ae7d335SArnaldo Carvalho de Melo size_t thread_map__fprintf(struct thread_map *threads, FILE *fp) 3699ae7d335SArnaldo Carvalho de Melo { 3709ae7d335SArnaldo Carvalho de Melo int i; 3719ae7d335SArnaldo Carvalho de Melo size_t printed = fprintf(fp, "%d thread%s: ", 3729ae7d335SArnaldo Carvalho de Melo threads->nr, threads->nr > 1 ? "s" : ""); 3739ae7d335SArnaldo Carvalho de Melo for (i = 0; i < threads->nr; ++i) 374e13798c7SJiri Olsa printed += fprintf(fp, "%s%d", i ? ", " : "", thread_map__pid(threads, i)); 3759ae7d335SArnaldo Carvalho de Melo 3769ae7d335SArnaldo Carvalho de Melo return printed + fprintf(fp, "\n"); 3779ae7d335SArnaldo Carvalho de Melo } 378792402fdSJiri Olsa 379792402fdSJiri Olsa static int get_comm(char **comm, pid_t pid) 380792402fdSJiri Olsa { 381792402fdSJiri Olsa char *path; 382792402fdSJiri Olsa size_t size; 383792402fdSJiri Olsa int err; 384792402fdSJiri Olsa 385792402fdSJiri Olsa if (asprintf(&path, "%s/%d/comm", procfs__mountpoint(), pid) == -1) 386792402fdSJiri Olsa return -ENOMEM; 387792402fdSJiri Olsa 388792402fdSJiri Olsa err = filename__read_str(path, comm, &size); 389792402fdSJiri Olsa if (!err) { 390792402fdSJiri Olsa /* 391792402fdSJiri Olsa * We're reading 16 bytes, while filename__read_str 392792402fdSJiri Olsa * allocates data per BUFSIZ bytes, so we can safely 393792402fdSJiri Olsa * mark the end of the string. 394792402fdSJiri Olsa */ 395792402fdSJiri Olsa (*comm)[size] = 0; 396*13c230abSArnaldo Carvalho de Melo strim(*comm); 397792402fdSJiri Olsa } 398792402fdSJiri Olsa 399792402fdSJiri Olsa free(path); 400792402fdSJiri Olsa return err; 401792402fdSJiri Olsa } 402792402fdSJiri Olsa 403792402fdSJiri Olsa static void comm_init(struct thread_map *map, int i) 404792402fdSJiri Olsa { 405792402fdSJiri Olsa pid_t pid = thread_map__pid(map, i); 406792402fdSJiri Olsa char *comm = NULL; 407792402fdSJiri Olsa 408792402fdSJiri Olsa /* dummy pid comm initialization */ 409792402fdSJiri Olsa if (pid == -1) { 410792402fdSJiri Olsa map->map[i].comm = strdup("dummy"); 411792402fdSJiri Olsa return; 412792402fdSJiri Olsa } 413792402fdSJiri Olsa 414792402fdSJiri Olsa /* 415792402fdSJiri Olsa * The comm name is like extra bonus ;-), 416792402fdSJiri Olsa * so just warn if we fail for any reason. 417792402fdSJiri Olsa */ 418792402fdSJiri Olsa if (get_comm(&comm, pid)) 419792402fdSJiri Olsa pr_warning("Couldn't resolve comm name for pid %d\n", pid); 420792402fdSJiri Olsa 421792402fdSJiri Olsa map->map[i].comm = comm; 422792402fdSJiri Olsa } 423792402fdSJiri Olsa 424792402fdSJiri Olsa void thread_map__read_comms(struct thread_map *threads) 425792402fdSJiri Olsa { 426792402fdSJiri Olsa int i; 427792402fdSJiri Olsa 428792402fdSJiri Olsa for (i = 0; i < threads->nr; ++i) 429792402fdSJiri Olsa comm_init(threads, i); 430792402fdSJiri Olsa } 43159660942SJiri Olsa 43259660942SJiri Olsa static void thread_map__copy_event(struct thread_map *threads, 43359660942SJiri Olsa struct thread_map_event *event) 43459660942SJiri Olsa { 43559660942SJiri Olsa unsigned i; 43659660942SJiri Olsa 43759660942SJiri Olsa threads->nr = (int) event->nr; 43859660942SJiri Olsa 43959660942SJiri Olsa for (i = 0; i < event->nr; i++) { 44059660942SJiri Olsa thread_map__set_pid(threads, i, (pid_t) event->entries[i].pid); 44159660942SJiri Olsa threads->map[i].comm = strndup(event->entries[i].comm, 16); 44259660942SJiri Olsa } 44359660942SJiri Olsa 444364fed35SElena Reshetova refcount_set(&threads->refcnt, 1); 44559660942SJiri Olsa } 44659660942SJiri Olsa 44759660942SJiri Olsa struct thread_map *thread_map__new_event(struct thread_map_event *event) 44859660942SJiri Olsa { 44959660942SJiri Olsa struct thread_map *threads; 45059660942SJiri Olsa 45159660942SJiri Olsa threads = thread_map__alloc(event->nr); 45259660942SJiri Olsa if (threads) 45359660942SJiri Olsa thread_map__copy_event(threads, event); 45459660942SJiri Olsa 45559660942SJiri Olsa return threads; 45659660942SJiri Olsa } 4573407df8bSJiri Olsa 4583407df8bSJiri Olsa bool thread_map__has(struct thread_map *threads, pid_t pid) 4593407df8bSJiri Olsa { 4603407df8bSJiri Olsa int i; 4613407df8bSJiri Olsa 4623407df8bSJiri Olsa for (i = 0; i < threads->nr; ++i) { 4633407df8bSJiri Olsa if (threads->map[i].pid == pid) 4643407df8bSJiri Olsa return true; 4653407df8bSJiri Olsa } 4663407df8bSJiri Olsa 4673407df8bSJiri Olsa return false; 4683407df8bSJiri Olsa } 46938af91f0SJiri Olsa 47038af91f0SJiri Olsa int thread_map__remove(struct thread_map *threads, int idx) 47138af91f0SJiri Olsa { 47238af91f0SJiri Olsa int i; 47338af91f0SJiri Olsa 47438af91f0SJiri Olsa if (threads->nr < 1) 47538af91f0SJiri Olsa return -EINVAL; 47638af91f0SJiri Olsa 47738af91f0SJiri Olsa if (idx >= threads->nr) 47838af91f0SJiri Olsa return -EINVAL; 47938af91f0SJiri Olsa 48038af91f0SJiri Olsa /* 48138af91f0SJiri Olsa * Free the 'idx' item and shift the rest up. 48238af91f0SJiri Olsa */ 48338af91f0SJiri Olsa free(threads->map[idx].comm); 48438af91f0SJiri Olsa 48538af91f0SJiri Olsa for (i = idx; i < threads->nr - 1; i++) 48638af91f0SJiri Olsa threads->map[i] = threads->map[i + 1]; 48738af91f0SJiri Olsa 48838af91f0SJiri Olsa threads->nr--; 48938af91f0SJiri Olsa return 0; 49038af91f0SJiri Olsa } 491