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 "types.h"
10 : : #include "atomic.h"
11 : : #include "syscall.h"
12 : : #include "util.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 : 1024 : return atomic_get(&f->raw);
25 : : }
26 : :
27 : : /* Set futex @f value to @v */
28 : : static inline void futex_set(futex_t *f, u32 v)
29 : : {
30 : 7364 : atomic_set(&f->raw, 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 = atomic_get(&(__f)->raw); \
43 : : if ((tmp & FUTEX_ABORT_FLAG) || \
44 : : (tmp __cond (__v))) \
45 : : break; \
46 : : ret = sys_futex(&(__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 : 1225 : static inline void futex_set_and_wake(futex_t *f, u32 v)
54 : : {
55 : 1225 : atomic_set(&f->raw, v);
56 [ - + ]: 1225 : BUG_ON(sys_futex(&f->raw.counter, FUTEX_WAKE, INT_MAX, NULL, NULL, 0) < 0);
57 : 1225 : }
58 : :
59 : : /* Mark futex @f as wait abort needed and wake up all waiters */
60 : 0 : 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 : 0 : }
65 : :
66 : : /* Decrement futex @f value and wake up all waiters */
67 : 722 : static inline void futex_dec_and_wake(futex_t *f)
68 : : {
69 : 722 : atomic_dec(&f->raw);
70 [ - + ]: 722 : BUG_ON(sys_futex(&f->raw.counter, FUTEX_WAKE, INT_MAX, NULL, NULL, 0) < 0);
71 : 722 : }
72 : :
73 : : /* Plain increment futex @f value */
74 : 76 : static inline void futex_inc(futex_t *f) { atomic_inc(&f->raw); }
75 : :
76 : : /* Plain decrement futex @f value */
77 : 38 : static inline void futex_dec(futex_t *f) { atomic_dec(&f->raw); }
78 : :
79 : : /* Wait until futex @f value become @v */
80 : 215 : static inline void futex_wait_until(futex_t *f, u32 v)
81 [ + + ][ + - ]: 526 : { futex_wait_if_cond(f, v, ==); }
82 : :
83 : : /* Wait while futex @f value is greater than @v */
84 : 498 : static inline void futex_wait_while_gt(futex_t *f, u32 v)
85 [ + + ][ + - ]: 1267 : { futex_wait_if_cond(f, v, <=); }
86 : :
87 : : /* Wait while futex @f value is @v */
88 : 1256 : static inline void futex_wait_while(futex_t *f, u32 v)
89 : : {
90 [ + + ]: 3311 : while (atomic_get(&f->raw) == v) {
91 : 799 : int ret = sys_futex(&f->raw.counter, FUTEX_WAIT, v, NULL, NULL, 0);
92 [ + - ]: 2055 : BUG_ON(ret < 0 && ret != -EWOULDBLOCK);
93 : : }
94 : 1256 : }
95 : :
96 : : typedef struct {
97 : : atomic_t raw;
98 : : } mutex_t;
99 : :
100 : : static void inline mutex_init(mutex_t *m)
101 : : {
102 : 1059 : u32 c = 0;
103 : 1059 : atomic_set(&m->raw, c);
104 : : }
105 : :
106 : 33 : static void inline mutex_lock(mutex_t *m)
107 : : {
108 : : u32 c;
109 : : int ret;
110 : :
111 [ - + ]: 66 : while ((c = atomic_inc(&m->raw))) {
112 : 0 : ret = sys_futex(&m->raw.counter, FUTEX_WAIT, c + 1, NULL, NULL, 0);
113 [ # # ]: 33 : BUG_ON(ret < 0 && ret != -EWOULDBLOCK);
114 : : }
115 : 33 : }
116 : :
117 : 33 : static void inline mutex_unlock(mutex_t *m)
118 : : {
119 : 33 : u32 c = 0;
120 : 33 : atomic_set(&m->raw, c);
121 [ - + ]: 33 : BUG_ON(sys_futex(&m->raw.counter, FUTEX_WAKE, 1, NULL, NULL, 0) < 0);
122 : 33 : }
123 : :
124 : : #endif /* __CR_LOCK_H__ */
|