linux/tools/perf/util/thread_map.c
<<
>>
Prefs
   1#include <dirent.h>
   2#include <limits.h>
   3#include <stdbool.h>
   4#include <stdlib.h>
   5#include <stdio.h>
   6#include <sys/types.h>
   7#include <sys/stat.h>
   8#include <unistd.h>
   9#include "strlist.h"
  10#include <string.h>
  11#include "thread_map.h"
  12
  13/* Skip "." and ".." directories */
  14static int filter(const struct dirent *dir)
  15{
  16        if (dir->d_name[0] == '.')
  17                return 0;
  18        else
  19                return 1;
  20}
  21
  22struct thread_map *thread_map__new_by_pid(pid_t pid)
  23{
  24        struct thread_map *threads;
  25        char name[256];
  26        int items;
  27        struct dirent **namelist = NULL;
  28        int i;
  29
  30        sprintf(name, "/proc/%d/task", pid);
  31        items = scandir(name, &namelist, filter, NULL);
  32        if (items <= 0)
  33                return NULL;
  34
  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);
  39                threads->nr = items;
  40        }
  41
  42        for (i=0; i<items; i++)
  43                free(namelist[i]);
  44        free(namelist);
  45
  46        return threads;
  47}
  48
  49struct thread_map *thread_map__new_by_tid(pid_t tid)
  50{
  51        struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t));
  52
  53        if (threads != NULL) {
  54                threads->map[0] = tid;
  55                threads->nr     = 1;
  56        }
  57
  58        return threads;
  59}
  60
  61struct thread_map *thread_map__new_by_uid(uid_t uid)
  62{
  63        DIR *proc;
  64        int max_threads = 32, items, i;
  65        char path[256];
  66        struct dirent dirent, *next, **namelist = NULL;
  67        struct thread_map *threads = malloc(sizeof(*threads) +
  68                                            max_threads * sizeof(pid_t));
  69        if (threads == NULL)
  70                goto out;
  71
  72        proc = opendir("/proc");
  73        if (proc == NULL)
  74                goto out_free_threads;
  75
  76        threads->nr = 0;
  77
  78        while (!readdir_r(proc, &dirent, &next) && next) {
  79                char *end;
  80                bool grow = false;
  81                struct stat st;
  82                pid_t pid = strtol(dirent.d_name, &end, 10);
  83
  84                if (*end) /* only interested in proper numerical dirents */
  85                        continue;
  86
  87                snprintf(path, sizeof(path), "/proc/%s", dirent.d_name);
  88
  89                if (stat(path, &st) != 0)
  90                        continue;
  91
  92                if (st.st_uid != uid)
  93                        continue;
  94
  95                snprintf(path, sizeof(path), "/proc/%d/task", pid);
  96                items = scandir(path, &namelist, filter, NULL);
  97                if (items <= 0)
  98                        goto out_free_closedir;
  99
 100                while (threads->nr + items >= max_threads) {
 101                        max_threads *= 2;
 102                        grow = true;
 103                }
 104
 105                if (grow) {
 106                        struct thread_map *tmp;
 107
 108                        tmp = realloc(threads, (sizeof(*threads) +
 109                                                max_threads * sizeof(pid_t)));
 110                        if (tmp == NULL)
 111                                goto out_free_namelist;
 112
 113                        threads = tmp;
 114                }
 115
 116                for (i = 0; i < items; i++)
 117                        threads->map[threads->nr + i] = atoi(namelist[i]->d_name);
 118
 119                for (i = 0; i < items; i++)
 120                        free(namelist[i]);
 121                free(namelist);
 122
 123                threads->nr += items;
 124        }
 125
 126out_closedir:
 127        closedir(proc);
 128out:
 129        return threads;
 130
 131out_free_threads:
 132        free(threads);
 133        return NULL;
 134
 135out_free_namelist:
 136        for (i = 0; i < items; i++)
 137                free(namelist[i]);
 138        free(namelist);
 139
 140out_free_closedir:
 141        free(threads);
 142        threads = NULL;
 143        goto out_closedir;
 144}
 145
 146struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
 147{
 148        if (pid != -1)
 149                return thread_map__new_by_pid(pid);
 150
 151        if (tid == -1 && uid != UINT_MAX)
 152                return thread_map__new_by_uid(uid);
 153
 154        return thread_map__new_by_tid(tid);
 155}
 156
 157static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
 158{
 159        struct thread_map *threads = NULL, *nt;
 160        char name[256];
 161        int items, total_tasks = 0;
 162        struct dirent **namelist = NULL;
 163        int i, j = 0;
 164        pid_t pid, prev_pid = INT_MAX;
 165        char *end_ptr;
 166        struct str_node *pos;
 167        struct strlist *slist = strlist__new(false, pid_str);
 168
 169        if (!slist)
 170                return NULL;
 171
 172        strlist__for_each(pos, slist) {
 173                pid = strtol(pos->s, &end_ptr, 10);
 174
 175                if (pid == INT_MIN || pid == INT_MAX ||
 176                    (*end_ptr != '\0' && *end_ptr != ','))
 177                        goto out_free_threads;
 178
 179                if (pid == prev_pid)
 180                        continue;
 181
 182                sprintf(name, "/proc/%d/task", pid);
 183                items = scandir(name, &namelist, filter, NULL);
 184                if (items <= 0)
 185                        goto out_free_threads;
 186
 187                total_tasks += items;
 188                nt = realloc(threads, (sizeof(*threads) +
 189                                       sizeof(pid_t) * total_tasks));
 190                if (nt == NULL)
 191                        goto out_free_namelist;
 192
 193                threads = nt;
 194
 195                for (i = 0; i < items; i++) {
 196                        threads->map[j++] = atoi(namelist[i]->d_name);
 197                        free(namelist[i]);
 198                }
 199                threads->nr = total_tasks;
 200                free(namelist);
 201        }
 202
 203out:
 204        strlist__delete(slist);
 205        return threads;
 206
 207out_free_namelist:
 208        for (i = 0; i < items; i++)
 209                free(namelist[i]);
 210        free(namelist);
 211
 212out_free_threads:
 213        free(threads);
 214        threads = NULL;
 215        goto out;
 216}
 217
 218static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
 219{
 220        struct thread_map *threads = NULL, *nt;
 221        int ntasks = 0;
 222        pid_t tid, prev_tid = INT_MAX;
 223        char *end_ptr;
 224        struct str_node *pos;
 225        struct strlist *slist;
 226
 227        /* perf-stat expects threads to be generated even if tid not given */
 228        if (!tid_str) {
 229                threads = malloc(sizeof(*threads) + sizeof(pid_t));
 230                if (threads != NULL) {
 231                        threads->map[0] = -1;
 232                        threads->nr     = 1;
 233                }
 234                return threads;
 235        }
 236
 237        slist = strlist__new(false, tid_str);
 238        if (!slist)
 239                return NULL;
 240
 241        strlist__for_each(pos, slist) {
 242                tid = strtol(pos->s, &end_ptr, 10);
 243
 244                if (tid == INT_MIN || tid == INT_MAX ||
 245                    (*end_ptr != '\0' && *end_ptr != ','))
 246                        goto out_free_threads;
 247
 248                if (tid == prev_tid)
 249                        continue;
 250
 251                ntasks++;
 252                nt = realloc(threads, sizeof(*threads) + sizeof(pid_t) * ntasks);
 253
 254                if (nt == NULL)
 255                        goto out_free_threads;
 256
 257                threads = nt;
 258                threads->map[ntasks - 1] = tid;
 259                threads->nr              = ntasks;
 260        }
 261out:
 262        return threads;
 263
 264out_free_threads:
 265        free(threads);
 266        threads = NULL;
 267        goto out;
 268}
 269
 270struct thread_map *thread_map__new_str(const char *pid, const char *tid,
 271                                       uid_t uid)
 272{
 273        if (pid)
 274                return thread_map__new_by_pid_str(pid);
 275
 276        if (!tid && uid != UINT_MAX)
 277                return thread_map__new_by_uid(uid);
 278
 279        return thread_map__new_by_tid_str(tid);
 280}
 281
 282void thread_map__delete(struct thread_map *threads)
 283{
 284        free(threads);
 285}
 286
 287size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
 288{
 289        int i;
 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]);
 294
 295        return printed + fprintf(fp, "\n");
 296}
 297