162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <dirent.h>
362306a36Sopenharmony_ci#include <errno.h>
462306a36Sopenharmony_ci#include <limits.h>
562306a36Sopenharmony_ci#include <stdbool.h>
662306a36Sopenharmony_ci#include <stdlib.h>
762306a36Sopenharmony_ci#include <stdio.h>
862306a36Sopenharmony_ci#include <sys/types.h>
962306a36Sopenharmony_ci#include <sys/stat.h>
1062306a36Sopenharmony_ci#include <unistd.h>
1162306a36Sopenharmony_ci#include "string2.h"
1262306a36Sopenharmony_ci#include "strlist.h"
1362306a36Sopenharmony_ci#include <string.h>
1462306a36Sopenharmony_ci#include <api/fs/fs.h>
1562306a36Sopenharmony_ci#include <linux/string.h>
1662306a36Sopenharmony_ci#include <linux/zalloc.h>
1762306a36Sopenharmony_ci#include "asm/bug.h"
1862306a36Sopenharmony_ci#include "thread_map.h"
1962306a36Sopenharmony_ci#include "debug.h"
2062306a36Sopenharmony_ci#include "event.h"
2162306a36Sopenharmony_ci#include <internal/threadmap.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/* Skip "." and ".." directories */
2462306a36Sopenharmony_cistatic int filter(const struct dirent *dir)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	if (dir->d_name[0] == '.')
2762306a36Sopenharmony_ci		return 0;
2862306a36Sopenharmony_ci	else
2962306a36Sopenharmony_ci		return 1;
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define thread_map__alloc(__nr) perf_thread_map__realloc(NULL, __nr)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistruct perf_thread_map *thread_map__new_by_pid(pid_t pid)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	struct perf_thread_map *threads;
3762306a36Sopenharmony_ci	char name[256];
3862306a36Sopenharmony_ci	int items;
3962306a36Sopenharmony_ci	struct dirent **namelist = NULL;
4062306a36Sopenharmony_ci	int i;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	sprintf(name, "/proc/%d/task", pid);
4362306a36Sopenharmony_ci	items = scandir(name, &namelist, filter, NULL);
4462306a36Sopenharmony_ci	if (items <= 0)
4562306a36Sopenharmony_ci		return NULL;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	threads = thread_map__alloc(items);
4862306a36Sopenharmony_ci	if (threads != NULL) {
4962306a36Sopenharmony_ci		for (i = 0; i < items; i++)
5062306a36Sopenharmony_ci			perf_thread_map__set_pid(threads, i, atoi(namelist[i]->d_name));
5162306a36Sopenharmony_ci		threads->nr = items;
5262306a36Sopenharmony_ci		refcount_set(&threads->refcnt, 1);
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	for (i=0; i<items; i++)
5662306a36Sopenharmony_ci		zfree(&namelist[i]);
5762306a36Sopenharmony_ci	free(namelist);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	return threads;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistruct perf_thread_map *thread_map__new_by_tid(pid_t tid)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct perf_thread_map *threads = thread_map__alloc(1);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (threads != NULL) {
6762306a36Sopenharmony_ci		perf_thread_map__set_pid(threads, 0, tid);
6862306a36Sopenharmony_ci		threads->nr = 1;
6962306a36Sopenharmony_ci		refcount_set(&threads->refcnt, 1);
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	return threads;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic struct perf_thread_map *__thread_map__new_all_cpus(uid_t uid)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	DIR *proc;
7862306a36Sopenharmony_ci	int max_threads = 32, items, i;
7962306a36Sopenharmony_ci	char path[NAME_MAX + 1 + 6];
8062306a36Sopenharmony_ci	struct dirent *dirent, **namelist = NULL;
8162306a36Sopenharmony_ci	struct perf_thread_map *threads = thread_map__alloc(max_threads);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if (threads == NULL)
8462306a36Sopenharmony_ci		goto out;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	proc = opendir("/proc");
8762306a36Sopenharmony_ci	if (proc == NULL)
8862306a36Sopenharmony_ci		goto out_free_threads;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	threads->nr = 0;
9162306a36Sopenharmony_ci	refcount_set(&threads->refcnt, 1);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	while ((dirent = readdir(proc)) != NULL) {
9462306a36Sopenharmony_ci		char *end;
9562306a36Sopenharmony_ci		bool grow = false;
9662306a36Sopenharmony_ci		pid_t pid = strtol(dirent->d_name, &end, 10);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci		if (*end) /* only interested in proper numerical dirents */
9962306a36Sopenharmony_ci			continue;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		snprintf(path, sizeof(path), "/proc/%s", dirent->d_name);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci		if (uid != UINT_MAX) {
10462306a36Sopenharmony_ci			struct stat st;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci			if (stat(path, &st) != 0 || st.st_uid != uid)
10762306a36Sopenharmony_ci				continue;
10862306a36Sopenharmony_ci		}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci		snprintf(path, sizeof(path), "/proc/%d/task", pid);
11162306a36Sopenharmony_ci		items = scandir(path, &namelist, filter, NULL);
11262306a36Sopenharmony_ci		if (items <= 0)
11362306a36Sopenharmony_ci			goto out_free_closedir;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci		while (threads->nr + items >= max_threads) {
11662306a36Sopenharmony_ci			max_threads *= 2;
11762306a36Sopenharmony_ci			grow = true;
11862306a36Sopenharmony_ci		}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci		if (grow) {
12162306a36Sopenharmony_ci			struct perf_thread_map *tmp;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci			tmp = perf_thread_map__realloc(threads, max_threads);
12462306a36Sopenharmony_ci			if (tmp == NULL)
12562306a36Sopenharmony_ci				goto out_free_namelist;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci			threads = tmp;
12862306a36Sopenharmony_ci		}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		for (i = 0; i < items; i++) {
13162306a36Sopenharmony_ci			perf_thread_map__set_pid(threads, threads->nr + i,
13262306a36Sopenharmony_ci						    atoi(namelist[i]->d_name));
13362306a36Sopenharmony_ci		}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci		for (i = 0; i < items; i++)
13662306a36Sopenharmony_ci			zfree(&namelist[i]);
13762306a36Sopenharmony_ci		free(namelist);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		threads->nr += items;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ciout_closedir:
14362306a36Sopenharmony_ci	closedir(proc);
14462306a36Sopenharmony_ciout:
14562306a36Sopenharmony_ci	return threads;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ciout_free_threads:
14862306a36Sopenharmony_ci	free(threads);
14962306a36Sopenharmony_ci	return NULL;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ciout_free_namelist:
15262306a36Sopenharmony_ci	for (i = 0; i < items; i++)
15362306a36Sopenharmony_ci		zfree(&namelist[i]);
15462306a36Sopenharmony_ci	free(namelist);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ciout_free_closedir:
15762306a36Sopenharmony_ci	zfree(&threads);
15862306a36Sopenharmony_ci	goto out_closedir;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistruct perf_thread_map *thread_map__new_all_cpus(void)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	return __thread_map__new_all_cpus(UINT_MAX);
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistruct perf_thread_map *thread_map__new_by_uid(uid_t uid)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	return __thread_map__new_all_cpus(uid);
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistruct perf_thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	if (pid != -1)
17462306a36Sopenharmony_ci		return thread_map__new_by_pid(pid);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if (tid == -1 && uid != UINT_MAX)
17762306a36Sopenharmony_ci		return thread_map__new_by_uid(uid);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	return thread_map__new_by_tid(tid);
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic struct perf_thread_map *thread_map__new_by_pid_str(const char *pid_str)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	struct perf_thread_map *threads = NULL, *nt;
18562306a36Sopenharmony_ci	char name[256];
18662306a36Sopenharmony_ci	int items, total_tasks = 0;
18762306a36Sopenharmony_ci	struct dirent **namelist = NULL;
18862306a36Sopenharmony_ci	int i, j = 0;
18962306a36Sopenharmony_ci	pid_t pid, prev_pid = INT_MAX;
19062306a36Sopenharmony_ci	char *end_ptr;
19162306a36Sopenharmony_ci	struct str_node *pos;
19262306a36Sopenharmony_ci	struct strlist_config slist_config = { .dont_dupstr = true, };
19362306a36Sopenharmony_ci	struct strlist *slist = strlist__new(pid_str, &slist_config);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	if (!slist)
19662306a36Sopenharmony_ci		return NULL;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	strlist__for_each_entry(pos, slist) {
19962306a36Sopenharmony_ci		pid = strtol(pos->s, &end_ptr, 10);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		if (pid == INT_MIN || pid == INT_MAX ||
20262306a36Sopenharmony_ci		    (*end_ptr != '\0' && *end_ptr != ','))
20362306a36Sopenharmony_ci			goto out_free_threads;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci		if (pid == prev_pid)
20662306a36Sopenharmony_ci			continue;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci		sprintf(name, "/proc/%d/task", pid);
20962306a36Sopenharmony_ci		items = scandir(name, &namelist, filter, NULL);
21062306a36Sopenharmony_ci		if (items <= 0)
21162306a36Sopenharmony_ci			goto out_free_threads;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci		total_tasks += items;
21462306a36Sopenharmony_ci		nt = perf_thread_map__realloc(threads, total_tasks);
21562306a36Sopenharmony_ci		if (nt == NULL)
21662306a36Sopenharmony_ci			goto out_free_namelist;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci		threads = nt;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		for (i = 0; i < items; i++) {
22162306a36Sopenharmony_ci			perf_thread_map__set_pid(threads, j++, atoi(namelist[i]->d_name));
22262306a36Sopenharmony_ci			zfree(&namelist[i]);
22362306a36Sopenharmony_ci		}
22462306a36Sopenharmony_ci		threads->nr = total_tasks;
22562306a36Sopenharmony_ci		free(namelist);
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ciout:
22962306a36Sopenharmony_ci	strlist__delete(slist);
23062306a36Sopenharmony_ci	if (threads)
23162306a36Sopenharmony_ci		refcount_set(&threads->refcnt, 1);
23262306a36Sopenharmony_ci	return threads;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ciout_free_namelist:
23562306a36Sopenharmony_ci	for (i = 0; i < items; i++)
23662306a36Sopenharmony_ci		zfree(&namelist[i]);
23762306a36Sopenharmony_ci	free(namelist);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ciout_free_threads:
24062306a36Sopenharmony_ci	zfree(&threads);
24162306a36Sopenharmony_ci	goto out;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistruct perf_thread_map *thread_map__new_by_tid_str(const char *tid_str)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	struct perf_thread_map *threads = NULL, *nt;
24762306a36Sopenharmony_ci	int ntasks = 0;
24862306a36Sopenharmony_ci	pid_t tid, prev_tid = INT_MAX;
24962306a36Sopenharmony_ci	char *end_ptr;
25062306a36Sopenharmony_ci	struct str_node *pos;
25162306a36Sopenharmony_ci	struct strlist_config slist_config = { .dont_dupstr = true, };
25262306a36Sopenharmony_ci	struct strlist *slist;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/* perf-stat expects threads to be generated even if tid not given */
25562306a36Sopenharmony_ci	if (!tid_str)
25662306a36Sopenharmony_ci		return perf_thread_map__new_dummy();
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	slist = strlist__new(tid_str, &slist_config);
25962306a36Sopenharmony_ci	if (!slist)
26062306a36Sopenharmony_ci		return NULL;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	strlist__for_each_entry(pos, slist) {
26362306a36Sopenharmony_ci		tid = strtol(pos->s, &end_ptr, 10);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci		if (tid == INT_MIN || tid == INT_MAX ||
26662306a36Sopenharmony_ci		    (*end_ptr != '\0' && *end_ptr != ','))
26762306a36Sopenharmony_ci			goto out_free_threads;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci		if (tid == prev_tid)
27062306a36Sopenharmony_ci			continue;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		ntasks++;
27362306a36Sopenharmony_ci		nt = perf_thread_map__realloc(threads, ntasks);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		if (nt == NULL)
27662306a36Sopenharmony_ci			goto out_free_threads;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci		threads = nt;
27962306a36Sopenharmony_ci		perf_thread_map__set_pid(threads, ntasks - 1, tid);
28062306a36Sopenharmony_ci		threads->nr = ntasks;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ciout:
28362306a36Sopenharmony_ci	strlist__delete(slist);
28462306a36Sopenharmony_ci	if (threads)
28562306a36Sopenharmony_ci		refcount_set(&threads->refcnt, 1);
28662306a36Sopenharmony_ci	return threads;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ciout_free_threads:
28962306a36Sopenharmony_ci	zfree(&threads);
29062306a36Sopenharmony_ci	goto out;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistruct perf_thread_map *thread_map__new_str(const char *pid, const char *tid,
29462306a36Sopenharmony_ci				       uid_t uid, bool all_threads)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	if (pid)
29762306a36Sopenharmony_ci		return thread_map__new_by_pid_str(pid);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	if (!tid && uid != UINT_MAX)
30062306a36Sopenharmony_ci		return thread_map__new_by_uid(uid);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (all_threads)
30362306a36Sopenharmony_ci		return thread_map__new_all_cpus();
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	return thread_map__new_by_tid_str(tid);
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cisize_t thread_map__fprintf(struct perf_thread_map *threads, FILE *fp)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	int i;
31162306a36Sopenharmony_ci	size_t printed = fprintf(fp, "%d thread%s: ",
31262306a36Sopenharmony_ci				 threads->nr, threads->nr > 1 ? "s" : "");
31362306a36Sopenharmony_ci	for (i = 0; i < threads->nr; ++i)
31462306a36Sopenharmony_ci		printed += fprintf(fp, "%s%d", i ? ", " : "", perf_thread_map__pid(threads, i));
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	return printed + fprintf(fp, "\n");
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic int get_comm(char **comm, pid_t pid)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	char *path;
32262306a36Sopenharmony_ci	size_t size;
32362306a36Sopenharmony_ci	int err;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (asprintf(&path, "%s/%d/comm", procfs__mountpoint(), pid) == -1)
32662306a36Sopenharmony_ci		return -ENOMEM;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	err = filename__read_str(path, comm, &size);
32962306a36Sopenharmony_ci	if (!err) {
33062306a36Sopenharmony_ci		/*
33162306a36Sopenharmony_ci		 * We're reading 16 bytes, while filename__read_str
33262306a36Sopenharmony_ci		 * allocates data per BUFSIZ bytes, so we can safely
33362306a36Sopenharmony_ci		 * mark the end of the string.
33462306a36Sopenharmony_ci		 */
33562306a36Sopenharmony_ci		(*comm)[size] = 0;
33662306a36Sopenharmony_ci		strim(*comm);
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	free(path);
34062306a36Sopenharmony_ci	return err;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic void comm_init(struct perf_thread_map *map, int i)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	pid_t pid = perf_thread_map__pid(map, i);
34662306a36Sopenharmony_ci	char *comm = NULL;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/* dummy pid comm initialization */
34962306a36Sopenharmony_ci	if (pid == -1) {
35062306a36Sopenharmony_ci		map->map[i].comm = strdup("dummy");
35162306a36Sopenharmony_ci		return;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/*
35562306a36Sopenharmony_ci	 * The comm name is like extra bonus ;-),
35662306a36Sopenharmony_ci	 * so just warn if we fail for any reason.
35762306a36Sopenharmony_ci	 */
35862306a36Sopenharmony_ci	if (get_comm(&comm, pid))
35962306a36Sopenharmony_ci		pr_warning("Couldn't resolve comm name for pid %d\n", pid);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	map->map[i].comm = comm;
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_civoid thread_map__read_comms(struct perf_thread_map *threads)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	int i;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	for (i = 0; i < threads->nr; ++i)
36962306a36Sopenharmony_ci		comm_init(threads, i);
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic void thread_map__copy_event(struct perf_thread_map *threads,
37362306a36Sopenharmony_ci				   struct perf_record_thread_map *event)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	unsigned i;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	threads->nr = (int) event->nr;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	for (i = 0; i < event->nr; i++) {
38062306a36Sopenharmony_ci		perf_thread_map__set_pid(threads, i, (pid_t) event->entries[i].pid);
38162306a36Sopenharmony_ci		threads->map[i].comm = strndup(event->entries[i].comm, 16);
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	refcount_set(&threads->refcnt, 1);
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistruct perf_thread_map *thread_map__new_event(struct perf_record_thread_map *event)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct perf_thread_map *threads;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	threads = thread_map__alloc(event->nr);
39262306a36Sopenharmony_ci	if (threads)
39362306a36Sopenharmony_ci		thread_map__copy_event(threads, event);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	return threads;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cibool thread_map__has(struct perf_thread_map *threads, pid_t pid)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	int i;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	for (i = 0; i < threads->nr; ++i) {
40362306a36Sopenharmony_ci		if (threads->map[i].pid == pid)
40462306a36Sopenharmony_ci			return true;
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	return false;
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ciint thread_map__remove(struct perf_thread_map *threads, int idx)
41162306a36Sopenharmony_ci{
41262306a36Sopenharmony_ci	int i;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (threads->nr < 1)
41562306a36Sopenharmony_ci		return -EINVAL;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	if (idx >= threads->nr)
41862306a36Sopenharmony_ci		return -EINVAL;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/*
42162306a36Sopenharmony_ci	 * Free the 'idx' item and shift the rest up.
42262306a36Sopenharmony_ci	 */
42362306a36Sopenharmony_ci	zfree(&threads->map[idx].comm);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	for (i = idx; i < threads->nr - 1; i++)
42662306a36Sopenharmony_ci		threads->map[i] = threads->map[i + 1];
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	threads->nr--;
42962306a36Sopenharmony_ci	return 0;
43062306a36Sopenharmony_ci}
431