[PATCH] Change tevent "standard" backend to fall back from epoll -> poll

Stefan (metze) Metzmacher metze at samba.org
Thu Feb 14 08:04:34 MST 2013


Hi Jeremy,

> Second attempt :-). This is the original patchset
> forward ported to master after Volker and Metze fixed
> the issues with the poll backend.
> 
> Please review and push to master if you're happy with it !

I reviewed it and made some changes to it to fix some details
and make it easier to understand for me.

- I added a replay flag to epoll_panic() to indicate if it was called
  from before calling an event handler or from within an event handler.
  We should only call loop_once() of the poll backend if epoll_panic
  was called before calling an event handler.
  tevent_loop_once() should only trigger just one event handler.

- I introduced a 'struct std_event_glue' instead of using
  tricks with const struct tevent_ops **

I've tested the fallback with the last two HACK patches,
which are reverted again and should not reach master.

I'm currently doing private autobuilds with and without the hack patches.

metze
-------------- next part --------------
From 8389c04ade90ebf37ad19f9e7d4c5d4ad88dd175 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 11 Feb 2013 10:36:52 -0800
Subject: [PATCH 01/17] tevent: Preparing to fix "standard" backend fallback.
 Initialize standard after epoll.

Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index fa842e4..e307dba 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -115,10 +115,10 @@ static void tevent_backend_init(void)
 	tevent_select_init();
 	tevent_poll_init();
 	tevent_poll_mt_init();
-	tevent_standard_init();
 #ifdef HAVE_EPOLL
 	tevent_epoll_init();
 #endif
+	tevent_standard_init();
 }
 
 /*
-- 
1.7.9.5


From 9be7b5ee2e4746c121779291a84395012597689f Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 11 Feb 2013 10:38:01 -0800
Subject: [PATCH 02/17] tevent: Ensure we return after every call to
 epoll_panic().

Currently we can't return from this, but the new fallback
code will change this.

Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent_epoll.c |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 5f93de2..8e7bc4d 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -152,6 +152,7 @@ static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_
 	event.data.ptr = fde;
 	if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
 		epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed");
+		return;
 	}
 	fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
 
@@ -201,6 +202,7 @@ static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct tevent_
 	event.data.ptr = fde;
 	if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
 		epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed");
+		return;
 	}
 
 	/* only if we want to read we want to tell the event handler about errors */
-- 
1.7.9.5


From f0737d466cb3a085fe1e11e6713bf6ddedfd1b04 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 14 Feb 2013 10:58:55 +0100
Subject: [PATCH 03/17] tevent: pass 'bool replay' to epoll_panic()

A fallback panic handler will need to know if
there was an error while waiting for events
(replay=true) or if the error happened on modify
(replay=false).

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent_epoll.c |   11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 8e7bc4d..c7936d3 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -44,7 +44,8 @@ struct epoll_event_context {
 /*
   called when a epoll call fails
 */
-static void epoll_panic(struct epoll_event_context *epoll_ev, const char *reason)
+static void epoll_panic(struct epoll_event_context *epoll_ev,
+			const char *reason, bool replay)
 {
 	tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
 		 "%s (%s) - calling abort()\n", reason, strerror(errno));
@@ -151,7 +152,7 @@ static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_
 	event.events = epoll_map_flags(fde->flags);
 	event.data.ptr = fde;
 	if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
-		epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed");
+		epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed", false);
 		return;
 	}
 	fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
@@ -201,7 +202,7 @@ static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct tevent_
 	event.events = epoll_map_flags(fde->flags);
 	event.data.ptr = fde;
 	if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
-		epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed");
+		epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed", false);
 		return;
 	}
 
@@ -277,7 +278,7 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval
 	}
 
 	if (ret == -1 && errno != EINTR) {
-		epoll_panic(epoll_ev, "epoll_wait() failed");
+		epoll_panic(epoll_ev, "epoll_wait() failed", true);
 		return -1;
 	}
 
@@ -293,7 +294,7 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval
 		uint16_t flags = 0;
 
 		if (fde == NULL) {
-			epoll_panic(epoll_ev, "epoll_wait() gave bad data");
+			epoll_panic(epoll_ev, "epoll_wait() gave bad data", true);
 			return -1;
 		}
 		if (events[i].events & (EPOLLHUP|EPOLLERR)) {
-- 
1.7.9.5


From b2de6eb0252bff3f2a08729a4004ead157cb1c67 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 11 Feb 2013 10:43:39 -0800
Subject: [PATCH 04/17] tevent: Add an internal function
 tevent_epoll_set_panic_fallback().

Can be set externally, allows us to fallback if epoll
fails at runtime.

Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent_epoll.c    |   24 ++++++++++++++++++++++++
 lib/tevent/tevent_internal.h |    3 +++
 2 files changed, 27 insertions(+)

diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index c7936d3..8a48d1d 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -39,9 +39,33 @@ struct epoll_event_context {
 	int epoll_fd;
 
 	pid_t pid;
+
+	bool (*panic_fallback)(struct tevent_context *ev, bool replay);
 };
 
 /*
+  called to set the panic fallback function.
+*/
+_PRIVATE_ bool tevent_epoll_set_panic_fallback(struct tevent_context *ev,
+				bool (*panic_fallback)(struct tevent_context *ev,
+						       bool replay))
+{
+	struct epoll_event_context *epoll_ev;
+
+	if (ev->additional_data == NULL) {
+		return false;
+	}
+
+	epoll_ev = talloc_get_type(ev->additional_data,
+				struct epoll_event_context);
+	if (epoll_ev == NULL) {
+		return false;
+	}
+	epoll_ev->panic_fallback = panic_fallback;
+	return true;
+}
+
+/*
   called when a epoll call fails
 */
 static void epoll_panic(struct epoll_event_context *epoll_ev,
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index f09cf57..4e9cd69 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -318,6 +318,9 @@ bool tevent_poll_init(void);
 bool tevent_poll_mt_init(void);
 #ifdef HAVE_EPOLL
 bool tevent_epoll_init(void);
+bool tevent_epoll_set_panic_fallback(struct tevent_context *ev,
+			bool (*panic_fallback)(struct tevent_context *ev,
+					       bool replay));
 #endif
 
 void tevent_trace_point_callback(struct tevent_context *ev,
-- 
1.7.9.5


From c5e16ed2c8964a5a371fad947bd70a8cf0990bba Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 11 Feb 2013 10:48:02 -0800
Subject: [PATCH 05/17] tevent: Plumb in the panic fallback code into the
 epoll_panic() runtime call.

Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent_epoll.c |   23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 8a48d1d..0ef1ffe 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -71,9 +71,26 @@ _PRIVATE_ bool tevent_epoll_set_panic_fallback(struct tevent_context *ev,
 static void epoll_panic(struct epoll_event_context *epoll_ev,
 			const char *reason, bool replay)
 {
-	tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
-		 "%s (%s) - calling abort()\n", reason, strerror(errno));
-	abort();
+	struct tevent_context *ev = epoll_ev->ev;
+
+	if (epoll_ev->panic_fallback == NULL) {
+		tevent_debug(ev, TEVENT_DEBUG_FATAL,
+			"%s (%s) replay[%u] - calling abort()\n",
+			reason, strerror(errno), (unsigned)replay);
+		abort();
+	}
+
+	tevent_debug(ev, TEVENT_DEBUG_WARNING,
+		     "%s (%s) replay[%u] - calling panic_fallback\n",
+		     reason, strerror(errno), (unsigned)replay);
+
+	if (!epoll_ev->panic_fallback(ev, replay)) {
+		/* Fallback failed. */
+		tevent_debug(ev, TEVENT_DEBUG_FATAL,
+			"%s (%s) replay[%u] - calling abort()\n",
+			reason, strerror(errno), (unsigned)replay);
+		abort();
+	}
 }
 
 /*
-- 
1.7.9.5


From 964c96bb13b9e2dab4e240e03f07702f0659eba5 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 11 Feb 2013 10:52:30 -0800
Subject: [PATCH 06/17] tevent: Add in some test code to allow the panic
 fallback path to be tested.

Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent_epoll.c |   18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 0ef1ffe..5a17331 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -43,6 +43,24 @@ struct epoll_event_context {
 	bool (*panic_fallback)(struct tevent_context *ev, bool replay);
 };
 
+#ifdef TEST_PANIC_FALLBACK
+static int epoll_wait_panic_fallback(int epfd,
+				struct epoll_event *events,
+				int maxevents,
+				int timeout)
+{
+	/* 50% of the time, fail... */
+	if ((random() % 2) == 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	return epoll_wait(epfd, events, maxevents, timeout);
+}
+
+#define epoll_wait epoll_wait_panic_fallback
+#endif
+
 /*
   called to set the panic fallback function.
 */
-- 
1.7.9.5


From befe91aa7b8ba7bf2697b59918c9e370cc0bb97a Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 11 Feb 2013 10:53:15 -0800
Subject: [PATCH 07/17] tevent: Add in the same tevent_re_initialise() fix
 Metze put in the tevent_poll backend.

We might be called during tevent_re_initialise()
which means we need to free our old additional_data.

Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent_epoll.c    |    6 ++++++
 lib/tevent/tevent_select.c   |    6 ++++++
 lib/tevent/tevent_standard.c |    6 ++++++
 3 files changed, 18 insertions(+)

diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 5a17331..8696215 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -389,6 +389,12 @@ static int epoll_event_context_init(struct tevent_context *ev)
 	int ret;
 	struct epoll_event_context *epoll_ev;
 
+	/*
+	 * We might be called during tevent_re_initialise()
+	 * which means we need to free our old additional_data.
+	 */
+	TALLOC_FREE(ev->additional_data);
+
 	epoll_ev = talloc_zero(ev, struct epoll_event_context);
 	if (!epoll_ev) return -1;
 	epoll_ev->ev = ev;
diff --git a/lib/tevent/tevent_select.c b/lib/tevent/tevent_select.c
index c11f0e8..7e0c927 100644
--- a/lib/tevent/tevent_select.c
+++ b/lib/tevent/tevent_select.c
@@ -47,6 +47,12 @@ static int select_event_context_init(struct tevent_context *ev)
 {
 	struct select_event_context *select_ev;
 
+	/*
+	 * We might be called during tevent_re_initialise()
+	 * which means we need to free our old additional_data.
+	 */
+	TALLOC_FREE(ev->additional_data);
+
 	select_ev = talloc_zero(ev, struct select_event_context);
 	if (!select_ev) return -1;
 	select_ev->ev = ev;
diff --git a/lib/tevent/tevent_standard.c b/lib/tevent/tevent_standard.c
index 1e33720..938b223 100644
--- a/lib/tevent/tevent_standard.c
+++ b/lib/tevent/tevent_standard.c
@@ -348,6 +348,12 @@ static int std_event_context_init(struct tevent_context *ev)
 {
 	struct std_event_context *std_ev;
 
+	/*
+	 * We might be called during tevent_re_initialise()
+	 * which means we need to free our old additional_data.
+	 */
+	TALLOC_FREE(ev->additional_data);
+
 	std_ev = talloc_zero(ev, struct std_event_context);
 	if (!std_ev) return -1;
 	std_ev->ev = ev;
-- 
1.7.9.5


From 99a60209da8bb2ae5769e0e126d7d6e016192b94 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 11 Feb 2013 10:56:58 -0800
Subject: [PATCH 08/17] tevent: Add a utility function
 tevent_find_ops_byname().

Returns an event ops struct given a string name. Not
yet used, but will be part of the new "standard" fallback
code.

Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent.c          |   22 ++++++++++++++++++++++
 lib/tevent/tevent_internal.h |    1 +
 2 files changed, 23 insertions(+)

diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index e307dba..6352471 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -121,6 +121,28 @@ static void tevent_backend_init(void)
 	tevent_standard_init();
 }
 
+_PRIVATE_ const struct tevent_ops *tevent_find_ops_byname(const char *name)
+{
+	struct tevent_ops_list *e;
+
+	tevent_backend_init();
+
+	if (name == NULL) {
+		name = tevent_default_backend;
+	}
+	if (name == NULL) {
+		name = "standard";
+	}
+
+	for (e = tevent_backends; e != NULL; e = e->next) {
+		if (0 == strcmp(e->name, name)) {
+			return e->ops;
+		}
+	}
+
+	return NULL;
+}
+
 /*
   list available backends
 */
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index 4e9cd69..fa6652c 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -265,6 +265,7 @@ struct tevent_context {
 	} tracing;
 };
 
+const struct tevent_ops *tevent_find_ops_byname(const char *name);
 
 int tevent_common_context_destructor(struct tevent_context *ev);
 int tevent_common_loop_wait(struct tevent_context *ev,
-- 
1.7.9.5


From 4744433a68324e5781a47c1d04688a43d3329c56 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 14 Feb 2013 09:29:57 +0100
Subject: [PATCH 09/17] tevent: make sure tevent_backend_init() only runs once

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent.c |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index 6352471..669b778 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -112,6 +112,14 @@ void tevent_set_default_backend(const char *backend)
 */
 static void tevent_backend_init(void)
 {
+	static bool done;
+
+	if (done) {
+		return;
+	}
+
+	done = true;
+
 	tevent_select_init();
 	tevent_poll_init();
 	tevent_poll_mt_init();
-- 
1.7.9.5


From a3b0aebf1f6f5c0513502d629b42095848b8db29 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 14 Feb 2013 09:30:31 +0100
Subject: [PATCH 10/17] tevent: make use of tevent_find_ops_byname() in
 tevent_context_init_byname()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent.c |   19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index 669b778..aa758de 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -273,23 +273,14 @@ struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
 						  const char *name)
 {
-	struct tevent_ops_list *e;
-
-	tevent_backend_init();
+	struct tevent_ops *ops;
 
-	if (name == NULL) {
-		name = tevent_default_backend;
-	}
-	if (name == NULL) {
-		name = "standard";
+	ops = tevent_find_ops_byname(name);
+	if (ops == NULL) {
+		return NULL;
 	}
 
-	for (e=tevent_backends;e;e=e->next) {
-		if (strcmp(name, e->name) == 0) {
-			return tevent_context_init_ops(mem_ctx, e->ops, NULL);
-		}
-	}
-	return NULL;
+	return tevent_context_init_ops(mem_ctx, ops, NULL);
 }
 
 
-- 
1.7.9.5


From 5d1a76b9c01e0e0902db06853dbfce067dde01ea Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 11 Feb 2013 11:20:28 -0800
Subject: [PATCH 11/17] tevent: Add a private function
 tevent_poll_event_add_fd_internal().

Not yet used, but will be called by the "standard"
fallback from epoll -> poll backends.

Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent_internal.h |    3 +++
 lib/tevent/tevent_poll.c     |   16 ++++++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index fa6652c..8433333 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -316,6 +316,8 @@ void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se);
 bool tevent_standard_init(void);
 bool tevent_select_init(void);
 bool tevent_poll_init(void);
+void tevent_poll_event_add_fd_internal(struct tevent_context *ev,
+				       struct tevent_fd *fde);
 bool tevent_poll_mt_init(void);
 #ifdef HAVE_EPOLL
 bool tevent_epoll_init(void);
@@ -324,5 +326,6 @@ bool tevent_epoll_set_panic_fallback(struct tevent_context *ev,
 					       bool replay));
 #endif
 
+
 void tevent_trace_point_callback(struct tevent_context *ev,
 				 enum tevent_trace_point);
diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c
index 5479f2f..89b3bbc 100644
--- a/lib/tevent/tevent_poll.c
+++ b/lib/tevent/tevent_poll.c
@@ -256,6 +256,22 @@ static void poll_event_schedule_immediate(struct tevent_immediate *im,
 }
 
 /*
+  Private function called by "standard" backend fallback.
+  Note this only allows fallback to "poll" backend, not "poll-mt".
+*/
+_PRIVATE_ void tevent_poll_event_add_fd_internal(struct tevent_context *ev,
+						 struct tevent_fd *fde)
+{
+	struct poll_event_context *poll_ev = talloc_get_type_abort(
+		ev->additional_data, struct poll_event_context);
+
+	fde->additional_flags	= UINT64_MAX;
+	fde->additional_data	= NULL;
+	DLIST_ADD(poll_ev->fresh, fde);
+	talloc_set_destructor(fde, poll_fresh_fde_destructor);
+}
+
+/*
   add a fd based event
   return NULL on failure (memory allocation error)
 */
-- 
1.7.9.5


From 964a8354baaf1f4e0f440cfc1a1e2912227d40c9 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 11 Feb 2013 11:40:49 -0800
Subject: [PATCH 12/17] tevent: Add in the new implementation of "standard"
 tevent backend.

Falls back cleanly from epoll -> poll, or uses poll if
epoll not available.

Signed-off-by: Jeremy Allison <jra at samba.org>
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent_standard.c |  186 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 180 insertions(+), 6 deletions(-)

diff --git a/lib/tevent/tevent_standard.c b/lib/tevent/tevent_standard.c
index 938b223..0c72226 100644
--- a/lib/tevent/tevent_standard.c
+++ b/lib/tevent/tevent_standard.c
@@ -2,7 +2,8 @@
    Unix SMB/CIFS implementation.
    main select loop and event handling
    Copyright (C) Andrew Tridgell	2003-2005
-   Copyright (C) Stefan Metzmacher	2005-2009
+   Copyright (C) Stefan Metzmacher      2005-2013
+   Copyright (C) Jeremy Allison         2013
 
      ** NOTE! The following LGPL license applies to the tevent
      ** library. This does NOT imply that all of Samba is released
@@ -26,18 +27,17 @@
   This is SAMBA's default event loop code
 
   - we try to use epoll if configure detected support for it
-    otherwise we use select()
+    otherwise we use poll()
   - if epoll is broken on the system or the kernel doesn't support it
-    at runtime we fallback to select()
+    at runtime we fallback to poll()
 */
 
 #include "replace.h"
-#include "system/filesys.h"
-#include "system/select.h"
 #include "tevent.h"
 #include "tevent_util.h"
 #include "tevent_internal.h"
 
+#if 0
 struct std_event_context {
 	/* a pointer back to the generic event_context */
 	struct tevent_context *ev;
@@ -589,10 +589,184 @@ static const struct tevent_ops std_event_ops = {
 	.loop_once		= std_event_loop_once,
 	.loop_wait		= tevent_common_loop_wait,
 };
+#endif
+
+struct std_event_glue {
+	const struct tevent_ops *epoll_ops;
+	const struct tevent_ops *poll_ops;
+	struct tevent_ops *glue_ops;
+	bool fallback_replay;
+};
+
+static int std_event_context_init(struct tevent_context *ev);
+
+static const struct tevent_ops std_event_ops = {
+	.context_init           = std_event_context_init,
+};
+
+/*
+  If this function gets called. epoll failed at runtime.
+  Move us to using poll instead. If we return false here,
+  caller should abort().
+*/
+static bool std_fallback_to_poll(struct tevent_context *ev, bool replay)
+{
+	void *glue_ptr = talloc_parent(ev->ops);
+	struct std_event_glue *glue =
+		talloc_get_type_abort(glue_ptr,
+		struct std_event_glue);
+	int ret;
+	struct tevent_fd *fde;
+	struct tevent_fd *fde_next;
+
+	glue->fallback_replay = replay;
+
+	/* First switch all the ops to poll. */
+	glue->epoll_ops = NULL;
+	TALLOC_FREE(ev->additional_data);
+
+	/*
+	 * Set custom_ops the same as poll.
+	 */
+	*glue->glue_ops = *glue->poll_ops;
+	glue->glue_ops->context_init = std_event_context_init;
 
+	/* Next initialize the poll backend. */
+	ret = glue->poll_ops->context_init(ev);
+	if (ret != 0) {
+		return false;
+	}
+
+	/*
+	 * Now we have to change all the existing file descriptor
+	 * events from the epoll backend to the poll backend.
+	 */
+	for (fde = ev->fd_events; fde; fde = fde_next) {
+		/*
+		 * We must remove this fde off the ev->fd_events list.
+		 */
+		fde_next = fde->next;
+
+		/* Remove from the ev->fd_events list. */
+		DLIST_REMOVE(ev->fd_events, fde);
+
+		/* Re-add this event as a poll backend event. */
+		tevent_poll_event_add_fd_internal(ev, fde);
+	}
+
+	return true;
+}
+
+static int std_event_loop_once(struct tevent_context *ev, const char *location)
+{
+	void *glue_ptr = talloc_parent(ev->ops);
+	struct std_event_glue *glue =
+		talloc_get_type_abort(glue_ptr,
+		struct std_event_glue);
+	int ret;
+
+	ret = glue->epoll_ops->loop_once(ev, location);
+	if (glue->epoll_ops != NULL) {
+		/* No fallback */
+		return ret;
+	}
+
+	if (!glue->fallback_replay) {
+		/*
+		 * The problem happened while modifying an event.
+		 * An event handler was triggered in this case
+		 * and there is no need to call loop_once() again.
+		 */
+		return ret;
+	}
+
+	return glue->poll_ops->loop_once(ev, location);
+}
+
+/*
+  Initialize the epoll backend and allow it to call a
+  switch function if epoll fails at runtime.
+*/
+static int std_event_context_init(struct tevent_context *ev)
+{
+	struct std_event_glue *glue;
+	int ret;
+
+	/*
+	 * If this is the first initialization
+	 * we need to set up the allocated ops
+	 * pointers.
+	 */
+
+	if (ev->ops == &std_event_ops) {
+		glue = talloc_zero(ev, struct std_event_glue);
+		if (glue == NULL) {
+			return -1;
+		}
+
+		glue->epoll_ops = tevent_find_ops_byname("epoll");
+
+		glue->poll_ops = tevent_find_ops_byname("poll");
+		if (glue->poll_ops == NULL) {
+			return -1;
+		}
+
+		/*
+		 * Allocate space for our custom ops.
+		 * Allocate as a child of our epoll_ops pointer
+		 * so we can easily get to it using talloc_parent.
+		 */
+		glue->glue_ops = talloc_zero(glue, struct tevent_ops);
+		if (glue->glue_ops == NULL) {
+			talloc_free(glue);
+			return -1;
+		}
+
+		ev->ops = glue->glue_ops;
+	} else {
+		void *glue_ptr = talloc_parent(ev->ops);
+		glue = talloc_get_type_abort(glue_ptr, struct std_event_glue);
+	}
+
+	if (glue->epoll_ops != NULL) {
+		/*
+		 * Set custom_ops the same as epoll,
+		 * except re-init using std_event_context_init()
+		 * and use std_event_loop_once() to add the
+		 * ability to fallback to a poll backend on
+		 * epoll runtime error.
+		 */
+		*glue->glue_ops = *glue->epoll_ops;
+		glue->glue_ops->context_init = std_event_context_init;
+		glue->glue_ops->loop_once = std_event_loop_once;
+
+		ret = glue->epoll_ops->context_init(ev);
+		if (ret == -1) {
+			goto fallback;
+		}
+#ifdef HAVE_EPOLL
+		if (!tevent_epoll_set_panic_fallback(ev, std_fallback_to_poll)) {
+			TALLOC_FREE(ev->additional_data);
+			goto fallback;
+		}
+#endif
+
+		return ret;
+	}
+
+fallback:
+	glue->epoll_ops = NULL;
+
+	/*
+	 * Set custom_ops the same as poll.
+	 */
+	*glue->glue_ops = *glue->poll_ops;
+	glue->glue_ops->context_init = std_event_context_init;
+
+	return glue->poll_ops->context_init(ev);
+}
 
 _PRIVATE_ bool tevent_standard_init(void)
 {
 	return tevent_register_backend("standard", &std_event_ops);
 }
-
-- 
1.7.9.5


From 27e0a9a470a8cd8fdf11a7541f40056a364d1080 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Mon, 11 Feb 2013 11:42:08 -0800
Subject: [PATCH 13/17] tevent: Remove the previous "standard" tevent backend
 implementation.

This was a horrible hybrid of duplicated epoll and select()
code.

Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 lib/tevent/tevent_standard.c |  557 +-----------------------------------------
 1 file changed, 1 insertion(+), 556 deletions(-)

diff --git a/lib/tevent/tevent_standard.c b/lib/tevent/tevent_standard.c
index 0c72226..d7a5bd7 100644
--- a/lib/tevent/tevent_standard.c
+++ b/lib/tevent/tevent_standard.c
@@ -1,8 +1,7 @@
 /* 
    Unix SMB/CIFS implementation.
    main select loop and event handling
-   Copyright (C) Andrew Tridgell	2003-2005
-   Copyright (C) Stefan Metzmacher      2005-2013
+   Copyright (C) Stefan Metzmacher      2013
    Copyright (C) Jeremy Allison         2013
 
      ** NOTE! The following LGPL license applies to the tevent
@@ -37,560 +36,6 @@
 #include "tevent_util.h"
 #include "tevent_internal.h"
 
-#if 0
-struct std_event_context {
-	/* a pointer back to the generic event_context */
-	struct tevent_context *ev;
-
-	/* the maximum file descriptor number in fd_events */
-	int maxfd;
-
-	/* information for exiting from the event loop */
-	int exit_code;
-
-	/* when using epoll this is the handle from epoll_create */
-	int epoll_fd;
-
-	/* our pid at the time the epoll_fd was created */
-	pid_t pid;
-};
-
-/* use epoll if it is available */
-#if HAVE_EPOLL
-/*
-  called when a epoll call fails, and we should fallback
-  to using select
-*/
-static void epoll_fallback_to_select(struct std_event_context *std_ev, const char *reason)
-{
-	tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
-		     "%s (%s) - falling back to select()\n",
-		     reason, strerror(errno));
-	close(std_ev->epoll_fd);
-	std_ev->epoll_fd = -1;
-	talloc_set_destructor(std_ev, NULL);
-}
-
-/*
-  map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
-*/
-static uint32_t epoll_map_flags(uint16_t flags)
-{
-	uint32_t ret = 0;
-	if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
-	if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
-	return ret;
-}
-
-/*
- free the epoll fd
-*/
-static int epoll_ctx_destructor(struct std_event_context *std_ev)
-{
-	if (std_ev->epoll_fd != -1) {
-		close(std_ev->epoll_fd);
-	}
-	std_ev->epoll_fd = -1;
-	return 0;
-}
-
-/*
- init the epoll fd
-*/
-static void epoll_init_ctx(struct std_event_context *std_ev)
-{
-	std_ev->epoll_fd = epoll_create(64);
-	if (std_ev->epoll_fd == -1) {
-		tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
-			     "Failed to create epoll handle.\n");
-		return;
-	}
-
-	if (!ev_set_close_on_exec(std_ev->epoll_fd)) {
-		tevent_debug(std_ev->ev, TEVENT_DEBUG_WARNING,
-			     "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
-	}
-
-	std_ev->pid = getpid();
-	talloc_set_destructor(std_ev, epoll_ctx_destructor);
-}
-
-static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde);
-
-/*
-  reopen the epoll handle when our pid changes
-  see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an 
-  demonstration of why this is needed
- */
-static void epoll_check_reopen(struct std_event_context *std_ev)
-{
-	struct tevent_fd *fde;
-
-	if (std_ev->pid == getpid()) {
-		return;
-	}
-
-	close(std_ev->epoll_fd);
-	std_ev->epoll_fd = epoll_create(64);
-	if (std_ev->epoll_fd == -1) {
-		tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
-			     "Failed to recreate epoll handle after fork\n");
-		return;
-	}
-
-	if (!ev_set_close_on_exec(std_ev->epoll_fd)) {
-		tevent_debug(std_ev->ev, TEVENT_DEBUG_WARNING,
-			     "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
-	}
-
-	std_ev->pid = getpid();
-	for (fde=std_ev->ev->fd_events;fde;fde=fde->next) {
-		epoll_add_event(std_ev, fde);
-	}
-}
-
-#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT	(1<<0)
-#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR	(1<<1)
-#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR	(1<<2)
-
-/*
- add the epoll event to the given fd_event
-*/
-static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde)
-{
-	struct epoll_event event;
-	if (std_ev->epoll_fd == -1) return;
-
-	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
-
-	/* if we don't want events yet, don't add an epoll_event */
-	if (fde->flags == 0) return;
-
-	ZERO_STRUCT(event);
-	event.events = epoll_map_flags(fde->flags);
-	event.data.ptr = fde;
-	if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
-		epoll_fallback_to_select(std_ev, "EPOLL_CTL_ADD failed");
-	}
-	fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
-
-	/* only if we want to read we want to tell the event handler about errors */
-	if (fde->flags & TEVENT_FD_READ) {
-		fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
-	}
-}
-
-/*
- delete the epoll event for given fd_event
-*/
-static void epoll_del_event(struct std_event_context *std_ev, struct tevent_fd *fde)
-{
-	struct epoll_event event;
-	if (std_ev->epoll_fd == -1) return;
-
-	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
-
-	/* if there's no epoll_event, we don't need to delete it */
-	if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;
-
-	ZERO_STRUCT(event);
-	event.events = epoll_map_flags(fde->flags);
-	event.data.ptr = fde;
-	epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
-	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
-}
-
-/*
- change the epoll event to the given fd_event
-*/
-static void epoll_mod_event(struct std_event_context *std_ev, struct tevent_fd *fde)
-{
-	struct epoll_event event;
-	if (std_ev->epoll_fd == -1) return;
-
-	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
-
-	ZERO_STRUCT(event);
-	event.events = epoll_map_flags(fde->flags);
-	event.data.ptr = fde;
-	if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
-		epoll_fallback_to_select(std_ev, "EPOLL_CTL_MOD failed");
-	}
-
-	/* only if we want to read we want to tell the event handler about errors */
-	if (fde->flags & TEVENT_FD_READ) {
-		fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
-	}
-}
-
-static void epoll_change_event(struct std_event_context *std_ev, struct tevent_fd *fde)
-{
-	bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
-	bool want_read = (fde->flags & TEVENT_FD_READ);
-	bool want_write= (fde->flags & TEVENT_FD_WRITE);
-
-	if (std_ev->epoll_fd == -1) return;
-
-	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
-
-	/* there's already an event */
-	if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
-		if (want_read || (want_write && !got_error)) {
-			epoll_mod_event(std_ev, fde);
-			return;
-		}
-		/* 
-		 * if we want to match the select behavior, we need to remove the epoll_event
-		 * when the caller isn't interested in events.
-		 *
-		 * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
-		 */
-		epoll_del_event(std_ev, fde);
-		return;
-	}
-
-	/* there's no epoll_event attached to the fde */
-	if (want_read || (want_write && !got_error)) {
-		epoll_add_event(std_ev, fde);
-		return;
-	}
-}
-
-/*
-  event loop handling using epoll
-*/
-static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tvalp)
-{
-	int ret, i;
-#define MAXEVENTS 1
-	struct epoll_event events[MAXEVENTS];
-	int timeout = -1;
-
-	if (std_ev->epoll_fd == -1) return -1;
-
-	if (tvalp) {
-		/* it's better to trigger timed events a bit later than to early */
-		timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
-	}
-
-	if (std_ev->ev->signal_events &&
-	    tevent_common_check_signal(std_ev->ev)) {
-		return 0;
-	}
-
-	tevent_trace_point_callback(std_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
-	ret = epoll_wait(std_ev->epoll_fd, events, MAXEVENTS, timeout);
-	tevent_trace_point_callback(std_ev->ev, TEVENT_TRACE_AFTER_WAIT);
-
-	if (ret == -1 && errno == EINTR && std_ev->ev->signal_events) {
-		if (tevent_common_check_signal(std_ev->ev)) {
-			return 0;
-		}
-	}
-
-	if (ret == -1 && errno != EINTR) {
-		epoll_fallback_to_select(std_ev, "epoll_wait() failed");
-		return -1;
-	}
-
-	if (ret == 0 && tvalp) {
-		/* we don't care about a possible delay here */
-		tevent_common_loop_timer_delay(std_ev->ev);
-		return 0;
-	}
-
-	for (i=0;i<ret;i++) {
-		struct tevent_fd *fde = talloc_get_type(events[i].data.ptr, 
-						       struct tevent_fd);
-		uint16_t flags = 0;
-
-		if (fde == NULL) {
-			epoll_fallback_to_select(std_ev, "epoll_wait() gave bad data");
-			return -1;
-		}
-		if (events[i].events & (EPOLLHUP|EPOLLERR)) {
-			fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
-			/*
-			 * if we only wait for TEVENT_FD_WRITE, we should not tell the
-			 * event handler about it, and remove the epoll_event,
-			 * as we only report errors when waiting for read events,
-			 * to match the select() behavior
-			 */
-			if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
-				epoll_del_event(std_ev, fde);
-				continue;
-			}
-			flags |= TEVENT_FD_READ;
-		}
-		if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
-		if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
-		if (flags) {
-			fde->handler(std_ev->ev, fde, flags, fde->private_data);
-			break;
-		}
-	}
-
-	return 0;
-}
-#else
-#define epoll_init_ctx(std_ev) 
-#define epoll_add_event(std_ev,fde)
-#define epoll_del_event(std_ev,fde)
-#define epoll_change_event(std_ev,fde)
-#define epoll_event_loop(std_ev,tvalp) (-1)
-#define epoll_check_reopen(std_ev)
-#endif
-
-/*
-  create a std_event_context structure.
-*/
-static int std_event_context_init(struct tevent_context *ev)
-{
-	struct std_event_context *std_ev;
-
-	/*
-	 * We might be called during tevent_re_initialise()
-	 * which means we need to free our old additional_data.
-	 */
-	TALLOC_FREE(ev->additional_data);
-
-	std_ev = talloc_zero(ev, struct std_event_context);
-	if (!std_ev) return -1;
-	std_ev->ev = ev;
-	std_ev->epoll_fd = -1;
-
-	epoll_init_ctx(std_ev);
-
-	ev->additional_data = std_ev;
-	return 0;
-}
-
-/*
-  recalculate the maxfd
-*/
-static void calc_maxfd(struct std_event_context *std_ev)
-{
-	struct tevent_fd *fde;
-
-	std_ev->maxfd = 0;
-	for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
-		if (fde->fd > std_ev->maxfd) {
-			std_ev->maxfd = fde->fd;
-		}
-	}
-}
-
-
-/* to mark the ev->maxfd invalid
- * this means we need to recalculate it
- */
-#define EVENT_INVALID_MAXFD (-1)
-
-/*
-  destroy an fd_event
-*/
-static int std_event_fd_destructor(struct tevent_fd *fde)
-{
-	struct tevent_context *ev = fde->event_ctx;
-	struct std_event_context *std_ev = NULL;
-
-	if (ev) {
-		std_ev = talloc_get_type(ev->additional_data,
-					 struct std_event_context);
-
-		epoll_check_reopen(std_ev);
-
-		if (std_ev->maxfd == fde->fd) {
-			std_ev->maxfd = EVENT_INVALID_MAXFD;
-		}
-
-		epoll_del_event(std_ev, fde);
-	}
-
-	return tevent_common_fd_destructor(fde);
-}
-
-/*
-  add a fd based event
-  return NULL on failure (memory allocation error)
-*/
-static struct tevent_fd *std_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
-					  int fd, uint16_t flags,
-					  tevent_fd_handler_t handler,
-					  void *private_data,
-					  const char *handler_name,
-					  const char *location)
-{
-	struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
-							   struct std_event_context);
-	struct tevent_fd *fde;
-
-	epoll_check_reopen(std_ev);
-
-	fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
-				   handler, private_data,
-				   handler_name, location);
-	if (!fde) return NULL;
-
-	if ((std_ev->maxfd != EVENT_INVALID_MAXFD)
-	    && (fde->fd > std_ev->maxfd)) {
-		std_ev->maxfd = fde->fd;
-	}
-	talloc_set_destructor(fde, std_event_fd_destructor);
-
-	epoll_add_event(std_ev, fde);
-
-	return fde;
-}
-
-/*
-  set the fd event flags
-*/
-static void std_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
-{
-	struct tevent_context *ev;
-	struct std_event_context *std_ev;
-
-	if (fde->flags == flags) return;
-
-	ev = fde->event_ctx;
-	std_ev = talloc_get_type(ev->additional_data, struct std_event_context);
-
-	fde->flags = flags;
-
-	epoll_check_reopen(std_ev);
-
-	epoll_change_event(std_ev, fde);
-}
-
-/*
-  event loop handling using select()
-*/
-static int std_event_loop_select(struct std_event_context *std_ev, struct timeval *tvalp)
-{
-	fd_set r_fds, w_fds;
-	struct tevent_fd *fde;
-	int selrtn;
-
-	/* we maybe need to recalculate the maxfd */
-	if (std_ev->maxfd == EVENT_INVALID_MAXFD) {
-		calc_maxfd(std_ev);
-	}
-
-	FD_ZERO(&r_fds);
-	FD_ZERO(&w_fds);
-
-	/* setup any fd events */
-	for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
-		if (fde->fd < 0 || fde->fd >= FD_SETSIZE) {
-			std_ev->exit_code = EBADF;
-			return -1;
-		}
-		if (fde->flags & TEVENT_FD_READ) {
-			FD_SET(fde->fd, &r_fds);
-		}
-		if (fde->flags & TEVENT_FD_WRITE) {
-			FD_SET(fde->fd, &w_fds);
-		}
-	}
-
-	if (std_ev->ev->signal_events &&
-	    tevent_common_check_signal(std_ev->ev)) {
-		return 0;
-	}
-
-	selrtn = select(std_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
-
-	if (selrtn == -1 && errno == EINTR && 
-	    std_ev->ev->signal_events) {
-		tevent_common_check_signal(std_ev->ev);
-		return 0;
-	}
-
-	if (selrtn == -1 && errno == EBADF) {
-		/* the socket is dead! this should never
-		   happen as the socket should have first been
-		   made readable and that should have removed
-		   the event, so this must be a bug. This is a
-		   fatal error. */
-		tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
-			     "ERROR: EBADF on std_event_loop_once\n");
-		std_ev->exit_code = EBADF;
-		return -1;
-	}
-
-	if (selrtn == 0 && tvalp) {
-		/* we don't care about a possible delay here */
-		tevent_common_loop_timer_delay(std_ev->ev);
-		return 0;
-	}
-
-	if (selrtn > 0) {
-		/* at least one file descriptor is ready - check
-		   which ones and call the handler, being careful to allow
-		   the handler to remove itself when called */
-		for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
-			uint16_t flags = 0;
-
-			if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
-			if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
-			if (flags & fde->flags) {
-				fde->handler(std_ev->ev, fde, flags, fde->private_data);
-				break;
-			}
-		}
-	}
-
-	return 0;
-}		
-
-/*
-  do a single event loop using the events defined in ev 
-*/
-static int std_event_loop_once(struct tevent_context *ev, const char *location)
-{
-	struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
-		 					   struct std_event_context);
-	struct timeval tval;
-
-	if (ev->signal_events &&
-	    tevent_common_check_signal(ev)) {
-		return 0;
-	}
-
-	if (ev->immediate_events &&
-	    tevent_common_loop_immediate(ev)) {
-		return 0;
-	}
-
-	tval = tevent_common_loop_timer_delay(ev);
-	if (tevent_timeval_is_zero(&tval)) {
-		return 0;
-	}
-
-	epoll_check_reopen(std_ev);
-
-	if (epoll_event_loop(std_ev, &tval) == 0) {
-		return 0;
-	}
-
-	return std_event_loop_select(std_ev, &tval);
-}
-
-static const struct tevent_ops std_event_ops = {
-	.context_init		= std_event_context_init,
-	.add_fd			= std_event_add_fd,
-	.set_fd_close_fn	= tevent_common_fd_set_close_fn,
-	.get_fd_flags		= tevent_common_fd_get_flags,
-	.set_fd_flags		= std_event_set_fd_flags,
-	.add_timer		= tevent_common_add_timer,
-	.schedule_immediate	= tevent_common_schedule_immediate,
-	.add_signal		= tevent_common_add_signal,
-	.loop_once		= std_event_loop_once,
-	.loop_wait		= tevent_common_loop_wait,
-};
-#endif
-
 struct std_event_glue {
 	const struct tevent_ops *epoll_ops;
 	const struct tevent_ops *poll_ops;
-- 
1.7.9.5


From 9995e3fc9e9ee6cb91563e5ec2d21bd944f191e2 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 14 Feb 2013 15:46:18 +0100
Subject: [PATCH 14/17] HACK tevent fallback testing

TDB_NO_FSYNC=1 buildnice make -j test TESTS=LOCAL-WBCLIENT
---
 lib/tevent/tevent_epoll.c |   16 ++++++++++++++++
 lib/tevent/tevent_poll.c  |    2 ++
 source3/torture/torture.c |   19 ++++++++++++++++++-
 3 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 8696215..81949d4 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -43,7 +43,9 @@ struct epoll_event_context {
 	bool (*panic_fallback)(struct tevent_context *ev, bool replay);
 };
 
+#define TEST_PANIC_FALLBACK
 #ifdef TEST_PANIC_FALLBACK
+
 static int epoll_wait_panic_fallback(int epfd,
 				struct epoll_event *events,
 				int maxevents,
@@ -58,7 +60,19 @@ static int epoll_wait_panic_fallback(int epfd,
 	return epoll_wait(epfd, events, maxevents, timeout);
 }
 
+static int epoll_ctl_panic_fallback(int epfd, int op, int fd, struct epoll_event *event)
+{
+	/* 50% of the time, fail... */
+	if ((random() % 2) == 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	return epoll_ctl(epfd, op, fd, event);
+}
+
 #define epoll_wait epoll_wait_panic_fallback
+#define epoll_ctl epoll_ctl_panic_fallback
 #endif
 
 /*
@@ -488,6 +502,8 @@ static int epoll_event_loop_once(struct tevent_context *ev, const char *location
 		 					   struct epoll_event_context);
 	struct timeval tval;
 
+	tevent_debug(ev, TEVENT_DEBUG_WARNING,
+		     "%s:%s\n", __location__, __FUNCTION__);
 	if (ev->signal_events &&
 	    tevent_common_check_signal(ev)) {
 		return 0;
diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c
index 89b3bbc..8c5f834 100644
--- a/lib/tevent/tevent_poll.c
+++ b/lib/tevent/tevent_poll.c
@@ -545,6 +545,8 @@ static int poll_event_loop_once(struct tevent_context *ev,
 {
 	struct timeval tval;
 
+	tevent_debug(ev, TEVENT_DEBUG_WARNING,
+		     "%s:%s\n", __location__, __FUNCTION__);
 	if (ev->signal_events &&
 	    tevent_common_check_signal(ev)) {
 		return 0;
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index b59ac30..d93a23c 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -8516,6 +8516,22 @@ static void wbclient_done(struct tevent_req *req)
 	d_printf("wb_trans_recv %d returned %s\n", *i, wbcErrorString(wbc_err));
 }
 
+/*
+  this is used to catch debug messages from events
+*/
+static void s3t_event_debug(void *context, enum tevent_debug_level level,
+			   const char *fmt, va_list ap)  PRINTF_ATTRIBUTE(3,0);
+
+static void s3t_event_debug(void *context, enum tevent_debug_level level,
+			   const char *fmt, va_list ap)
+{
+	char *s = NULL;
+	if (vasprintf(&s, fmt, ap) == -1) {
+		return;
+	}
+	d_printf("s3t_event: %s", s);
+	free(s);
+}
 static bool run_local_wbclient(int dummy)
 {
 	struct event_context *ev;
@@ -8526,10 +8542,11 @@ static bool run_local_wbclient(int dummy)
 
 	BlockSignals(True, SIGPIPE);
 
-	ev = tevent_context_init_byname(talloc_tos(), "epoll");
+	ev = tevent_context_init_byname(talloc_tos(), "standard");
 	if (ev == NULL) {
 		goto fail;
 	}
+	tevent_set_debug(ev, s3t_event_debug, NULL);
 
 	wb_ctx = talloc_array(ev, struct wb_context *, torture_nprocs);
 	if (wb_ctx == NULL) {
-- 
1.7.9.5


From 2e42cad9195a2c8bc4dddc64dd2032a0c3b08ecc Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 14 Feb 2013 15:52:46 +0100
Subject: [PATCH 15/17] HACK blackbox subunit print ok

TDB_NO_FSYNC=1 buildnice make -j test TESTS=LOCAL-WBCLIENT
...
less st/subunit
---
 testprogs/blackbox/subunit.sh |    1 +
 1 file changed, 1 insertion(+)

diff --git a/testprogs/blackbox/subunit.sh b/testprogs/blackbox/subunit.sh
index 9b047a2..03e6e51 100755
--- a/testprogs/blackbox/subunit.sh
+++ b/testprogs/blackbox/subunit.sh
@@ -62,6 +62,7 @@ testit () {
 	output=`$cmdline 2>&1`
 	status=$?
 	if [ x$status = x0 ]; then
+		echo "$output"
 		subunit_pass_test "$name"
 	else
 		echo "$output" | subunit_fail_test "$name"
-- 
1.7.9.5


From 42c6997e26f129ff98087402d1cdab789a32c7a4 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 14 Feb 2013 15:59:11 +0100
Subject: [PATCH 16/17] Revert "HACK blackbox subunit print ok"

This reverts commit 2e42cad9195a2c8bc4dddc64dd2032a0c3b08ecc.
---
 testprogs/blackbox/subunit.sh |    1 -
 1 file changed, 1 deletion(-)

diff --git a/testprogs/blackbox/subunit.sh b/testprogs/blackbox/subunit.sh
index 03e6e51..9b047a2 100755
--- a/testprogs/blackbox/subunit.sh
+++ b/testprogs/blackbox/subunit.sh
@@ -62,7 +62,6 @@ testit () {
 	output=`$cmdline 2>&1`
 	status=$?
 	if [ x$status = x0 ]; then
-		echo "$output"
 		subunit_pass_test "$name"
 	else
 		echo "$output" | subunit_fail_test "$name"
-- 
1.7.9.5


From f722eb01ba5eb611fb99208a6188c9a8bc675e99 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 14 Feb 2013 15:59:18 +0100
Subject: [PATCH 17/17] Revert "HACK tevent fallback testing"

This reverts commit 9995e3fc9e9ee6cb91563e5ec2d21bd944f191e2.
---
 lib/tevent/tevent_epoll.c |   16 ----------------
 lib/tevent/tevent_poll.c  |    2 --
 source3/torture/torture.c |   19 +------------------
 3 files changed, 1 insertion(+), 36 deletions(-)

diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 81949d4..8696215 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -43,9 +43,7 @@ struct epoll_event_context {
 	bool (*panic_fallback)(struct tevent_context *ev, bool replay);
 };
 
-#define TEST_PANIC_FALLBACK
 #ifdef TEST_PANIC_FALLBACK
-
 static int epoll_wait_panic_fallback(int epfd,
 				struct epoll_event *events,
 				int maxevents,
@@ -60,19 +58,7 @@ static int epoll_wait_panic_fallback(int epfd,
 	return epoll_wait(epfd, events, maxevents, timeout);
 }
 
-static int epoll_ctl_panic_fallback(int epfd, int op, int fd, struct epoll_event *event)
-{
-	/* 50% of the time, fail... */
-	if ((random() % 2) == 0) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	return epoll_ctl(epfd, op, fd, event);
-}
-
 #define epoll_wait epoll_wait_panic_fallback
-#define epoll_ctl epoll_ctl_panic_fallback
 #endif
 
 /*
@@ -502,8 +488,6 @@ static int epoll_event_loop_once(struct tevent_context *ev, const char *location
 		 					   struct epoll_event_context);
 	struct timeval tval;
 
-	tevent_debug(ev, TEVENT_DEBUG_WARNING,
-		     "%s:%s\n", __location__, __FUNCTION__);
 	if (ev->signal_events &&
 	    tevent_common_check_signal(ev)) {
 		return 0;
diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c
index 8c5f834..89b3bbc 100644
--- a/lib/tevent/tevent_poll.c
+++ b/lib/tevent/tevent_poll.c
@@ -545,8 +545,6 @@ static int poll_event_loop_once(struct tevent_context *ev,
 {
 	struct timeval tval;
 
-	tevent_debug(ev, TEVENT_DEBUG_WARNING,
-		     "%s:%s\n", __location__, __FUNCTION__);
 	if (ev->signal_events &&
 	    tevent_common_check_signal(ev)) {
 		return 0;
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index d93a23c..b59ac30 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -8516,22 +8516,6 @@ static void wbclient_done(struct tevent_req *req)
 	d_printf("wb_trans_recv %d returned %s\n", *i, wbcErrorString(wbc_err));
 }
 
-/*
-  this is used to catch debug messages from events
-*/
-static void s3t_event_debug(void *context, enum tevent_debug_level level,
-			   const char *fmt, va_list ap)  PRINTF_ATTRIBUTE(3,0);
-
-static void s3t_event_debug(void *context, enum tevent_debug_level level,
-			   const char *fmt, va_list ap)
-{
-	char *s = NULL;
-	if (vasprintf(&s, fmt, ap) == -1) {
-		return;
-	}
-	d_printf("s3t_event: %s", s);
-	free(s);
-}
 static bool run_local_wbclient(int dummy)
 {
 	struct event_context *ev;
@@ -8542,11 +8526,10 @@ static bool run_local_wbclient(int dummy)
 
 	BlockSignals(True, SIGPIPE);
 
-	ev = tevent_context_init_byname(talloc_tos(), "standard");
+	ev = tevent_context_init_byname(talloc_tos(), "epoll");
 	if (ev == NULL) {
 		goto fail;
 	}
-	tevent_set_debug(ev, s3t_event_debug, NULL);
 
 	wb_ctx = talloc_array(ev, struct wb_context *, torture_nprocs);
 	if (wb_ctx == NULL) {
-- 
1.7.9.5

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 261 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20130214/0ab70a2d/attachment-0001.pgp>


More information about the samba-technical mailing list