futex.h 4.94 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
/**
 * \brief Simple wrapper functions for the Linux Futex system call
 * \file futex.h
 *
 * This header provides small wrapper functions for the futex system call. It
 * has, however, the following limitations:
 *  - no support for wait operations with timeout
 *  - no support for intra-process futexes via shared memory mappings
 *  - no sophisticated futex operations like \c FUTEX_REQUEUE, \c FUTEX_WAIT_BITSET,
 *    or \c FUTEX_WAKE_OP.
 *
 * \warning This code requires gcc or a compatible compiler (e.g. clang)
 * \warning The futex system call is linux-specific and therefore not portable
 */
#ifndef __FUTEX_H_INCLUDED__
#define __FUTEX_H_INCLUDED__

#include <linux/futex.h>
#include <limits.h>
#include <stddef.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdatomic.h>

#ifndef SYS_futex
#  error "The futex system call is not available"
#endif

#ifndef __GNUC__
#  error "please use gcc, clang, or a compatible compiler"
#endif

/**
 * \brief Let functions behave like macros
 *
 * This modifier allows placement of functions in header files. The compiler
 * will inline them (just like macros) and will not complain about unused
 * functions.
 *
 * In general, functions have multple advantages over macros, e.g.
 *  - Type safety
 *  - No double argument expansion
 *  - No unexpected text replacement in other source code files
 *  - Better debugging information
 *
 * \warning This macro is intended for internal use only
 */
#ifdef __GNUC__
#  define futex__exposed static inline __attribute__((__always_inline__,__unused__))
#else
#  define futex__exposed /* this macro confuses doxygen */
#endif

/**
 * \brief Wait for a variable to change
 *
 * This function causes the calling thread to sleep, but only if the value at
 * \c *addr is equal to \c exp. If the values are not equal (e.g. due to a
 * concurrent modification), this system call returns.
 *
 * The thread will not wake up automatically when the variable changes.
 * Instead, each thread that updates the variable is responsible to call
 * futex_wake_one or futex_wake_all, to wake up sleeping threads.
 *
 * \param addr The address of the variable of interest
 * \param exp  The expected value of that variable
 * \returns 0 on success
 * \returns -1 on error
 *
 * \see [man 2 syscall](http://man7.org/linux/man-pages/man2/syscall.2.html)
 * \see [man 2 futex](http://man7.org/linux/man-pages/man2/futex.2.html)
 * \see [man 7 futex](http://man7.org/linux/man-pages/man7/futex.7.html)
 */
futex__exposed int futex_wait(atomic_int *addr, int exp)
{
	return syscall(SYS_futex, addr, FUTEX_WAIT_PRIVATE, exp, NULL);
}

/**
 * \brief Wake up a thread waiting on a futex variable
 *
 * This function wakes up a thread waiting on a futex. However, the number of
 * threads that actually wake up is not clear. If there is a thread waiting on
 * the given variable, then at least one thread will wake up. However, it is
 * possible that no thread wakes up (if no thread is waiting on the variable),
 * and it is also possible that more than one thread wakes up (e.g. if a thread
 * is concurrently going to sleep).
 *
 * \param addr The address of the variable of interest
 * \returns 0 on success
 * \returns -1 on error
 *
 * \see [man 2 syscall](http://man7.org/linux/man-pages/man2/syscall.2.html)
 * \see [man 2 futex](http://man7.org/linux/man-pages/man2/futex.2.html)
 * \see [man 7 futex](http://man7.org/linux/man-pages/man7/futex.7.html)
 */
futex__exposed int futex_wake_one(atomic_int *addr)
{
	return syscall(SYS_futex, addr, FUTEX_WAKE_PRIVATE, 1);
}

/**
 * \brief Wake up a thread waiting on a futex variable
 *
 * This function wakes up all threads waiting on a futex. However, it is not
 * clear whether a thread that concurrently calls futex_wait will wake up as
 * well.
 *
 * \param addr The address of the variable of interest
 * \returns 0 on success
 * \returns -1 on error
 *
 * \see [man 2 syscall](http://man7.org/linux/man-pages/man2/syscall.2.html)
 * \see [man 2 futex](http://man7.org/linux/man-pages/man2/futex.2.html)
 * \see [man 7 futex](http://man7.org/linux/man-pages/man7/futex.7.html)
 */
futex__exposed int futex_wake_all(atomic_int *addr)
{
	return syscall(SYS_futex, addr, FUTEX_WAKE_PRIVATE, INT_MAX);
}

Stefan Reif's avatar
Stefan Reif committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
/**
 * \brief Wait for a variable to change, with timeout
 *
 * This function is equivalent to futex_wait, but it takes an additional
 * timeout parameter that limits the waiting time.
 *
 * \param addr The address of the variable of interest
 * \param exp  The expected value of that variable
 * \param time The waiting timeout
 * \returns 0 on success
 * \returns -1 on error
 *
 * \see [man 2 syscall](http://man7.org/linux/man-pages/man2/syscall.2.html)
 * \see [man 2 futex](http://man7.org/linux/man-pages/man2/futex.2.html)
 * \see [man 7 futex](http://man7.org/linux/man-pages/man7/futex.7.html)
 */
futex__exposed int futex_wait_until(atomic_int *addr, int exp, struct timespec *time)
{
	return syscall(SYS_futex, addr, FUTEX_WAIT_PRIVATE, exp, time);
}

144
#endif /* __FUTEX_H_INCLUDED__ */