[3RDPARTY] Add wait_on_atomic_t() and wake_up_atomic_t()
[platform/kernel/swap-modules.git] / master / wait.c
1 /*
2  * This code copied from linux kernel 3.11+
3  * commit cb65537ee1134d3cc55c1fa83952bc8eb1212833
4  */
5
6
7 #include "wait.h"
8
9
10 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
11
12 #include <linux/wait.h>
13 #include <linux/module.h>
14
15
16 #define WAIT_ATOMIC_T_BIT_NR -1
17 #define __WAIT_ATOMIC_T_KEY_INITIALIZER(p)                              \
18         { .flags = p, .bit_nr = WAIT_ATOMIC_T_BIT_NR, }
19
20
21 /*
22  * Manipulate the atomic_t address to produce a better bit waitqueue table hash
23  * index (we're keying off bit -1, but that would produce a horrible hash
24  * value).
25  */
26 static inline wait_queue_head_t *atomic_t_waitqueue(atomic_t *p)
27 {
28         if (BITS_PER_LONG == 64) {
29                 unsigned long q = (unsigned long)p;
30                 return bit_waitqueue((void *)(q & ~1), q & 1);
31         }
32         return bit_waitqueue(p, 0);
33 }
34
35 static int wake_atomic_t_function(wait_queue_t *wait, unsigned mode, int sync,
36                                   void *arg)
37 {
38         struct wait_bit_key *key = arg;
39         struct wait_bit_queue *wait_bit
40                 = container_of(wait, struct wait_bit_queue, wait);
41         atomic_t *val = key->flags;
42
43         if (wait_bit->key.flags != key->flags ||
44             wait_bit->key.bit_nr != key->bit_nr ||
45             atomic_read(val) != 0)
46                 return 0;
47         return autoremove_wake_function(wait, mode, sync, key);
48 }
49
50 /*
51  * To allow interruptible waiting and asynchronous (i.e. nonblocking) waiting,
52  * the actions of __wait_on_atomic_t() are permitted return codes.  Nonzero
53  * return codes halt waiting and return.
54  */
55 static int __wait_on_atomic_t(wait_queue_head_t *wq, struct wait_bit_queue *q,
56                               int (*action)(atomic_t *), unsigned mode)
57 {
58         atomic_t *val;
59         int ret = 0;
60
61         do {
62                 prepare_to_wait(wq, &q->wait, mode);
63                 val = q->key.flags;
64                 if (atomic_read(val) == 0)
65                         ret = (*action)(val);
66         } while (!ret && atomic_read(val) != 0);
67         finish_wait(wq, &q->wait);
68         return ret;
69 }
70
71 #define DEFINE_WAIT_ATOMIC_T(name, p)                                   \
72         struct wait_bit_queue name = {                                  \
73                 .key = __WAIT_ATOMIC_T_KEY_INITIALIZER(p),              \
74                 .wait = {                                               \
75                         .private        = current,                      \
76                         .func           = wake_atomic_t_function,       \
77                         .task_list      =                               \
78                                 LIST_HEAD_INIT((name).wait.task_list),  \
79                 },                                                      \
80         }
81
82 int out_of_line_wait_on_atomic_t(atomic_t *p, int (*action)(atomic_t *),
83                                         unsigned mode)
84 {
85         wait_queue_head_t *wq = atomic_t_waitqueue(p);
86         DEFINE_WAIT_ATOMIC_T(wait, p);
87
88         return __wait_on_atomic_t(wq, &wait, action, mode);
89 }
90 EXPORT_SYMBOL(out_of_line_wait_on_atomic_t);
91
92 /**
93  * wake_up_atomic_t - Wake up a waiter on a atomic_t
94  * @word: The word being waited on, a kernel virtual address
95  * @bit: The bit of the word being waited on
96  *
97  * Wake up anyone waiting for the atomic_t to go to zero.
98  *
99  * Abuse the bit-waker function and its waitqueue hash table set (the atomic_t
100  * check is done by the waiter's wake function, not the by the waker itself).
101  */
102 void wake_up_atomic_t(atomic_t *p)
103 {
104         __wake_up_bit(atomic_t_waitqueue(p), p, WAIT_ATOMIC_T_BIT_NR);
105 }
106 EXPORT_SYMBOL(wake_up_atomic_t);
107
108 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) */