public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] introduce wait_event_common()
@ 2013-06-06 20:02 Oleg Nesterov
  2013-06-06 20:03 ` [PATCH 1/2] wait: introduce wait_event_common(wq, condition, state, timeout) Oleg Nesterov
  2013-06-06 20:03 ` [PATCH 2/2] wait: introduce prepare_to_wait_event() Oleg Nesterov
  0 siblings, 2 replies; 7+ messages in thread
From: Oleg Nesterov @ 2013-06-06 20:02 UTC (permalink / raw)
  To: Andrew Morton, Daniel Vetter, Dave Jones, David Howells,
	Imre Deak, Jens Axboe, Linus Torvalds, Lukas Czerner,
	Paul E. McKenney, Tejun Heo
  Cc: linux-kernel

Hello.

To remind, I think that 4c663cfc "wait: fix false timeouts when using
wait_event_timeout()" is not enough, wait(wq, true, 0) still returns
zero.

But to me the main problem is that wait_event* macros duplicate the
same code again and again. Imho it would be nice to create a single
helper. To simplify the review, this is the code after 1/2:

	#define __wait_no_timeout(tout)	\
		(__builtin_constant_p(tout) && (tout) == MAX_SCHEDULE_TIMEOUT)

	/* uglified signal_pending_state() optimized for constant state */
	#define __wait_signal_pending(state)					\
		((state == TASK_INTERRUPTIBLE) ? signal_pending(current) :	\
		 (state == TASK_KILLABLE) ? fatal_signal_pending(current) :	\
		  0)

	#define __wait_event_common(wq, condition, state, tout)			\
	({									\
		DEFINE_WAIT(__wait);						\
		long __ret = 0, __tout = tout;					\
										\
		for (;;) {							\
			prepare_to_wait(&wq, &__wait, state);			\
			if (condition) {					\
				__ret = __wait_no_timeout(tout) ?: __tout ?: 1;	\
				break;						\
			}							\
										\
			if (__wait_signal_pending(state)) {			\
				__ret = -ERESTARTSYS;				\
				break;						\
			}							\
										\
			if (__wait_no_timeout(tout))				\
				schedule();					\
			else if (__tout)					\
				__tout = schedule_timeout(__tout);		\
			else							\
				break;						\
		}								\
		finish_wait(&wq, &__wait);					\
		__ret;								\
	})

	#define wait_event_common(wq, condition, state, tout)			\
	({									\
		long __ret;							\
		if (condition)							\
			__ret = __wait_no_timeout(tout) ?: (tout) ?: 1;		\
		else								\
			__ret = __wait_event_common(wq, condition, state, tout);\
		__ret;								\
	})

2/2 doesn't look like a cleanup. But personally I think that it makes
sense to shrink .text,

	-	4977769 2930984 10104832        18013585        112dd91 vmlinux
	+	4976847	2930984	10104832	18012663	112d9f7	vmlinux

on my build.

Please comment.

Oleg.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] wait: introduce wait_event_common(wq, condition, state, timeout)
  2013-06-06 20:02 [PATCH 0/2] introduce wait_event_common() Oleg Nesterov
@ 2013-06-06 20:03 ` Oleg Nesterov
  2013-06-18 22:06   ` Andrew Morton
  2013-06-06 20:03 ` [PATCH 2/2] wait: introduce prepare_to_wait_event() Oleg Nesterov
  1 sibling, 1 reply; 7+ messages in thread
From: Oleg Nesterov @ 2013-06-06 20:03 UTC (permalink / raw)
  To: Andrew Morton, Daniel Vetter, Dave Jones, David Howells,
	Imre Deak, Jens Axboe, Linus Torvalds, Lukas Czerner,
	Paul E. McKenney, Tejun Heo
  Cc: linux-kernel

1. wait_event_timeout(wq, true, 0) returns zero, I think this is
   wrong and should be fixed.

   __wait_event_timeout() was already changed by 4c663cfc but we
   need the same logic in wait_event_timeout() if the fast-path
   check succeeds.

2. wait_event_timeout/__wait_event_timeout interface do not match
   wait_event(), you can't use __wait_event_timeout() instead of
   wait_event_timeout() if you do not need the fast-path check.

3. wait_event_* macros duplicate the same code.

This patch adds a single helper wait_event_common() which hopefully
does everything right. Compiler optimizes out the "dead" code when
we do not need signal_pending/schedule_timeout.

With this patch "size vmlinux" reports that .text/data shrinks but
I think this depends on gcc/config.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Reviewed-by: Tejun Heo <tj@kernel.org>
---
 include/linux/wait.h |  181 +++++++++++++++++++------------------------------
 1 files changed, 70 insertions(+), 111 deletions(-)

diff --git a/include/linux/wait.h b/include/linux/wait.h
index 1133695..392c54d 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -173,18 +173,52 @@ wait_queue_head_t *bit_waitqueue(void *, int);
 #define wake_up_interruptible_sync_poll(x, m)				\
 	__wake_up_sync_key((x), TASK_INTERRUPTIBLE, 1, (void *) (m))
 
-#define __wait_event(wq, condition) 					\
-do {									\
+#define __wait_no_timeout(tout)	\
+	(__builtin_constant_p(tout) && (tout) == MAX_SCHEDULE_TIMEOUT)
+
+/* uglified signal_pending_state() optimized for constant state */
+#define __wait_signal_pending(state)					\
+	((state == TASK_INTERRUPTIBLE) ? signal_pending(current) :	\
+	 (state == TASK_KILLABLE) ? fatal_signal_pending(current) :	\
+	  0)
+
+#define __wait_event_common(wq, condition, state, tout)			\
+({									\
 	DEFINE_WAIT(__wait);						\
+	long __ret = 0, __tout = tout;					\
 									\
 	for (;;) {							\
-		prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);	\
-		if (condition)						\
+		prepare_to_wait(&wq, &__wait, state);			\
+		if (condition) {					\
+			__ret = __wait_no_timeout(tout) ?: __tout ?: 1;	\
+			break;						\
+		}							\
+									\
+		if (__wait_signal_pending(state)) {			\
+			__ret = -ERESTARTSYS;				\
+			break;						\
+		}							\
+									\
+		if (__wait_no_timeout(tout))				\
+			schedule();					\
+		else if (__tout)					\
+			__tout = schedule_timeout(__tout);		\
+		else							\
 			break;						\
-		schedule();						\
 	}								\
 	finish_wait(&wq, &__wait);					\
-} while (0)
+	__ret;								\
+})
+
+#define wait_event_common(wq, condition, state, tout)			\
+({									\
+	long __ret;							\
+	if (condition)							\
+		__ret = __wait_no_timeout(tout) ?: (tout) ?: 1;		\
+	else								\
+		__ret = __wait_event_common(wq, condition, state, tout);\
+	__ret;								\
+})
 
 /**
  * wait_event - sleep until a condition gets true
@@ -198,29 +232,13 @@ do {									\
  * wake_up() has to be called after changing any variable that could
  * change the result of the wait condition.
  */
-#define wait_event(wq, condition) 					\
-do {									\
-	if (condition)	 						\
-		break;							\
-	__wait_event(wq, condition);					\
-} while (0)
+#define __wait_event(wq, condition) 					\
+	__wait_event_common(wq, condition,				\
+			TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT)	\
 
-#define __wait_event_timeout(wq, condition, ret)			\
-do {									\
-	DEFINE_WAIT(__wait);						\
-									\
-	for (;;) {							\
-		prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);	\
-		if (condition)						\
-			break;						\
-		ret = schedule_timeout(ret);				\
-		if (!ret)						\
-			break;						\
-	}								\
-	if (!ret && (condition))					\
-		ret = 1;						\
-	finish_wait(&wq, &__wait);					\
-} while (0)
+#define wait_event(wq, condition) 					\
+	wait_event_common(wq, condition,				\
+			TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT)	\
 
 /**
  * wait_event_timeout - sleep until a condition gets true or a timeout elapses
@@ -239,31 +257,13 @@ do {									\
  * jiffies (at least 1) if the @condition evaluated to %true before
  * the @timeout elapsed.
  */
-#define wait_event_timeout(wq, condition, timeout)			\
-({									\
-	long __ret = timeout;						\
-	if (!(condition)) 						\
-		__wait_event_timeout(wq, condition, __ret);		\
-	__ret;								\
-})
+#define __wait_event_timeout(wq, condition, timeout)			\
+	__wait_event_common(wq, condition,				\
+			TASK_UNINTERRUPTIBLE, timeout)
 
-#define __wait_event_interruptible(wq, condition, ret)			\
-do {									\
-	DEFINE_WAIT(__wait);						\
-									\
-	for (;;) {							\
-		prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);	\
-		if (condition)						\
-			break;						\
-		if (!signal_pending(current)) {				\
-			schedule();					\
-			continue;					\
-		}							\
-		ret = -ERESTARTSYS;					\
-		break;							\
-	}								\
-	finish_wait(&wq, &__wait);					\
-} while (0)
+#define wait_event_timeout(wq, condition, timeout)			\
+	wait_event_common(wq, condition,				\
+			TASK_UNINTERRUPTIBLE, timeout)
 
 /**
  * wait_event_interruptible - sleep until a condition gets true
@@ -280,35 +280,13 @@ do {									\
  * The function will return -ERESTARTSYS if it was interrupted by a
  * signal and 0 if @condition evaluated to true.
  */
-#define wait_event_interruptible(wq, condition)				\
-({									\
-	int __ret = 0;							\
-	if (!(condition))						\
-		__wait_event_interruptible(wq, condition, __ret);	\
-	__ret;								\
-})
+#define __wait_event_interruptible(wq, condition)			\
+	__wait_event_common(wq, condition,				\
+			TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT)
 
-#define __wait_event_interruptible_timeout(wq, condition, ret)		\
-do {									\
-	DEFINE_WAIT(__wait);						\
-									\
-	for (;;) {							\
-		prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);	\
-		if (condition)						\
-			break;						\
-		if (!signal_pending(current)) {				\
-			ret = schedule_timeout(ret);			\
-			if (!ret)					\
-				break;					\
-			continue;					\
-		}							\
-		ret = -ERESTARTSYS;					\
-		break;							\
-	}								\
-	if (!ret && (condition))					\
-		ret = 1;						\
-	finish_wait(&wq, &__wait);					\
-} while (0)
+#define wait_event_interruptible(wq, condition)				\
+	wait_event_common(wq, condition,				\
+			TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT)
 
 /**
  * wait_event_interruptible_timeout - sleep until a condition gets true or a timeout elapses
@@ -328,13 +306,13 @@ do {									\
  * a signal, or the remaining jiffies (at least 1) if the @condition
  * evaluated to %true before the @timeout elapsed.
  */
+#define __wait_event_interruptible_timeout(wq, condition, timeout)	\
+	__wait_event_common(wq, condition,				\
+			TASK_INTERRUPTIBLE, timeout)
+
 #define wait_event_interruptible_timeout(wq, condition, timeout)	\
-({									\
-	long __ret = timeout;						\
-	if (!(condition))						\
-		__wait_event_interruptible_timeout(wq, condition, __ret); \
-	__ret;								\
-})
+	wait_event_common(wq, condition,				\
+			TASK_INTERRUPTIBLE, timeout)
 
 #define __wait_event_hrtimeout(wq, condition, timeout, state)		\
 ({									\
@@ -601,24 +579,6 @@ do {									\
 
 
 
-#define __wait_event_killable(wq, condition, ret)			\
-do {									\
-	DEFINE_WAIT(__wait);						\
-									\
-	for (;;) {							\
-		prepare_to_wait(&wq, &__wait, TASK_KILLABLE);		\
-		if (condition)						\
-			break;						\
-		if (!fatal_signal_pending(current)) {			\
-			schedule();					\
-			continue;					\
-		}							\
-		ret = -ERESTARTSYS;					\
-		break;							\
-	}								\
-	finish_wait(&wq, &__wait);					\
-} while (0)
-
 /**
  * wait_event_killable - sleep until a condition gets true
  * @wq: the waitqueue to wait on
@@ -634,14 +594,13 @@ do {									\
  * The function will return -ERESTARTSYS if it was interrupted by a
  * signal and 0 if @condition evaluated to true.
  */
-#define wait_event_killable(wq, condition)				\
-({									\
-	int __ret = 0;							\
-	if (!(condition))						\
-		__wait_event_killable(wq, condition, __ret);		\
-	__ret;								\
-})
+#define __wait_event_killable(wq, condition)				\
+	__wait_event_common(wq, condition,				\
+			TASK_KILLABLE, MAX_SCHEDULE_TIMEOUT)
 
+#define wait_event_killable(wq, condition)				\
+	wait_event_common(wq, condition,				\
+			TASK_KILLABLE, MAX_SCHEDULE_TIMEOUT)
 
 #define __wait_event_lock_irq(wq, condition, lock, cmd)			\
 do {									\
-- 
1.5.5.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] wait: introduce prepare_to_wait_event()
  2013-06-06 20:02 [PATCH 0/2] introduce wait_event_common() Oleg Nesterov
  2013-06-06 20:03 ` [PATCH 1/2] wait: introduce wait_event_common(wq, condition, state, timeout) Oleg Nesterov
@ 2013-06-06 20:03 ` Oleg Nesterov
  2013-06-06 21:36   ` Tejun Heo
  1 sibling, 1 reply; 7+ messages in thread
From: Oleg Nesterov @ 2013-06-06 20:03 UTC (permalink / raw)
  To: Andrew Morton, Daniel Vetter, Dave Jones, David Howells,
	Imre Deak, Jens Axboe, Linus Torvalds, Lukas Czerner,
	Paul E. McKenney, Tejun Heo
  Cc: linux-kernel

Add the new helper, prepare_to_wait_event() which should only be used
by wait_event_common/etc.

prepare_to_wait_event() returns -ERESTARTSYS if signal_pending_state()
is true, otherwise it calls prepare_to_wait(). This allows to uninline
the signal-pending checks in wait_event_*.

Also, it can initialize wait->private/func. We do not care they were
already initialized, the values are the same. This also shaves a couple
of insns from the inlined code.

Unlike the previous change, this patch "reliably" shrinks the size of
generated code for every wait_event*() call.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 include/linux/wait.h |   22 +++++++++++-----------
 kernel/wait.c        |   14 ++++++++++++++
 2 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/include/linux/wait.h b/include/linux/wait.h
index 392c54d..a2314dd 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -176,28 +176,27 @@ wait_queue_head_t *bit_waitqueue(void *, int);
 #define __wait_no_timeout(tout)	\
 	(__builtin_constant_p(tout) && (tout) == MAX_SCHEDULE_TIMEOUT)
 
-/* uglified signal_pending_state() optimized for constant state */
-#define __wait_signal_pending(state)					\
-	((state == TASK_INTERRUPTIBLE) ? signal_pending(current) :	\
-	 (state == TASK_KILLABLE) ? fatal_signal_pending(current) :	\
-	  0)
+#define __wait_interruptible(state)					\
+	(!__builtin_constant_p(state) ||				\
+	 	state == TASK_INTERRUPTIBLE || state == TASK_KILLABLE)
 
 #define __wait_event_common(wq, condition, state, tout)			\
 ({									\
-	DEFINE_WAIT(__wait);						\
-	long __ret = 0, __tout = tout;					\
+	long __ret, __tout = tout;					\
+	wait_queue_t __wait;						\
+									\
+	INIT_LIST_HEAD(&__wait.task_list);				\
+	__wait.flags = 0;						\
 									\
 	for (;;) {							\
-		prepare_to_wait(&wq, &__wait, state);			\
+		__ret = prepare_to_wait_event(&wq, &__wait, state);	\
 		if (condition) {					\
 			__ret = __wait_no_timeout(tout) ?: __tout ?: 1;	\
 			break;						\
 		}							\
 									\
-		if (__wait_signal_pending(state)) {			\
-			__ret = -ERESTARTSYS;				\
+		if (__wait_interruptible(state) && __ret)		\
 			break;						\
-		}							\
 									\
 		if (__wait_no_timeout(tout))				\
 			schedule();					\
@@ -781,6 +780,7 @@ extern long interruptible_sleep_on_timeout(wait_queue_head_t *q,
  * Waitqueues which are removed from the waitqueue_head at wakeup time
  */
 void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state);
+int prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state);
 void prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state);
 void finish_wait(wait_queue_head_t *q, wait_queue_t *wait);
 void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait,
diff --git a/kernel/wait.c b/kernel/wait.c
index 6698e0c..57cc6e7 100644
--- a/kernel/wait.c
+++ b/kernel/wait.c
@@ -78,6 +78,20 @@ prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
 }
 EXPORT_SYMBOL(prepare_to_wait);
 
+int
+prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+	if (signal_pending_state(state, current))
+		return -ERESTARTSYS;
+
+	wait->private = current;
+	wait->func = autoremove_wake_function;
+	prepare_to_wait(q, wait, state);
+
+	return 0;
+}
+EXPORT_SYMBOL(prepare_to_wait_event);
+
 void
 prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
 {
-- 
1.5.5.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] wait: introduce prepare_to_wait_event()
  2013-06-06 20:03 ` [PATCH 2/2] wait: introduce prepare_to_wait_event() Oleg Nesterov
@ 2013-06-06 21:36   ` Tejun Heo
  2013-06-07 13:07     ` Oleg Nesterov
  0 siblings, 1 reply; 7+ messages in thread
From: Tejun Heo @ 2013-06-06 21:36 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Andrew Morton, Daniel Vetter, Dave Jones, David Howells,
	Imre Deak, Jens Axboe, Linus Torvalds, Lukas Czerner,
	Paul E. McKenney, linux-kernel

Hello, Oleg.

On Thu, Jun 06, 2013 at 10:03:34PM +0200, Oleg Nesterov wrote:
> Add the new helper, prepare_to_wait_event() which should only be used
> by wait_event_common/etc.
> 
> prepare_to_wait_event() returns -ERESTARTSYS if signal_pending_state()
> is true, otherwise it calls prepare_to_wait(). This allows to uninline
> the signal-pending checks in wait_event_*.
> 
> Also, it can initialize wait->private/func. We do not care they were
> already initialized, the values are the same. This also shaves a couple
> of insns from the inlined code.
> 
> Unlike the previous change, this patch "reliably" shrinks the size of
> generated code for every wait_event*() call.
> 
> Signed-off-by: Oleg Nesterov <oleg@redhat.com>

Which tree are the patches based on?  I'm getting conflicts on
linus#master, mmotd and next.

Reviewed-by: Tejun Heo <tj@kernel.org>

But a couple nits.

> +int

I don't think we need to keep the unnecessary line break here.  All
other functions in the file don't do it except for the two
prepare_to_wait functions.  No need to give the weirdos more power. :)

> +prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state)
> +{
> +	if (signal_pending_state(state, current))
> +		return -ERESTARTSYS;
> +
> +	wait->private = current;
> +	wait->func = autoremove_wake_function;
> +	prepare_to_wait(q, wait, state);

I wonder whether it'd be worthwhile to make prepare_to_wait() inline
so that it can be inlined into the above.  I think gcc is smart enough
to emit inline for in-file stuff and then build a proper function for
external references.  No biggie.  Just wondering.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] wait: introduce prepare_to_wait_event()
  2013-06-06 21:36   ` Tejun Heo
@ 2013-06-07 13:07     ` Oleg Nesterov
  0 siblings, 0 replies; 7+ messages in thread
From: Oleg Nesterov @ 2013-06-07 13:07 UTC (permalink / raw)
  To: Tejun Heo
  Cc: Andrew Morton, Daniel Vetter, Dave Jones, David Howells,
	Imre Deak, Jens Axboe, Linus Torvalds, Lukas Czerner,
	Paul E. McKenney, linux-kernel

Hi Tejun,

On 06/06, Tejun Heo wrote:
>
> Which tree are the patches based on?  I'm getting conflicts on
> linus#master, mmotd and next.

Hmm. linus#master. I just verified that the patches apply cleanly
after git-pull.

> Reviewed-by: Tejun Heo <tj@kernel.org>

Thanks,

> But a couple nits.
>
> > +int
>
> I don't think we need to keep the unnecessary line break here.  All
> other functions in the file don't do it except for the two
> prepare_to_wait functions.  No need to give the weirdos more power. :)

Yes, I tried to follow the style around the new helper, but the extra
line is not needed.

Please see v2 below, no other changes.

> > +prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state)
> > +{
> > +	if (signal_pending_state(state, current))
> > +		return -ERESTARTSYS;
> > +
> > +	wait->private = current;
> > +	wait->func = autoremove_wake_function;
> > +	prepare_to_wait(q, wait, state);
>
> I wonder whether it'd be worthwhile to make prepare_to_wait() inline
> so that it can be inlined into the above.  I think gcc is smart enough
> to emit inline for in-file stuff and then build a proper function for
> external references.  No biggie.  Just wondering.

Not sure... As you can see from this patch, I like -Os more than -O2 ;)


------------------------------------------------------------------------------
Subject: [PATCH v2 2/2] wait: introduce prepare_to_wait_event()

Add the new helper, prepare_to_wait_event() which should only be used
by wait_event_common/etc.

prepare_to_wait_event() returns -ERESTARTSYS if signal_pending_state()
is true, otherwise it calls prepare_to_wait(). This allows to uninline
the signal-pending checks in wait_event_*.

Also, it can initialize wait->private/func. We do not care they were
already initialized, the values are the same. This also shaves a couple
of insns from the inlined code.

Unlike the previous change, this patch "reliably" shrinks the size of
generated code for every wait_event*() call.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Reviewed-by: Tejun Heo <tj@kernel.org>
---
 include/linux/wait.h |   22 +++++++++++-----------
 kernel/wait.c        |   13 +++++++++++++
 2 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/include/linux/wait.h b/include/linux/wait.h
index 392c54d..a2314dd 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -176,28 +176,27 @@ wait_queue_head_t *bit_waitqueue(void *, int);
 #define __wait_no_timeout(tout)	\
 	(__builtin_constant_p(tout) && (tout) == MAX_SCHEDULE_TIMEOUT)
 
-/* uglified signal_pending_state() optimized for constant state */
-#define __wait_signal_pending(state)					\
-	((state == TASK_INTERRUPTIBLE) ? signal_pending(current) :	\
-	 (state == TASK_KILLABLE) ? fatal_signal_pending(current) :	\
-	  0)
+#define __wait_interruptible(state)					\
+	(!__builtin_constant_p(state) ||				\
+	 	state == TASK_INTERRUPTIBLE || state == TASK_KILLABLE)
 
 #define __wait_event_common(wq, condition, state, tout)			\
 ({									\
-	DEFINE_WAIT(__wait);						\
-	long __ret = 0, __tout = tout;					\
+	long __ret, __tout = tout;					\
+	wait_queue_t __wait;						\
+									\
+	INIT_LIST_HEAD(&__wait.task_list);				\
+	__wait.flags = 0;						\
 									\
 	for (;;) {							\
-		prepare_to_wait(&wq, &__wait, state);			\
+		__ret = prepare_to_wait_event(&wq, &__wait, state);	\
 		if (condition) {					\
 			__ret = __wait_no_timeout(tout) ?: __tout ?: 1;	\
 			break;						\
 		}							\
 									\
-		if (__wait_signal_pending(state)) {			\
-			__ret = -ERESTARTSYS;				\
+		if (__wait_interruptible(state) && __ret)		\
 			break;						\
-		}							\
 									\
 		if (__wait_no_timeout(tout))				\
 			schedule();					\
@@ -781,6 +780,7 @@ extern long interruptible_sleep_on_timeout(wait_queue_head_t *q,
  * Waitqueues which are removed from the waitqueue_head at wakeup time
  */
 void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state);
+int prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state);
 void prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state);
 void finish_wait(wait_queue_head_t *q, wait_queue_t *wait);
 void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait,
diff --git a/kernel/wait.c b/kernel/wait.c
index 6698e0c..3b8619a 100644
--- a/kernel/wait.c
+++ b/kernel/wait.c
@@ -78,6 +78,19 @@ prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
 }
 EXPORT_SYMBOL(prepare_to_wait);
 
+int prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+	if (signal_pending_state(state, current))
+		return -ERESTARTSYS;
+
+	wait->private = current;
+	wait->func = autoremove_wake_function;
+	prepare_to_wait(q, wait, state);
+
+	return 0;
+}
+EXPORT_SYMBOL(prepare_to_wait_event);
+
 void
 prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
 {
-- 
1.5.5.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] wait: introduce wait_event_common(wq, condition, state, timeout)
  2013-06-06 20:03 ` [PATCH 1/2] wait: introduce wait_event_common(wq, condition, state, timeout) Oleg Nesterov
@ 2013-06-18 22:06   ` Andrew Morton
  2013-06-19 16:14     ` Oleg Nesterov
  0 siblings, 1 reply; 7+ messages in thread
From: Andrew Morton @ 2013-06-18 22:06 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Daniel Vetter, Dave Jones, David Howells, Imre Deak, Jens Axboe,
	Linus Torvalds, Lukas Czerner, Paul E. McKenney, Tejun Heo,
	linux-kernel

On Thu, 6 Jun 2013 22:03:16 +0200 Oleg Nesterov <oleg@redhat.com> wrote:

> 1. wait_event_timeout(wq, true, 0) returns zero, I think this is
>    wrong and should be fixed.
> 
>    __wait_event_timeout() was already changed by 4c663cfc but we
>    need the same logic in wait_event_timeout() if the fast-path
>    check succeeds.
> 
> 2. wait_event_timeout/__wait_event_timeout interface do not match
>    wait_event(), you can't use __wait_event_timeout() instead of
>    wait_event_timeout() if you do not need the fast-path check.
> 
> 3. wait_event_* macros duplicate the same code.
> 
> This patch adds a single helper wait_event_common() which hopefully
> does everything right. Compiler optimizes out the "dead" code when
> we do not need signal_pending/schedule_timeout.
> 
> With this patch "size vmlinux" reports that .text/data shrinks but
> I think this depends on gcc/config.

hm,

> -#define __wait_event_interruptible(wq, condition, ret)
> +#define __wait_event_interruptible(wq, condition)

net/irda/af_irda.c:2568:13: error: macro "__wait_event_interruptible" passed 3 arguments, but takes just 2

waddup with that?

__wait_event_interruptible() has several callsites.  I think I'll go
zap and await v2 ;)


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] wait: introduce wait_event_common(wq, condition, state, timeout)
  2013-06-18 22:06   ` Andrew Morton
@ 2013-06-19 16:14     ` Oleg Nesterov
  0 siblings, 0 replies; 7+ messages in thread
From: Oleg Nesterov @ 2013-06-19 16:14 UTC (permalink / raw)
  To: Andrew Morton, Samuel Ortiz
  Cc: Daniel Vetter, Dave Jones, David Howells, Imre Deak, Jens Axboe,
	Linus Torvalds, Lukas Czerner, Paul E. McKenney, Tejun Heo,
	linux-kernel

On 06/18, Andrew Morton wrote:
>
> On Thu, 6 Jun 2013 22:03:16 +0200 Oleg Nesterov <oleg@redhat.com> wrote:
> > -#define __wait_event_interruptible(wq, condition, ret)
> > +#define __wait_event_interruptible(wq, condition)
>
> net/irda/af_irda.c:2568:13: error: macro "__wait_event_interruptible" passed 3 arguments, but takes just 2

Aaah. Thanks.

> waddup with that?

Will read "man grep" again.

> __wait_event_interruptible() has several callsites.  I think I'll go
> zap and await v2 ;)

Yes, will do, thanks.

And note that one of the reasons for this patch was to make
wait_event_interruptible() and __wait_event_interruptible()
interchangeable, like wait_event() and __wait_event().
irda_getsockopt() uses __wait* exactly because it has already
checked the condition.



Samuel, will you agree with the patch below?

Yes, this adds the unnecessary check. We will remove it later,
after we change wait_event* macros, just

	- err = wait_event_interruptible(...);
	+ err = __wait_event_interruptible(...);

Otherwise, this patch should also change af_irda.c (and probably
other callers), not good.

Oleg.

--- x/net/irda/af_irda.c
+++ x/net/irda/af_irda.c
@@ -2563,9 +2563,8 @@ bed:
 				  jiffies + msecs_to_jiffies(val));
 
 			/* Wait for IR-LMP to call us back */
-			__wait_event_interruptible(self->query_wait,
-			      (self->cachedaddr != 0 || self->errno == -ETIME),
-						   err);
+			err = wait_event_interruptible(self->query_wait,
+			      (self->cachedaddr != 0 || self->errno == -ETIME));
 
 			/* If watchdog is still activated, kill it! */
 			del_timer(&(self->watchdog));


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2013-06-19 16:20 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-06 20:02 [PATCH 0/2] introduce wait_event_common() Oleg Nesterov
2013-06-06 20:03 ` [PATCH 1/2] wait: introduce wait_event_common(wq, condition, state, timeout) Oleg Nesterov
2013-06-18 22:06   ` Andrew Morton
2013-06-19 16:14     ` Oleg Nesterov
2013-06-06 20:03 ` [PATCH 2/2] wait: introduce prepare_to_wait_event() Oleg Nesterov
2013-06-06 21:36   ` Tejun Heo
2013-06-07 13:07     ` Oleg Nesterov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox