hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/tools/testing/selftests/rseq/param_test.c
....@@ -1,8 +1,10 @@
11 // SPDX-License-Identifier: LGPL-2.1
22 #define _GNU_SOURCE
33 #include <assert.h>
4
+#include <linux/membarrier.h>
45 #include <pthread.h>
56 #include <sched.h>
7
+#include <stdatomic.h>
68 #include <stdint.h>
79 #include <stdio.h>
810 #include <stdlib.h>
....@@ -159,7 +161,7 @@
159161 " cbnz " INJECT_ASM_REG ", 222b\n" \
160162 "333:\n"
161163
162
-#elif __PPC__
164
+#elif defined(__PPC__)
163165
164166 #define RSEQ_INJECT_INPUT \
165167 , [loop_cnt_1]"m"(loop_cnt[1]) \
....@@ -366,9 +368,7 @@
366368 abort();
367369 reps = thread_data->reps;
368370 for (i = 0; i < reps; i++) {
369
- int cpu = rseq_cpu_start();
370
-
371
- cpu = rseq_this_cpu_lock(&data->lock);
371
+ int cpu = rseq_this_cpu_lock(&data->lock);
372372 data->c[cpu].count++;
373373 rseq_percpu_unlock(&data->lock, cpu);
374374 #ifndef BENCHMARK
....@@ -549,7 +549,7 @@
549549 for (;;) {
550550 struct percpu_list_node *head;
551551 intptr_t *targetptr, expectnot, *load;
552
- off_t offset;
552
+ long offset;
553553 int ret;
554554
555555 cpu = rseq_cpu_start();
....@@ -1131,6 +1131,220 @@
11311131 return ret;
11321132 }
11331133
1134
+struct test_membarrier_thread_args {
1135
+ int stop;
1136
+ intptr_t percpu_list_ptr;
1137
+};
1138
+
1139
+/* Worker threads modify data in their "active" percpu lists. */
1140
+void *test_membarrier_worker_thread(void *arg)
1141
+{
1142
+ struct test_membarrier_thread_args *args =
1143
+ (struct test_membarrier_thread_args *)arg;
1144
+ const int iters = opt_reps;
1145
+ int i;
1146
+
1147
+ if (rseq_register_current_thread()) {
1148
+ fprintf(stderr, "Error: rseq_register_current_thread(...) failed(%d): %s\n",
1149
+ errno, strerror(errno));
1150
+ abort();
1151
+ }
1152
+
1153
+ /* Wait for initialization. */
1154
+ while (!atomic_load(&args->percpu_list_ptr)) {}
1155
+
1156
+ for (i = 0; i < iters; ++i) {
1157
+ int ret;
1158
+
1159
+ do {
1160
+ int cpu = rseq_cpu_start();
1161
+
1162
+ ret = rseq_offset_deref_addv(&args->percpu_list_ptr,
1163
+ sizeof(struct percpu_list_entry) * cpu, 1, cpu);
1164
+ } while (rseq_unlikely(ret));
1165
+ }
1166
+
1167
+ if (rseq_unregister_current_thread()) {
1168
+ fprintf(stderr, "Error: rseq_unregister_current_thread(...) failed(%d): %s\n",
1169
+ errno, strerror(errno));
1170
+ abort();
1171
+ }
1172
+ return NULL;
1173
+}
1174
+
1175
+void test_membarrier_init_percpu_list(struct percpu_list *list)
1176
+{
1177
+ int i;
1178
+
1179
+ memset(list, 0, sizeof(*list));
1180
+ for (i = 0; i < CPU_SETSIZE; i++) {
1181
+ struct percpu_list_node *node;
1182
+
1183
+ node = malloc(sizeof(*node));
1184
+ assert(node);
1185
+ node->data = 0;
1186
+ node->next = NULL;
1187
+ list->c[i].head = node;
1188
+ }
1189
+}
1190
+
1191
+void test_membarrier_free_percpu_list(struct percpu_list *list)
1192
+{
1193
+ int i;
1194
+
1195
+ for (i = 0; i < CPU_SETSIZE; i++)
1196
+ free(list->c[i].head);
1197
+}
1198
+
1199
+static int sys_membarrier(int cmd, int flags, int cpu_id)
1200
+{
1201
+ return syscall(__NR_membarrier, cmd, flags, cpu_id);
1202
+}
1203
+
1204
+/*
1205
+ * The manager thread swaps per-cpu lists that worker threads see,
1206
+ * and validates that there are no unexpected modifications.
1207
+ */
1208
+void *test_membarrier_manager_thread(void *arg)
1209
+{
1210
+ struct test_membarrier_thread_args *args =
1211
+ (struct test_membarrier_thread_args *)arg;
1212
+ struct percpu_list list_a, list_b;
1213
+ intptr_t expect_a = 0, expect_b = 0;
1214
+ int cpu_a = 0, cpu_b = 0;
1215
+
1216
+ if (rseq_register_current_thread()) {
1217
+ fprintf(stderr, "Error: rseq_register_current_thread(...) failed(%d): %s\n",
1218
+ errno, strerror(errno));
1219
+ abort();
1220
+ }
1221
+
1222
+ /* Init lists. */
1223
+ test_membarrier_init_percpu_list(&list_a);
1224
+ test_membarrier_init_percpu_list(&list_b);
1225
+
1226
+ atomic_store(&args->percpu_list_ptr, (intptr_t)&list_a);
1227
+
1228
+ while (!atomic_load(&args->stop)) {
1229
+ /* list_a is "active". */
1230
+ cpu_a = rand() % CPU_SETSIZE;
1231
+ /*
1232
+ * As list_b is "inactive", we should never see changes
1233
+ * to list_b.
1234
+ */
1235
+ if (expect_b != atomic_load(&list_b.c[cpu_b].head->data)) {
1236
+ fprintf(stderr, "Membarrier test failed\n");
1237
+ abort();
1238
+ }
1239
+
1240
+ /* Make list_b "active". */
1241
+ atomic_store(&args->percpu_list_ptr, (intptr_t)&list_b);
1242
+ if (sys_membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ,
1243
+ MEMBARRIER_CMD_FLAG_CPU, cpu_a) &&
1244
+ errno != ENXIO /* missing CPU */) {
1245
+ perror("sys_membarrier");
1246
+ abort();
1247
+ }
1248
+ /*
1249
+ * Cpu A should now only modify list_b, so the values
1250
+ * in list_a should be stable.
1251
+ */
1252
+ expect_a = atomic_load(&list_a.c[cpu_a].head->data);
1253
+
1254
+ cpu_b = rand() % CPU_SETSIZE;
1255
+ /*
1256
+ * As list_a is "inactive", we should never see changes
1257
+ * to list_a.
1258
+ */
1259
+ if (expect_a != atomic_load(&list_a.c[cpu_a].head->data)) {
1260
+ fprintf(stderr, "Membarrier test failed\n");
1261
+ abort();
1262
+ }
1263
+
1264
+ /* Make list_a "active". */
1265
+ atomic_store(&args->percpu_list_ptr, (intptr_t)&list_a);
1266
+ if (sys_membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ,
1267
+ MEMBARRIER_CMD_FLAG_CPU, cpu_b) &&
1268
+ errno != ENXIO /* missing CPU*/) {
1269
+ perror("sys_membarrier");
1270
+ abort();
1271
+ }
1272
+ /* Remember a value from list_b. */
1273
+ expect_b = atomic_load(&list_b.c[cpu_b].head->data);
1274
+ }
1275
+
1276
+ test_membarrier_free_percpu_list(&list_a);
1277
+ test_membarrier_free_percpu_list(&list_b);
1278
+
1279
+ if (rseq_unregister_current_thread()) {
1280
+ fprintf(stderr, "Error: rseq_unregister_current_thread(...) failed(%d): %s\n",
1281
+ errno, strerror(errno));
1282
+ abort();
1283
+ }
1284
+ return NULL;
1285
+}
1286
+
1287
+/* Test MEMBARRIER_CMD_PRIVATE_RESTART_RSEQ_ON_CPU membarrier command. */
1288
+#ifdef RSEQ_ARCH_HAS_OFFSET_DEREF_ADDV
1289
+void test_membarrier(void)
1290
+{
1291
+ const int num_threads = opt_threads;
1292
+ struct test_membarrier_thread_args thread_args;
1293
+ pthread_t worker_threads[num_threads];
1294
+ pthread_t manager_thread;
1295
+ int i, ret;
1296
+
1297
+ if (sys_membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ, 0, 0)) {
1298
+ perror("sys_membarrier");
1299
+ abort();
1300
+ }
1301
+
1302
+ thread_args.stop = 0;
1303
+ thread_args.percpu_list_ptr = 0;
1304
+ ret = pthread_create(&manager_thread, NULL,
1305
+ test_membarrier_manager_thread, &thread_args);
1306
+ if (ret) {
1307
+ errno = ret;
1308
+ perror("pthread_create");
1309
+ abort();
1310
+ }
1311
+
1312
+ for (i = 0; i < num_threads; i++) {
1313
+ ret = pthread_create(&worker_threads[i], NULL,
1314
+ test_membarrier_worker_thread, &thread_args);
1315
+ if (ret) {
1316
+ errno = ret;
1317
+ perror("pthread_create");
1318
+ abort();
1319
+ }
1320
+ }
1321
+
1322
+
1323
+ for (i = 0; i < num_threads; i++) {
1324
+ ret = pthread_join(worker_threads[i], NULL);
1325
+ if (ret) {
1326
+ errno = ret;
1327
+ perror("pthread_join");
1328
+ abort();
1329
+ }
1330
+ }
1331
+
1332
+ atomic_store(&thread_args.stop, 1);
1333
+ ret = pthread_join(manager_thread, NULL);
1334
+ if (ret) {
1335
+ errno = ret;
1336
+ perror("pthread_join");
1337
+ abort();
1338
+ }
1339
+}
1340
+#else /* RSEQ_ARCH_HAS_OFFSET_DEREF_ADDV */
1341
+void test_membarrier(void)
1342
+{
1343
+ fprintf(stderr, "rseq_offset_deref_addv is not implemented on this architecture. "
1344
+ "Skipping membarrier test.\n");
1345
+}
1346
+#endif
1347
+
11341348 static void show_usage(int argc, char **argv)
11351349 {
11361350 printf("Usage : %s <OPTIONS>\n",
....@@ -1153,7 +1367,7 @@
11531367 printf(" [-r N] Number of repetitions per thread (default 5000)\n");
11541368 printf(" [-d] Disable rseq system call (no initialization)\n");
11551369 printf(" [-D M] Disable rseq for each M threads\n");
1156
- printf(" [-T test] Choose test: (s)pinlock, (l)ist, (b)uffer, (m)emcpy, (i)ncrement\n");
1370
+ printf(" [-T test] Choose test: (s)pinlock, (l)ist, (b)uffer, (m)emcpy, (i)ncrement, membarrie(r)\n");
11571371 printf(" [-M] Push into buffer and memcpy buffer with memory barriers.\n");
11581372 printf(" [-v] Verbose output.\n");
11591373 printf(" [-h] Show this help.\n");
....@@ -1268,6 +1482,7 @@
12681482 case 'i':
12691483 case 'b':
12701484 case 'm':
1485
+ case 'r':
12711486 break;
12721487 default:
12731488 show_usage(argc, argv);
....@@ -1320,6 +1535,10 @@
13201535 printf_verbose("counter increment\n");
13211536 test_percpu_inc();
13221537 break;
1538
+ case 'r':
1539
+ printf_verbose("membarrier\n");
1540
+ test_membarrier();
1541
+ break;
13231542 }
13241543 if (!opt_disable_rseq && rseq_unregister_current_thread())
13251544 abort();