summaryrefslogtreecommitdiff
path: root/include/linux/wait.h
blob: 4b9cbf38d52afef017d59d215bfe4006798afbf0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#ifndef _LINUX_WAIT_H
#define _LINUX_WAIT_H

#include <pthread.h>
#include <linux/bitmap.h>
#include <linux/list.h>
#include <linux/spinlock.h>

typedef struct __wait_queue wait_queue_t;
typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int flags, void *key);

#define WQ_FLAG_EXCLUSIVE	0x01

struct __wait_queue {
	unsigned int		flags;
	void			*private;
	wait_queue_func_t	func;
	struct list_head	task_list;
};

struct wait_queue_head {
	spinlock_t		lock;
	struct list_head	task_list;
};

typedef struct wait_queue_head wait_queue_head_t;

void wake_up(wait_queue_head_t *);
void wake_up_all(wait_queue_head_t *);
void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state);
void finish_wait(wait_queue_head_t *q, wait_queue_t *wait);
int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
int default_wake_function(wait_queue_t *wait, unsigned mode, int flags, void *key);

#define DECLARE_WAITQUEUE(name, tsk)					\
	wait_queue_t name = {						\
		.private	= tsk,					\
		.func		= default_wake_function,		\
		.task_list	= { NULL, NULL }			\
	}

#define __WAIT_QUEUE_HEAD_INITIALIZER(name) {				\
	.lock		= __SPIN_LOCK_UNLOCKED(name.lock),		\
	.task_list	= { &(name).task_list, &(name).task_list } }

#define DECLARE_WAIT_QUEUE_HEAD(name) \
	struct wait_queue_head name = __WAIT_QUEUE_HEAD_INITIALIZER(name)

static inline void init_waitqueue_head(wait_queue_head_t *q)
{
	spin_lock_init(&q->lock);
	INIT_LIST_HEAD(&q->task_list);
}

#define DEFINE_WAIT(name)						\
	wait_queue_t name = {						\
		.private	= current,				\
		.func		= autoremove_wake_function,		\
		.task_list	= LIST_HEAD_INIT((name).task_list),	\
	}

#define ___wait_cond_timeout(condition)					\
({									\
	bool __cond = (condition);					\
	if (__cond && !__ret)						\
		__ret = 1;						\
	__cond || !__ret;						\
})

#define ___wait_event(wq, condition, state, exclusive, ret, cmd)	\
({									\
	DEFINE_WAIT(__wait);						\
	long __ret = ret;						\
									\
	for (;;) {							\
		prepare_to_wait(&wq, &__wait, state);			\
		if (condition)						\
			break;						\
		cmd;							\
	}								\
	finish_wait(&wq, &__wait);					\
	__ret;								\
})

#define __wait_event(wq, condition)					\
	(void)___wait_event(wq, condition, TASK_UNINTERRUPTIBLE, 0, 0,	\
			    schedule())

#define wait_event(wq, condition)					\
do {									\
	if (condition)							\
		break;							\
	__wait_event(wq, condition);					\
} while (0)

#define wait_event_freezable(wq, condition)	({wait_event(wq, condition); 0; })
#define wait_event_killable(wq, condition)	({wait_event(wq, condition); 0; })
#define wait_event_interruptible(wq, condition)	({wait_event(wq, condition); 0; })

#define __wait_event_timeout(wq, condition, timeout)			\
	___wait_event(wq, ___wait_cond_timeout(condition),		\
		      TASK_UNINTERRUPTIBLE, 0, timeout,			\
		      __ret = schedule_timeout(__ret))

#define wait_event_timeout(wq, condition, timeout)			\
({									\
	long __ret = timeout;						\
	if (!___wait_cond_timeout(condition))				\
		__ret = __wait_event_timeout(wq, condition, timeout);	\
	__ret;								\
})

void wake_up_bit(void *, int);
void __wait_on_bit(void *, int, unsigned);
void __wait_on_bit_lock(void *, int, unsigned);

static inline int
wait_on_bit(unsigned long *word, int bit, unsigned mode)
{
	if (!test_bit(bit, word))
		return 0;
	__wait_on_bit(word, bit, mode);
	return 0;
}

static inline int
wait_on_bit_lock(unsigned long *word, int bit, unsigned mode)
{
	if (!test_and_set_bit(bit, word))
		return 0;
	__wait_on_bit_lock(word, bit, mode);
	return 0;
}

#define wait_on_bit_io(w, b, m)			wait_on_bit(w, b, m)
#define wait_on_bit_lock_io(w, b, m)		wait_on_bit_lock(w, b, m)

#endif /* _LINUX_WAIT_H */