linux/tools/testing/selftests/futex/include/futextest.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-or-later */
   2/******************************************************************************
   3 *
   4 *   Copyright © International Business Machines  Corp., 2009
   5 *
   6 * DESCRIPTION
   7 *      Glibc independent futex library for testing kernel functionality.
   8 *
   9 * AUTHOR
  10 *      Darren Hart <dvhart@linux.intel.com>
  11 *
  12 * HISTORY
  13 *      2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com>
  14 *
  15 *****************************************************************************/
  16
  17#ifndef _FUTEXTEST_H
  18#define _FUTEXTEST_H
  19
  20#include <unistd.h>
  21#include <sys/syscall.h>
  22#include <sys/types.h>
  23#include <linux/futex.h>
  24
  25typedef volatile u_int32_t futex_t;
  26#define FUTEX_INITIALIZER 0
  27
  28/* Define the newer op codes if the system header file is not up to date. */
  29#ifndef FUTEX_WAIT_BITSET
  30#define FUTEX_WAIT_BITSET               9
  31#endif
  32#ifndef FUTEX_WAKE_BITSET
  33#define FUTEX_WAKE_BITSET               10
  34#endif
  35#ifndef FUTEX_WAIT_REQUEUE_PI
  36#define FUTEX_WAIT_REQUEUE_PI           11
  37#endif
  38#ifndef FUTEX_CMP_REQUEUE_PI
  39#define FUTEX_CMP_REQUEUE_PI            12
  40#endif
  41#ifndef FUTEX_WAIT_REQUEUE_PI_PRIVATE
  42#define FUTEX_WAIT_REQUEUE_PI_PRIVATE   (FUTEX_WAIT_REQUEUE_PI | \
  43                                         FUTEX_PRIVATE_FLAG)
  44#endif
  45#ifndef FUTEX_REQUEUE_PI_PRIVATE
  46#define FUTEX_CMP_REQUEUE_PI_PRIVATE    (FUTEX_CMP_REQUEUE_PI | \
  47                                         FUTEX_PRIVATE_FLAG)
  48#endif
  49
  50/**
  51 * futex() - SYS_futex syscall wrapper
  52 * @uaddr:      address of first futex
  53 * @op:         futex op code
  54 * @val:        typically expected value of uaddr, but varies by op
  55 * @timeout:    typically an absolute struct timespec (except where noted
  56 *              otherwise). Overloaded by some ops
  57 * @uaddr2:     address of second futex for some ops\
  58 * @val3:       varies by op
  59 * @opflags:    flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG
  60 *
  61 * futex() is used by all the following futex op wrappers. It can also be
  62 * used for misuse and abuse testing. Generally, the specific op wrappers
  63 * should be used instead. It is a macro instead of an static inline function as
  64 * some of the types over overloaded (timeout is used for nr_requeue for
  65 * example).
  66 *
  67 * These argument descriptions are the defaults for all
  68 * like-named arguments in the following wrappers except where noted below.
  69 */
  70#define futex(uaddr, op, val, timeout, uaddr2, val3, opflags) \
  71        syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3)
  72
  73/**
  74 * futex_wait() - block on uaddr with optional timeout
  75 * @timeout:    relative timeout
  76 */
  77static inline int
  78futex_wait(futex_t *uaddr, futex_t val, struct timespec *timeout, int opflags)
  79{
  80        return futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags);
  81}
  82
  83/**
  84 * futex_wake() - wake one or more tasks blocked on uaddr
  85 * @nr_wake:    wake up to this many tasks
  86 */
  87static inline int
  88futex_wake(futex_t *uaddr, int nr_wake, int opflags)
  89{
  90        return futex(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags);
  91}
  92
  93/**
  94 * futex_wait_bitset() - block on uaddr with bitset
  95 * @bitset:     bitset to be used with futex_wake_bitset
  96 */
  97static inline int
  98futex_wait_bitset(futex_t *uaddr, futex_t val, struct timespec *timeout,
  99                  u_int32_t bitset, int opflags)
 100{
 101        return futex(uaddr, FUTEX_WAIT_BITSET, val, timeout, NULL, bitset,
 102                     opflags);
 103}
 104
 105/**
 106 * futex_wake_bitset() - wake one or more tasks blocked on uaddr with bitset
 107 * @bitset:     bitset to compare with that used in futex_wait_bitset
 108 */
 109static inline int
 110futex_wake_bitset(futex_t *uaddr, int nr_wake, u_int32_t bitset, int opflags)
 111{
 112        return futex(uaddr, FUTEX_WAKE_BITSET, nr_wake, NULL, NULL, bitset,
 113                     opflags);
 114}
 115
 116/**
 117 * futex_lock_pi() - block on uaddr as a PI mutex
 118 * @detect:     whether (1) or not (0) to perform deadlock detection
 119 */
 120static inline int
 121futex_lock_pi(futex_t *uaddr, struct timespec *timeout, int detect,
 122              int opflags)
 123{
 124        return futex(uaddr, FUTEX_LOCK_PI, detect, timeout, NULL, 0, opflags);
 125}
 126
 127/**
 128 * futex_unlock_pi() - release uaddr as a PI mutex, waking the top waiter
 129 */
 130static inline int
 131futex_unlock_pi(futex_t *uaddr, int opflags)
 132{
 133        return futex(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags);
 134}
 135
 136/**
 137 * futex_wake_op() - FIXME: COME UP WITH A GOOD ONE LINE DESCRIPTION
 138 */
 139static inline int
 140futex_wake_op(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_wake2,
 141              int wake_op, int opflags)
 142{
 143        return futex(uaddr, FUTEX_WAKE_OP, nr_wake, nr_wake2, uaddr2, wake_op,
 144                     opflags);
 145}
 146
 147/**
 148 * futex_requeue() - requeue without expected value comparison, deprecated
 149 * @nr_wake:    wake up to this many tasks
 150 * @nr_requeue: requeue up to this many tasks
 151 *
 152 * Due to its inherently racy implementation, futex_requeue() is deprecated in
 153 * favor of futex_cmp_requeue().
 154 */
 155static inline int
 156futex_requeue(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_requeue,
 157              int opflags)
 158{
 159        return futex(uaddr, FUTEX_REQUEUE, nr_wake, nr_requeue, uaddr2, 0,
 160                     opflags);
 161}
 162
 163/**
 164 * futex_cmp_requeue() - requeue tasks from uaddr to uaddr2
 165 * @nr_wake:    wake up to this many tasks
 166 * @nr_requeue: requeue up to this many tasks
 167 */
 168static inline int
 169futex_cmp_requeue(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake,
 170                  int nr_requeue, int opflags)
 171{
 172        return futex(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2,
 173                     val, opflags);
 174}
 175
 176/**
 177 * futex_wait_requeue_pi() - block on uaddr and prepare to requeue to uaddr2
 178 * @uaddr:      non-PI futex source
 179 * @uaddr2:     PI futex target
 180 *
 181 * This is the first half of the requeue_pi mechanism. It shall always be
 182 * paired with futex_cmp_requeue_pi().
 183 */
 184static inline int
 185futex_wait_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2,
 186                      struct timespec *timeout, int opflags)
 187{
 188        return futex(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0,
 189                     opflags);
 190}
 191
 192/**
 193 * futex_cmp_requeue_pi() - requeue tasks from uaddr to uaddr2 (PI aware)
 194 * @uaddr:      non-PI futex source
 195 * @uaddr2:     PI futex target
 196 * @nr_wake:    wake up to this many tasks
 197 * @nr_requeue: requeue up to this many tasks
 198 */
 199static inline int
 200futex_cmp_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake,
 201                     int nr_requeue, int opflags)
 202{
 203        return futex(uaddr, FUTEX_CMP_REQUEUE_PI, nr_wake, nr_requeue, uaddr2,
 204                     val, opflags);
 205}
 206
 207/**
 208 * futex_cmpxchg() - atomic compare and exchange
 209 * @uaddr:      The address of the futex to be modified
 210 * @oldval:     The expected value of the futex
 211 * @newval:     The new value to try and assign the futex
 212 *
 213 * Implement cmpxchg using gcc atomic builtins.
 214 * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
 215 *
 216 * Return the old futex value.
 217 */
 218static inline u_int32_t
 219futex_cmpxchg(futex_t *uaddr, u_int32_t oldval, u_int32_t newval)
 220{
 221        return __sync_val_compare_and_swap(uaddr, oldval, newval);
 222}
 223
 224/**
 225 * futex_dec() - atomic decrement of the futex value
 226 * @uaddr:      The address of the futex to be modified
 227 *
 228 * Return the new futex value.
 229 */
 230static inline u_int32_t
 231futex_dec(futex_t *uaddr)
 232{
 233        return __sync_sub_and_fetch(uaddr, 1);
 234}
 235
 236/**
 237 * futex_inc() - atomic increment of the futex value
 238 * @uaddr:      the address of the futex to be modified
 239 *
 240 * Return the new futex value.
 241 */
 242static inline u_int32_t
 243futex_inc(futex_t *uaddr)
 244{
 245        return __sync_add_and_fetch(uaddr, 1);
 246}
 247
 248/**
 249 * futex_set() - atomic decrement of the futex value
 250 * @uaddr:      the address of the futex to be modified
 251 * @newval:     New value for the atomic_t
 252 *
 253 * Return the new futex value.
 254 */
 255static inline u_int32_t
 256futex_set(futex_t *uaddr, u_int32_t newval)
 257{
 258        *uaddr = newval;
 259        return newval;
 260}
 261
 262#endif
 263