Skip to content

Commit a255b78

Browse files
Sebastian Andrzej SiewiorPeter Zijlstra
authored andcommitted
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 <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent d7b8f8e commit a255b78

File tree

1 file changed

+41
-1
lines changed

1 file changed

+41
-1
lines changed

tools/testing/selftests/futex/functional/futex_priv_hash.c

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,30 @@ static void join_max_threads(void)
111111
}
112112
}
113113

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+
114138
static void usage(char *prog)
115139
{
116140
printf("Usage: %s\n", prog);
@@ -129,7 +153,7 @@ int main(int argc, char *argv[])
129153
int futex_slots1, futex_slotsn, online_cpus;
130154
pthread_mutexattr_t mutex_attr_pi;
131155
int use_global_hash = 0;
132-
int ret;
156+
int ret, retry = 20;
133157
int c;
134158

135159
while ((c = getopt(argc, argv, "cghv:")) != -1) {
@@ -208,8 +232,24 @@ int main(int argc, char *argv[])
208232
*/
209233
ksft_print_msg("Online CPUs: %d\n", online_cpus);
210234
if (online_cpus > 16) {
235+
retry_getslots:
211236
futex_slotsn = futex_hash_slots_get();
212237
if (futex_slotsn < 0 || futex_slots1 == futex_slotsn) {
238+
retry--;
239+
/*
240+
* Auto scaling on thread creation can be slightly delayed
241+
* because it waits for a RCU grace period twice. The new
242+
* private hash is assigned upon the first futex operation
243+
* after grace period.
244+
* To cover all this for testing purposes the function
245+
* below will acquire a lock and acquire it again with a
246+
* 100ms timeout which must timeout. This ensures we
247+
* sleep for 100ms and issue a futex operation.
248+
*/
249+
if (retry > 0) {
250+
futex_dummy_op();
251+
goto retry_getslots;
252+
}
213253
ksft_print_msg("Expected increase of hash buckets but got: %d -> %d\n",
214254
futex_slots1, futex_slotsn);
215255
ksft_exit_fail_msg(test_msg_auto_inc);

0 commit comments

Comments
 (0)