Branch data Line data Source code
1 : : #ifndef __CR_LOCK_H__
2 : : #define __CR_LOCK_H__
3 : :
4 : : #include <linux/futex.h>
5 : : #include <sys/time.h>
6 : : #include <limits.h>
7 : : #include <errno.h>
8 : :
9 : : #include "asm/types.h"
10 : : #include "asm/atomic.h"
11 : : #include "syscall.h"
12 : : #include "bug.h"
13 : :
14 : : typedef struct {
15 : : atomic_t raw;
16 : : } futex_t;
17 : :
18 : : #define FUTEX_ABORT_FLAG (0x80000000)
19 : : #define FUTEX_ABORT_RAW (-1U)
20 : :
21 : : /* Get current futex @f value */
22 : : static inline u32 futex_get(futex_t *f)
23 : : {
24 : 1465 : return atomic_read(&f->raw);
25 : : }
26 : :
27 : : /* Set futex @f value to @v */
28 : : static inline void futex_set(futex_t *f, u32 v)
29 : : {
30 : : atomic_set(&f->raw, (int)v);
31 : : }
32 : :
33 : : #define futex_init(f) futex_set(f, 0)
34 : :
35 : : /* Wait on futex @__f value @__v become in condition @__c */
36 : : #define futex_wait_if_cond(__f, __v, __cond) \
37 : : do { \
38 : : int ret; \
39 : : u32 tmp; \
40 : : \
41 : : while (1) { \
42 : : tmp = (u32)atomic_read(&(__f)->raw); \
43 : : if ((tmp & FUTEX_ABORT_FLAG) || \
44 : : (tmp __cond (__v))) \
45 : : break; \
46 : : ret = sys_futex((u32 *)&(__f)->raw.counter, FUTEX_WAIT,\
47 : : tmp, NULL, NULL, 0); \
48 : : BUG_ON(ret < 0 && ret != -EWOULDBLOCK); \
49 : : } \
50 : : } while (0)
51 : :
52 : : /* Set futex @f to @v and wake up all waiters */
53 : 2805 : static inline void futex_set_and_wake(futex_t *f, u32 v)
54 : : {
55 : 2805 : atomic_set(&f->raw, (int)v);
56 [ - + ]: 2805 : BUG_ON(sys_futex((u32 *)&f->raw.counter, FUTEX_WAKE, INT_MAX, NULL, NULL, 0) < 0);
57 : 2805 : }
58 : :
59 : : /* Mark futex @f as wait abort needed and wake up all waiters */
60 : : static inline void futex_abort_and_wake(futex_t *f)
61 : : {
62 : : BUILD_BUG_ON(!(FUTEX_ABORT_RAW & FUTEX_ABORT_FLAG));
63 : 0 : futex_set_and_wake(f, FUTEX_ABORT_RAW);
64 : : }
65 : :
66 : : /* Decrement futex @f value and wake up all waiters */
67 : 925 : static inline void futex_dec_and_wake(futex_t *f)
68 : : {
69 : 925 : atomic_dec(&f->raw);
70 [ - + ]: 925 : BUG_ON(sys_futex((u32 *)&f->raw.counter, FUTEX_WAKE, INT_MAX, NULL, NULL, 0) < 0);
71 : 925 : }
72 : :
73 : : /* Increment futex @f value and wake up all waiters */
74 : 8 : static inline void futex_inc_and_wake(futex_t *f)
75 : : {
76 : 8 : atomic_inc(&f->raw);
77 [ - + ]: 8 : BUG_ON(sys_futex((u32 *)&f->raw.counter, FUTEX_WAKE, INT_MAX, NULL, NULL, 0) < 0);
78 : 8 : }
79 : :
80 : : /* Plain increment futex @f value */
81 : 182 : static inline void futex_inc(futex_t *f) { atomic_inc(&f->raw); }
82 : :
83 : : /* Plain decrement futex @f value */
84 : 62 : static inline void futex_dec(futex_t *f) { atomic_dec(&f->raw); }
85 : :
86 : : /* Wait until futex @f value become @v */
87 : 76 : static inline void futex_wait_until(futex_t *f, u32 v)
88 [ + + ][ + - ]: 55 : { futex_wait_if_cond(f, v, ==); }
89 : :
90 : : /* Wait while futex @f value is greater than @v */
91 : 4480 : static inline void futex_wait_while_gt(futex_t *f, u32 v)
92 [ + + ][ + - ]: 6124 : { futex_wait_if_cond(f, v, <=); }
93 : :
94 : : /* Wait while futex @f value is less than @v */
95 : 14 : static inline void futex_wait_while_lt(futex_t *f, u32 v)
96 [ + + ][ + - ]: 13 : { futex_wait_if_cond(f, v, >=); }
97 : :
98 : : /* Wait while futex @f value is equal to @v */
99 : 0 : static inline void futex_wait_while_eq(futex_t *f, u32 v)
100 [ # # ][ # # ]: 0 : { futex_wait_if_cond(f, v, !=); }
101 : :
102 : : /* Wait while futex @f value is @v */
103 : 1477 : static inline void futex_wait_while(futex_t *f, u32 v)
104 : : {
105 [ + + ]: 3861 : while ((u32)atomic_read(&f->raw) == v) {
106 : 907 : int ret = sys_futex((u32 *)&f->raw.counter, FUTEX_WAIT, v, NULL, NULL, 0);
107 [ + - ]: 2384 : BUG_ON(ret < 0 && ret != -EWOULDBLOCK);
108 : : }
109 : 1477 : }
110 : :
111 : : typedef struct {
112 : : atomic_t raw;
113 : : } mutex_t;
114 : :
115 : : static inline void mutex_init(mutex_t *m)
116 : : {
117 : : u32 c = 0;
118 : : atomic_set(&m->raw, (int)c);
119 : : }
120 : :
121 : 57 : static inline void mutex_lock(mutex_t *m)
122 : : {
123 : : u32 c;
124 : : int ret;
125 : :
126 [ + + ]: 117 : while ((c = (u32)atomic_inc_return(&m->raw)) != 1) {
127 : 3 : ret = sys_futex((u32 *)&m->raw.counter, FUTEX_WAIT, c, NULL, NULL, 0);
128 [ + - ]: 60 : BUG_ON(ret < 0 && ret != -EWOULDBLOCK);
129 : : }
130 : 57 : }
131 : :
132 : 50 : static inline void mutex_unlock(mutex_t *m)
133 : : {
134 : : u32 c = 0;
135 : : atomic_set(&m->raw, (int)c);
136 [ - + ]: 50 : BUG_ON(sys_futex((u32 *)&m->raw.counter, FUTEX_WAKE, 1, NULL, NULL, 0) < 0);
137 : 50 : }
138 : :
139 : : #endif /* __CR_LOCK_H__ */
|