diff options
-rw-r--r-- | include/linux/wait.h | 24 | ||||
-rw-r--r-- | kernel/wait.c | 88 |
2 files changed, 112 insertions, 0 deletions
diff --git a/include/linux/wait.h b/include/linux/wait.h index ac38be2692d8..5bacfc4b336d 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h | |||
@@ -23,6 +23,7 @@ struct __wait_queue { | |||
23 | struct wait_bit_key { | 23 | struct wait_bit_key { |
24 | void *flags; | 24 | void *flags; |
25 | int bit_nr; | 25 | int bit_nr; |
26 | #define WAIT_ATOMIC_T_BIT_NR -1 | ||
26 | }; | 27 | }; |
27 | 28 | ||
28 | struct wait_bit_queue { | 29 | struct wait_bit_queue { |
@@ -60,6 +61,9 @@ struct task_struct; | |||
60 | #define __WAIT_BIT_KEY_INITIALIZER(word, bit) \ | 61 | #define __WAIT_BIT_KEY_INITIALIZER(word, bit) \ |
61 | { .flags = word, .bit_nr = bit, } | 62 | { .flags = word, .bit_nr = bit, } |
62 | 63 | ||
64 | #define __WAIT_ATOMIC_T_KEY_INITIALIZER(p) \ | ||
65 | { .flags = p, .bit_nr = WAIT_ATOMIC_T_BIT_NR, } | ||
66 | |||
63 | extern void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *); | 67 | extern void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *); |
64 | 68 | ||
65 | #define init_waitqueue_head(q) \ | 69 | #define init_waitqueue_head(q) \ |
@@ -146,8 +150,10 @@ void __wake_up_bit(wait_queue_head_t *, void *, int); | |||
146 | int __wait_on_bit(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned); | 150 | int __wait_on_bit(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned); |
147 | int __wait_on_bit_lock(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned); | 151 | int __wait_on_bit_lock(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned); |
148 | void wake_up_bit(void *, int); | 152 | void wake_up_bit(void *, int); |
153 | void wake_up_atomic_t(atomic_t *); | ||
149 | int out_of_line_wait_on_bit(void *, int, int (*)(void *), unsigned); | 154 | int out_of_line_wait_on_bit(void *, int, int (*)(void *), unsigned); |
150 | int out_of_line_wait_on_bit_lock(void *, int, int (*)(void *), unsigned); | 155 | int out_of_line_wait_on_bit_lock(void *, int, int (*)(void *), unsigned); |
156 | int out_of_line_wait_on_atomic_t(atomic_t *, int (*)(atomic_t *), unsigned); | ||
151 | wait_queue_head_t *bit_waitqueue(void *, int); | 157 | wait_queue_head_t *bit_waitqueue(void *, int); |
152 | 158 | ||
153 | #define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL) | 159 | #define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL) |
@@ -896,5 +902,23 @@ static inline int wait_on_bit_lock(void *word, int bit, | |||
896 | return 0; | 902 | return 0; |
897 | return out_of_line_wait_on_bit_lock(word, bit, action, mode); | 903 | return out_of_line_wait_on_bit_lock(word, bit, action, mode); |
898 | } | 904 | } |
905 | |||
906 | /** | ||
907 | * wait_on_atomic_t - Wait for an atomic_t to become 0 | ||
908 | * @val: The atomic value being waited on, a kernel virtual address | ||
909 | * @action: the function used to sleep, which may take special actions | ||
910 | * @mode: the task state to sleep in | ||
911 | * | ||
912 | * Wait for an atomic_t to become 0. We abuse the bit-wait waitqueue table for | ||
913 | * the purpose of getting a waitqueue, but we set the key to a bit number | ||
914 | * outside of the target 'word'. | ||
915 | */ | ||
916 | static inline | ||
917 | int wait_on_atomic_t(atomic_t *val, int (*action)(atomic_t *), unsigned mode) | ||
918 | { | ||
919 | if (atomic_read(val) == 0) | ||
920 | return 0; | ||
921 | return out_of_line_wait_on_atomic_t(val, action, mode); | ||
922 | } | ||
899 | 923 | ||
900 | #endif | 924 | #endif |
diff --git a/kernel/wait.c b/kernel/wait.c index 6698e0c04ead..ce0daa320a26 100644 --- a/kernel/wait.c +++ b/kernel/wait.c | |||
@@ -287,3 +287,91 @@ wait_queue_head_t *bit_waitqueue(void *word, int bit) | |||
287 | return &zone->wait_table[hash_long(val, zone->wait_table_bits)]; | 287 | return &zone->wait_table[hash_long(val, zone->wait_table_bits)]; |
288 | } | 288 | } |
289 | EXPORT_SYMBOL(bit_waitqueue); | 289 | EXPORT_SYMBOL(bit_waitqueue); |
290 | |||
291 | /* | ||
292 | * Manipulate the atomic_t address to produce a better bit waitqueue table hash | ||
293 | * index (we're keying off bit -1, but that would produce a horrible hash | ||
294 | * value). | ||
295 | */ | ||
296 | static inline wait_queue_head_t *atomic_t_waitqueue(atomic_t *p) | ||
297 | { | ||
298 | if (BITS_PER_LONG == 64) { | ||
299 | unsigned long q = (unsigned long)p; | ||
300 | return bit_waitqueue((void *)(q & ~1), q & 1); | ||
301 | } | ||
302 | return bit_waitqueue(p, 0); | ||
303 | } | ||
304 | |||
305 | static int wake_atomic_t_function(wait_queue_t *wait, unsigned mode, int sync, | ||
306 | void *arg) | ||
307 | { | ||
308 | struct wait_bit_key *key = arg; | ||
309 | struct wait_bit_queue *wait_bit | ||
310 | = container_of(wait, struct wait_bit_queue, wait); | ||
311 | atomic_t *val = key->flags; | ||
312 | |||
313 | if (wait_bit->key.flags != key->flags || | ||
314 | wait_bit->key.bit_nr != key->bit_nr || | ||
315 | atomic_read(val) != 0) | ||
316 | return 0; | ||
317 | return autoremove_wake_function(wait, mode, sync, key); | ||
318 | } | ||
319 | |||
320 | /* | ||
321 | * To allow interruptible waiting and asynchronous (i.e. nonblocking) waiting, | ||
322 | * the actions of __wait_on_atomic_t() are permitted return codes. Nonzero | ||
323 | * return codes halt waiting and return. | ||
324 | */ | ||
325 | static __sched | ||
326 | int __wait_on_atomic_t(wait_queue_head_t *wq, struct wait_bit_queue *q, | ||
327 | int (*action)(atomic_t *), unsigned mode) | ||
328 | { | ||
329 | atomic_t *val; | ||
330 | int ret = 0; | ||
331 | |||
332 | do { | ||
333 | prepare_to_wait(wq, &q->wait, mode); | ||
334 | val = q->key.flags; | ||
335 | if (atomic_read(val) == 0) | ||
336 | ret = (*action)(val); | ||
337 | } while (!ret && atomic_read(val) != 0); | ||
338 | finish_wait(wq, &q->wait); | ||
339 | return ret; | ||
340 | } | ||
341 | |||
342 | #define DEFINE_WAIT_ATOMIC_T(name, p) \ | ||
343 | struct wait_bit_queue name = { \ | ||
344 | .key = __WAIT_ATOMIC_T_KEY_INITIALIZER(p), \ | ||
345 | .wait = { \ | ||
346 | .private = current, \ | ||
347 | .func = wake_atomic_t_function, \ | ||
348 | .task_list = \ | ||
349 | LIST_HEAD_INIT((name).wait.task_list), \ | ||
350 | }, \ | ||
351 | } | ||
352 | |||
353 | __sched int out_of_line_wait_on_atomic_t(atomic_t *p, int (*action)(atomic_t *), | ||
354 | unsigned mode) | ||
355 | { | ||
356 | wait_queue_head_t *wq = atomic_t_waitqueue(p); | ||
357 | DEFINE_WAIT_ATOMIC_T(wait, p); | ||
358 | |||
359 | return __wait_on_atomic_t(wq, &wait, action, mode); | ||
360 | } | ||
361 | EXPORT_SYMBOL(out_of_line_wait_on_atomic_t); | ||
362 | |||
363 | /** | ||
364 | * wake_up_atomic_t - Wake up a waiter on a atomic_t | ||
365 | * @word: The word being waited on, a kernel virtual address | ||
366 | * @bit: The bit of the word being waited on | ||
367 | * | ||
368 | * Wake up anyone waiting for the atomic_t to go to zero. | ||
369 | * | ||
370 | * Abuse the bit-waker function and its waitqueue hash table set (the atomic_t | ||
371 | * check is done by the waiter's wake function, not the by the waker itself). | ||
372 | */ | ||
373 | void wake_up_atomic_t(atomic_t *p) | ||
374 | { | ||
375 | __wake_up_bit(atomic_t_waitqueue(p), p, WAIT_ATOMIC_T_BIT_NR); | ||
376 | } | ||
377 | EXPORT_SYMBOL(wake_up_atomic_t); | ||