xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/getcpu/getcpu01.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright © International Business Machines  Corp., 2007, 2008
4  *
5  * Test Description:
6  *  The test process is affined to a CPU. It then calls getcpu and
7  *  checks that the CPU and node (if supported) match the expected
8  *  values.
9  */
10 
11 #define _GNU_SOURCE
12 #include <dirent.h>
13 #include <errno.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <sys/types.h>
17 #include "tst_test.h"
18 #include "lapi/cpuset.h"
19 #include "lapi/sched.h"
20 
max_cpuid(size_t size,cpu_set_t * set)21 static unsigned int max_cpuid(size_t size, cpu_set_t * set)
22 {
23 	unsigned int index, max = 0;
24 	for (index = 0; index < size * 8; index++)
25 		if (CPU_ISSET_S(index, size, set))
26 			max = index;
27 	return max;
28 }
29 
30 /*
31  * This will set the affinity to max cpu on which process can run
32  * and return that cpu id to the calling process
33  */
set_cpu_affinity(void)34 static unsigned int set_cpu_affinity(void)
35 {
36 	unsigned cpu_max;
37 	cpu_set_t *set;
38 	size_t size;
39 	int nrcpus = 1024;
40 
41 realloc:
42 	set = CPU_ALLOC(nrcpus);
43 	if (!set)
44 		tst_brk(TBROK | TERRNO, "CPU_ALLOC()");
45 
46 	size = CPU_ALLOC_SIZE(nrcpus);
47 	CPU_ZERO_S(size, set);
48 	if (sched_getaffinity(0, size, set) < 0) {
49 		CPU_FREE(set);
50 		if (errno == EINVAL && nrcpus < (1024 << 8)) {
51 			nrcpus = nrcpus << 2;
52 			goto realloc;
53 		}
54 		tst_brk(TBROK | TERRNO, "sched_getaffinity()");
55 	}
56 	cpu_max = max_cpuid(size, set);
57 	CPU_ZERO_S(size, set);
58 	CPU_SET_S(cpu_max, size, set);
59 	if (sched_setaffinity(0, size, set) < 0) {
60 		CPU_FREE(set);
61 		tst_brk(TBROK | TERRNO, "sched_setaffinity()");
62 	}
63 	CPU_FREE(set);
64 	return cpu_max;
65 }
66 
get_nodeid(unsigned int cpu_id)67 static unsigned int get_nodeid(unsigned int cpu_id)
68 {
69 	DIR *directory_parent, *directory_node;
70 	struct dirent *de, *dn;
71 	char directory_path[PATH_MAX];
72 	char *invalid_number;
73 	unsigned int cpu;
74 	int node_id = 0;
75 
76 	directory_parent = opendir("/sys/devices/system/node");
77 	if (!directory_parent) {
78 		tst_res(TINFO,
79 			"/sys not mounted or not a numa system. "
80 			"Assuming one node");
81 		tst_res(TINFO, "Error opening: /sys/devices/system/node :%s",
82 			strerror(errno));
83 		/* Assume CPU belongs to the only node, node zero. */
84 		return 0;
85 	} else {
86 		while ((de = readdir(directory_parent)) != NULL) {
87 			if (strncmp(de->d_name, "node", 4))
88 				continue;
89 			sprintf(directory_path, "/sys/devices/system/node/%s",
90 				de->d_name);
91 			directory_node = opendir(directory_path);
92 			while ((dn = readdir(directory_node)) != NULL) {
93 				if (strncmp(dn->d_name, "cpu", 3))
94 					continue;
95 				cpu = strtoul(dn->d_name + 3, &invalid_number, 0);
96 				if (strcmp(invalid_number, "\0"))
97 					continue;
98 				if (cpu == cpu_id) {
99 					node_id =
100 					    strtoul(de->d_name + 4, NULL, 0);
101 					break;
102 				}
103 			}
104 			closedir(directory_node);
105 		}
106 		closedir(directory_parent);
107 	}
108 	return node_id;
109 }
110 
run(void)111 static void run(void)
112 {
113 	unsigned int cpu_id, node_id = 0;
114 	unsigned int cpu_set;
115 	unsigned int node_set;
116 
117 	cpu_set = set_cpu_affinity();
118 	node_set = get_nodeid(cpu_set);
119 
120 	TEST(getcpu(&cpu_id, &node_id));
121 	if (TST_RET == 0) {
122 		if (cpu_id != cpu_set)
123 			tst_res(TFAIL, "getcpu() returned wrong value"
124 				" expected cpuid:%d, returned value cpuid: %d",
125 				cpu_set, cpu_id);
126 		else if (node_id != node_set)
127 			tst_res(TFAIL, "getcpu() returned wrong value"
128 				" expected  node id:%d returned  node id:%d",
129 				node_set, node_id);
130 		else
131 			tst_res(TPASS, "getcpu() returned proper"
132 				" cpuid:%d, node id:%d", cpu_id,
133 				node_id);
134 	} else {
135 		tst_res(TFAIL, "getcpu() Failed, errno=%d:%s",
136 			TST_ERR, strerror(TST_ERR));
137 	}
138 }
139 
140 static struct tst_test test = {
141 	.test_all = run,
142 };
143