Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

selftests/futex: Adapt the private hash test to RCU related changes

The auto scaling on create creation used to automatically assign the new
hash because there was the private hash was unused and could be replaced
right away.

This is already racy because if the private hash is in use by a thread
then the visibile resize will be delayed. With the upcoming change to
wait for a RCU grace period before the hash can be assigned, the test
will always fail.

If the reported number of hash buckets is not updated after an
auto scaling event, block on an acquired lock with a timeout. The timeout
is the delay to wait towards a grace period and locking and a locked
pthread_mutex_t ensure that glibc calls into kernel using futex
operation which will assign new private hash if available.
This will retry every 100ms up to 2 seconds in total.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20250710110011.384614-2-bigeasy@linutronix.de

authored by

Sebastian Andrzej Siewior and committed by
Peter Zijlstra
a255b78d d7b8f8e2

+41 -1
+41 -1
tools/testing/selftests/futex/functional/futex_priv_hash.c
··· 111 111 } 112 112 } 113 113 114 + #define SEC_IN_NSEC 1000000000 115 + #define MSEC_IN_NSEC 1000000 116 + 117 + static void futex_dummy_op(void) 118 + { 119 + pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 120 + struct timespec timeout; 121 + int ret; 122 + 123 + pthread_mutex_lock(&lock); 124 + clock_gettime(CLOCK_REALTIME, &timeout); 125 + timeout.tv_nsec += 100 * MSEC_IN_NSEC; 126 + if (timeout.tv_nsec >= SEC_IN_NSEC) { 127 + timeout.tv_nsec -= SEC_IN_NSEC; 128 + timeout.tv_sec++; 129 + } 130 + ret = pthread_mutex_timedlock(&lock, &timeout); 131 + if (ret == 0) 132 + ksft_exit_fail_msg("Succeffuly locked an already locked mutex.\n"); 133 + 134 + if (ret != ETIMEDOUT) 135 + ksft_exit_fail_msg("pthread_mutex_timedlock() did not timeout: %d.\n", ret); 136 + } 137 + 114 138 static void usage(char *prog) 115 139 { 116 140 printf("Usage: %s\n", prog); ··· 153 129 int futex_slots1, futex_slotsn, online_cpus; 154 130 pthread_mutexattr_t mutex_attr_pi; 155 131 int use_global_hash = 0; 156 - int ret; 132 + int ret, retry = 20; 157 133 int c; 158 134 159 135 while ((c = getopt(argc, argv, "cghv:")) != -1) { ··· 232 208 */ 233 209 ksft_print_msg("Online CPUs: %d\n", online_cpus); 234 210 if (online_cpus > 16) { 211 + retry_getslots: 235 212 futex_slotsn = futex_hash_slots_get(); 236 213 if (futex_slotsn < 0 || futex_slots1 == futex_slotsn) { 214 + retry--; 215 + /* 216 + * Auto scaling on thread creation can be slightly delayed 217 + * because it waits for a RCU grace period twice. The new 218 + * private hash is assigned upon the first futex operation 219 + * after grace period. 220 + * To cover all this for testing purposes the function 221 + * below will acquire a lock and acquire it again with a 222 + * 100ms timeout which must timeout. This ensures we 223 + * sleep for 100ms and issue a futex operation. 224 + */ 225 + if (retry > 0) { 226 + futex_dummy_op(); 227 + goto retry_getslots; 228 + } 237 229 ksft_print_msg("Expected increase of hash buckets but got: %d -> %d\n", 238 230 futex_slots1, futex_slotsn); 239 231 ksft_exit_fail_msg(test_msg_auto_inc);