1 /*
2 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 /*
8 * @file linux/condition.h
9 * @brief Linux condition variable primitives for libmetal.
10 */
11
12 #ifndef __METAL_CONDITION__H__
13 #error "Include metal/condition.h instead of metal/linux/condition.h"
14 #endif
15
16 #ifndef __METAL_LINUX_CONDITION__H__
17 #define __METAL_LINUX_CONDITION__H__
18
19 #include <unistd.h>
20 #include <sys/syscall.h>
21 #include <linux/futex.h>
22 #include <metal/atomic.h>
23 #include <metal/errno.h>
24 #include <stdint.h>
25 #include <limits.h>
26
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30
31 struct metal_condition {
32 atomic_uintptr_t mptr; /**< mutex pointer.
33 * The condition variable is attached to
34 * this mutex when it is waiting.
35 * It is also used to check correctness
36 * in case there are multiple waiters.
37 */
38 atomic_int waiters; /**< number of waiters. */
39 atomic_int wakeups; /**< number of wakeups. */
40 };
41
42 /** Static metal condition variable initialization. */
43 #define METAL_CONDITION_INIT { ATOMIC_VAR_INIT(0), ATOMIC_VAR_INIT(0), \
44 ATOMIC_VAR_INIT(0) }
45
metal_condition_init(struct metal_condition * cv)46 static inline void metal_condition_init(struct metal_condition *cv)
47 {
48 atomic_init(&cv->mptr, 0);
49 atomic_init(&cv->waiters, 0);
50 atomic_init(&cv->wakeups, 0);
51 }
52
metal_condition_signal(struct metal_condition * cv)53 static inline int metal_condition_signal(struct metal_condition *cv)
54 {
55 if (!cv)
56 return -EINVAL;
57
58 atomic_fetch_add(&cv->wakeups, 1);
59 if (atomic_load(&cv->waiters) > 0)
60 syscall(SYS_futex, &cv->wakeups, FUTEX_WAKE, 1, NULL, NULL, 0);
61 return 0;
62 }
63
metal_condition_broadcast(struct metal_condition * cv)64 static inline int metal_condition_broadcast(struct metal_condition *cv)
65 {
66 if (!cv)
67 return -EINVAL;
68
69 atomic_fetch_add(&cv->wakeups, 1);
70 if (atomic_load(&cv->waiters) > 0)
71 syscall(SYS_futex, &cv->wakeups, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
72 return 0;
73 }
74
75 #endif /* __METAL_LINUX_CONDITION__H__ */
76