18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1 28c2ecf20Sopenharmony_ci#define _GNU_SOURCE 38c2ecf20Sopenharmony_ci#include <assert.h> 48c2ecf20Sopenharmony_ci#include <linux/membarrier.h> 58c2ecf20Sopenharmony_ci#include <pthread.h> 68c2ecf20Sopenharmony_ci#include <sched.h> 78c2ecf20Sopenharmony_ci#include <stdatomic.h> 88c2ecf20Sopenharmony_ci#include <stdint.h> 98c2ecf20Sopenharmony_ci#include <stdio.h> 108c2ecf20Sopenharmony_ci#include <stdlib.h> 118c2ecf20Sopenharmony_ci#include <string.h> 128c2ecf20Sopenharmony_ci#include <syscall.h> 138c2ecf20Sopenharmony_ci#include <unistd.h> 148c2ecf20Sopenharmony_ci#include <poll.h> 158c2ecf20Sopenharmony_ci#include <sys/types.h> 168c2ecf20Sopenharmony_ci#include <signal.h> 178c2ecf20Sopenharmony_ci#include <errno.h> 188c2ecf20Sopenharmony_ci#include <stddef.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic inline pid_t rseq_gettid(void) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci return syscall(__NR_gettid); 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define NR_INJECT 9 268c2ecf20Sopenharmony_cistatic int loop_cnt[NR_INJECT + 1]; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic int loop_cnt_1 asm("asm_loop_cnt_1") __attribute__((used)); 298c2ecf20Sopenharmony_cistatic int loop_cnt_2 asm("asm_loop_cnt_2") __attribute__((used)); 308c2ecf20Sopenharmony_cistatic int loop_cnt_3 asm("asm_loop_cnt_3") __attribute__((used)); 318c2ecf20Sopenharmony_cistatic int loop_cnt_4 asm("asm_loop_cnt_4") __attribute__((used)); 328c2ecf20Sopenharmony_cistatic int loop_cnt_5 asm("asm_loop_cnt_5") __attribute__((used)); 338c2ecf20Sopenharmony_cistatic int loop_cnt_6 asm("asm_loop_cnt_6") __attribute__((used)); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int opt_modulo, verbose; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int opt_yield, opt_signal, opt_sleep, 388c2ecf20Sopenharmony_ci opt_disable_rseq, opt_threads = 200, 398c2ecf20Sopenharmony_ci opt_disable_mod = 0, opt_test = 's', opt_mb = 0; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#ifndef RSEQ_SKIP_FASTPATH 428c2ecf20Sopenharmony_cistatic long long opt_reps = 5000; 438c2ecf20Sopenharmony_ci#else 448c2ecf20Sopenharmony_cistatic long long opt_reps = 100; 458c2ecf20Sopenharmony_ci#endif 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic __thread __attribute__((tls_model("initial-exec"))) 488c2ecf20Sopenharmony_ciunsigned int signals_delivered; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#ifndef BENCHMARK 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic __thread __attribute__((tls_model("initial-exec"), unused)) 538c2ecf20Sopenharmony_ciunsigned int yield_mod_cnt, nr_abort; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define printf_verbose(fmt, ...) \ 568c2ecf20Sopenharmony_ci do { \ 578c2ecf20Sopenharmony_ci if (verbose) \ 588c2ecf20Sopenharmony_ci printf(fmt, ## __VA_ARGS__); \ 598c2ecf20Sopenharmony_ci } while (0) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#ifdef __i386__ 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define INJECT_ASM_REG "eax" 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define RSEQ_INJECT_CLOBBER \ 668c2ecf20Sopenharmony_ci , INJECT_ASM_REG 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define RSEQ_INJECT_ASM(n) \ 698c2ecf20Sopenharmony_ci "mov asm_loop_cnt_" #n ", %%" INJECT_ASM_REG "\n\t" \ 708c2ecf20Sopenharmony_ci "test %%" INJECT_ASM_REG ",%%" INJECT_ASM_REG "\n\t" \ 718c2ecf20Sopenharmony_ci "jz 333f\n\t" \ 728c2ecf20Sopenharmony_ci "222:\n\t" \ 738c2ecf20Sopenharmony_ci "dec %%" INJECT_ASM_REG "\n\t" \ 748c2ecf20Sopenharmony_ci "jnz 222b\n\t" \ 758c2ecf20Sopenharmony_ci "333:\n\t" 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#elif defined(__x86_64__) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define INJECT_ASM_REG_P "rax" 808c2ecf20Sopenharmony_ci#define INJECT_ASM_REG "eax" 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define RSEQ_INJECT_CLOBBER \ 838c2ecf20Sopenharmony_ci , INJECT_ASM_REG_P \ 848c2ecf20Sopenharmony_ci , INJECT_ASM_REG 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define RSEQ_INJECT_ASM(n) \ 878c2ecf20Sopenharmony_ci "lea asm_loop_cnt_" #n "(%%rip), %%" INJECT_ASM_REG_P "\n\t" \ 888c2ecf20Sopenharmony_ci "mov (%%" INJECT_ASM_REG_P "), %%" INJECT_ASM_REG "\n\t" \ 898c2ecf20Sopenharmony_ci "test %%" INJECT_ASM_REG ",%%" INJECT_ASM_REG "\n\t" \ 908c2ecf20Sopenharmony_ci "jz 333f\n\t" \ 918c2ecf20Sopenharmony_ci "222:\n\t" \ 928c2ecf20Sopenharmony_ci "dec %%" INJECT_ASM_REG "\n\t" \ 938c2ecf20Sopenharmony_ci "jnz 222b\n\t" \ 948c2ecf20Sopenharmony_ci "333:\n\t" 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#elif defined(__s390__) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#define RSEQ_INJECT_INPUT \ 998c2ecf20Sopenharmony_ci , [loop_cnt_1]"m"(loop_cnt[1]) \ 1008c2ecf20Sopenharmony_ci , [loop_cnt_2]"m"(loop_cnt[2]) \ 1018c2ecf20Sopenharmony_ci , [loop_cnt_3]"m"(loop_cnt[3]) \ 1028c2ecf20Sopenharmony_ci , [loop_cnt_4]"m"(loop_cnt[4]) \ 1038c2ecf20Sopenharmony_ci , [loop_cnt_5]"m"(loop_cnt[5]) \ 1048c2ecf20Sopenharmony_ci , [loop_cnt_6]"m"(loop_cnt[6]) 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#define INJECT_ASM_REG "r12" 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#define RSEQ_INJECT_CLOBBER \ 1098c2ecf20Sopenharmony_ci , INJECT_ASM_REG 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci#define RSEQ_INJECT_ASM(n) \ 1128c2ecf20Sopenharmony_ci "l %%" INJECT_ASM_REG ", %[loop_cnt_" #n "]\n\t" \ 1138c2ecf20Sopenharmony_ci "ltr %%" INJECT_ASM_REG ", %%" INJECT_ASM_REG "\n\t" \ 1148c2ecf20Sopenharmony_ci "je 333f\n\t" \ 1158c2ecf20Sopenharmony_ci "222:\n\t" \ 1168c2ecf20Sopenharmony_ci "ahi %%" INJECT_ASM_REG ", -1\n\t" \ 1178c2ecf20Sopenharmony_ci "jnz 222b\n\t" \ 1188c2ecf20Sopenharmony_ci "333:\n\t" 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci#elif defined(__ARMEL__) 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define RSEQ_INJECT_INPUT \ 1238c2ecf20Sopenharmony_ci , [loop_cnt_1]"m"(loop_cnt[1]) \ 1248c2ecf20Sopenharmony_ci , [loop_cnt_2]"m"(loop_cnt[2]) \ 1258c2ecf20Sopenharmony_ci , [loop_cnt_3]"m"(loop_cnt[3]) \ 1268c2ecf20Sopenharmony_ci , [loop_cnt_4]"m"(loop_cnt[4]) \ 1278c2ecf20Sopenharmony_ci , [loop_cnt_5]"m"(loop_cnt[5]) \ 1288c2ecf20Sopenharmony_ci , [loop_cnt_6]"m"(loop_cnt[6]) 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#define INJECT_ASM_REG "r4" 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci#define RSEQ_INJECT_CLOBBER \ 1338c2ecf20Sopenharmony_ci , INJECT_ASM_REG 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci#define RSEQ_INJECT_ASM(n) \ 1368c2ecf20Sopenharmony_ci "ldr " INJECT_ASM_REG ", %[loop_cnt_" #n "]\n\t" \ 1378c2ecf20Sopenharmony_ci "cmp " INJECT_ASM_REG ", #0\n\t" \ 1388c2ecf20Sopenharmony_ci "beq 333f\n\t" \ 1398c2ecf20Sopenharmony_ci "222:\n\t" \ 1408c2ecf20Sopenharmony_ci "subs " INJECT_ASM_REG ", #1\n\t" \ 1418c2ecf20Sopenharmony_ci "bne 222b\n\t" \ 1428c2ecf20Sopenharmony_ci "333:\n\t" 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci#elif defined(__AARCH64EL__) 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci#define RSEQ_INJECT_INPUT \ 1478c2ecf20Sopenharmony_ci , [loop_cnt_1] "Qo" (loop_cnt[1]) \ 1488c2ecf20Sopenharmony_ci , [loop_cnt_2] "Qo" (loop_cnt[2]) \ 1498c2ecf20Sopenharmony_ci , [loop_cnt_3] "Qo" (loop_cnt[3]) \ 1508c2ecf20Sopenharmony_ci , [loop_cnt_4] "Qo" (loop_cnt[4]) \ 1518c2ecf20Sopenharmony_ci , [loop_cnt_5] "Qo" (loop_cnt[5]) \ 1528c2ecf20Sopenharmony_ci , [loop_cnt_6] "Qo" (loop_cnt[6]) 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci#define INJECT_ASM_REG RSEQ_ASM_TMP_REG32 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci#define RSEQ_INJECT_ASM(n) \ 1578c2ecf20Sopenharmony_ci " ldr " INJECT_ASM_REG ", %[loop_cnt_" #n "]\n" \ 1588c2ecf20Sopenharmony_ci " cbz " INJECT_ASM_REG ", 333f\n" \ 1598c2ecf20Sopenharmony_ci "222:\n" \ 1608c2ecf20Sopenharmony_ci " sub " INJECT_ASM_REG ", " INJECT_ASM_REG ", #1\n" \ 1618c2ecf20Sopenharmony_ci " cbnz " INJECT_ASM_REG ", 222b\n" \ 1628c2ecf20Sopenharmony_ci "333:\n" 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci#elif defined(__PPC__) 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#define RSEQ_INJECT_INPUT \ 1678c2ecf20Sopenharmony_ci , [loop_cnt_1]"m"(loop_cnt[1]) \ 1688c2ecf20Sopenharmony_ci , [loop_cnt_2]"m"(loop_cnt[2]) \ 1698c2ecf20Sopenharmony_ci , [loop_cnt_3]"m"(loop_cnt[3]) \ 1708c2ecf20Sopenharmony_ci , [loop_cnt_4]"m"(loop_cnt[4]) \ 1718c2ecf20Sopenharmony_ci , [loop_cnt_5]"m"(loop_cnt[5]) \ 1728c2ecf20Sopenharmony_ci , [loop_cnt_6]"m"(loop_cnt[6]) 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci#define INJECT_ASM_REG "r18" 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#define RSEQ_INJECT_CLOBBER \ 1778c2ecf20Sopenharmony_ci , INJECT_ASM_REG 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci#define RSEQ_INJECT_ASM(n) \ 1808c2ecf20Sopenharmony_ci "lwz %%" INJECT_ASM_REG ", %[loop_cnt_" #n "]\n\t" \ 1818c2ecf20Sopenharmony_ci "cmpwi %%" INJECT_ASM_REG ", 0\n\t" \ 1828c2ecf20Sopenharmony_ci "beq 333f\n\t" \ 1838c2ecf20Sopenharmony_ci "222:\n\t" \ 1848c2ecf20Sopenharmony_ci "subic. %%" INJECT_ASM_REG ", %%" INJECT_ASM_REG ", 1\n\t" \ 1858c2ecf20Sopenharmony_ci "bne 222b\n\t" \ 1868c2ecf20Sopenharmony_ci "333:\n\t" 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#elif defined(__mips__) 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#define RSEQ_INJECT_INPUT \ 1918c2ecf20Sopenharmony_ci , [loop_cnt_1]"m"(loop_cnt[1]) \ 1928c2ecf20Sopenharmony_ci , [loop_cnt_2]"m"(loop_cnt[2]) \ 1938c2ecf20Sopenharmony_ci , [loop_cnt_3]"m"(loop_cnt[3]) \ 1948c2ecf20Sopenharmony_ci , [loop_cnt_4]"m"(loop_cnt[4]) \ 1958c2ecf20Sopenharmony_ci , [loop_cnt_5]"m"(loop_cnt[5]) \ 1968c2ecf20Sopenharmony_ci , [loop_cnt_6]"m"(loop_cnt[6]) 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci#define INJECT_ASM_REG "$5" 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci#define RSEQ_INJECT_CLOBBER \ 2018c2ecf20Sopenharmony_ci , INJECT_ASM_REG 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci#define RSEQ_INJECT_ASM(n) \ 2048c2ecf20Sopenharmony_ci "lw " INJECT_ASM_REG ", %[loop_cnt_" #n "]\n\t" \ 2058c2ecf20Sopenharmony_ci "beqz " INJECT_ASM_REG ", 333f\n\t" \ 2068c2ecf20Sopenharmony_ci "222:\n\t" \ 2078c2ecf20Sopenharmony_ci "addiu " INJECT_ASM_REG ", -1\n\t" \ 2088c2ecf20Sopenharmony_ci "bnez " INJECT_ASM_REG ", 222b\n\t" \ 2098c2ecf20Sopenharmony_ci "333:\n\t" 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci#else 2128c2ecf20Sopenharmony_ci#error unsupported target 2138c2ecf20Sopenharmony_ci#endif 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci#define RSEQ_INJECT_FAILED \ 2168c2ecf20Sopenharmony_ci nr_abort++; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci#define RSEQ_INJECT_C(n) \ 2198c2ecf20Sopenharmony_ci{ \ 2208c2ecf20Sopenharmony_ci int loc_i, loc_nr_loops = loop_cnt[n]; \ 2218c2ecf20Sopenharmony_ci \ 2228c2ecf20Sopenharmony_ci for (loc_i = 0; loc_i < loc_nr_loops; loc_i++) { \ 2238c2ecf20Sopenharmony_ci rseq_barrier(); \ 2248c2ecf20Sopenharmony_ci } \ 2258c2ecf20Sopenharmony_ci if (loc_nr_loops == -1 && opt_modulo) { \ 2268c2ecf20Sopenharmony_ci if (yield_mod_cnt == opt_modulo - 1) { \ 2278c2ecf20Sopenharmony_ci if (opt_sleep > 0) \ 2288c2ecf20Sopenharmony_ci poll(NULL, 0, opt_sleep); \ 2298c2ecf20Sopenharmony_ci if (opt_yield) \ 2308c2ecf20Sopenharmony_ci sched_yield(); \ 2318c2ecf20Sopenharmony_ci if (opt_signal) \ 2328c2ecf20Sopenharmony_ci raise(SIGUSR1); \ 2338c2ecf20Sopenharmony_ci yield_mod_cnt = 0; \ 2348c2ecf20Sopenharmony_ci } else { \ 2358c2ecf20Sopenharmony_ci yield_mod_cnt++; \ 2368c2ecf20Sopenharmony_ci } \ 2378c2ecf20Sopenharmony_ci } \ 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#else 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci#define printf_verbose(fmt, ...) 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci#endif /* BENCHMARK */ 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci#include "rseq.h" 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistruct percpu_lock_entry { 2498c2ecf20Sopenharmony_ci intptr_t v; 2508c2ecf20Sopenharmony_ci} __attribute__((aligned(128))); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistruct percpu_lock { 2538c2ecf20Sopenharmony_ci struct percpu_lock_entry c[CPU_SETSIZE]; 2548c2ecf20Sopenharmony_ci}; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistruct test_data_entry { 2578c2ecf20Sopenharmony_ci intptr_t count; 2588c2ecf20Sopenharmony_ci} __attribute__((aligned(128))); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistruct spinlock_test_data { 2618c2ecf20Sopenharmony_ci struct percpu_lock lock; 2628c2ecf20Sopenharmony_ci struct test_data_entry c[CPU_SETSIZE]; 2638c2ecf20Sopenharmony_ci}; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistruct spinlock_thread_test_data { 2668c2ecf20Sopenharmony_ci struct spinlock_test_data *data; 2678c2ecf20Sopenharmony_ci long long reps; 2688c2ecf20Sopenharmony_ci int reg; 2698c2ecf20Sopenharmony_ci}; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistruct inc_test_data { 2728c2ecf20Sopenharmony_ci struct test_data_entry c[CPU_SETSIZE]; 2738c2ecf20Sopenharmony_ci}; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistruct inc_thread_test_data { 2768c2ecf20Sopenharmony_ci struct inc_test_data *data; 2778c2ecf20Sopenharmony_ci long long reps; 2788c2ecf20Sopenharmony_ci int reg; 2798c2ecf20Sopenharmony_ci}; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistruct percpu_list_node { 2828c2ecf20Sopenharmony_ci intptr_t data; 2838c2ecf20Sopenharmony_ci struct percpu_list_node *next; 2848c2ecf20Sopenharmony_ci}; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistruct percpu_list_entry { 2878c2ecf20Sopenharmony_ci struct percpu_list_node *head; 2888c2ecf20Sopenharmony_ci} __attribute__((aligned(128))); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistruct percpu_list { 2918c2ecf20Sopenharmony_ci struct percpu_list_entry c[CPU_SETSIZE]; 2928c2ecf20Sopenharmony_ci}; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci#define BUFFER_ITEM_PER_CPU 100 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistruct percpu_buffer_node { 2978c2ecf20Sopenharmony_ci intptr_t data; 2988c2ecf20Sopenharmony_ci}; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistruct percpu_buffer_entry { 3018c2ecf20Sopenharmony_ci intptr_t offset; 3028c2ecf20Sopenharmony_ci intptr_t buflen; 3038c2ecf20Sopenharmony_ci struct percpu_buffer_node **array; 3048c2ecf20Sopenharmony_ci} __attribute__((aligned(128))); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistruct percpu_buffer { 3078c2ecf20Sopenharmony_ci struct percpu_buffer_entry c[CPU_SETSIZE]; 3088c2ecf20Sopenharmony_ci}; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci#define MEMCPY_BUFFER_ITEM_PER_CPU 100 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistruct percpu_memcpy_buffer_node { 3138c2ecf20Sopenharmony_ci intptr_t data1; 3148c2ecf20Sopenharmony_ci uint64_t data2; 3158c2ecf20Sopenharmony_ci}; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistruct percpu_memcpy_buffer_entry { 3188c2ecf20Sopenharmony_ci intptr_t offset; 3198c2ecf20Sopenharmony_ci intptr_t buflen; 3208c2ecf20Sopenharmony_ci struct percpu_memcpy_buffer_node *array; 3218c2ecf20Sopenharmony_ci} __attribute__((aligned(128))); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistruct percpu_memcpy_buffer { 3248c2ecf20Sopenharmony_ci struct percpu_memcpy_buffer_entry c[CPU_SETSIZE]; 3258c2ecf20Sopenharmony_ci}; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci/* A simple percpu spinlock. Grabs lock on current cpu. */ 3288c2ecf20Sopenharmony_cistatic int rseq_this_cpu_lock(struct percpu_lock *lock) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci int cpu; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci for (;;) { 3338c2ecf20Sopenharmony_ci int ret; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci cpu = rseq_cpu_start(); 3368c2ecf20Sopenharmony_ci ret = rseq_cmpeqv_storev(&lock->c[cpu].v, 3378c2ecf20Sopenharmony_ci 0, 1, cpu); 3388c2ecf20Sopenharmony_ci if (rseq_likely(!ret)) 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci /* Retry if comparison fails or rseq aborts. */ 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci /* 3438c2ecf20Sopenharmony_ci * Acquire semantic when taking lock after control dependency. 3448c2ecf20Sopenharmony_ci * Matches rseq_smp_store_release(). 3458c2ecf20Sopenharmony_ci */ 3468c2ecf20Sopenharmony_ci rseq_smp_acquire__after_ctrl_dep(); 3478c2ecf20Sopenharmony_ci return cpu; 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic void rseq_percpu_unlock(struct percpu_lock *lock, int cpu) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci assert(lock->c[cpu].v == 1); 3538c2ecf20Sopenharmony_ci /* 3548c2ecf20Sopenharmony_ci * Release lock, with release semantic. Matches 3558c2ecf20Sopenharmony_ci * rseq_smp_acquire__after_ctrl_dep(). 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci rseq_smp_store_release(&lock->c[cpu].v, 0); 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_civoid *test_percpu_spinlock_thread(void *arg) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct spinlock_thread_test_data *thread_data = arg; 3638c2ecf20Sopenharmony_ci struct spinlock_test_data *data = thread_data->data; 3648c2ecf20Sopenharmony_ci long long i, reps; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (!opt_disable_rseq && thread_data->reg && 3678c2ecf20Sopenharmony_ci rseq_register_current_thread()) 3688c2ecf20Sopenharmony_ci abort(); 3698c2ecf20Sopenharmony_ci reps = thread_data->reps; 3708c2ecf20Sopenharmony_ci for (i = 0; i < reps; i++) { 3718c2ecf20Sopenharmony_ci int cpu = rseq_this_cpu_lock(&data->lock); 3728c2ecf20Sopenharmony_ci data->c[cpu].count++; 3738c2ecf20Sopenharmony_ci rseq_percpu_unlock(&data->lock, cpu); 3748c2ecf20Sopenharmony_ci#ifndef BENCHMARK 3758c2ecf20Sopenharmony_ci if (i != 0 && !(i % (reps / 10))) 3768c2ecf20Sopenharmony_ci printf_verbose("tid %d: count %lld\n", 3778c2ecf20Sopenharmony_ci (int) rseq_gettid(), i); 3788c2ecf20Sopenharmony_ci#endif 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n", 3818c2ecf20Sopenharmony_ci (int) rseq_gettid(), nr_abort, signals_delivered); 3828c2ecf20Sopenharmony_ci if (!opt_disable_rseq && thread_data->reg && 3838c2ecf20Sopenharmony_ci rseq_unregister_current_thread()) 3848c2ecf20Sopenharmony_ci abort(); 3858c2ecf20Sopenharmony_ci return NULL; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci/* 3898c2ecf20Sopenharmony_ci * A simple test which implements a sharded counter using a per-cpu 3908c2ecf20Sopenharmony_ci * lock. Obviously real applications might prefer to simply use a 3918c2ecf20Sopenharmony_ci * per-cpu increment; however, this is reasonable for a test and the 3928c2ecf20Sopenharmony_ci * lock can be extended to synchronize more complicated operations. 3938c2ecf20Sopenharmony_ci */ 3948c2ecf20Sopenharmony_civoid test_percpu_spinlock(void) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci const int num_threads = opt_threads; 3978c2ecf20Sopenharmony_ci int i, ret; 3988c2ecf20Sopenharmony_ci uint64_t sum; 3998c2ecf20Sopenharmony_ci pthread_t test_threads[num_threads]; 4008c2ecf20Sopenharmony_ci struct spinlock_test_data data; 4018c2ecf20Sopenharmony_ci struct spinlock_thread_test_data thread_data[num_threads]; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci memset(&data, 0, sizeof(data)); 4048c2ecf20Sopenharmony_ci for (i = 0; i < num_threads; i++) { 4058c2ecf20Sopenharmony_ci thread_data[i].reps = opt_reps; 4068c2ecf20Sopenharmony_ci if (opt_disable_mod <= 0 || (i % opt_disable_mod)) 4078c2ecf20Sopenharmony_ci thread_data[i].reg = 1; 4088c2ecf20Sopenharmony_ci else 4098c2ecf20Sopenharmony_ci thread_data[i].reg = 0; 4108c2ecf20Sopenharmony_ci thread_data[i].data = &data; 4118c2ecf20Sopenharmony_ci ret = pthread_create(&test_threads[i], NULL, 4128c2ecf20Sopenharmony_ci test_percpu_spinlock_thread, 4138c2ecf20Sopenharmony_ci &thread_data[i]); 4148c2ecf20Sopenharmony_ci if (ret) { 4158c2ecf20Sopenharmony_ci errno = ret; 4168c2ecf20Sopenharmony_ci perror("pthread_create"); 4178c2ecf20Sopenharmony_ci abort(); 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci for (i = 0; i < num_threads; i++) { 4228c2ecf20Sopenharmony_ci ret = pthread_join(test_threads[i], NULL); 4238c2ecf20Sopenharmony_ci if (ret) { 4248c2ecf20Sopenharmony_ci errno = ret; 4258c2ecf20Sopenharmony_ci perror("pthread_join"); 4268c2ecf20Sopenharmony_ci abort(); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci sum = 0; 4318c2ecf20Sopenharmony_ci for (i = 0; i < CPU_SETSIZE; i++) 4328c2ecf20Sopenharmony_ci sum += data.c[i].count; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci assert(sum == (uint64_t)opt_reps * num_threads); 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_civoid *test_percpu_inc_thread(void *arg) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct inc_thread_test_data *thread_data = arg; 4408c2ecf20Sopenharmony_ci struct inc_test_data *data = thread_data->data; 4418c2ecf20Sopenharmony_ci long long i, reps; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (!opt_disable_rseq && thread_data->reg && 4448c2ecf20Sopenharmony_ci rseq_register_current_thread()) 4458c2ecf20Sopenharmony_ci abort(); 4468c2ecf20Sopenharmony_ci reps = thread_data->reps; 4478c2ecf20Sopenharmony_ci for (i = 0; i < reps; i++) { 4488c2ecf20Sopenharmony_ci int ret; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci do { 4518c2ecf20Sopenharmony_ci int cpu; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci cpu = rseq_cpu_start(); 4548c2ecf20Sopenharmony_ci ret = rseq_addv(&data->c[cpu].count, 1, cpu); 4558c2ecf20Sopenharmony_ci } while (rseq_unlikely(ret)); 4568c2ecf20Sopenharmony_ci#ifndef BENCHMARK 4578c2ecf20Sopenharmony_ci if (i != 0 && !(i % (reps / 10))) 4588c2ecf20Sopenharmony_ci printf_verbose("tid %d: count %lld\n", 4598c2ecf20Sopenharmony_ci (int) rseq_gettid(), i); 4608c2ecf20Sopenharmony_ci#endif 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n", 4638c2ecf20Sopenharmony_ci (int) rseq_gettid(), nr_abort, signals_delivered); 4648c2ecf20Sopenharmony_ci if (!opt_disable_rseq && thread_data->reg && 4658c2ecf20Sopenharmony_ci rseq_unregister_current_thread()) 4668c2ecf20Sopenharmony_ci abort(); 4678c2ecf20Sopenharmony_ci return NULL; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_civoid test_percpu_inc(void) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci const int num_threads = opt_threads; 4738c2ecf20Sopenharmony_ci int i, ret; 4748c2ecf20Sopenharmony_ci uint64_t sum; 4758c2ecf20Sopenharmony_ci pthread_t test_threads[num_threads]; 4768c2ecf20Sopenharmony_ci struct inc_test_data data; 4778c2ecf20Sopenharmony_ci struct inc_thread_test_data thread_data[num_threads]; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci memset(&data, 0, sizeof(data)); 4808c2ecf20Sopenharmony_ci for (i = 0; i < num_threads; i++) { 4818c2ecf20Sopenharmony_ci thread_data[i].reps = opt_reps; 4828c2ecf20Sopenharmony_ci if (opt_disable_mod <= 0 || (i % opt_disable_mod)) 4838c2ecf20Sopenharmony_ci thread_data[i].reg = 1; 4848c2ecf20Sopenharmony_ci else 4858c2ecf20Sopenharmony_ci thread_data[i].reg = 0; 4868c2ecf20Sopenharmony_ci thread_data[i].data = &data; 4878c2ecf20Sopenharmony_ci ret = pthread_create(&test_threads[i], NULL, 4888c2ecf20Sopenharmony_ci test_percpu_inc_thread, 4898c2ecf20Sopenharmony_ci &thread_data[i]); 4908c2ecf20Sopenharmony_ci if (ret) { 4918c2ecf20Sopenharmony_ci errno = ret; 4928c2ecf20Sopenharmony_ci perror("pthread_create"); 4938c2ecf20Sopenharmony_ci abort(); 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci for (i = 0; i < num_threads; i++) { 4988c2ecf20Sopenharmony_ci ret = pthread_join(test_threads[i], NULL); 4998c2ecf20Sopenharmony_ci if (ret) { 5008c2ecf20Sopenharmony_ci errno = ret; 5018c2ecf20Sopenharmony_ci perror("pthread_join"); 5028c2ecf20Sopenharmony_ci abort(); 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci sum = 0; 5078c2ecf20Sopenharmony_ci for (i = 0; i < CPU_SETSIZE; i++) 5088c2ecf20Sopenharmony_ci sum += data.c[i].count; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci assert(sum == (uint64_t)opt_reps * num_threads); 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_civoid this_cpu_list_push(struct percpu_list *list, 5148c2ecf20Sopenharmony_ci struct percpu_list_node *node, 5158c2ecf20Sopenharmony_ci int *_cpu) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci int cpu; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci for (;;) { 5208c2ecf20Sopenharmony_ci intptr_t *targetptr, newval, expect; 5218c2ecf20Sopenharmony_ci int ret; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci cpu = rseq_cpu_start(); 5248c2ecf20Sopenharmony_ci /* Load list->c[cpu].head with single-copy atomicity. */ 5258c2ecf20Sopenharmony_ci expect = (intptr_t)RSEQ_READ_ONCE(list->c[cpu].head); 5268c2ecf20Sopenharmony_ci newval = (intptr_t)node; 5278c2ecf20Sopenharmony_ci targetptr = (intptr_t *)&list->c[cpu].head; 5288c2ecf20Sopenharmony_ci node->next = (struct percpu_list_node *)expect; 5298c2ecf20Sopenharmony_ci ret = rseq_cmpeqv_storev(targetptr, expect, newval, cpu); 5308c2ecf20Sopenharmony_ci if (rseq_likely(!ret)) 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci /* Retry if comparison fails or rseq aborts. */ 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci if (_cpu) 5358c2ecf20Sopenharmony_ci *_cpu = cpu; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci/* 5398c2ecf20Sopenharmony_ci * Unlike a traditional lock-less linked list; the availability of a 5408c2ecf20Sopenharmony_ci * rseq primitive allows us to implement pop without concerns over 5418c2ecf20Sopenharmony_ci * ABA-type races. 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_cistruct percpu_list_node *this_cpu_list_pop(struct percpu_list *list, 5448c2ecf20Sopenharmony_ci int *_cpu) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct percpu_list_node *node = NULL; 5478c2ecf20Sopenharmony_ci int cpu; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci for (;;) { 5508c2ecf20Sopenharmony_ci struct percpu_list_node *head; 5518c2ecf20Sopenharmony_ci intptr_t *targetptr, expectnot, *load; 5528c2ecf20Sopenharmony_ci long offset; 5538c2ecf20Sopenharmony_ci int ret; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci cpu = rseq_cpu_start(); 5568c2ecf20Sopenharmony_ci targetptr = (intptr_t *)&list->c[cpu].head; 5578c2ecf20Sopenharmony_ci expectnot = (intptr_t)NULL; 5588c2ecf20Sopenharmony_ci offset = offsetof(struct percpu_list_node, next); 5598c2ecf20Sopenharmony_ci load = (intptr_t *)&head; 5608c2ecf20Sopenharmony_ci ret = rseq_cmpnev_storeoffp_load(targetptr, expectnot, 5618c2ecf20Sopenharmony_ci offset, load, cpu); 5628c2ecf20Sopenharmony_ci if (rseq_likely(!ret)) { 5638c2ecf20Sopenharmony_ci node = head; 5648c2ecf20Sopenharmony_ci break; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci if (ret > 0) 5678c2ecf20Sopenharmony_ci break; 5688c2ecf20Sopenharmony_ci /* Retry if rseq aborts. */ 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci if (_cpu) 5718c2ecf20Sopenharmony_ci *_cpu = cpu; 5728c2ecf20Sopenharmony_ci return node; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci/* 5768c2ecf20Sopenharmony_ci * __percpu_list_pop is not safe against concurrent accesses. Should 5778c2ecf20Sopenharmony_ci * only be used on lists that are not concurrently modified. 5788c2ecf20Sopenharmony_ci */ 5798c2ecf20Sopenharmony_cistruct percpu_list_node *__percpu_list_pop(struct percpu_list *list, int cpu) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct percpu_list_node *node; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci node = list->c[cpu].head; 5848c2ecf20Sopenharmony_ci if (!node) 5858c2ecf20Sopenharmony_ci return NULL; 5868c2ecf20Sopenharmony_ci list->c[cpu].head = node->next; 5878c2ecf20Sopenharmony_ci return node; 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_civoid *test_percpu_list_thread(void *arg) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci long long i, reps; 5938c2ecf20Sopenharmony_ci struct percpu_list *list = (struct percpu_list *)arg; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (!opt_disable_rseq && rseq_register_current_thread()) 5968c2ecf20Sopenharmony_ci abort(); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci reps = opt_reps; 5998c2ecf20Sopenharmony_ci for (i = 0; i < reps; i++) { 6008c2ecf20Sopenharmony_ci struct percpu_list_node *node; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci node = this_cpu_list_pop(list, NULL); 6038c2ecf20Sopenharmony_ci if (opt_yield) 6048c2ecf20Sopenharmony_ci sched_yield(); /* encourage shuffling */ 6058c2ecf20Sopenharmony_ci if (node) 6068c2ecf20Sopenharmony_ci this_cpu_list_push(list, node, NULL); 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n", 6108c2ecf20Sopenharmony_ci (int) rseq_gettid(), nr_abort, signals_delivered); 6118c2ecf20Sopenharmony_ci if (!opt_disable_rseq && rseq_unregister_current_thread()) 6128c2ecf20Sopenharmony_ci abort(); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci return NULL; 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci/* Simultaneous modification to a per-cpu linked list from many threads. */ 6188c2ecf20Sopenharmony_civoid test_percpu_list(void) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci const int num_threads = opt_threads; 6218c2ecf20Sopenharmony_ci int i, j, ret; 6228c2ecf20Sopenharmony_ci uint64_t sum = 0, expected_sum = 0; 6238c2ecf20Sopenharmony_ci struct percpu_list list; 6248c2ecf20Sopenharmony_ci pthread_t test_threads[num_threads]; 6258c2ecf20Sopenharmony_ci cpu_set_t allowed_cpus; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci memset(&list, 0, sizeof(list)); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* Generate list entries for every usable cpu. */ 6308c2ecf20Sopenharmony_ci sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus); 6318c2ecf20Sopenharmony_ci for (i = 0; i < CPU_SETSIZE; i++) { 6328c2ecf20Sopenharmony_ci if (!CPU_ISSET(i, &allowed_cpus)) 6338c2ecf20Sopenharmony_ci continue; 6348c2ecf20Sopenharmony_ci for (j = 1; j <= 100; j++) { 6358c2ecf20Sopenharmony_ci struct percpu_list_node *node; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci expected_sum += j; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci node = malloc(sizeof(*node)); 6408c2ecf20Sopenharmony_ci assert(node); 6418c2ecf20Sopenharmony_ci node->data = j; 6428c2ecf20Sopenharmony_ci node->next = list.c[i].head; 6438c2ecf20Sopenharmony_ci list.c[i].head = node; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci for (i = 0; i < num_threads; i++) { 6488c2ecf20Sopenharmony_ci ret = pthread_create(&test_threads[i], NULL, 6498c2ecf20Sopenharmony_ci test_percpu_list_thread, &list); 6508c2ecf20Sopenharmony_ci if (ret) { 6518c2ecf20Sopenharmony_ci errno = ret; 6528c2ecf20Sopenharmony_ci perror("pthread_create"); 6538c2ecf20Sopenharmony_ci abort(); 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci for (i = 0; i < num_threads; i++) { 6588c2ecf20Sopenharmony_ci ret = pthread_join(test_threads[i], NULL); 6598c2ecf20Sopenharmony_ci if (ret) { 6608c2ecf20Sopenharmony_ci errno = ret; 6618c2ecf20Sopenharmony_ci perror("pthread_join"); 6628c2ecf20Sopenharmony_ci abort(); 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci for (i = 0; i < CPU_SETSIZE; i++) { 6678c2ecf20Sopenharmony_ci struct percpu_list_node *node; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (!CPU_ISSET(i, &allowed_cpus)) 6708c2ecf20Sopenharmony_ci continue; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci while ((node = __percpu_list_pop(&list, i))) { 6738c2ecf20Sopenharmony_ci sum += node->data; 6748c2ecf20Sopenharmony_ci free(node); 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci /* 6798c2ecf20Sopenharmony_ci * All entries should now be accounted for (unless some external 6808c2ecf20Sopenharmony_ci * actor is interfering with our allowed affinity while this 6818c2ecf20Sopenharmony_ci * test is running). 6828c2ecf20Sopenharmony_ci */ 6838c2ecf20Sopenharmony_ci assert(sum == expected_sum); 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cibool this_cpu_buffer_push(struct percpu_buffer *buffer, 6878c2ecf20Sopenharmony_ci struct percpu_buffer_node *node, 6888c2ecf20Sopenharmony_ci int *_cpu) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci bool result = false; 6918c2ecf20Sopenharmony_ci int cpu; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci for (;;) { 6948c2ecf20Sopenharmony_ci intptr_t *targetptr_spec, newval_spec; 6958c2ecf20Sopenharmony_ci intptr_t *targetptr_final, newval_final; 6968c2ecf20Sopenharmony_ci intptr_t offset; 6978c2ecf20Sopenharmony_ci int ret; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci cpu = rseq_cpu_start(); 7008c2ecf20Sopenharmony_ci offset = RSEQ_READ_ONCE(buffer->c[cpu].offset); 7018c2ecf20Sopenharmony_ci if (offset == buffer->c[cpu].buflen) 7028c2ecf20Sopenharmony_ci break; 7038c2ecf20Sopenharmony_ci newval_spec = (intptr_t)node; 7048c2ecf20Sopenharmony_ci targetptr_spec = (intptr_t *)&buffer->c[cpu].array[offset]; 7058c2ecf20Sopenharmony_ci newval_final = offset + 1; 7068c2ecf20Sopenharmony_ci targetptr_final = &buffer->c[cpu].offset; 7078c2ecf20Sopenharmony_ci if (opt_mb) 7088c2ecf20Sopenharmony_ci ret = rseq_cmpeqv_trystorev_storev_release( 7098c2ecf20Sopenharmony_ci targetptr_final, offset, targetptr_spec, 7108c2ecf20Sopenharmony_ci newval_spec, newval_final, cpu); 7118c2ecf20Sopenharmony_ci else 7128c2ecf20Sopenharmony_ci ret = rseq_cmpeqv_trystorev_storev(targetptr_final, 7138c2ecf20Sopenharmony_ci offset, targetptr_spec, newval_spec, 7148c2ecf20Sopenharmony_ci newval_final, cpu); 7158c2ecf20Sopenharmony_ci if (rseq_likely(!ret)) { 7168c2ecf20Sopenharmony_ci result = true; 7178c2ecf20Sopenharmony_ci break; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci /* Retry if comparison fails or rseq aborts. */ 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci if (_cpu) 7228c2ecf20Sopenharmony_ci *_cpu = cpu; 7238c2ecf20Sopenharmony_ci return result; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistruct percpu_buffer_node *this_cpu_buffer_pop(struct percpu_buffer *buffer, 7278c2ecf20Sopenharmony_ci int *_cpu) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci struct percpu_buffer_node *head; 7308c2ecf20Sopenharmony_ci int cpu; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci for (;;) { 7338c2ecf20Sopenharmony_ci intptr_t *targetptr, newval; 7348c2ecf20Sopenharmony_ci intptr_t offset; 7358c2ecf20Sopenharmony_ci int ret; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci cpu = rseq_cpu_start(); 7388c2ecf20Sopenharmony_ci /* Load offset with single-copy atomicity. */ 7398c2ecf20Sopenharmony_ci offset = RSEQ_READ_ONCE(buffer->c[cpu].offset); 7408c2ecf20Sopenharmony_ci if (offset == 0) { 7418c2ecf20Sopenharmony_ci head = NULL; 7428c2ecf20Sopenharmony_ci break; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci head = RSEQ_READ_ONCE(buffer->c[cpu].array[offset - 1]); 7458c2ecf20Sopenharmony_ci newval = offset - 1; 7468c2ecf20Sopenharmony_ci targetptr = (intptr_t *)&buffer->c[cpu].offset; 7478c2ecf20Sopenharmony_ci ret = rseq_cmpeqv_cmpeqv_storev(targetptr, offset, 7488c2ecf20Sopenharmony_ci (intptr_t *)&buffer->c[cpu].array[offset - 1], 7498c2ecf20Sopenharmony_ci (intptr_t)head, newval, cpu); 7508c2ecf20Sopenharmony_ci if (rseq_likely(!ret)) 7518c2ecf20Sopenharmony_ci break; 7528c2ecf20Sopenharmony_ci /* Retry if comparison fails or rseq aborts. */ 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci if (_cpu) 7558c2ecf20Sopenharmony_ci *_cpu = cpu; 7568c2ecf20Sopenharmony_ci return head; 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci/* 7608c2ecf20Sopenharmony_ci * __percpu_buffer_pop is not safe against concurrent accesses. Should 7618c2ecf20Sopenharmony_ci * only be used on buffers that are not concurrently modified. 7628c2ecf20Sopenharmony_ci */ 7638c2ecf20Sopenharmony_cistruct percpu_buffer_node *__percpu_buffer_pop(struct percpu_buffer *buffer, 7648c2ecf20Sopenharmony_ci int cpu) 7658c2ecf20Sopenharmony_ci{ 7668c2ecf20Sopenharmony_ci struct percpu_buffer_node *head; 7678c2ecf20Sopenharmony_ci intptr_t offset; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci offset = buffer->c[cpu].offset; 7708c2ecf20Sopenharmony_ci if (offset == 0) 7718c2ecf20Sopenharmony_ci return NULL; 7728c2ecf20Sopenharmony_ci head = buffer->c[cpu].array[offset - 1]; 7738c2ecf20Sopenharmony_ci buffer->c[cpu].offset = offset - 1; 7748c2ecf20Sopenharmony_ci return head; 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_civoid *test_percpu_buffer_thread(void *arg) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci long long i, reps; 7808c2ecf20Sopenharmony_ci struct percpu_buffer *buffer = (struct percpu_buffer *)arg; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (!opt_disable_rseq && rseq_register_current_thread()) 7838c2ecf20Sopenharmony_ci abort(); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci reps = opt_reps; 7868c2ecf20Sopenharmony_ci for (i = 0; i < reps; i++) { 7878c2ecf20Sopenharmony_ci struct percpu_buffer_node *node; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci node = this_cpu_buffer_pop(buffer, NULL); 7908c2ecf20Sopenharmony_ci if (opt_yield) 7918c2ecf20Sopenharmony_ci sched_yield(); /* encourage shuffling */ 7928c2ecf20Sopenharmony_ci if (node) { 7938c2ecf20Sopenharmony_ci if (!this_cpu_buffer_push(buffer, node, NULL)) { 7948c2ecf20Sopenharmony_ci /* Should increase buffer size. */ 7958c2ecf20Sopenharmony_ci abort(); 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n", 8018c2ecf20Sopenharmony_ci (int) rseq_gettid(), nr_abort, signals_delivered); 8028c2ecf20Sopenharmony_ci if (!opt_disable_rseq && rseq_unregister_current_thread()) 8038c2ecf20Sopenharmony_ci abort(); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return NULL; 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci/* Simultaneous modification to a per-cpu buffer from many threads. */ 8098c2ecf20Sopenharmony_civoid test_percpu_buffer(void) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci const int num_threads = opt_threads; 8128c2ecf20Sopenharmony_ci int i, j, ret; 8138c2ecf20Sopenharmony_ci uint64_t sum = 0, expected_sum = 0; 8148c2ecf20Sopenharmony_ci struct percpu_buffer buffer; 8158c2ecf20Sopenharmony_ci pthread_t test_threads[num_threads]; 8168c2ecf20Sopenharmony_ci cpu_set_t allowed_cpus; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci memset(&buffer, 0, sizeof(buffer)); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci /* Generate list entries for every usable cpu. */ 8218c2ecf20Sopenharmony_ci sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus); 8228c2ecf20Sopenharmony_ci for (i = 0; i < CPU_SETSIZE; i++) { 8238c2ecf20Sopenharmony_ci if (!CPU_ISSET(i, &allowed_cpus)) 8248c2ecf20Sopenharmony_ci continue; 8258c2ecf20Sopenharmony_ci /* Worse-case is every item in same CPU. */ 8268c2ecf20Sopenharmony_ci buffer.c[i].array = 8278c2ecf20Sopenharmony_ci malloc(sizeof(*buffer.c[i].array) * CPU_SETSIZE * 8288c2ecf20Sopenharmony_ci BUFFER_ITEM_PER_CPU); 8298c2ecf20Sopenharmony_ci assert(buffer.c[i].array); 8308c2ecf20Sopenharmony_ci buffer.c[i].buflen = CPU_SETSIZE * BUFFER_ITEM_PER_CPU; 8318c2ecf20Sopenharmony_ci for (j = 1; j <= BUFFER_ITEM_PER_CPU; j++) { 8328c2ecf20Sopenharmony_ci struct percpu_buffer_node *node; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci expected_sum += j; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci /* 8378c2ecf20Sopenharmony_ci * We could theoretically put the word-sized 8388c2ecf20Sopenharmony_ci * "data" directly in the buffer. However, we 8398c2ecf20Sopenharmony_ci * want to model objects that would not fit 8408c2ecf20Sopenharmony_ci * within a single word, so allocate an object 8418c2ecf20Sopenharmony_ci * for each node. 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_ci node = malloc(sizeof(*node)); 8448c2ecf20Sopenharmony_ci assert(node); 8458c2ecf20Sopenharmony_ci node->data = j; 8468c2ecf20Sopenharmony_ci buffer.c[i].array[j - 1] = node; 8478c2ecf20Sopenharmony_ci buffer.c[i].offset++; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci for (i = 0; i < num_threads; i++) { 8528c2ecf20Sopenharmony_ci ret = pthread_create(&test_threads[i], NULL, 8538c2ecf20Sopenharmony_ci test_percpu_buffer_thread, &buffer); 8548c2ecf20Sopenharmony_ci if (ret) { 8558c2ecf20Sopenharmony_ci errno = ret; 8568c2ecf20Sopenharmony_ci perror("pthread_create"); 8578c2ecf20Sopenharmony_ci abort(); 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci for (i = 0; i < num_threads; i++) { 8628c2ecf20Sopenharmony_ci ret = pthread_join(test_threads[i], NULL); 8638c2ecf20Sopenharmony_ci if (ret) { 8648c2ecf20Sopenharmony_ci errno = ret; 8658c2ecf20Sopenharmony_ci perror("pthread_join"); 8668c2ecf20Sopenharmony_ci abort(); 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci for (i = 0; i < CPU_SETSIZE; i++) { 8718c2ecf20Sopenharmony_ci struct percpu_buffer_node *node; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (!CPU_ISSET(i, &allowed_cpus)) 8748c2ecf20Sopenharmony_ci continue; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci while ((node = __percpu_buffer_pop(&buffer, i))) { 8778c2ecf20Sopenharmony_ci sum += node->data; 8788c2ecf20Sopenharmony_ci free(node); 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci free(buffer.c[i].array); 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci /* 8848c2ecf20Sopenharmony_ci * All entries should now be accounted for (unless some external 8858c2ecf20Sopenharmony_ci * actor is interfering with our allowed affinity while this 8868c2ecf20Sopenharmony_ci * test is running). 8878c2ecf20Sopenharmony_ci */ 8888c2ecf20Sopenharmony_ci assert(sum == expected_sum); 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cibool this_cpu_memcpy_buffer_push(struct percpu_memcpy_buffer *buffer, 8928c2ecf20Sopenharmony_ci struct percpu_memcpy_buffer_node item, 8938c2ecf20Sopenharmony_ci int *_cpu) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci bool result = false; 8968c2ecf20Sopenharmony_ci int cpu; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci for (;;) { 8998c2ecf20Sopenharmony_ci intptr_t *targetptr_final, newval_final, offset; 9008c2ecf20Sopenharmony_ci char *destptr, *srcptr; 9018c2ecf20Sopenharmony_ci size_t copylen; 9028c2ecf20Sopenharmony_ci int ret; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci cpu = rseq_cpu_start(); 9058c2ecf20Sopenharmony_ci /* Load offset with single-copy atomicity. */ 9068c2ecf20Sopenharmony_ci offset = RSEQ_READ_ONCE(buffer->c[cpu].offset); 9078c2ecf20Sopenharmony_ci if (offset == buffer->c[cpu].buflen) 9088c2ecf20Sopenharmony_ci break; 9098c2ecf20Sopenharmony_ci destptr = (char *)&buffer->c[cpu].array[offset]; 9108c2ecf20Sopenharmony_ci srcptr = (char *)&item; 9118c2ecf20Sopenharmony_ci /* copylen must be <= 4kB. */ 9128c2ecf20Sopenharmony_ci copylen = sizeof(item); 9138c2ecf20Sopenharmony_ci newval_final = offset + 1; 9148c2ecf20Sopenharmony_ci targetptr_final = &buffer->c[cpu].offset; 9158c2ecf20Sopenharmony_ci if (opt_mb) 9168c2ecf20Sopenharmony_ci ret = rseq_cmpeqv_trymemcpy_storev_release( 9178c2ecf20Sopenharmony_ci targetptr_final, offset, 9188c2ecf20Sopenharmony_ci destptr, srcptr, copylen, 9198c2ecf20Sopenharmony_ci newval_final, cpu); 9208c2ecf20Sopenharmony_ci else 9218c2ecf20Sopenharmony_ci ret = rseq_cmpeqv_trymemcpy_storev(targetptr_final, 9228c2ecf20Sopenharmony_ci offset, destptr, srcptr, copylen, 9238c2ecf20Sopenharmony_ci newval_final, cpu); 9248c2ecf20Sopenharmony_ci if (rseq_likely(!ret)) { 9258c2ecf20Sopenharmony_ci result = true; 9268c2ecf20Sopenharmony_ci break; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci /* Retry if comparison fails or rseq aborts. */ 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci if (_cpu) 9318c2ecf20Sopenharmony_ci *_cpu = cpu; 9328c2ecf20Sopenharmony_ci return result; 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cibool this_cpu_memcpy_buffer_pop(struct percpu_memcpy_buffer *buffer, 9368c2ecf20Sopenharmony_ci struct percpu_memcpy_buffer_node *item, 9378c2ecf20Sopenharmony_ci int *_cpu) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci bool result = false; 9408c2ecf20Sopenharmony_ci int cpu; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci for (;;) { 9438c2ecf20Sopenharmony_ci intptr_t *targetptr_final, newval_final, offset; 9448c2ecf20Sopenharmony_ci char *destptr, *srcptr; 9458c2ecf20Sopenharmony_ci size_t copylen; 9468c2ecf20Sopenharmony_ci int ret; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci cpu = rseq_cpu_start(); 9498c2ecf20Sopenharmony_ci /* Load offset with single-copy atomicity. */ 9508c2ecf20Sopenharmony_ci offset = RSEQ_READ_ONCE(buffer->c[cpu].offset); 9518c2ecf20Sopenharmony_ci if (offset == 0) 9528c2ecf20Sopenharmony_ci break; 9538c2ecf20Sopenharmony_ci destptr = (char *)item; 9548c2ecf20Sopenharmony_ci srcptr = (char *)&buffer->c[cpu].array[offset - 1]; 9558c2ecf20Sopenharmony_ci /* copylen must be <= 4kB. */ 9568c2ecf20Sopenharmony_ci copylen = sizeof(*item); 9578c2ecf20Sopenharmony_ci newval_final = offset - 1; 9588c2ecf20Sopenharmony_ci targetptr_final = &buffer->c[cpu].offset; 9598c2ecf20Sopenharmony_ci ret = rseq_cmpeqv_trymemcpy_storev(targetptr_final, 9608c2ecf20Sopenharmony_ci offset, destptr, srcptr, copylen, 9618c2ecf20Sopenharmony_ci newval_final, cpu); 9628c2ecf20Sopenharmony_ci if (rseq_likely(!ret)) { 9638c2ecf20Sopenharmony_ci result = true; 9648c2ecf20Sopenharmony_ci break; 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci /* Retry if comparison fails or rseq aborts. */ 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci if (_cpu) 9698c2ecf20Sopenharmony_ci *_cpu = cpu; 9708c2ecf20Sopenharmony_ci return result; 9718c2ecf20Sopenharmony_ci} 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci/* 9748c2ecf20Sopenharmony_ci * __percpu_memcpy_buffer_pop is not safe against concurrent accesses. Should 9758c2ecf20Sopenharmony_ci * only be used on buffers that are not concurrently modified. 9768c2ecf20Sopenharmony_ci */ 9778c2ecf20Sopenharmony_cibool __percpu_memcpy_buffer_pop(struct percpu_memcpy_buffer *buffer, 9788c2ecf20Sopenharmony_ci struct percpu_memcpy_buffer_node *item, 9798c2ecf20Sopenharmony_ci int cpu) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci intptr_t offset; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci offset = buffer->c[cpu].offset; 9848c2ecf20Sopenharmony_ci if (offset == 0) 9858c2ecf20Sopenharmony_ci return false; 9868c2ecf20Sopenharmony_ci memcpy(item, &buffer->c[cpu].array[offset - 1], sizeof(*item)); 9878c2ecf20Sopenharmony_ci buffer->c[cpu].offset = offset - 1; 9888c2ecf20Sopenharmony_ci return true; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_civoid *test_percpu_memcpy_buffer_thread(void *arg) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci long long i, reps; 9948c2ecf20Sopenharmony_ci struct percpu_memcpy_buffer *buffer = (struct percpu_memcpy_buffer *)arg; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (!opt_disable_rseq && rseq_register_current_thread()) 9978c2ecf20Sopenharmony_ci abort(); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci reps = opt_reps; 10008c2ecf20Sopenharmony_ci for (i = 0; i < reps; i++) { 10018c2ecf20Sopenharmony_ci struct percpu_memcpy_buffer_node item; 10028c2ecf20Sopenharmony_ci bool result; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci result = this_cpu_memcpy_buffer_pop(buffer, &item, NULL); 10058c2ecf20Sopenharmony_ci if (opt_yield) 10068c2ecf20Sopenharmony_ci sched_yield(); /* encourage shuffling */ 10078c2ecf20Sopenharmony_ci if (result) { 10088c2ecf20Sopenharmony_ci if (!this_cpu_memcpy_buffer_push(buffer, item, NULL)) { 10098c2ecf20Sopenharmony_ci /* Should increase buffer size. */ 10108c2ecf20Sopenharmony_ci abort(); 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n", 10168c2ecf20Sopenharmony_ci (int) rseq_gettid(), nr_abort, signals_delivered); 10178c2ecf20Sopenharmony_ci if (!opt_disable_rseq && rseq_unregister_current_thread()) 10188c2ecf20Sopenharmony_ci abort(); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci return NULL; 10218c2ecf20Sopenharmony_ci} 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci/* Simultaneous modification to a per-cpu buffer from many threads. */ 10248c2ecf20Sopenharmony_civoid test_percpu_memcpy_buffer(void) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci const int num_threads = opt_threads; 10278c2ecf20Sopenharmony_ci int i, j, ret; 10288c2ecf20Sopenharmony_ci uint64_t sum = 0, expected_sum = 0; 10298c2ecf20Sopenharmony_ci struct percpu_memcpy_buffer buffer; 10308c2ecf20Sopenharmony_ci pthread_t test_threads[num_threads]; 10318c2ecf20Sopenharmony_ci cpu_set_t allowed_cpus; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci memset(&buffer, 0, sizeof(buffer)); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci /* Generate list entries for every usable cpu. */ 10368c2ecf20Sopenharmony_ci sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus); 10378c2ecf20Sopenharmony_ci for (i = 0; i < CPU_SETSIZE; i++) { 10388c2ecf20Sopenharmony_ci if (!CPU_ISSET(i, &allowed_cpus)) 10398c2ecf20Sopenharmony_ci continue; 10408c2ecf20Sopenharmony_ci /* Worse-case is every item in same CPU. */ 10418c2ecf20Sopenharmony_ci buffer.c[i].array = 10428c2ecf20Sopenharmony_ci malloc(sizeof(*buffer.c[i].array) * CPU_SETSIZE * 10438c2ecf20Sopenharmony_ci MEMCPY_BUFFER_ITEM_PER_CPU); 10448c2ecf20Sopenharmony_ci assert(buffer.c[i].array); 10458c2ecf20Sopenharmony_ci buffer.c[i].buflen = CPU_SETSIZE * MEMCPY_BUFFER_ITEM_PER_CPU; 10468c2ecf20Sopenharmony_ci for (j = 1; j <= MEMCPY_BUFFER_ITEM_PER_CPU; j++) { 10478c2ecf20Sopenharmony_ci expected_sum += 2 * j + 1; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci /* 10508c2ecf20Sopenharmony_ci * We could theoretically put the word-sized 10518c2ecf20Sopenharmony_ci * "data" directly in the buffer. However, we 10528c2ecf20Sopenharmony_ci * want to model objects that would not fit 10538c2ecf20Sopenharmony_ci * within a single word, so allocate an object 10548c2ecf20Sopenharmony_ci * for each node. 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_ci buffer.c[i].array[j - 1].data1 = j; 10578c2ecf20Sopenharmony_ci buffer.c[i].array[j - 1].data2 = j + 1; 10588c2ecf20Sopenharmony_ci buffer.c[i].offset++; 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci for (i = 0; i < num_threads; i++) { 10638c2ecf20Sopenharmony_ci ret = pthread_create(&test_threads[i], NULL, 10648c2ecf20Sopenharmony_ci test_percpu_memcpy_buffer_thread, 10658c2ecf20Sopenharmony_ci &buffer); 10668c2ecf20Sopenharmony_ci if (ret) { 10678c2ecf20Sopenharmony_ci errno = ret; 10688c2ecf20Sopenharmony_ci perror("pthread_create"); 10698c2ecf20Sopenharmony_ci abort(); 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci for (i = 0; i < num_threads; i++) { 10748c2ecf20Sopenharmony_ci ret = pthread_join(test_threads[i], NULL); 10758c2ecf20Sopenharmony_ci if (ret) { 10768c2ecf20Sopenharmony_ci errno = ret; 10778c2ecf20Sopenharmony_ci perror("pthread_join"); 10788c2ecf20Sopenharmony_ci abort(); 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci for (i = 0; i < CPU_SETSIZE; i++) { 10838c2ecf20Sopenharmony_ci struct percpu_memcpy_buffer_node item; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci if (!CPU_ISSET(i, &allowed_cpus)) 10868c2ecf20Sopenharmony_ci continue; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci while (__percpu_memcpy_buffer_pop(&buffer, &item, i)) { 10898c2ecf20Sopenharmony_ci sum += item.data1; 10908c2ecf20Sopenharmony_ci sum += item.data2; 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci free(buffer.c[i].array); 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci /* 10968c2ecf20Sopenharmony_ci * All entries should now be accounted for (unless some external 10978c2ecf20Sopenharmony_ci * actor is interfering with our allowed affinity while this 10988c2ecf20Sopenharmony_ci * test is running). 10998c2ecf20Sopenharmony_ci */ 11008c2ecf20Sopenharmony_ci assert(sum == expected_sum); 11018c2ecf20Sopenharmony_ci} 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_cistatic void test_signal_interrupt_handler(int signo) 11048c2ecf20Sopenharmony_ci{ 11058c2ecf20Sopenharmony_ci signals_delivered++; 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cistatic int set_signal_handler(void) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci int ret = 0; 11118c2ecf20Sopenharmony_ci struct sigaction sa; 11128c2ecf20Sopenharmony_ci sigset_t sigset; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci ret = sigemptyset(&sigset); 11158c2ecf20Sopenharmony_ci if (ret < 0) { 11168c2ecf20Sopenharmony_ci perror("sigemptyset"); 11178c2ecf20Sopenharmony_ci return ret; 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci sa.sa_handler = test_signal_interrupt_handler; 11218c2ecf20Sopenharmony_ci sa.sa_mask = sigset; 11228c2ecf20Sopenharmony_ci sa.sa_flags = 0; 11238c2ecf20Sopenharmony_ci ret = sigaction(SIGUSR1, &sa, NULL); 11248c2ecf20Sopenharmony_ci if (ret < 0) { 11258c2ecf20Sopenharmony_ci perror("sigaction"); 11268c2ecf20Sopenharmony_ci return ret; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci printf_verbose("Signal handler set for SIGUSR1\n"); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci return ret; 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_cistruct test_membarrier_thread_args { 11358c2ecf20Sopenharmony_ci int stop; 11368c2ecf20Sopenharmony_ci intptr_t percpu_list_ptr; 11378c2ecf20Sopenharmony_ci}; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci/* Worker threads modify data in their "active" percpu lists. */ 11408c2ecf20Sopenharmony_civoid *test_membarrier_worker_thread(void *arg) 11418c2ecf20Sopenharmony_ci{ 11428c2ecf20Sopenharmony_ci struct test_membarrier_thread_args *args = 11438c2ecf20Sopenharmony_ci (struct test_membarrier_thread_args *)arg; 11448c2ecf20Sopenharmony_ci const int iters = opt_reps; 11458c2ecf20Sopenharmony_ci int i; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci if (rseq_register_current_thread()) { 11488c2ecf20Sopenharmony_ci fprintf(stderr, "Error: rseq_register_current_thread(...) failed(%d): %s\n", 11498c2ecf20Sopenharmony_ci errno, strerror(errno)); 11508c2ecf20Sopenharmony_ci abort(); 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci /* Wait for initialization. */ 11548c2ecf20Sopenharmony_ci while (!atomic_load(&args->percpu_list_ptr)) {} 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci for (i = 0; i < iters; ++i) { 11578c2ecf20Sopenharmony_ci int ret; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci do { 11608c2ecf20Sopenharmony_ci int cpu = rseq_cpu_start(); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci ret = rseq_offset_deref_addv(&args->percpu_list_ptr, 11638c2ecf20Sopenharmony_ci sizeof(struct percpu_list_entry) * cpu, 1, cpu); 11648c2ecf20Sopenharmony_ci } while (rseq_unlikely(ret)); 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (rseq_unregister_current_thread()) { 11688c2ecf20Sopenharmony_ci fprintf(stderr, "Error: rseq_unregister_current_thread(...) failed(%d): %s\n", 11698c2ecf20Sopenharmony_ci errno, strerror(errno)); 11708c2ecf20Sopenharmony_ci abort(); 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci return NULL; 11738c2ecf20Sopenharmony_ci} 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_civoid test_membarrier_init_percpu_list(struct percpu_list *list) 11768c2ecf20Sopenharmony_ci{ 11778c2ecf20Sopenharmony_ci int i; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci memset(list, 0, sizeof(*list)); 11808c2ecf20Sopenharmony_ci for (i = 0; i < CPU_SETSIZE; i++) { 11818c2ecf20Sopenharmony_ci struct percpu_list_node *node; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci node = malloc(sizeof(*node)); 11848c2ecf20Sopenharmony_ci assert(node); 11858c2ecf20Sopenharmony_ci node->data = 0; 11868c2ecf20Sopenharmony_ci node->next = NULL; 11878c2ecf20Sopenharmony_ci list->c[i].head = node; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci} 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_civoid test_membarrier_free_percpu_list(struct percpu_list *list) 11928c2ecf20Sopenharmony_ci{ 11938c2ecf20Sopenharmony_ci int i; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci for (i = 0; i < CPU_SETSIZE; i++) 11968c2ecf20Sopenharmony_ci free(list->c[i].head); 11978c2ecf20Sopenharmony_ci} 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic int sys_membarrier(int cmd, int flags, int cpu_id) 12008c2ecf20Sopenharmony_ci{ 12018c2ecf20Sopenharmony_ci return syscall(__NR_membarrier, cmd, flags, cpu_id); 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci/* 12058c2ecf20Sopenharmony_ci * The manager thread swaps per-cpu lists that worker threads see, 12068c2ecf20Sopenharmony_ci * and validates that there are no unexpected modifications. 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_civoid *test_membarrier_manager_thread(void *arg) 12098c2ecf20Sopenharmony_ci{ 12108c2ecf20Sopenharmony_ci struct test_membarrier_thread_args *args = 12118c2ecf20Sopenharmony_ci (struct test_membarrier_thread_args *)arg; 12128c2ecf20Sopenharmony_ci struct percpu_list list_a, list_b; 12138c2ecf20Sopenharmony_ci intptr_t expect_a = 0, expect_b = 0; 12148c2ecf20Sopenharmony_ci int cpu_a = 0, cpu_b = 0; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci if (rseq_register_current_thread()) { 12178c2ecf20Sopenharmony_ci fprintf(stderr, "Error: rseq_register_current_thread(...) failed(%d): %s\n", 12188c2ecf20Sopenharmony_ci errno, strerror(errno)); 12198c2ecf20Sopenharmony_ci abort(); 12208c2ecf20Sopenharmony_ci } 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci /* Init lists. */ 12238c2ecf20Sopenharmony_ci test_membarrier_init_percpu_list(&list_a); 12248c2ecf20Sopenharmony_ci test_membarrier_init_percpu_list(&list_b); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci atomic_store(&args->percpu_list_ptr, (intptr_t)&list_a); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci while (!atomic_load(&args->stop)) { 12298c2ecf20Sopenharmony_ci /* list_a is "active". */ 12308c2ecf20Sopenharmony_ci cpu_a = rand() % CPU_SETSIZE; 12318c2ecf20Sopenharmony_ci /* 12328c2ecf20Sopenharmony_ci * As list_b is "inactive", we should never see changes 12338c2ecf20Sopenharmony_ci * to list_b. 12348c2ecf20Sopenharmony_ci */ 12358c2ecf20Sopenharmony_ci if (expect_b != atomic_load(&list_b.c[cpu_b].head->data)) { 12368c2ecf20Sopenharmony_ci fprintf(stderr, "Membarrier test failed\n"); 12378c2ecf20Sopenharmony_ci abort(); 12388c2ecf20Sopenharmony_ci } 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci /* Make list_b "active". */ 12418c2ecf20Sopenharmony_ci atomic_store(&args->percpu_list_ptr, (intptr_t)&list_b); 12428c2ecf20Sopenharmony_ci if (sys_membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ, 12438c2ecf20Sopenharmony_ci MEMBARRIER_CMD_FLAG_CPU, cpu_a) && 12448c2ecf20Sopenharmony_ci errno != ENXIO /* missing CPU */) { 12458c2ecf20Sopenharmony_ci perror("sys_membarrier"); 12468c2ecf20Sopenharmony_ci abort(); 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci /* 12498c2ecf20Sopenharmony_ci * Cpu A should now only modify list_b, so the values 12508c2ecf20Sopenharmony_ci * in list_a should be stable. 12518c2ecf20Sopenharmony_ci */ 12528c2ecf20Sopenharmony_ci expect_a = atomic_load(&list_a.c[cpu_a].head->data); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci cpu_b = rand() % CPU_SETSIZE; 12558c2ecf20Sopenharmony_ci /* 12568c2ecf20Sopenharmony_ci * As list_a is "inactive", we should never see changes 12578c2ecf20Sopenharmony_ci * to list_a. 12588c2ecf20Sopenharmony_ci */ 12598c2ecf20Sopenharmony_ci if (expect_a != atomic_load(&list_a.c[cpu_a].head->data)) { 12608c2ecf20Sopenharmony_ci fprintf(stderr, "Membarrier test failed\n"); 12618c2ecf20Sopenharmony_ci abort(); 12628c2ecf20Sopenharmony_ci } 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci /* Make list_a "active". */ 12658c2ecf20Sopenharmony_ci atomic_store(&args->percpu_list_ptr, (intptr_t)&list_a); 12668c2ecf20Sopenharmony_ci if (sys_membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ, 12678c2ecf20Sopenharmony_ci MEMBARRIER_CMD_FLAG_CPU, cpu_b) && 12688c2ecf20Sopenharmony_ci errno != ENXIO /* missing CPU*/) { 12698c2ecf20Sopenharmony_ci perror("sys_membarrier"); 12708c2ecf20Sopenharmony_ci abort(); 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci /* Remember a value from list_b. */ 12738c2ecf20Sopenharmony_ci expect_b = atomic_load(&list_b.c[cpu_b].head->data); 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci test_membarrier_free_percpu_list(&list_a); 12778c2ecf20Sopenharmony_ci test_membarrier_free_percpu_list(&list_b); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (rseq_unregister_current_thread()) { 12808c2ecf20Sopenharmony_ci fprintf(stderr, "Error: rseq_unregister_current_thread(...) failed(%d): %s\n", 12818c2ecf20Sopenharmony_ci errno, strerror(errno)); 12828c2ecf20Sopenharmony_ci abort(); 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci return NULL; 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci/* Test MEMBARRIER_CMD_PRIVATE_RESTART_RSEQ_ON_CPU membarrier command. */ 12888c2ecf20Sopenharmony_ci#ifdef RSEQ_ARCH_HAS_OFFSET_DEREF_ADDV 12898c2ecf20Sopenharmony_civoid test_membarrier(void) 12908c2ecf20Sopenharmony_ci{ 12918c2ecf20Sopenharmony_ci const int num_threads = opt_threads; 12928c2ecf20Sopenharmony_ci struct test_membarrier_thread_args thread_args; 12938c2ecf20Sopenharmony_ci pthread_t worker_threads[num_threads]; 12948c2ecf20Sopenharmony_ci pthread_t manager_thread; 12958c2ecf20Sopenharmony_ci int i, ret; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci if (sys_membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ, 0, 0)) { 12988c2ecf20Sopenharmony_ci perror("sys_membarrier"); 12998c2ecf20Sopenharmony_ci abort(); 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci thread_args.stop = 0; 13038c2ecf20Sopenharmony_ci thread_args.percpu_list_ptr = 0; 13048c2ecf20Sopenharmony_ci ret = pthread_create(&manager_thread, NULL, 13058c2ecf20Sopenharmony_ci test_membarrier_manager_thread, &thread_args); 13068c2ecf20Sopenharmony_ci if (ret) { 13078c2ecf20Sopenharmony_ci errno = ret; 13088c2ecf20Sopenharmony_ci perror("pthread_create"); 13098c2ecf20Sopenharmony_ci abort(); 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci for (i = 0; i < num_threads; i++) { 13138c2ecf20Sopenharmony_ci ret = pthread_create(&worker_threads[i], NULL, 13148c2ecf20Sopenharmony_ci test_membarrier_worker_thread, &thread_args); 13158c2ecf20Sopenharmony_ci if (ret) { 13168c2ecf20Sopenharmony_ci errno = ret; 13178c2ecf20Sopenharmony_ci perror("pthread_create"); 13188c2ecf20Sopenharmony_ci abort(); 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci for (i = 0; i < num_threads; i++) { 13248c2ecf20Sopenharmony_ci ret = pthread_join(worker_threads[i], NULL); 13258c2ecf20Sopenharmony_ci if (ret) { 13268c2ecf20Sopenharmony_ci errno = ret; 13278c2ecf20Sopenharmony_ci perror("pthread_join"); 13288c2ecf20Sopenharmony_ci abort(); 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci atomic_store(&thread_args.stop, 1); 13338c2ecf20Sopenharmony_ci ret = pthread_join(manager_thread, NULL); 13348c2ecf20Sopenharmony_ci if (ret) { 13358c2ecf20Sopenharmony_ci errno = ret; 13368c2ecf20Sopenharmony_ci perror("pthread_join"); 13378c2ecf20Sopenharmony_ci abort(); 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci#else /* RSEQ_ARCH_HAS_OFFSET_DEREF_ADDV */ 13418c2ecf20Sopenharmony_civoid test_membarrier(void) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci fprintf(stderr, "rseq_offset_deref_addv is not implemented on this architecture. " 13448c2ecf20Sopenharmony_ci "Skipping membarrier test.\n"); 13458c2ecf20Sopenharmony_ci} 13468c2ecf20Sopenharmony_ci#endif 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_cistatic void show_usage(int argc, char **argv) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci printf("Usage : %s <OPTIONS>\n", 13518c2ecf20Sopenharmony_ci argv[0]); 13528c2ecf20Sopenharmony_ci printf("OPTIONS:\n"); 13538c2ecf20Sopenharmony_ci printf(" [-1 loops] Number of loops for delay injection 1\n"); 13548c2ecf20Sopenharmony_ci printf(" [-2 loops] Number of loops for delay injection 2\n"); 13558c2ecf20Sopenharmony_ci printf(" [-3 loops] Number of loops for delay injection 3\n"); 13568c2ecf20Sopenharmony_ci printf(" [-4 loops] Number of loops for delay injection 4\n"); 13578c2ecf20Sopenharmony_ci printf(" [-5 loops] Number of loops for delay injection 5\n"); 13588c2ecf20Sopenharmony_ci printf(" [-6 loops] Number of loops for delay injection 6\n"); 13598c2ecf20Sopenharmony_ci printf(" [-7 loops] Number of loops for delay injection 7 (-1 to enable -m)\n"); 13608c2ecf20Sopenharmony_ci printf(" [-8 loops] Number of loops for delay injection 8 (-1 to enable -m)\n"); 13618c2ecf20Sopenharmony_ci printf(" [-9 loops] Number of loops for delay injection 9 (-1 to enable -m)\n"); 13628c2ecf20Sopenharmony_ci printf(" [-m N] Yield/sleep/kill every modulo N (default 0: disabled) (>= 0)\n"); 13638c2ecf20Sopenharmony_ci printf(" [-y] Yield\n"); 13648c2ecf20Sopenharmony_ci printf(" [-k] Kill thread with signal\n"); 13658c2ecf20Sopenharmony_ci printf(" [-s S] S: =0: disabled (default), >0: sleep time (ms)\n"); 13668c2ecf20Sopenharmony_ci printf(" [-t N] Number of threads (default 200)\n"); 13678c2ecf20Sopenharmony_ci printf(" [-r N] Number of repetitions per thread (default 5000)\n"); 13688c2ecf20Sopenharmony_ci printf(" [-d] Disable rseq system call (no initialization)\n"); 13698c2ecf20Sopenharmony_ci printf(" [-D M] Disable rseq for each M threads\n"); 13708c2ecf20Sopenharmony_ci printf(" [-T test] Choose test: (s)pinlock, (l)ist, (b)uffer, (m)emcpy, (i)ncrement, membarrie(r)\n"); 13718c2ecf20Sopenharmony_ci printf(" [-M] Push into buffer and memcpy buffer with memory barriers.\n"); 13728c2ecf20Sopenharmony_ci printf(" [-v] Verbose output.\n"); 13738c2ecf20Sopenharmony_ci printf(" [-h] Show this help.\n"); 13748c2ecf20Sopenharmony_ci printf("\n"); 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ciint main(int argc, char **argv) 13788c2ecf20Sopenharmony_ci{ 13798c2ecf20Sopenharmony_ci int i; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci for (i = 1; i < argc; i++) { 13828c2ecf20Sopenharmony_ci if (argv[i][0] != '-') 13838c2ecf20Sopenharmony_ci continue; 13848c2ecf20Sopenharmony_ci switch (argv[i][1]) { 13858c2ecf20Sopenharmony_ci case '1': 13868c2ecf20Sopenharmony_ci case '2': 13878c2ecf20Sopenharmony_ci case '3': 13888c2ecf20Sopenharmony_ci case '4': 13898c2ecf20Sopenharmony_ci case '5': 13908c2ecf20Sopenharmony_ci case '6': 13918c2ecf20Sopenharmony_ci case '7': 13928c2ecf20Sopenharmony_ci case '8': 13938c2ecf20Sopenharmony_ci case '9': 13948c2ecf20Sopenharmony_ci if (argc < i + 2) { 13958c2ecf20Sopenharmony_ci show_usage(argc, argv); 13968c2ecf20Sopenharmony_ci goto error; 13978c2ecf20Sopenharmony_ci } 13988c2ecf20Sopenharmony_ci loop_cnt[argv[i][1] - '0'] = atol(argv[i + 1]); 13998c2ecf20Sopenharmony_ci i++; 14008c2ecf20Sopenharmony_ci break; 14018c2ecf20Sopenharmony_ci case 'm': 14028c2ecf20Sopenharmony_ci if (argc < i + 2) { 14038c2ecf20Sopenharmony_ci show_usage(argc, argv); 14048c2ecf20Sopenharmony_ci goto error; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci opt_modulo = atol(argv[i + 1]); 14078c2ecf20Sopenharmony_ci if (opt_modulo < 0) { 14088c2ecf20Sopenharmony_ci show_usage(argc, argv); 14098c2ecf20Sopenharmony_ci goto error; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci i++; 14128c2ecf20Sopenharmony_ci break; 14138c2ecf20Sopenharmony_ci case 's': 14148c2ecf20Sopenharmony_ci if (argc < i + 2) { 14158c2ecf20Sopenharmony_ci show_usage(argc, argv); 14168c2ecf20Sopenharmony_ci goto error; 14178c2ecf20Sopenharmony_ci } 14188c2ecf20Sopenharmony_ci opt_sleep = atol(argv[i + 1]); 14198c2ecf20Sopenharmony_ci if (opt_sleep < 0) { 14208c2ecf20Sopenharmony_ci show_usage(argc, argv); 14218c2ecf20Sopenharmony_ci goto error; 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci i++; 14248c2ecf20Sopenharmony_ci break; 14258c2ecf20Sopenharmony_ci case 'y': 14268c2ecf20Sopenharmony_ci opt_yield = 1; 14278c2ecf20Sopenharmony_ci break; 14288c2ecf20Sopenharmony_ci case 'k': 14298c2ecf20Sopenharmony_ci opt_signal = 1; 14308c2ecf20Sopenharmony_ci break; 14318c2ecf20Sopenharmony_ci case 'd': 14328c2ecf20Sopenharmony_ci opt_disable_rseq = 1; 14338c2ecf20Sopenharmony_ci break; 14348c2ecf20Sopenharmony_ci case 'D': 14358c2ecf20Sopenharmony_ci if (argc < i + 2) { 14368c2ecf20Sopenharmony_ci show_usage(argc, argv); 14378c2ecf20Sopenharmony_ci goto error; 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci opt_disable_mod = atol(argv[i + 1]); 14408c2ecf20Sopenharmony_ci if (opt_disable_mod < 0) { 14418c2ecf20Sopenharmony_ci show_usage(argc, argv); 14428c2ecf20Sopenharmony_ci goto error; 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci i++; 14458c2ecf20Sopenharmony_ci break; 14468c2ecf20Sopenharmony_ci case 't': 14478c2ecf20Sopenharmony_ci if (argc < i + 2) { 14488c2ecf20Sopenharmony_ci show_usage(argc, argv); 14498c2ecf20Sopenharmony_ci goto error; 14508c2ecf20Sopenharmony_ci } 14518c2ecf20Sopenharmony_ci opt_threads = atol(argv[i + 1]); 14528c2ecf20Sopenharmony_ci if (opt_threads < 0) { 14538c2ecf20Sopenharmony_ci show_usage(argc, argv); 14548c2ecf20Sopenharmony_ci goto error; 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci i++; 14578c2ecf20Sopenharmony_ci break; 14588c2ecf20Sopenharmony_ci case 'r': 14598c2ecf20Sopenharmony_ci if (argc < i + 2) { 14608c2ecf20Sopenharmony_ci show_usage(argc, argv); 14618c2ecf20Sopenharmony_ci goto error; 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci opt_reps = atoll(argv[i + 1]); 14648c2ecf20Sopenharmony_ci if (opt_reps < 0) { 14658c2ecf20Sopenharmony_ci show_usage(argc, argv); 14668c2ecf20Sopenharmony_ci goto error; 14678c2ecf20Sopenharmony_ci } 14688c2ecf20Sopenharmony_ci i++; 14698c2ecf20Sopenharmony_ci break; 14708c2ecf20Sopenharmony_ci case 'h': 14718c2ecf20Sopenharmony_ci show_usage(argc, argv); 14728c2ecf20Sopenharmony_ci goto end; 14738c2ecf20Sopenharmony_ci case 'T': 14748c2ecf20Sopenharmony_ci if (argc < i + 2) { 14758c2ecf20Sopenharmony_ci show_usage(argc, argv); 14768c2ecf20Sopenharmony_ci goto error; 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci opt_test = *argv[i + 1]; 14798c2ecf20Sopenharmony_ci switch (opt_test) { 14808c2ecf20Sopenharmony_ci case 's': 14818c2ecf20Sopenharmony_ci case 'l': 14828c2ecf20Sopenharmony_ci case 'i': 14838c2ecf20Sopenharmony_ci case 'b': 14848c2ecf20Sopenharmony_ci case 'm': 14858c2ecf20Sopenharmony_ci case 'r': 14868c2ecf20Sopenharmony_ci break; 14878c2ecf20Sopenharmony_ci default: 14888c2ecf20Sopenharmony_ci show_usage(argc, argv); 14898c2ecf20Sopenharmony_ci goto error; 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci i++; 14928c2ecf20Sopenharmony_ci break; 14938c2ecf20Sopenharmony_ci case 'v': 14948c2ecf20Sopenharmony_ci verbose = 1; 14958c2ecf20Sopenharmony_ci break; 14968c2ecf20Sopenharmony_ci case 'M': 14978c2ecf20Sopenharmony_ci opt_mb = 1; 14988c2ecf20Sopenharmony_ci break; 14998c2ecf20Sopenharmony_ci default: 15008c2ecf20Sopenharmony_ci show_usage(argc, argv); 15018c2ecf20Sopenharmony_ci goto error; 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci loop_cnt_1 = loop_cnt[1]; 15068c2ecf20Sopenharmony_ci loop_cnt_2 = loop_cnt[2]; 15078c2ecf20Sopenharmony_ci loop_cnt_3 = loop_cnt[3]; 15088c2ecf20Sopenharmony_ci loop_cnt_4 = loop_cnt[4]; 15098c2ecf20Sopenharmony_ci loop_cnt_5 = loop_cnt[5]; 15108c2ecf20Sopenharmony_ci loop_cnt_6 = loop_cnt[6]; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci if (set_signal_handler()) 15138c2ecf20Sopenharmony_ci goto error; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci if (!opt_disable_rseq && rseq_register_current_thread()) 15168c2ecf20Sopenharmony_ci goto error; 15178c2ecf20Sopenharmony_ci switch (opt_test) { 15188c2ecf20Sopenharmony_ci case 's': 15198c2ecf20Sopenharmony_ci printf_verbose("spinlock\n"); 15208c2ecf20Sopenharmony_ci test_percpu_spinlock(); 15218c2ecf20Sopenharmony_ci break; 15228c2ecf20Sopenharmony_ci case 'l': 15238c2ecf20Sopenharmony_ci printf_verbose("linked list\n"); 15248c2ecf20Sopenharmony_ci test_percpu_list(); 15258c2ecf20Sopenharmony_ci break; 15268c2ecf20Sopenharmony_ci case 'b': 15278c2ecf20Sopenharmony_ci printf_verbose("buffer\n"); 15288c2ecf20Sopenharmony_ci test_percpu_buffer(); 15298c2ecf20Sopenharmony_ci break; 15308c2ecf20Sopenharmony_ci case 'm': 15318c2ecf20Sopenharmony_ci printf_verbose("memcpy buffer\n"); 15328c2ecf20Sopenharmony_ci test_percpu_memcpy_buffer(); 15338c2ecf20Sopenharmony_ci break; 15348c2ecf20Sopenharmony_ci case 'i': 15358c2ecf20Sopenharmony_ci printf_verbose("counter increment\n"); 15368c2ecf20Sopenharmony_ci test_percpu_inc(); 15378c2ecf20Sopenharmony_ci break; 15388c2ecf20Sopenharmony_ci case 'r': 15398c2ecf20Sopenharmony_ci printf_verbose("membarrier\n"); 15408c2ecf20Sopenharmony_ci test_membarrier(); 15418c2ecf20Sopenharmony_ci break; 15428c2ecf20Sopenharmony_ci } 15438c2ecf20Sopenharmony_ci if (!opt_disable_rseq && rseq_unregister_current_thread()) 15448c2ecf20Sopenharmony_ci abort(); 15458c2ecf20Sopenharmony_ciend: 15468c2ecf20Sopenharmony_ci return 0; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_cierror: 15498c2ecf20Sopenharmony_ci return -1; 15508c2ecf20Sopenharmony_ci} 1551