[PATCH] Fix epoll backend to allow separate read/write events on one fd.
Jeremy Allison
jra at samba.org
Thu Feb 14 17:37:20 MST 2013
Here is an amended patchset.
On Thu, Feb 14, 2013 at 03:18:27PM +0100, Stefan (metze) Metzmacher wrote:
> I see the protection against more than two handlers.
I think you mean "don't see the protection against", yes ?
I've made it clearer where the protection is - having
more than 2 handlers is treated internally as a logic
error.
Note this doesn't cope with the case where the same
fd is added multiple times with a flags==0, and then
tevent_fd_set_flags() is called multiple times to turn
on flags on all the events, but then again neither does
the original epoll backend code.
Fixing that I think should be an additional patch
(after this patchset) that adds the 'no more than
two handlers per-fd, one read, one write, or one
handler with read+write' restriction on all the tevent
backends, so isn't part of this patch.
> The tricky part is the EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR
> and EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR. I don't think that's
> handled correct in your patches.
Ok, I have looked really carefully at this, and I found
what (I hope :-) you were referring to and have fixed it.
Essentially once epoll_wait returns EPOLLHUP|EPOLLERR
I need to ensure both paired fde events are handled
correctly, by removing the event that has TEVENT_FD_WRITE
set, and then ensuring the handler is called for
the paired event with TEVENT_FD_READ set.
I now handle that case correctly, but check the new
code inside epoll_event_loop() to be sure !
> I'm also not sure if the EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT is filled
> and cleared correctly.
Actually I think that's right. It's set in the epoll_add_event()
case when flags != 0, that hasn't changed. It's cleared in
the epoll_del_event() case after the event is deleted, or
when the event is swapped over to the paired event. The logic
there is pretty simple IMHO and I don't think I've broken it.
> Can you change the code to store the pointer to the other event
> in fde->addtitional_data toghether with the
> EPOLL_ADDITIONAL_FD_WAS_MULTIPLEXED
> flag? That would avoid a list traverse for a lot of cases.
Done - great idea and made the code simpler, thanks !
> We need a destructor that removes the cross-reference on delete.
That's done in the epoll_del_event code (it removes the
cross reference when it un-pairs a paired set of events).
When deleting the event itself it doesn't matter (memory will
be freed anyway) and in the fallback code from epoll->poll
the poll code already overwrites the additional_flags and
additional_data fields.
> This way we can preferr the write handler over the read handler
> and also make sure that tevent_fd_set_flags doesn't set the same flag
> to both handlers.
ESCOPE :-). Not in the scope of this patchset. Let's
add it on top after you've reviewed this one.
> It would be good to enforce the rule of just one fd event for
> TEVENT_FD_READ and just one fd event for TEVENT_FD_WRITE.
> We need to enforce this on tevent_add_fd() and on tevent_fd_set_flags()
> and for all backends.
ESCOPE again.. :-).
> It's good to get this finally fixed, thanks!
You're welcome !
Cheers,
Jeremy.
-------------- next part --------------
From 7dc547ed12b98db1c3c9b8577e5f8e62414f9219 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Thu, 14 Feb 2013 13:50:56 -0800
Subject: [PATCH 1/7] Start to fix the epoll backend to support 2 fd events on
the same fd correctly.
Add a utility function epoll_add_duplicate_fd() and
a new flag EPOLL_ADDITIONAL_FD_WAS_MULTIPLEXED.
This will be called by epoll_add_event() to merge two
fde events with the same file descriptor.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
lib/tevent/tevent_epoll.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 8696215..7076161 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -192,6 +192,72 @@ static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
#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)
+#define EPOLL_ADDITIONAL_FD_WAS_MULTIPLEXED (1<<3)
+
+/*
+ epoll cannot add the same file descriptor twice, once
+ with read, once with write which is allowed by the
+ tevent backend. Multiplex the existing fde, flag it
+ as such so we can search for the correct fde on
+ event triggering.
+*/
+
+static int epoll_add_duplicate_fd(struct epoll_event_context *epoll_ev,
+ struct tevent_fd *add_fde)
+{
+ struct epoll_event event;
+ struct tevent_fd *orig_fde;
+ int ret;
+
+ /* Find the existing fde that caused the EEXIST error. */
+ for (orig_fde = epoll_ev->ev->fd_events; orig_fde; orig_fde = orig_fde->next) {
+ if (orig_fde == add_fde) {
+ continue;
+ }
+ /*
+ * The multiplex fde must have the same fd, and also
+ * already have an epoll event attached.
+ */
+ if (orig_fde->fd == add_fde->fd &&
+ (orig_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) {
+ break;
+ }
+ }
+ if (orig_fde == NULL) {
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+ "can't find multiplex fde");
+ return -1;
+ }
+
+ if (orig_fde->additional_flags & EPOLL_ADDITIONAL_FD_WAS_MULTIPLEXED) {
+ /* Logic error. Can't have more than 2 multiplexed fde's. */
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+ "multiplex fde has bad additional_flags");
+ return -1;
+ }
+
+ /* Modify the orig_fde to add in the new flags. */
+ ZERO_STRUCT(event);
+ event.events = epoll_map_flags(orig_fde->flags) |
+ epoll_map_flags(add_fde->flags);
+ event.data.ptr = orig_fde;
+ ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, orig_fde->fd, &event);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Now flag both fde's as being multiplexed. */
+ orig_fde->additional_flags |= EPOLL_ADDITIONAL_FD_WAS_MULTIPLEXED;
+ add_fde->additional_flags |= EPOLL_ADDITIONAL_FD_WAS_MULTIPLEXED;
+ /*
+ * Make each fde->additional_data pointers point at each other
+ * so we can look them up from each other. They are now paired.
+ */
+ orig_fde->additional_data = (struct tevent_fd *)add_fde;
+ add_fde->additional_data = (struct tevent_fd *)orig_fde;
+
+ return 0;
+}
/*
add the epoll event to the given fd_event
--
1.8.1
From da7377783d496a44c0d16dd7a179cd990b1589e4 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Thu, 14 Feb 2013 13:52:41 -0800
Subject: [PATCH 2/7] If epoll_ctl(..EPOLL_CTL_ADD,..) failes with EEXIST,
merge the two fde's into one epoll event.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
lib/tevent/tevent_epoll.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 7076161..8b22483 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -277,8 +277,16 @@ 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", false);
- return;
+ if (errno == EEXIST) {
+ if (epoll_add_duplicate_fd(epoll_ev, fde) != 0) {
+ epoll_panic(epoll_ev, "epoll_add_duplicate_fd "
+ "failed", false);
+ return;
+ }
+ } else {
+ epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed", false);
+ return;
+ }
}
fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
--
1.8.1
From f41b4cd150a17f638f0be27e8b5aef7b345b0523 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Thu, 14 Feb 2013 14:13:05 -0800
Subject: [PATCH 3/7] Fix up epoll_del_event to cope with deleting a
multiplexed fde event.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
lib/tevent/tevent_epoll.c | 39 +++++++++++++++++++++++++++++++++++----
1 file changed, 35 insertions(+), 4 deletions(-)
diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 8b22483..94cb1e8 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -302,6 +302,7 @@ static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_
static void epoll_del_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
{
struct epoll_event event;
+ int op = EPOLL_CTL_DEL;
if (epoll_ev->epoll_fd == -1) return;
@@ -310,13 +311,43 @@ static void epoll_del_event(struct epoll_event_context *epoll_ev, struct tevent_
/* if there's no epoll_event, we don't need to delete it */
if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;
+ if (fde->additional_flags & EPOLL_ADDITIONAL_FD_WAS_MULTIPLEXED) {
+ /*
+ * If this is a multiplexed fde, we need to replace it
+ * with the remaining paired event.
+ */
+ struct tevent_fd *mpx_fde = (struct tevent_fd *)fde->additional_data;
+ if (mpx_fde == NULL) {
+ epoll_panic(epoll_ev, "fde->additional_data==NULL", false);
+ return;
+ }
+ /* Remove multiplexed flag from both events. */
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_WAS_MULTIPLEXED;
+ mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_WAS_MULTIPLEXED;
+ /* And unpair the two events. */
+ fde->additional_data = NULL;
+ mpx_fde->additional_data = NULL;
+
+ /* Modify, don't delete the remaining event. */
+ op = EPOLL_CTL_MOD;
+ fde = mpx_fde;
+ }
+
ZERO_STRUCT(event);
event.events = epoll_map_flags(fde->flags);
event.data.ptr = fde;
- if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event) != 0) {
- tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
- "epoll_del_event failed! probable early close bug (%s)\n",
- strerror(errno));
+ if (epoll_ctl(epoll_ev->epoll_fd, op, fde->fd, &event) != 0) {
+ if (op == EPOLL_CTL_DEL) {
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+ "EPOLL_CTL_DEL failed. probable early close bug (%s)\n",
+ strerror(errno));
+ } else {
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+ "failed changing mpx fd (%s)\n",
+ strerror(errno));
+ epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed", false);
+ return;
+ }
}
fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
}
--
1.8.1
From 2344aaf9b41bf24773298351060c0fbe7b4f79a0 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Thu, 14 Feb 2013 14:14:50 -0800
Subject: [PATCH 4/7] Fix epoll_mod_event() to cope with modifying a
multiplexed fde event.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
lib/tevent/tevent_epoll.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 94cb1e8..7bc33a7 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -364,6 +364,18 @@ static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct tevent_
ZERO_STRUCT(event);
event.events = epoll_map_flags(fde->flags);
+ if (fde->additional_flags & EPOLL_ADDITIONAL_FD_WAS_MULTIPLEXED) {
+ /*
+ * This is a multiplexed fde, we need to include both
+ * flags in the modified event.
+ */
+ struct tevent_fd *mpx_fde = (struct tevent_fd *)fde->additional_data;
+ if (mpx_fde == NULL) {
+ epoll_panic(epoll_ev, "fde->additional_data==NULL", false);
+ return;
+ }
+ event.events |= epoll_map_flags(mpx_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", false);
--
1.8.1
From 22b1d9992f83c3ce9d504d6bf6ae587ad65f444d Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Thu, 14 Feb 2013 15:53:38 -0800
Subject: [PATCH 5/7] Add utility function epoll_handle_hup_or_err()
We'll use this to handle the EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR
and EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR flags with multiplexed
events in the event loop.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
lib/tevent/tevent_epoll.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 7bc33a7..6d5e879 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -422,6 +422,37 @@ static void epoll_change_event(struct epoll_event_context *epoll_ev, struct teve
}
/*
+ Cope with epoll returning EPOLLHUP|EPOLLERR on an event.
+ Return true if there's nothing else to do, false if
+ this event needs further handling.
+*/
+static bool epoll_handle_hup_or_err(struct epoll_event_context *epoll_ev,
+ struct tevent_fd *fde)
+{
+ if (fde == NULL) {
+ /* Nothing to do if no event. */
+ return true;
+ }
+
+ 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(epoll_ev, fde);
+ /* Do the same as the poll backend and
+ remove the writeable flag. */
+ fde->flags &= ~TEVENT_FD_WRITE;
+ return true;
+ }
+ /* This has TEVENT_FD_READ set, we're not finished. */
+ return false;
+}
+
+/*
event loop handling using epoll
*/
static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
--
1.8.1
From 8468e83f210576ad027f2b33092be45491395bf3 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Thu, 14 Feb 2013 15:59:40 -0800
Subject: [PATCH 6/7] In epoll_event_loop() ensure we trigger the right handler
for a multiplexed fde event.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
lib/tevent/tevent_epoll.c | 38 ++++++++++++++++++++++++++++++--------
1 file changed, 30 insertions(+), 8 deletions(-)
diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 6d5e879..abfbfe2 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -499,27 +499,49 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval
struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
struct tevent_fd);
uint16_t flags = 0;
+ struct tevent_fd *mpx_fde = NULL;
if (fde == NULL) {
epoll_panic(epoll_ev, "epoll_wait() gave bad data", true);
return -1;
}
- if (events[i].events & (EPOLLHUP|EPOLLERR)) {
- fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
+ if (fde->additional_flags & EPOLL_ADDITIONAL_FD_WAS_MULTIPLEXED) {
/*
- * 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
+ * Save off the multiplexed event in case we need
+ * to use it to call the handler function.
*/
- if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
- epoll_del_event(epoll_ev, fde);
+ mpx_fde = (struct tevent_fd *)fde->additional_data;
+ if (mpx_fde == NULL) {
+ epoll_panic(epoll_ev, "logic error", true);
+ return -1;
+ }
+ }
+ if (events[i].events & (EPOLLHUP|EPOLLERR)) {
+ bool handled_fde = epoll_handle_hup_or_err(epoll_ev, fde);
+ bool handled_mpx = epoll_handle_hup_or_err(epoll_ev, mpx_fde);
+
+ if (handled_fde && handled_mpx) {
+ /* Fully dealt with this event. */
continue;
}
+ if (!handled_mpx) {
+ /*
+ * If the mpx event was the one that needs
+ * further handling, it's the TEVENT_FD_READ
+ * event so switch over and call that handler.
+ */
+ fde = mpx_fde;
+ }
flags |= TEVENT_FD_READ;
}
if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
+ if (mpx_fde) {
+ /* Ensure we got the right fde. */
+ if ((flags & fde->flags) == 0) {
+ fde = mpx_fde;
+ }
+ }
if (flags) {
fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
break;
--
1.8.1
From b27f0db426b8515ea306fe8c7177c83806b9bdb1 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Thu, 14 Feb 2013 14:16:31 -0800
Subject: [PATCH 7/7] Regression test to ensure that a tevent backend can cope
with separate read/write events on a single fd.
This tests the multiplex fd changes to the epoll backend to
ensure they work correctly.
Signed-off-by: Jeremy Allison <jra at samba.org>
---
lib/tevent/testsuite.c | 51 ++++++++++++++++++++++++++++++++++----------------
1 file changed, 35 insertions(+), 16 deletions(-)
diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index 3d2a79a..6e490e4 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -34,19 +34,26 @@
#endif
static int fde_count;
+static int fde_wcount;
-static void fde_handler(struct tevent_context *ev_ctx, struct tevent_fd *f,
+static void fde_handler_readwrite(struct tevent_context *ev_ctx, struct tevent_fd *f,
uint16_t flags, void *private_data)
{
int *fd = (int *)private_data;
- char c;
+ char c = 0;
#ifdef SA_SIGINFO
kill(getpid(), SIGUSR1);
#endif
kill(getpid(), SIGALRM);
- read(fd[0], &c, 1);
- write(fd[1], &c, 1);
- fde_count++;
+
+ if ((flags & TEVENT_FD_WRITE) && (fde_wcount - fde_count < 256)) {
+ /* Don't fill the pipe and block... */
+ write(fd[1], &c, 1);
+ fde_wcount++;
+ } else {
+ read(fd[0], &c, 1);
+ fde_count++;
+ }
}
static void finished_handler(struct tevent_context *ev_ctx, struct tevent_timer *te,
@@ -70,7 +77,10 @@ static bool test_event_context(struct torture_context *test,
int fd[2] = { -1, -1 };
const char *backend = (const char *)test_data;
int alarm_count=0, info_count=0;
- struct tevent_fd *fde;
+ struct tevent_fd *fde_read;
+ struct tevent_fd *fde_read_1;
+ struct tevent_fd *fde_write;
+ struct tevent_fd *fde_write_1;
#ifdef SA_RESTART
struct tevent_signal *se1 = NULL;
#endif
@@ -80,7 +90,6 @@ static bool test_event_context(struct torture_context *test,
#endif
int finished=0;
struct timeval t;
- char c = 0;
ev_ctx = tevent_context_init_byname(test, backend);
if (ev_ctx == NULL) {
@@ -92,13 +101,23 @@ static bool test_event_context(struct torture_context *test,
/* reset globals */
fde_count = 0;
+ fde_wcount = 0;
/* create a pipe */
pipe(fd);
- fde = tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_READ,
- fde_handler, fd);
- tevent_fd_set_auto_close(fde);
+ fde_read = tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_READ,
+ fde_handler_readwrite, fd);
+ fde_write_1 = tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_WRITE,
+ fde_handler_readwrite, fd);
+
+ fde_write = tevent_add_fd(ev_ctx, ev_ctx, fd[1], TEVENT_FD_WRITE,
+ fde_handler_readwrite, fd);
+ fde_read_1 = tevent_add_fd(ev_ctx, ev_ctx, fd[1], TEVENT_FD_READ,
+ fde_handler_readwrite, fd);
+
+ tevent_fd_set_auto_close(fde_read);
+ tevent_fd_set_auto_close(fde_write);
tevent_add_timer(ev_ctx, ev_ctx, timeval_current_ofs(2,0),
finished_handler, &finished);
@@ -113,8 +132,6 @@ static bool test_event_context(struct torture_context *test,
se3 = tevent_add_signal(ev_ctx, ev_ctx, SIGUSR1, SA_SIGINFO, count_handler, &info_count);
#endif
- write(fd[1], &c, 1);
-
t = timeval_current();
while (!finished) {
errno = 0;
@@ -124,8 +141,10 @@ static bool test_event_context(struct torture_context *test,
}
}
- talloc_free(fde);
- close(fd[1]);
+ talloc_free(fde_read);
+ talloc_free(fde_write);
+ talloc_free(fde_read_1);
+ talloc_free(fde_write_1);
while (alarm_count < fde_count+1) {
if (tevent_loop_once(ev_ctx) == -1) {
@@ -139,11 +158,11 @@ static bool test_event_context(struct torture_context *test,
talloc_free(se1);
#endif
- torture_assert_int_equal(test, alarm_count, 1+fde_count, "alarm count mismatch");
+ torture_assert_int_equal(test, alarm_count, 1+fde_count+fde_wcount, "alarm count mismatch");
#ifdef SA_SIGINFO
talloc_free(se3);
- torture_assert_int_equal(test, info_count, fde_count, "info count mismatch");
+ torture_assert_int_equal(test, info_count, fde_count+fde_wcount, "info count mismatch");
#endif
talloc_free(ev_ctx);
--
1.8.1
More information about the samba-technical
mailing list