* [LTP] [PATCH v2 1/2] tst_atomic: drop legacy inline assembly and use __atomic or __sync builtins @ 2025-06-05 12:07 Li Wang via ltp 2025-06-05 12:07 ` [LTP] [PATCH v2 2/2] lib: moves test infrastructure states into a shared context structure Li Wang via ltp 2025-06-06 9:18 ` [LTP] [PATCH v2 1/2] tst_atomic: drop legacy inline assembly and use __atomic or __sync builtins Cyril Hrubis 0 siblings, 2 replies; 7+ messages in thread From: Li Wang via ltp @ 2025-06-05 12:07 UTC (permalink / raw) To: ltp Refactor tst_atomic.h to remove all legacy architecture-specific inline assembly and fallback code paths. The new implementation supports only two well-defined interfaces: __atomic_* built-ins (GCC ≥ 4.7) and __sync_* built-ins (GCC ≥ 4.1). This simplification improves maintainability, clarity, and portability across platforms. It also updates all function signatures to use int32_t for type consistency when operating on atomic counters, such as those in struct tst_results. The memory order is explicitly set to __ATOMIC_SEQ_CST to preserve strict sequential consistency, which aligns with the C++11 memory model. Reference: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html Signed-off-by: Li Wang <liwang@redhat.com> Suggested-by: Cyril Hrubis <chrubis@suse.cz> --- include/tst_atomic.h | 303 +++---------------------------------------- 1 file changed, 19 insertions(+), 284 deletions(-) diff --git a/include/tst_atomic.h b/include/tst_atomic.h index 061cd3dc6..9d92aa6d5 100644 --- a/include/tst_atomic.h +++ b/include/tst_atomic.h @@ -1,334 +1,69 @@ /* SPDX-License-Identifier: GPL-2.0-or-later * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz> - */ - -/* The LTP library has some of its own atomic synchronisation primitives - * contained in this file. Generally speaking these should not be used - * directly in tests for synchronisation, instead use tst_checkpoint.h, - * tst_fuzzy_sync.h or the POSIX library. - * - * Notes on compile and runtime memory barriers and atomics. - * - * Within the LTP library we have three concerns when accessing variables - * shared by multiple threads or processes: - * - * (1) Removal or reordering of accesses by the compiler. - * (2) Atomicity of addition. - * (3) LOAD-STORE ordering between threads. - * - * The first (1) is the most likely to cause an error if not properly - * handled. We avoid it by using volatile variables and statements which will - * not be removed or reordered by the compiler during optimisation. This includes - * the __atomic and __sync intrinsics and volatile asm statements marked with - * "memory" as well as variables marked with volatile. - * - * On any platform Linux is likely to run on, a LOAD (fetch) or STORE of a - * 32-bit integer will be atomic. However fetching and adding to a variable is - * quite likely not; so for (2) we need to ensure we use atomic addition. - * - * Finally, for tst_fuzzy_sync at least, we need to ensure that LOADs and - * STOREs of any shared variables (including non-atomics) that are made - * between calls to tst_fzsync_wait are completed (globally visible) before - * tst_fzsync_wait completes. For this, runtime memory and instruction - * barriers are required in addition to compile time. - * - * We use full sequential ordering (__ATOMIC_SEQ_CST) for the sake of - * simplicity. LTP tests tend to be syscall heavy so any performance gain from - * using a weaker memory model is unlikely to result in a relatively large - * performance improvement while at the same time being a potent source of - * confusion. - * - * Likewise, for the fallback ASM, the simplest "definitely will work, always" - * approach is preferred over anything more performant. - * - * Also see Documentation/memory-barriers.txt in the kernel tree and - * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html - * terminology may vary between sources. + * Copyright (c) 2025 Li Wang <liwang@redhat.com> */ #ifndef TST_ATOMIC_H__ #define TST_ATOMIC_H__ +#include <stdint.h> #include "config.h" #if HAVE_ATOMIC_MEMORY_MODEL == 1 -static inline int tst_atomic_add_return(int i, int *v) + +/* Use __atomic built-ins (GCC >= 4.7), with sequential consistency. */ + +static inline int tst_atomic_add_return(int i, int32_t *v) { return __atomic_add_fetch(v, i, __ATOMIC_SEQ_CST); } -static inline int tst_atomic_load(int *v) +static inline int32_t tst_atomic_load(int32_t *v) { return __atomic_load_n(v, __ATOMIC_SEQ_CST); } -static inline void tst_atomic_store(int i, int *v) +static inline void tst_atomic_store(int32_t i, int32_t *v) { __atomic_store_n(v, i, __ATOMIC_SEQ_CST); } #elif HAVE_SYNC_ADD_AND_FETCH == 1 -static inline int tst_atomic_add_return(int i, int *v) + +/* Use __sync built-ins (GCC >= 4.1), with explicit memory barriers. */ + +static inline int tst_atomic_add_return(int i, int32_t *v) { return __sync_add_and_fetch(v, i); } -static inline int tst_atomic_load(int *v) +static inline int32_t tst_atomic_load(int32_t *v) { - int ret; - __sync_synchronize(); - ret = *v; + int32_t ret = *v; __sync_synchronize(); return ret; } -static inline void tst_atomic_store(int i, int *v) +static inline void tst_atomic_store(int32_t i, int32_t *v) { __sync_synchronize(); *v = i; __sync_synchronize(); } -#elif defined(__i386__) || defined(__x86_64__) -# define LTP_USE_GENERIC_LOAD_STORE_ASM 1 - -static inline int tst_atomic_add_return(int i, int *v) -{ - int __ret = i; - - /* - * taken from arch/x86/include/asm/cmpxchg.h - */ - asm volatile ("lock; xaddl %0, %1\n" - : "+r" (__ret), "+m" (*v) : : "memory", "cc"); - - return i + __ret; -} - -#elif defined(__powerpc__) || defined(__powerpc64__) -static inline int tst_atomic_add_return(int i, int *v) -{ - int t; - - /* taken from arch/powerpc/include/asm/atomic.h */ - asm volatile( - " sync\n" - "1: lwarx %0,0,%2 # atomic_add_return\n" - " add %0,%1,%0\n" - " stwcx. %0,0,%2 \n" - " bne- 1b\n" - " sync\n" - : "=&r" (t) - : "r" (i), "r" (v) - : "cc", "memory"); - - return t; -} - -static inline int tst_atomic_load(int *v) -{ - int ret; - - asm volatile("sync\n" : : : "memory"); - ret = *v; - asm volatile("sync\n" : : : "memory"); - - return ret; -} - -static inline void tst_atomic_store(int i, int *v) -{ - asm volatile("sync\n" : : : "memory"); - *v = i; - asm volatile("sync\n" : : : "memory"); -} - -#elif defined(__s390__) || defined(__s390x__) -# define LTP_USE_GENERIC_LOAD_STORE_ASM 1 - -static inline int tst_atomic_add_return(int i, int *v) -{ - int old_val, new_val; - - /* taken from arch/s390/include/asm/atomic.h */ - asm volatile( - " l %0,%2\n" - "0: lr %1,%0\n" - " ar %1,%3\n" - " cs %0,%1,%2\n" - " jl 0b" - : "=&d" (old_val), "=&d" (new_val), "+Q" (*v) - : "d" (i) - : "cc", "memory"); - - return old_val + i; -} - -#elif defined(__arc__) - -/*ARCv2 defines the smp barriers */ -#ifdef __ARC700__ -#define smp_mb() asm volatile("" : : : "memory") #else -#define smp_mb() asm volatile("dmb 3\n" : : : "memory") -#endif - -static inline int tst_atomic_add_return(int i, int *v) -{ - unsigned int val; - - smp_mb(); - - asm volatile( - "1: llock %[val], [%[ctr]] \n" - " add %[val], %[val], %[i] \n" - " scond %[val], [%[ctr]] \n" - " bnz 1b \n" - : [val] "=&r" (val) - : [ctr] "r" (v), - [i] "ir" (i) - : "cc", "memory"); - - smp_mb(); - - return val; -} - -static inline int tst_atomic_load(int *v) -{ - int ret; - - smp_mb(); - ret = *v; - smp_mb(); - - return ret; -} - -static inline void tst_atomic_store(int i, int *v) -{ - smp_mb(); - *v = i; - smp_mb(); -} - -#elif defined (__aarch64__) -static inline int tst_atomic_add_return(int i, int *v) -{ - unsigned long tmp; - int result; - - __asm__ __volatile__( -" prfm pstl1strm, %2 \n" -"1: ldaxr %w0, %2 \n" -" add %w0, %w0, %w3 \n" -" stlxr %w1, %w0, %2 \n" -" cbnz %w1, 1b \n" -" dmb ish \n" - : "=&r" (result), "=&r" (tmp), "+Q" (*v) - : "Ir" (i) - : "memory"); - - return result; -} - -/* We are using load and store exclusive (ldaxr & stlxr) instructions to try - * and help prevent the tst_atomic_load and, more likely, tst_atomic_store - * functions from interfering with tst_atomic_add_return which takes advantage - * of exclusivity. It is not clear if this is a good idea or not, but does - * mean that all three functions are very similar. - */ -static inline int tst_atomic_load(int *v) -{ - int ret; - unsigned long tmp; - - asm volatile("//atomic_load \n" - " prfm pstl1strm, %[v] \n" - "1: ldaxr %w[ret], %[v] \n" - " stlxr %w[tmp], %w[ret], %[v] \n" - " cbnz %w[tmp], 1b \n" - " dmb ish \n" - : [tmp] "=&r" (tmp), [ret] "=&r" (ret), [v] "+Q" (*v) - : : "memory"); - - return ret; -} - -static inline void tst_atomic_store(int i, int *v) -{ - unsigned long tmp; - - asm volatile("//atomic_store \n" - " prfm pstl1strm, %[v] \n" - "1: ldaxr %w[tmp], %[v] \n" - " stlxr %w[tmp], %w[i], %[v] \n" - " cbnz %w[tmp], 1b \n" - " dmb ish \n" - : [tmp] "=&r" (tmp), [v] "+Q" (*v) - : [i] "r" (i) - : "memory"); -} - -#elif defined(__sparc__) && defined(__arch64__) -# define LTP_USE_GENERIC_LOAD_STORE_ASM 1 -static inline int tst_atomic_add_return(int i, int *v) -{ - int ret, tmp; - - /* Based on arch/sparc/lib/atomic_64.S with the exponential backoff - * function removed because we are unlikely to have a large (>= 16?) - * number of cores continuously trying to update one variable. - */ - asm volatile("/*atomic_add_return*/ \n" - "1: ldsw [%[v]], %[ret]; \n" - " add %[ret], %[i], %[tmp]; \n" - " cas [%[v]], %[ret], %[tmp]; \n" - " cmp %[ret], %[tmp]; \n" - " bne,pn %%icc, 1b; \n" - " nop; \n" - " add %[ret], %[i], %[ret]; \n" - : [ret] "=r&" (ret), [tmp] "=r&" (tmp) - : [i] "r" (i), [v] "r" (v) - : "memory", "cc"); - - return ret; -} - -#else /* HAVE_SYNC_ADD_AND_FETCH == 1 */ -# error Your compiler does not provide __atomic_add_fetch, __sync_add_and_fetch \ - and an LTP implementation is missing for your architecture. -#endif - -#ifdef LTP_USE_GENERIC_LOAD_STORE_ASM -static inline int tst_atomic_load(int *v) -{ - int ret; - - asm volatile("" : : : "memory"); - ret = *v; - asm volatile("" : : : "memory"); - - return ret; -} - -static inline void tst_atomic_store(int i, int *v) -{ - asm volatile("" : : : "memory"); - *v = i; - asm volatile("" : : : "memory"); -} +# error "Your compiler does not support atomic operations (__atomic or __sync)" #endif -static inline int tst_atomic_inc(int *v) +static inline int tst_atomic_inc(int32_t *v) { return tst_atomic_add_return(1, v); } -static inline int tst_atomic_dec(int *v) +static inline int tst_atomic_dec(int32_t *v) { return tst_atomic_add_return(-1, v); } -#endif /* TST_ATOMIC_H__ */ +#endif /* TST_ATOMIC_H__ */ -- 2.49.0 -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [LTP] [PATCH v2 2/2] lib: moves test infrastructure states into a shared context structure 2025-06-05 12:07 [LTP] [PATCH v2 1/2] tst_atomic: drop legacy inline assembly and use __atomic or __sync builtins Li Wang via ltp @ 2025-06-05 12:07 ` Li Wang via ltp 2025-06-05 12:20 ` Li Wang via ltp 2025-06-06 9:18 ` [LTP] [PATCH v2 1/2] tst_atomic: drop legacy inline assembly and use __atomic or __sync builtins Cyril Hrubis 1 sibling, 1 reply; 7+ messages in thread From: Li Wang via ltp @ 2025-06-05 12:07 UTC (permalink / raw) To: ltp This patch introduces a new struct context to consolidate various runtime state variables previously maintained as global variables in tst_test.c. The goal is to support better state sharing between parent and child processes particularly in scenarios that involve checkpointing or fork/exec patterns. To achieve this, a new struct ipc_region is defined, which encapsulates three components: a magic field for validation, a context structure for runtime metadata, and a results structure for test result counters. Optionally, a futex array is appended for test checkpoint synchronization. Test library IPC region (only one page size): +----------------------+ | Magic Number | +----------------------+ | struct context | +----------------------+ | struct results | +----------------------+ | futexes[], or N/A | +----------------------+ The shared memory region is allocated with a single page using mmap() and is zero-initialized with memset() to ensure a clean initial state. The patch refactors setup_ipc() and tst_reinit() to map this shared region and properly initialize internal pointers to the `context`, `results`, and `futexes` regions. Overall, this refactor reduces global state pollution, centralizes the runtime state management, and enables safe and efficient state sharing across test lifecycle phases. It also sets the foundation for future improvements such as multi-threaded test coordination or enhanced IPC mechanisms. Signed-off-by: Li Wang <liwang@redhat.com> Reviewed-by: Petr Vorel <pvorel@suse.cz> --- Notes: V1 -> V2: * make use of offsetof(struct ipc, futexes) * refine the tst_atomic functions to avoid pointer cast lib/tst_test.c | 212 ++++++++++++++++++++++++++++--------------------- 1 file changed, 121 insertions(+), 91 deletions(-) diff --git a/lib/tst_test.c b/lib/tst_test.c index 92dd6279d..ca5ccb89c 100644 --- a/lib/tst_test.c +++ b/lib/tst_test.c @@ -52,6 +52,7 @@ const char *TCID __attribute__((weak)); #define CVE_DB_URL "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-" #define DEFAULT_TIMEOUT 30 +#define LTP_MAGIC 0x4C54504D /* Magic number is "LTPM" */ struct tst_test *tst_test; @@ -59,36 +60,47 @@ static const char *tcid; static int iterations = 1; static float duration = -1; static float timeout_mul = -1; -static int mntpoint_mounted; -static int ovl_mounted; -static struct timespec tst_start_time; /* valid only for test pid */ -static int tdebug; static int reproducible_output; -struct results { - int passed; - int skipped; - int failed; - int warnings; - int broken; +struct context { + int32_t lib_pid; + int32_t main_pid; + struct timespec start_time; + int32_t runtime; + int32_t overall_time; /* * This is set by a call to tst_brk() with TBROK parameter and means * that the test should exit immediately. */ - int abort_flag; - unsigned int runtime; - unsigned int overall_time; - pid_t lib_pid; - pid_t main_pid; + int32_t abort_flag; + uint32_t mntpoint_mounted:1; + uint32_t ovl_mounted:1; + uint32_t tdebug:1; }; -static struct results *results; +struct results { + int32_t passed; + int32_t skipped; + int32_t failed; + int32_t warnings; + int32_t broken; +}; -static int ipc_fd; +struct ipc_region { + int32_t magic; + struct context context; + struct results results; + futex_t futexes[]; +}; -extern void *tst_futexes; +static struct ipc_region *ipc; +static struct context *context; +static struct results *results; + +extern volatile void *tst_futexes; extern unsigned int tst_max_futexes; +static int ipc_fd; static char ipc_path[1064]; const char *tst_ipc_path = ipc_path; @@ -127,25 +139,31 @@ static void setup_ipc(void) SAFE_FTRUNCATE(ipc_fd, size); - results = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0); - - /* Checkpoints needs to be accessible from processes started by exec() */ - if (tst_test->needs_checkpoints || tst_test->child_needs_reinit) { - sprintf(ipc_path, IPC_ENV_VAR "=%s", shm_path); - putenv(ipc_path); - } else { - SAFE_UNLINK(shm_path); - } + ipc = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ipc_fd, 0); SAFE_CLOSE(ipc_fd); + memset(ipc, 0, size); + + ipc->magic = LTP_MAGIC; + context = &ipc->context; + results = &ipc->results; + context->lib_pid = getpid(); + if (tst_test->needs_checkpoints) { - tst_futexes = (char *)results + sizeof(struct results); - tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t); + tst_futexes = ipc->futexes; + + size_t futexes_offset = offsetof(struct ipc_region, futexes); + tst_max_futexes = (size - futexes_offset) / sizeof(futex_t); } - memset(results, 0 , size); - results->lib_pid = getpid(); + /* Set environment variable for exec()'d children */ + if (tst_test->needs_checkpoints || tst_test->child_needs_reinit) { + snprintf(ipc_path, sizeof(ipc_path), IPC_ENV_VAR "=%s", shm_path); + putenv(ipc_path); + } else { + SAFE_UNLINK(shm_path); + } } static void cleanup_ipc(void) @@ -158,9 +176,11 @@ static void cleanup_ipc(void) if (shm_path[0] && !access(shm_path, F_OK) && unlink(shm_path)) tst_res(TWARN | TERRNO, "unlink(%s) failed", shm_path); - if (results) { - msync((void *)results, size, MS_SYNC); - munmap((void *)results, size); + if (ipc) { + msync((void *)ipc, size, MS_SYNC); + munmap((void *)ipc, size); + ipc = NULL; + context = NULL; results = NULL; } } @@ -178,12 +198,22 @@ void tst_reinit(void) tst_brk(TBROK, "File %s does not exist!", path); fd = SAFE_OPEN(path, O_RDWR); + ipc = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + SAFE_CLOSE(fd); - results = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - tst_futexes = (char *)results + sizeof(struct results); - tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t); + if (ipc->magic != LTP_MAGIC) + tst_brk(TBROK, "Invalid shared memory region (bad magic)"); - SAFE_CLOSE(fd); + /* Restore the parent context from IPC region */ + context = &ipc->context; + results = &ipc->results; + + tst_futexes = ipc->futexes; + size_t futexes_offset = offsetof(struct ipc_region, futexes); + tst_max_futexes = (size - futexes_offset) / sizeof(futex_t); + + if (context->tdebug) + tst_res(TINFO, "tst_reinit(): restored metadata for PID %d", getpid()); } extern char **environ; @@ -400,7 +430,7 @@ void tst_vbrk_(const char *file, const int lineno, int ttype, const char *fmt, * If tst_brk() is called from some of the C helpers even before the * library was initialized, just exit. */ - if (!results || !results->lib_pid) + if (!results || !context->lib_pid) exit(TTYPE_RESULT(ttype)); update_results(TTYPE_RESULT(ttype)); @@ -411,13 +441,13 @@ void tst_vbrk_(const char *file, const int lineno, int ttype, const char *fmt, * specified but CLONE_THREAD is not. Use direct syscall to avoid * cleanup running in the child. */ - if (tst_getpid() == results->main_pid) + if (tst_getpid() == context->main_pid) do_test_cleanup(); /* * The test library process reports result statistics and exits. */ - if (getpid() == results->lib_pid) + if (getpid() == context->lib_pid) do_exit(TTYPE_RESULT(ttype)); /* @@ -428,16 +458,16 @@ void tst_vbrk_(const char *file, const int lineno, int ttype, const char *fmt, */ if (TTYPE_RESULT(ttype) == TBROK) { if (results) - tst_atomic_inc(&results->abort_flag); + tst_atomic_inc(&context->abort_flag); /* * If TBROK was called from one of the child processes we kill * the main test process. That in turn triggers the code that * kills leftover children once the main test process did exit. */ - if (results->main_pid && tst_getpid() != results->main_pid) { + if (context->main_pid && tst_getpid() != context->main_pid) { tst_res(TINFO, "Child process reported TBROK killing the test"); - kill(results->main_pid, SIGKILL); + kill(context->main_pid, SIGKILL); } } @@ -449,7 +479,7 @@ void tst_res_(const char *file, const int lineno, int ttype, { va_list va; - if (ttype == TDEBUG && !tdebug) + if (ttype == TDEBUG && context && !context->tdebug) return; va_start(va, fmt); @@ -766,7 +796,7 @@ static void parse_opts(int argc, char *argv[]) break; case 'D': tst_res(TINFO, "Enabling debug info"); - tdebug = 1; + context->tdebug = 1; break; case 'h': print_help(); @@ -1111,7 +1141,7 @@ static int prepare_and_mount_ro_fs(const char *dev, const char *mntpoint, return 1; } - mntpoint_mounted = 1; + context->mntpoint_mounted = 1; snprintf(buf, sizeof(buf), "%s/dir/", mntpoint); SAFE_MKDIR(buf, 0777); @@ -1135,14 +1165,14 @@ static void prepare_and_mount_dev_fs(const char *mntpoint) tst_res(TINFO, "tmpdir isn't suitable for creating devices, " "mounting tmpfs without nodev on %s", mntpoint); SAFE_MOUNT(NULL, mntpoint, "tmpfs", 0, NULL); - mntpoint_mounted = 1; + context->mntpoint_mounted = 1; } } static void prepare_and_mount_hugetlb_fs(void) { SAFE_MOUNT("none", tst_test->mntpoint, "hugetlbfs", 0, NULL); - mntpoint_mounted = 1; + context->mntpoint_mounted = 1; } int tst_creat_unlinked(const char *path, int flags, mode_t mode) @@ -1228,7 +1258,7 @@ static void prepare_device(struct tst_fs *fs) SAFE_MOUNT(get_device_name(tdev.fs_type), tst_test->mntpoint, tdev.fs_type, fs->mnt_flags, mnt_data); - mntpoint_mounted = 1; + context->mntpoint_mounted = 1; } } @@ -1324,6 +1354,14 @@ static void do_setup(int argc, char *argv[]) if (tst_test->supported_archs && !tst_is_on_arch(tst_test->supported_archs)) tst_brk(TCONF, "This arch '%s' is not supported for test!", tst_arch.name); + if (tst_test->sample) + tst_test = tst_timer_test_setup(tst_test); + + if (tst_test->runs_script) { + tst_test->child_needs_reinit = 1; + tst_test->forks_child = 1; + } + if (reproducible_env && (!strcmp(reproducible_env, "1") || !strcmp(reproducible_env, "y"))) reproducible_output = 1; @@ -1332,23 +1370,15 @@ static void do_setup(int argc, char *argv[]) TCID = tcid = get_tcid(argv); - if (tst_test->sample) - tst_test = tst_timer_test_setup(tst_test); + setup_ipc(); parse_opts(argc, argv); if (tdebug_env && (!strcmp(tdebug_env, "1") || !strcmp(tdebug_env, "y"))) { tst_res(TINFO, "Enabling debug info"); - tdebug = 1; + context->tdebug = 1; } - if (tst_test->runs_script) { - tst_test->child_needs_reinit = 1; - tst_test->forks_child = 1; - } - - setup_ipc(); - if (tst_test->needs_kconfigs && tst_kconfig_check(tst_test->needs_kconfigs)) tst_brk(TCONF, "Aborting due to unsuitable kernel config, see above!"); @@ -1466,7 +1496,7 @@ static void do_setup(int argc, char *argv[]) if (tst_test->needs_hugetlbfs) prepare_and_mount_hugetlb_fs(); - if (tst_test->needs_device && !mntpoint_mounted) { + if (tst_test->needs_device && !context->mntpoint_mounted) { tdev.dev = tst_acquire_device_(NULL, tst_test->dev_min_size); if (!tdev.dev) @@ -1492,12 +1522,12 @@ static void do_setup(int argc, char *argv[]) if (tst_test->needs_overlay && !tst_test->mount_device) tst_brk(TBROK, "tst_test->mount_device must be set"); - if (tst_test->needs_overlay && !mntpoint_mounted) + if (tst_test->needs_overlay && !context->mntpoint_mounted) tst_brk(TBROK, "tst_test->mntpoint must be mounted"); - if (tst_test->needs_overlay && !ovl_mounted) { + if (tst_test->needs_overlay && !context->ovl_mounted) { SAFE_MOUNT_OVERLAY(); - ovl_mounted = 1; + context->ovl_mounted = 1; } if (tst_test->resource_files) @@ -1517,7 +1547,7 @@ static void do_setup(int argc, char *argv[]) static void do_test_setup(void) { - results->main_pid = getpid(); + context->main_pid = getpid(); if (!tst_test->all_filesystems && tst_test->skip_filesystems) { long fs_type = tst_fs_type("."); @@ -1537,7 +1567,7 @@ static void do_test_setup(void) if (tst_test->setup) tst_test->setup(); - if (results->main_pid != tst_getpid()) + if (context->main_pid != tst_getpid()) tst_brk(TBROK, "Runaway child in setup()!"); if (tst_test->caps) @@ -1549,10 +1579,10 @@ static void do_cleanup(void) if (tst_test->needs_cgroup_ctrls) tst_cg_cleanup(); - if (ovl_mounted) + if (context->ovl_mounted) SAFE_UMOUNT(OVL_MNT); - if (mntpoint_mounted) + if (context->mntpoint_mounted) tst_umount(tst_test->mntpoint); if (tst_test->needs_device && tdev.dev) @@ -1574,7 +1604,7 @@ static void do_cleanup(void) static void heartbeat(void) { - if (tst_clock_gettime(CLOCK_MONOTONIC, &tst_start_time)) + if (tst_clock_gettime(CLOCK_MONOTONIC, &context->start_time)) tst_res(TWARN | TERRNO, "tst_clock_gettime() failed"); if (getppid() == 1) { @@ -1600,7 +1630,7 @@ static void run_tests(void) heartbeat(); tst_test->test_all(); - if (tst_getpid() != results->main_pid) + if (tst_getpid() != context->main_pid) exit(0); tst_reap_children(); @@ -1616,7 +1646,7 @@ static void run_tests(void) heartbeat(); tst_test->test(i); - if (tst_getpid() != results->main_pid) + if (tst_getpid() != context->main_pid) exit(0); tst_reap_children(); @@ -1716,7 +1746,7 @@ static void alarm_handler(int sig LTP_ATTRIBUTE_UNUSED) static void heartbeat_handler(int sig LTP_ATTRIBUTE_UNUSED) { - alarm(results->overall_time); + alarm(context->overall_time); sigkill_retries = 0; } @@ -1733,15 +1763,15 @@ unsigned int tst_remaining_runtime(void) static struct timespec now; int elapsed; - if (results->runtime == 0) + if (context->runtime == 0) tst_brk(TBROK, "Runtime not set!"); if (tst_clock_gettime(CLOCK_MONOTONIC, &now)) tst_res(TWARN | TERRNO, "tst_clock_gettime() failed"); - elapsed = tst_timespec_diff_ms(now, tst_start_time) / 1000; - if (results->runtime > (unsigned int) elapsed) - return results->runtime - elapsed; + elapsed = tst_timespec_diff_ms(now, context->start_time) / 1000; + if (context->runtime > elapsed) + return context->runtime - elapsed; return 0; } @@ -1769,29 +1799,29 @@ static void set_overall_timeout(void) return; } - results->overall_time = tst_multiply_timeout(timeout) + results->runtime; + context->overall_time = tst_multiply_timeout(timeout) + context->runtime; tst_res(TINFO, "Overall timeout per run is %uh %02um %02us", - results->overall_time/3600, (results->overall_time%3600)/60, - results->overall_time % 60); + context->overall_time/3600, (context->overall_time%3600)/60, + context->overall_time % 60); } void tst_set_timeout(int timeout) { int timeout_adj = DEFAULT_TIMEOUT + timeout; - results->overall_time = tst_multiply_timeout(timeout_adj) + results->runtime; + context->overall_time = tst_multiply_timeout(timeout_adj) + context->runtime; tst_res(TINFO, "Overall timeout per run is %uh %02um %02us", - results->overall_time/3600, (results->overall_time%3600)/60, - results->overall_time % 60); + context->overall_time/3600, (context->overall_time%3600)/60, + context->overall_time % 60); heartbeat(); } void tst_set_runtime(int runtime) { - results->runtime = multiply_runtime(runtime); + context->runtime = multiply_runtime(runtime); tst_res(TINFO, "Updating runtime to %uh %02um %02us", runtime/3600, (runtime%3600)/60, runtime % 60); set_overall_timeout(); @@ -1805,7 +1835,7 @@ static int fork_testrun(void) SAFE_SIGNAL(SIGINT, sigint_handler); SAFE_SIGNAL(SIGTERM, sigint_handler); - alarm(results->overall_time); + alarm(context->overall_time); show_failure_hints = 1; @@ -1839,7 +1869,7 @@ static int fork_testrun(void) if (WIFEXITED(status) && WEXITSTATUS(status)) tst_brk(TBROK, "Child returned with %i", WEXITSTATUS(status)); - if (results->abort_flag) + if (context->abort_flag) return 0; if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) { @@ -1898,9 +1928,9 @@ static int run_tcase_on_fs(struct tst_fs *fs, const char *fs_type) ret = fork_testrun(); - if (mntpoint_mounted) { + if (context->mntpoint_mounted) { tst_umount(tst_test->mntpoint); - mntpoint_mounted = 0; + context->mntpoint_mounted = 0; } return ret; @@ -1925,7 +1955,7 @@ static int run_tcases_per_fs(void) found_valid_fs = true; run_tcase_on_fs(fs, filesystems[i]); - if (tst_atomic_load(&results->abort_flag)) + if (tst_atomic_load(&context->abort_flag)) do_exit(0); } @@ -1945,7 +1975,7 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self) tst_test = self; do_setup(argc, argv); - tst_enable_oom_protection(results->lib_pid); + tst_enable_oom_protection(context->lib_pid); SAFE_SIGNAL(SIGALRM, alarm_handler); SAFE_SIGNAL(SIGUSR1, heartbeat_handler); @@ -1956,7 +1986,7 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self) tst_res(TINFO, "Tested kernel: %s %s %s", uval.release, uval.version, uval.machine); if (tst_test->runtime) - results->runtime = multiply_runtime(tst_test->runtime); + context->runtime = multiply_runtime(tst_test->runtime); set_overall_timeout(); @@ -1969,7 +1999,7 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self) else fork_testrun(); - if (tst_atomic_load(&results->abort_flag)) + if (tst_atomic_load(&context->abort_flag)) do_exit(0); } -- 2.49.0 -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v2 2/2] lib: moves test infrastructure states into a shared context structure 2025-06-05 12:07 ` [LTP] [PATCH v2 2/2] lib: moves test infrastructure states into a shared context structure Li Wang via ltp @ 2025-06-05 12:20 ` Li Wang via ltp 0 siblings, 0 replies; 7+ messages in thread From: Li Wang via ltp @ 2025-06-05 12:20 UTC (permalink / raw) To: Li Wang; +Cc: ltp Li Wang via ltp <ltp@lists.linux.it> wrote: > + size_t futexes_offset = offsetof(struct ipc_region, > futexes); > + tst_max_futexes = (size - futexes_offset) / > sizeof(futex_t); > I suddenly realized that Cyril's meant: tst_max_futexes = (size - offsetof(struct ipc_region, futexes)) / sizeof(futex_t); Okay, we can refine this before the patch merging (or in patch v3 if needed). @@ -178,12 +198,22 @@ void tst_reinit(void) > tst_brk(TBROK, "File %s does not exist!", path); > > fd = SAFE_OPEN(path, O_RDWR); > + ipc = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, > fd, 0); > + SAFE_CLOSE(fd); > > - results = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, > MAP_SHARED, fd, 0); > - tst_futexes = (char *)results + sizeof(struct results); > - tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t); > + if (ipc->magic != LTP_MAGIC) > + tst_brk(TBROK, "Invalid shared memory region (bad magic)"); > > - SAFE_CLOSE(fd); > + /* Restore the parent context from IPC region */ > + context = &ipc->context; > + results = &ipc->results; > + > + tst_futexes = ipc->futexes; > + size_t futexes_offset = offsetof(struct ipc_region, futexes); > + tst_max_futexes = (size - futexes_offset) / sizeof(futex_t); > tst_max_futexes = (size - offsetof(struct ipc_region, futexes)) / sizeof(futex_t); -- Regards, Li Wang -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v2 1/2] tst_atomic: drop legacy inline assembly and use __atomic or __sync builtins 2025-06-05 12:07 [LTP] [PATCH v2 1/2] tst_atomic: drop legacy inline assembly and use __atomic or __sync builtins Li Wang via ltp 2025-06-05 12:07 ` [LTP] [PATCH v2 2/2] lib: moves test infrastructure states into a shared context structure Li Wang via ltp @ 2025-06-06 9:18 ` Cyril Hrubis 2025-06-06 9:36 ` Li Wang via ltp 1 sibling, 1 reply; 7+ messages in thread From: Cyril Hrubis @ 2025-06-06 9:18 UTC (permalink / raw) To: Li Wang; +Cc: ltp Hi! > Refactor tst_atomic.h to remove all legacy architecture-specific inline > assembly and fallback code paths. The new implementation supports only > two well-defined interfaces: __atomic_* built-ins (GCC ≥ 4.7) and __sync_* > built-ins (GCC ≥ 4.1). > > This simplification improves maintainability, clarity, and portability > across platforms. It also updates all function signatures to use int32_t > for type consistency when operating on atomic counters, such as those in > struct tst_results. Can we please split the patch into the removal of the assembly and separate patch that changes the types? Also do we need to update fuzzy sync library in the second patch in order not to produce warnings? -- Cyril Hrubis chrubis@suse.cz -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v2 1/2] tst_atomic: drop legacy inline assembly and use __atomic or __sync builtins 2025-06-06 9:18 ` [LTP] [PATCH v2 1/2] tst_atomic: drop legacy inline assembly and use __atomic or __sync builtins Cyril Hrubis @ 2025-06-06 9:36 ` Li Wang via ltp 2025-06-06 10:10 ` Li Wang via ltp 0 siblings, 1 reply; 7+ messages in thread From: Li Wang via ltp @ 2025-06-06 9:36 UTC (permalink / raw) To: Cyril Hrubis; +Cc: ltp On Fri, Jun 6, 2025 at 5:18 PM Cyril Hrubis <chrubis@suse.cz> wrote: > Hi! > > Refactor tst_atomic.h to remove all legacy architecture-specific inline > > assembly and fallback code paths. The new implementation supports only > > two well-defined interfaces: __atomic_* built-ins (GCC ≥ 4.7) and > __sync_* > > built-ins (GCC ≥ 4.1). > > > > This simplification improves maintainability, clarity, and portability > > across platforms. It also updates all function signatures to use int32_t > > for type consistency when operating on atomic counters, such as those in > > struct tst_results. > > Can we please split the patch into the removal of the assembly and > separate patch that changes the types? > Of course sure. It would be clearer and tidier. > > Also do we need to update fuzzy sync library in the second patch in > order not to produce warnings? Good point, also we probably need to check all related atomic operations to ensure no new warnings by the type conversion. I will rework that into two separate patches and send v3. Thanks! -- Regards, Li Wang -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v2 1/2] tst_atomic: drop legacy inline assembly and use __atomic or __sync builtins 2025-06-06 9:36 ` Li Wang via ltp @ 2025-06-06 10:10 ` Li Wang via ltp 2025-06-06 10:16 ` Cyril Hrubis 0 siblings, 1 reply; 7+ messages in thread From: Li Wang via ltp @ 2025-06-06 10:10 UTC (permalink / raw) To: Cyril Hrubis; +Cc: ltp Hi Cyril, Li Wang <liwang@redhat.com> wrote: > Also do we need to update fuzzy sync library in the second patch in >> order not to produce warnings? > > > Good point, also we probably need to check all related atomic operations to > ensure no new warnings by the type conversion. > Or, do you think it's necessary to define a dedicated tst_atomic_t type, such as: typedef int32_t tst_atomic_t; and use it explicitly for all variables that are subject to atomic operations? This way, we can clearly declare which values are intended for atomic use, improving type safety and code clarity. -- Regards, Li Wang -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v2 1/2] tst_atomic: drop legacy inline assembly and use __atomic or __sync builtins 2025-06-06 10:10 ` Li Wang via ltp @ 2025-06-06 10:16 ` Cyril Hrubis 0 siblings, 0 replies; 7+ messages in thread From: Cyril Hrubis @ 2025-06-06 10:16 UTC (permalink / raw) To: Li Wang; +Cc: ltp Hi! > Or, do you think it's necessary to define a dedicated tst_atomic_t type, > such as: > typedef int32_t tst_atomic_t; > and use it explicitly for all variables that are subject to atomic > operations? > > This way, we can clearly declare which values are intended for atomic use, > improving type safety and code clarity. Sounds good to me. -- Cyril Hrubis chrubis@suse.cz -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2025-06-06 10:16 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-06-05 12:07 [LTP] [PATCH v2 1/2] tst_atomic: drop legacy inline assembly and use __atomic or __sync builtins Li Wang via ltp 2025-06-05 12:07 ` [LTP] [PATCH v2 2/2] lib: moves test infrastructure states into a shared context structure Li Wang via ltp 2025-06-05 12:20 ` Li Wang via ltp 2025-06-06 9:18 ` [LTP] [PATCH v2 1/2] tst_atomic: drop legacy inline assembly and use __atomic or __sync builtins Cyril Hrubis 2025-06-06 9:36 ` Li Wang via ltp 2025-06-06 10:10 ` Li Wang via ltp 2025-06-06 10:16 ` Cyril Hrubis
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.