linux/tools/testing/selftests/futex/functional/futex_requeue.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright Collabora Ltd., 2021
   4 *
   5 * futex cmp requeue test by André Almeida <andrealmeid@collabora.com>
   6 */
   7
   8#include <pthread.h>
   9#include <limits.h>
  10#include "logging.h"
  11#include "futextest.h"
  12
  13#define TEST_NAME "futex-requeue"
  14#define timeout_ns  30000000
  15#define WAKE_WAIT_US 10000
  16
  17volatile futex_t *f1;
  18
  19void usage(char *prog)
  20{
  21        printf("Usage: %s\n", prog);
  22        printf("  -c    Use color\n");
  23        printf("  -h    Display this help message\n");
  24        printf("  -v L  Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n",
  25               VQUIET, VCRITICAL, VINFO);
  26}
  27
  28void *waiterfn(void *arg)
  29{
  30        struct timespec to;
  31
  32        to.tv_sec = 0;
  33        to.tv_nsec = timeout_ns;
  34
  35        if (futex_wait(f1, *f1, &to, 0))
  36                printf("waiter failed errno %d\n", errno);
  37
  38        return NULL;
  39}
  40
  41int main(int argc, char *argv[])
  42{
  43        pthread_t waiter[10];
  44        int res, ret = RET_PASS;
  45        int c, i;
  46        volatile futex_t _f1 = 0;
  47        volatile futex_t f2 = 0;
  48
  49        f1 = &_f1;
  50
  51        while ((c = getopt(argc, argv, "cht:v:")) != -1) {
  52                switch (c) {
  53                case 'c':
  54                        log_color(1);
  55                        break;
  56                case 'h':
  57                        usage(basename(argv[0]));
  58                        exit(0);
  59                case 'v':
  60                        log_verbosity(atoi(optarg));
  61                        break;
  62                default:
  63                        usage(basename(argv[0]));
  64                        exit(1);
  65                }
  66        }
  67
  68        ksft_print_header();
  69        ksft_set_plan(2);
  70        ksft_print_msg("%s: Test futex_requeue\n",
  71                       basename(argv[0]));
  72
  73        /*
  74         * Requeue a waiter from f1 to f2, and wake f2.
  75         */
  76        if (pthread_create(&waiter[0], NULL, waiterfn, NULL))
  77                error("pthread_create failed\n", errno);
  78
  79        usleep(WAKE_WAIT_US);
  80
  81        info("Requeuing 1 futex from f1 to f2\n");
  82        res = futex_cmp_requeue(f1, 0, &f2, 0, 1, 0);
  83        if (res != 1) {
  84                ksft_test_result_fail("futex_requeue simple returned: %d %s\n",
  85                                      res ? errno : res,
  86                                      res ? strerror(errno) : "");
  87                ret = RET_FAIL;
  88        }
  89
  90
  91        info("Waking 1 futex at f2\n");
  92        res = futex_wake(&f2, 1, 0);
  93        if (res != 1) {
  94                ksft_test_result_fail("futex_requeue simple returned: %d %s\n",
  95                                      res ? errno : res,
  96                                      res ? strerror(errno) : "");
  97                ret = RET_FAIL;
  98        } else {
  99                ksft_test_result_pass("futex_requeue simple succeeds\n");
 100        }
 101
 102
 103        /*
 104         * Create 10 waiters at f1. At futex_requeue, wake 3 and requeue 7.
 105         * At futex_wake, wake INT_MAX (should be exactly 7).
 106         */
 107        for (i = 0; i < 10; i++) {
 108                if (pthread_create(&waiter[i], NULL, waiterfn, NULL))
 109                        error("pthread_create failed\n", errno);
 110        }
 111
 112        usleep(WAKE_WAIT_US);
 113
 114        info("Waking 3 futexes at f1 and requeuing 7 futexes from f1 to f2\n");
 115        res = futex_cmp_requeue(f1, 0, &f2, 3, 7, 0);
 116        if (res != 10) {
 117                ksft_test_result_fail("futex_requeue many returned: %d %s\n",
 118                                      res ? errno : res,
 119                                      res ? strerror(errno) : "");
 120                ret = RET_FAIL;
 121        }
 122
 123        info("Waking INT_MAX futexes at f2\n");
 124        res = futex_wake(&f2, INT_MAX, 0);
 125        if (res != 7) {
 126                ksft_test_result_fail("futex_requeue many returned: %d %s\n",
 127                                      res ? errno : res,
 128                                      res ? strerror(errno) : "");
 129                ret = RET_FAIL;
 130        } else {
 131                ksft_test_result_pass("futex_requeue many succeeds\n");
 132        }
 133
 134        ksft_print_cnts();
 135        return ret;
 136}
 137