[PATCH] Add winbind request profiling
Stefan Metzmacher
metze at samba.org
Wed Jul 11 20:08:54 UTC 2018
Am 11.07.2018 um 16:45 schrieb Ralph Böhme via samba-technical:
> On Tue, Jul 10, 2018 at 12:13:54AM +0200, Stefan Metzmacher via
> samba-technical wrote:
>> I guess I'll push it in the next days, most likely before 4.9.0rc1.
>
> as discussed: the two winbindd patches reviewed-by-me.
>
> *Really* nice stuff! :)
Ok, here's the patchset that passed a few private autobuilds.
Please recheck and push:-)
Thanks!
metze
-------------- next part --------------
From af4747aae19e9a76a23eb0830868c04298b28d6f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 18 Jun 2018 17:59:40 +0200
Subject: [PATCH 01/37] tevent: make use of tevent_common_wakeup() in the poll
and poll_mt backends
This simplifies the "poll_mt" logic a lot.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/tevent_poll.c | 100 ++++-----------------------------------
1 file changed, 9 insertions(+), 91 deletions(-)
diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c
index 09d85fa322ad..23b5779d7048 100644
--- a/lib/tevent/tevent_poll.c
+++ b/lib/tevent/tevent_poll.c
@@ -55,9 +55,9 @@ struct poll_event_context {
unsigned num_fds;
/*
- * Signal fd to wake the poll() thread
+ * use tevent_common_wakeup(ev) to wake the poll() thread
*/
- int signal_fd;
+ bool use_mt_mode;
};
static int poll_event_context_destructor(struct poll_event_context *poll_ev)
@@ -75,24 +75,6 @@ static int poll_event_context_destructor(struct poll_event_context *poll_ev)
fd->event_ctx = NULL;
DLIST_REMOVE(poll_ev->disabled, fd);
}
-
- if (poll_ev->signal_fd == -1) {
- /*
- * Non-threaded, no signal pipe
- */
- return 0;
- }
-
- close(poll_ev->signal_fd);
- poll_ev->signal_fd = -1;
-
- if (poll_ev->num_fds == 0) {
- return 0;
- }
- if (poll_ev->fds[0].fd != -1) {
- close(poll_ev->fds[0].fd);
- poll_ev->fds[0].fd = -1;
- }
return 0;
}
@@ -116,30 +98,14 @@ static int poll_event_context_init(struct tevent_context *ev)
return -1;
}
poll_ev->ev = ev;
- poll_ev->signal_fd = -1;
ev->additional_data = poll_ev;
talloc_set_destructor(poll_ev, poll_event_context_destructor);
return 0;
}
-static bool set_nonblock(int fd)
-{
- int val;
-
- val = fcntl(fd, F_GETFL, 0);
- if (val == -1) {
- return false;
- }
- val |= O_NONBLOCK;
-
- return (fcntl(fd, F_SETFL, val) != -1);
-}
-
static int poll_event_context_init_mt(struct tevent_context *ev)
{
struct poll_event_context *poll_ev;
- struct pollfd *pfd;
- int fds[2];
int ret;
ret = poll_event_context_init(ev);
@@ -150,67 +116,22 @@ static int poll_event_context_init_mt(struct tevent_context *ev)
poll_ev = talloc_get_type_abort(
ev->additional_data, struct poll_event_context);
- poll_ev->fds = talloc_zero(poll_ev, struct pollfd);
- if (poll_ev->fds == NULL) {
- return -1;
- }
-
- ret = pipe(fds);
- if (ret == -1) {
- return -1;
- }
-
- if (!set_nonblock(fds[0]) || !set_nonblock(fds[1])) {
- close(fds[0]);
- close(fds[1]);
- return -1;
+ ret = tevent_common_wakeup_init(ev);
+ if (ret != 0) {
+ return ret;
}
- poll_ev->signal_fd = fds[1];
-
- pfd = &poll_ev->fds[0];
- pfd->fd = fds[0];
- pfd->events = (POLLIN|POLLHUP);
-
- poll_ev->num_fds = 1;
-
- talloc_set_destructor(poll_ev, poll_event_context_destructor);
+ poll_ev->use_mt_mode = true;
return 0;
}
static void poll_event_wake_pollthread(struct poll_event_context *poll_ev)
{
- char c;
- ssize_t ret;
-
- if (poll_ev->signal_fd == -1) {
- return;
- }
- c = 0;
- do {
- ret = write(poll_ev->signal_fd, &c, sizeof(c));
- } while ((ret == -1) && (errno == EINTR));
-}
-
-static void poll_event_drain_signal_fd(struct poll_event_context *poll_ev)
-{
- char buf[16];
- ssize_t ret;
- int fd;
-
- if (poll_ev->signal_fd == -1) {
+ if (!poll_ev->use_mt_mode) {
return;
}
-
- if (poll_ev->num_fds < 1) {
- return;
- }
- fd = poll_ev->fds[0].fd;
-
- do {
- ret = read(fd, buf, sizeof(buf));
- } while (ret == sizeof(buf));
+ tevent_common_wakeup(poll_ev->ev);
}
/*
@@ -392,10 +313,9 @@ static bool poll_event_setup_fresh(struct tevent_context *ev,
unsigned num_fresh, num_fds;
if (poll_ev->deleted) {
- unsigned first_fd = (poll_ev->signal_fd != -1) ? 1 : 0;
unsigned i;
- for (i=first_fd; i < poll_ev->num_fds;) {
+ for (i=0; i < poll_ev->num_fds;) {
fde = poll_ev->fdes[i];
if (fde != NULL) {
i++;
@@ -510,8 +430,6 @@ static int poll_event_loop_poll(struct tevent_context *ev,
timeout += (tvalp->tv_usec + 999) / 1000;
}
- poll_event_drain_signal_fd(poll_ev);
-
if (!poll_event_setup_fresh(ev, poll_ev)) {
return -1;
}
--
2.17.1
From 77fb7311fa9e395fe195d6704f08c035fab13214 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 18 Jun 2018 19:49:52 +0200
Subject: [PATCH 02/37] tevent: rewrite/simplify tevent_poll and maintain
ev->fd_events correctly
The following patches will rely on having all valid fd events in
ev->fd_events, even if they are temporary disabled with
tevent_set_fd_flags(fde, 0);
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/tevent_internal.h | 2 +-
lib/tevent/tevent_poll.c | 296 +++++++++++++++++++----------------
lib/tevent/tevent_standard.c | 16 +-
3 files changed, 164 insertions(+), 150 deletions(-)
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index ec3955e70a49..692e8d0e0a2d 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -377,7 +377,7 @@ void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se);
bool tevent_standard_init(void);
bool tevent_poll_init(void);
-void tevent_poll_event_add_fd_internal(struct tevent_context *ev,
+bool tevent_poll_event_add_fd_internal(struct tevent_context *ev,
struct tevent_fd *fde);
bool tevent_poll_mt_init(void);
#ifdef HAVE_EPOLL
diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c
index 23b5779d7048..282f3cf3082c 100644
--- a/lib/tevent/tevent_poll.c
+++ b/lib/tevent/tevent_poll.c
@@ -33,15 +33,6 @@ struct poll_event_context {
/* a pointer back to the generic event_context */
struct tevent_context *ev;
- /*
- * A DLIST for fresh fde's added by poll_event_add_fd but not
- * picked up yet by poll_event_loop_once
- */
- struct tevent_fd *fresh;
- /*
- * A DLIST for disabled fde's.
- */
- struct tevent_fd *disabled;
/*
* one or more events were deleted or disabled
*/
@@ -49,10 +40,19 @@ struct poll_event_context {
/*
* These two arrays are maintained together.
+ *
+ * The following is always true:
+ * num_fds <= num_fdes
+ *
+ * new 'fresh' elements are added at the end
+ * of the 'fdes' array and picked up later
+ * to the 'fds' array in poll_event_sync_arrays()
+ * before the poll() syscall.
*/
struct pollfd *fds;
+ size_t num_fds;
struct tevent_fd **fdes;
- unsigned num_fds;
+ size_t num_fdes;
/*
* use tevent_common_wakeup(ev) to wake the poll() thread
@@ -60,24 +60,6 @@ struct poll_event_context {
bool use_mt_mode;
};
-static int poll_event_context_destructor(struct poll_event_context *poll_ev)
-{
- struct tevent_fd *fd, *fn;
-
- for (fd = poll_ev->fresh; fd; fd = fn) {
- fn = fd->next;
- fd->event_ctx = NULL;
- DLIST_REMOVE(poll_ev->fresh, fd);
- }
-
- for (fd = poll_ev->disabled; fd; fd = fn) {
- fn = fd->next;
- fd->event_ctx = NULL;
- DLIST_REMOVE(poll_ev->disabled, fd);
- }
- return 0;
-}
-
/*
create a poll_event_context structure.
*/
@@ -99,7 +81,6 @@ static int poll_event_context_init(struct tevent_context *ev)
}
poll_ev->ev = ev;
ev->additional_data = poll_ev;
- talloc_set_destructor(poll_ev, poll_event_context_destructor);
return 0;
}
@@ -151,10 +132,6 @@ static int poll_event_fd_destructor(struct tevent_fd *fde)
ev->additional_data, struct poll_event_context);
if (del_idx == UINT64_MAX) {
- struct tevent_fd **listp =
- (struct tevent_fd **)fde->additional_data;
-
- DLIST_REMOVE((*listp), fde);
goto done;
}
@@ -184,24 +161,50 @@ 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,
+_PRIVATE_ bool 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);
- struct tevent_fd **listp;
+ uint64_t fde_idx = UINT64_MAX;
+ size_t num_fdes;
- if (fde->flags != 0) {
- listp = &poll_ev->fresh;
- } else {
- listp = &poll_ev->disabled;
+ fde->additional_flags = UINT64_MAX;
+ talloc_set_destructor(fde, poll_event_fd_destructor);
+
+ if (fde->flags == 0) {
+ /*
+ * Nothing more to do...
+ */
+ return true;
}
- fde->additional_flags = UINT64_MAX;
- fde->additional_data = listp;
+ /*
+ * We need to add it to the end of the 'fdes' array.
+ */
+ num_fdes = poll_ev->num_fdes + 1;
+ if (num_fdes > talloc_array_length(poll_ev->fdes)) {
+ struct tevent_fd **tmp_fdes = NULL;
+ size_t array_length;
- DLIST_ADD((*listp), fde);
- talloc_set_destructor(fde, poll_event_fd_destructor);
+ array_length = (num_fdes + 15) & ~15; /* round up to 16 */
+
+ tmp_fdes = talloc_realloc(poll_ev,
+ poll_ev->fdes,
+ struct tevent_fd *,
+ array_length);
+ if (tmp_fdes == NULL) {
+ return false;
+ }
+ poll_ev->fdes = tmp_fdes;
+ }
+
+ fde_idx = poll_ev->num_fdes;
+ fde->additional_flags = fde_idx;
+ poll_ev->fdes[fde_idx] = fde;
+ poll_ev->num_fdes++;
+
+ return true;
}
/*
@@ -219,27 +222,29 @@ static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
struct poll_event_context *poll_ev = talloc_get_type_abort(
ev->additional_data, struct poll_event_context);
struct tevent_fd *fde;
+ bool ok;
if (fd < 0) {
return NULL;
}
- fde = talloc(mem_ctx ? mem_ctx : ev, struct tevent_fd);
+ fde = tevent_common_add_fd(ev,
+ mem_ctx,
+ fd,
+ flags,
+ handler,
+ private_data,
+ handler_name,
+ location);
if (fde == NULL) {
return NULL;
}
- fde->event_ctx = ev;
- fde->fd = fd;
- fde->flags = flags;
- fde->handler = handler;
- fde->close_fn = NULL;
- fde->private_data = private_data;
- fde->handler_name = handler_name;
- fde->location = location;
- fde->additional_flags = UINT64_MAX;
- fde->additional_data = NULL;
-
- tevent_poll_event_add_fd_internal(ev, fde);
+
+ ok = tevent_poll_event_add_fd_internal(ev, fde);
+ if (!ok) {
+ TALLOC_FREE(fde);
+ return NULL;
+ }
poll_event_wake_pollthread(poll_ev);
/*
@@ -262,19 +267,20 @@ static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
if (ev == NULL) {
return;
}
+
+ if (fde->flags == flags) {
+ return;
+ }
+
poll_ev = talloc_get_type_abort(
ev->additional_data, struct poll_event_context);
fde->flags = flags;
if (idx == UINT64_MAX) {
- struct tevent_fd **listp =
- (struct tevent_fd **)fde->additional_data;
-
/*
* We move it between the fresh and disabled lists.
*/
- DLIST_REMOVE((*listp), fde);
tevent_poll_event_add_fd_internal(ev, fde);
poll_event_wake_pollthread(poll_ev);
return;
@@ -287,8 +293,16 @@ static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
*/
poll_ev->fdes[idx] = NULL;
poll_ev->deleted = true;
- DLIST_REMOVE(ev->fd_events, fde);
- tevent_poll_event_add_fd_internal(ev, fde);
+ fde->additional_flags = UINT64_MAX;
+ poll_event_wake_pollthread(poll_ev);
+ return;
+ }
+
+ if (idx >= poll_ev->num_fds) {
+ /*
+ * Not yet added to the
+ * poll_ev->fds array.
+ */
poll_event_wake_pollthread(poll_ev);
return;
}
@@ -306,17 +320,18 @@ static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
poll_event_wake_pollthread(poll_ev);
}
-static bool poll_event_setup_fresh(struct tevent_context *ev,
+static bool poll_event_sync_arrays(struct tevent_context *ev,
struct poll_event_context *poll_ev)
{
- struct tevent_fd *fde, *next;
- unsigned num_fresh, num_fds;
+ size_t i;
+ size_t array_length;
if (poll_ev->deleted) {
- unsigned i;
for (i=0; i < poll_ev->num_fds;) {
- fde = poll_ev->fdes[i];
+ struct tevent_fd *fde = poll_ev->fdes[i];
+ size_t ci;
+
if (fde != NULL) {
i++;
continue;
@@ -327,61 +342,63 @@ static bool poll_event_setup_fresh(struct tevent_context *ev,
* from the arrays
*/
poll_ev->num_fds -= 1;
- if (poll_ev->num_fds == i) {
- break;
- }
- poll_ev->fds[i] = poll_ev->fds[poll_ev->num_fds];
- poll_ev->fdes[i] = poll_ev->fdes[poll_ev->num_fds];
- if (poll_ev->fdes[i] != NULL) {
- poll_ev->fdes[i]->additional_flags = i;
+ ci = poll_ev->num_fds;
+ if (ci > i) {
+ poll_ev->fds[i] = poll_ev->fds[ci];
+ poll_ev->fdes[i] = poll_ev->fdes[ci];
+ if (poll_ev->fdes[i] != NULL) {
+ poll_ev->fdes[i]->additional_flags = i;
+ }
}
+ poll_ev->fds[ci] = (struct pollfd) { .fd = -1 };
+ poll_ev->fdes[ci] = NULL;
}
poll_ev->deleted = false;
}
- if (poll_ev->fresh == NULL) {
+ if (poll_ev->num_fds == poll_ev->num_fdes) {
return true;
}
- num_fresh = 0;
- for (fde = poll_ev->fresh; fde; fde = fde->next) {
- num_fresh += 1;
- }
- num_fds = poll_ev->num_fds + num_fresh;
-
/*
- * We check the length of fdes here. It is the last one
- * enlarged, so if the realloc for poll_fd->fdes fails,
- * poll_fd->fds will have at least the size of poll_fd->fdes
+ * Recheck the size of both arrays and make sure
+ * poll_fd->fds array has at least the size of the
+ * in use poll_ev->fdes array.
*/
+ if (poll_ev->num_fdes > talloc_array_length(poll_ev->fds)) {
+ struct pollfd *tmp_fds = NULL;
- if (num_fds >= talloc_array_length(poll_ev->fdes)) {
- struct pollfd *tmp_fds;
- struct tevent_fd **tmp_fdes;
- unsigned array_length;
-
- array_length = (num_fds + 15) & ~15; /* round up to 16 */
+ /*
+ * Make sure both allocated the same length.
+ */
+ array_length = talloc_array_length(poll_ev->fdes);
- tmp_fds = talloc_realloc(
- poll_ev, poll_ev->fds, struct pollfd, array_length);
+ tmp_fds = talloc_realloc(poll_ev,
+ poll_ev->fds,
+ struct pollfd,
+ array_length);
if (tmp_fds == NULL) {
return false;
}
poll_ev->fds = tmp_fds;
-
- tmp_fdes = talloc_realloc(
- poll_ev, poll_ev->fdes, struct tevent_fd *,
- array_length);
- if (tmp_fdes == NULL) {
- return false;
- }
- poll_ev->fdes = tmp_fdes;
}
- for (fde = poll_ev->fresh; fde; fde = next) {
- struct pollfd *pfd;
+ /*
+ * Now setup the new elements.
+ */
+ for (i = poll_ev->num_fds; i < poll_ev->num_fdes; i++) {
+ struct tevent_fd *fde = poll_ev->fdes[i];
+ struct pollfd *pfd = &poll_ev->fds[poll_ev->num_fds];
+
+ if (fde == NULL) {
+ continue;
+ }
- pfd = &poll_ev->fds[poll_ev->num_fds];
+ if (i > poll_ev->num_fds) {
+ poll_ev->fdes[poll_ev->num_fds] = fde;
+ fde->additional_flags = poll_ev->num_fds;
+ poll_ev->fdes[i] = NULL;
+ }
pfd->fd = fde->fd;
pfd->events = 0;
@@ -394,15 +411,41 @@ static bool poll_event_setup_fresh(struct tevent_context *ev,
pfd->events |= (POLLOUT);
}
- fde->additional_flags = poll_ev->num_fds;
- poll_ev->fdes[poll_ev->num_fds] = fde;
+ poll_ev->num_fds += 1;
+ }
+ /* Both are in sync again */
+ poll_ev->num_fdes = poll_ev->num_fds;
- next = fde->next;
- DLIST_REMOVE(poll_ev->fresh, fde);
- DLIST_ADD(ev->fd_events, fde);
+ /*
+ * Check if we should shrink the arrays
+ * But keep at least 16 elements.
+ */
- poll_ev->num_fds += 1;
+ array_length = (poll_ev->num_fds + 15) & ~15; /* round up to 16 */
+ array_length = MAX(array_length, 16);
+ if (array_length < talloc_array_length(poll_ev->fdes)) {
+ struct tevent_fd **tmp_fdes = NULL;
+ struct pollfd *tmp_fds = NULL;
+
+ tmp_fdes = talloc_realloc(poll_ev,
+ poll_ev->fdes,
+ struct tevent_fd *,
+ array_length);
+ if (tmp_fdes == NULL) {
+ return false;
+ }
+ poll_ev->fdes = tmp_fdes;
+
+ tmp_fds = talloc_realloc(poll_ev,
+ poll_ev->fds,
+ struct pollfd,
+ array_length);
+ if (tmp_fds == NULL) {
+ return false;
+ }
+ poll_ev->fds = tmp_fds;
}
+
return true;
}
@@ -420,6 +463,7 @@ static int poll_event_loop_poll(struct tevent_context *ev,
struct tevent_fd *fde = NULL;
struct tevent_fd *next = NULL;
unsigned i;
+ bool ok;
if (ev->signal_events && tevent_common_check_signal(ev)) {
return 0;
@@ -430,7 +474,8 @@ static int poll_event_loop_poll(struct tevent_context *ev,
timeout += (tvalp->tv_usec + 999) / 1000;
}
- if (!poll_event_setup_fresh(ev, poll_ev)) {
+ ok = poll_event_sync_arrays(ev, poll_ev);
+ if (!ok) {
return -1;
}
@@ -580,33 +625,6 @@ static int poll_event_loop_once(struct tevent_context *ev,
return poll_event_loop_poll(ev, &tval);
}
-static int poll_event_loop_wait(struct tevent_context *ev,
- const char *location)
-{
- struct poll_event_context *poll_ev = talloc_get_type_abort(
- ev->additional_data, struct poll_event_context);
-
- /*
- * loop as long as we have events pending
- */
- while (tevent_common_have_events(ev) ||
- poll_ev->fresh ||
- poll_ev->disabled) {
- int ret;
- ret = _tevent_loop_once(ev, location);
- if (ret != 0) {
- tevent_debug(ev, TEVENT_DEBUG_FATAL,
- "_tevent_loop_once() failed: %d - %s\n",
- ret, strerror(errno));
- return ret;
- }
- }
-
- tevent_debug(ev, TEVENT_DEBUG_WARNING,
- "poll_event_loop_wait() out of events\n");
- return 0;
-}
-
static const struct tevent_ops poll_event_ops = {
.context_init = poll_event_context_init,
.add_fd = poll_event_add_fd,
@@ -617,7 +635,7 @@ static const struct tevent_ops poll_event_ops = {
.schedule_immediate = tevent_common_schedule_immediate,
.add_signal = tevent_common_add_signal,
.loop_once = poll_event_loop_once,
- .loop_wait = poll_event_loop_wait,
+ .loop_wait = tevent_common_loop_wait,
};
_PRIVATE_ bool tevent_poll_init(void)
@@ -635,7 +653,7 @@ static const struct tevent_ops poll_event_mt_ops = {
.schedule_immediate = poll_event_schedule_immediate,
.add_signal = tevent_common_add_signal,
.loop_once = poll_event_loop_once,
- .loop_wait = poll_event_loop_wait,
+ .loop_wait = tevent_common_loop_wait,
};
_PRIVATE_ bool tevent_poll_mt_init(void)
diff --git a/lib/tevent/tevent_standard.c b/lib/tevent/tevent_standard.c
index 30e9b91a8651..38720204e021 100644
--- a/lib/tevent/tevent_standard.c
+++ b/lib/tevent/tevent_standard.c
@@ -63,7 +63,6 @@ static bool std_fallback_to_poll(struct tevent_context *ev, bool replay)
struct std_event_glue);
int ret;
struct tevent_fd *fde;
- struct tevent_fd *fde_next;
glue->fallback_replay = replay;
@@ -86,17 +85,14 @@ static bool std_fallback_to_poll(struct tevent_context *ev, bool replay)
* 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);
+ for (fde = ev->fd_events; fde; fde = fde->next) {
+ bool ok;
/* Re-add this event as a poll backend event. */
- tevent_poll_event_add_fd_internal(ev, fde);
+ ok = tevent_poll_event_add_fd_internal(ev, fde);
+ if (!ok) {
+ return false;
+ }
}
return true;
--
2.17.1
From f034cd38ef21af26cc2769df92c228cf3259103a Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 23 Sep 2015 04:27:53 +0200
Subject: [PATCH 03/37] tevent.h: improve tevent_req documentation
Document tevent_req naming conventions.
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
lib/tevent/tevent.h | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
index 3ccac6a3600c..0e2e806ee5c4 100644
--- a/lib/tevent/tevent.h
+++ b/lib/tevent/tevent.h
@@ -697,6 +697,22 @@ void tevent_get_trace_callback(struct tevent_context *ev,
* the tevent_req structure can be talloc_free'ed. After it has
* finished, it should talloc_free'ed by the API user.
*
+ * tevent_req variable naming conventions:
+ *
+ * The name of the variable pointing to the tevent_req structure
+ * returned by a _send() function SHOULD be named differently between
+ * implementation and caller.
+ *
+ * From the point of view of the implementation (of the _send() and
+ * _recv() functions) the variable returned by tevent_req_create() is
+ * always called @em req.
+ *
+ * While the caller of the _send() function should use @em subreq to
+ * hold the result.
+ *
+ * @see tevent_req_create()
+ * @see tevent_req_fn()
+ *
* @{
*/
@@ -748,9 +764,9 @@ struct tevent_req;
/**
* @brief A tevent request callback function.
*
- * @param[in] req The tevent async request which executed this callback.
+ * @param[in] subreq The tevent async request which executed this callback.
*/
-typedef void (*tevent_req_fn)(struct tevent_req *req);
+typedef void (*tevent_req_fn)(struct tevent_req *subreq);
/**
* @brief Set an async request callback.
@@ -799,8 +815,6 @@ void *_tevent_req_callback_data(struct tevent_req *req);
*
* @param[in] req The structure to get the callback data from.
*
- * @param[in] req The structure to get the data from.
- *
* @return The private data or NULL if not set.
*/
void *tevent_req_callback_data_void(struct tevent_req *req);
--
2.17.1
From a879f5ed30106ba4b6852cbd09e928081e4d79c0 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 23 Oct 2014 06:54:10 +0200
Subject: [PATCH 04/37] tevent/testsuite: return after torture_fail()
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/testsuite.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index 63abbf2dc1a6..08aa7588acee 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -191,8 +191,9 @@ static bool test_event_context(struct torture_context *test,
while (!finished) {
errno = 0;
if (tevent_loop_once(ev_ctx) == -1) {
- talloc_free(ev_ctx);
+ TALLOC_FREE(ev_ctx);
torture_fail(test, talloc_asprintf(test, "Failed event loop %s\n", strerror(errno)));
+ return false;
}
}
--
2.17.1
From 139712daacb36af8f9df35c7425f40d7431d968e Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 22 Mar 2018 16:51:01 +0100
Subject: [PATCH 05/37] tevent: allow tevent_abort() to cope with ev == NULL
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/tevent.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index a2d2003cbf43..3d32fd7e12de 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -577,8 +577,10 @@ void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
static void tevent_abort(struct tevent_context *ev, const char *reason)
{
- tevent_debug(ev, TEVENT_DEBUG_FATAL,
- "abort: %s\n", reason);
+ if (ev != NULL) {
+ tevent_debug(ev, TEVENT_DEBUG_FATAL,
+ "abort: %s\n", reason);
+ }
if (!tevent_abort_fn) {
abort();
--
2.17.1
From f3433e1d71572eca51a5bad8f5ad018730f1c8f9 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 Jul 2014 15:10:00 +0200
Subject: [PATCH 06/37] tevent: make tevent_abort() available for backends
We'll undo the 0.9.36 ABI change on the 0.9.37 release
at the end of this patchset.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/ABI/tevent-0.9.36.sigs | 1 +
lib/tevent/tevent.c | 4 +---
lib/tevent/tevent_internal.h | 2 ++
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/lib/tevent/ABI/tevent-0.9.36.sigs b/lib/tevent/ABI/tevent-0.9.36.sigs
index 8a579c8ee7d0..07d6e29fddd4 100644
--- a/lib/tevent/ABI/tevent-0.9.36.sigs
+++ b/lib/tevent/ABI/tevent-0.9.36.sigs
@@ -17,6 +17,7 @@ _tevent_req_notify_callback: void (struct tevent_req *, const char *)
_tevent_req_oom: void (struct tevent_req *, const char *)
_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
tevent_backend_list: const char **(TALLOC_CTX *)
tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index 3d32fd7e12de..222a3a1a3ddd 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -70,8 +70,6 @@
#include <sys/eventfd.h>
#endif
-static void tevent_abort(struct tevent_context *ev, const char *reason);
-
struct tevent_ops_list {
struct tevent_ops_list *next, *prev;
const char *name;
@@ -575,7 +573,7 @@ void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
tevent_abort_fn = abort_fn;
}
-static void tevent_abort(struct tevent_context *ev, const char *reason)
+void tevent_abort(struct tevent_context *ev, const char *reason)
{
if (ev != NULL) {
tevent_debug(ev, TEVENT_DEBUG_FATAL,
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index 692e8d0e0a2d..b13efedb5d92 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -246,6 +246,8 @@ struct tevent_debug_ops {
void tevent_debug(struct tevent_context *ev, enum tevent_debug_level level,
const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+void tevent_abort(struct tevent_context *ev, const char *reason);
+
struct tevent_context {
/* the specific events implementation */
const struct tevent_ops *ops;
--
2.17.1
From ffcaddd4a1b09721ad97dc680969db537e61c661 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 23 Oct 2014 07:15:14 +0200
Subject: [PATCH 07/37] tevent: use struct initializers for tevent_fd
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/tevent_fd.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/lib/tevent/tevent_fd.c b/lib/tevent/tevent_fd.c
index 455961b67c84..f33ae841b396 100644
--- a/lib/tevent/tevent_fd.c
+++ b/lib/tevent/tevent_fd.c
@@ -60,16 +60,15 @@ struct tevent_fd *tevent_common_add_fd(struct tevent_context *ev, TALLOC_CTX *me
fde = talloc(mem_ctx?mem_ctx:ev, struct tevent_fd);
if (!fde) return NULL;
- fde->event_ctx = ev;
- fde->fd = fd;
- fde->flags = flags;
- fde->handler = handler;
- fde->close_fn = NULL;
- fde->private_data = private_data;
- fde->handler_name = handler_name;
- fde->location = location;
- fde->additional_flags = 0;
- fde->additional_data = NULL;
+ *fde = (struct tevent_fd) {
+ .event_ctx = ev,
+ .fd = fd,
+ .flags = flags,
+ .handler = handler,
+ .private_data = private_data,
+ .handler_name = handler_name,
+ .location = location,
+ };
DLIST_ADD(ev->fd_events, fde);
--
2.17.1
From c06b5bc1e23efa1879544de7d8c88d51771650e2 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 23 Oct 2014 07:15:14 +0200
Subject: [PATCH 08/37] tevent: use struct initializers for tevent_timer
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/tevent_timed.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/lib/tevent/tevent_timed.c b/lib/tevent/tevent_timed.c
index 92f3ed17b26e..ae1eb98d8b2a 100644
--- a/lib/tevent/tevent_timed.c
+++ b/lib/tevent/tevent_timed.c
@@ -224,13 +224,14 @@ static struct tevent_timer *tevent_common_add_timer_internal(
te = talloc(mem_ctx?mem_ctx:ev, struct tevent_timer);
if (te == NULL) return NULL;
- te->event_ctx = ev;
- te->next_event = next_event;
- te->handler = handler;
- te->private_data = private_data;
- te->handler_name = handler_name;
- te->location = location;
- te->additional_data = NULL;
+ *te = (struct tevent_timer) {
+ .event_ctx = ev,
+ .next_event = next_event,
+ .handler = handler,
+ .private_data = private_data,
+ .handler_name = handler_name,
+ .location = location,
+ };
if (ev->timer_events == NULL) {
ev->last_zero_timer = NULL;
--
2.17.1
From 518eeab82573b0f4f3b56010dafed8bdcfcbc33f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 23 Oct 2014 07:15:14 +0200
Subject: [PATCH 09/37] tevent: use struct initializers for tevent_signal
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/tevent_signal.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index c85e1c528c4e..1283aab48211 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -257,22 +257,23 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
se = talloc(mem_ctx?mem_ctx:ev, struct tevent_signal);
if (se == NULL) return NULL;
- se->event_ctx = ev;
- se->signum = signum;
- se->sa_flags = sa_flags;
- se->handler = handler;
- se->private_data = private_data;
- se->handler_name = handler_name;
- se->location = location;
- se->additional_data = NULL;
-
sl = talloc(se, struct tevent_common_signal_list);
if (!sl) {
talloc_free(se);
return NULL;
}
sl->se = se;
- se->additional_data = sl;
+
+ *se = (struct tevent_signal) {
+ .event_ctx = ev,
+ .signum = signum,
+ .sa_flags = sa_flags,
+ .handler = handler,
+ .private_data = private_data,
+ .handler_name = handler_name,
+ .location = location,
+ .additional_data= sl,
+ };
/* Ensure, no matter the destruction order, that we always have a handle on the global sig_state */
if (!talloc_reference(se, sig_state)) {
--
2.17.1
From 9a8dc4d5f2232b4904afac30f75fae2571684942 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 23 Oct 2014 07:15:14 +0200
Subject: [PATCH 10/37] tevent: use struct initializers for tevent_immediate
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/tevent_immediate.c | 30 ++++++++++++++++--------------
lib/tevent/tevent_threads.c | 16 +++++++++-------
2 files changed, 25 insertions(+), 21 deletions(-)
diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c
index 9ff532234306..7b4c3e843ded 100644
--- a/lib/tevent/tevent_immediate.c
+++ b/lib/tevent/tevent_immediate.c
@@ -30,6 +30,8 @@
static void tevent_common_immediate_cancel(struct tevent_immediate *im)
{
+ const char *create_location = im->create_location;
+
if (!im->event_ctx) {
return;
}
@@ -44,13 +46,10 @@ static void tevent_common_immediate_cancel(struct tevent_immediate *im)
}
DLIST_REMOVE(im->event_ctx->immediate_events, im);
- im->event_ctx = NULL;
- im->handler = NULL;
- im->private_data = NULL;
- im->handler_name = NULL;
- im->schedule_location = NULL;
- im->cancel_fn = NULL;
- im->additional_data = NULL;
+
+ *im = (struct tevent_immediate) {
+ .create_location = create_location,
+ };
talloc_set_destructor(im, NULL);
}
@@ -74,19 +73,22 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
const char *handler_name,
const char *location)
{
+ const char *create_location = im->create_location;
+
tevent_common_immediate_cancel(im);
if (!handler) {
return;
}
- im->event_ctx = ev;
- im->handler = handler;
- im->private_data = private_data;
- im->handler_name = handler_name;
- im->schedule_location = location;
- im->cancel_fn = NULL;
- im->additional_data = NULL;
+ *im = (struct tevent_immediate) {
+ .event_ctx = ev,
+ .handler = handler,
+ .private_data = private_data,
+ .handler_name = handler_name,
+ .create_location = create_location,
+ .schedule_location = location,
+ };
DLIST_ADD_END(ev->immediate_events, im);
talloc_set_destructor(im, tevent_common_immediate_destructor);
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index 2c6e66b09049..728f8416d452 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -449,6 +449,7 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
const char *location)
{
#ifdef HAVE_PTHREAD
+ const char *create_location = im->create_location;
struct tevent_context *ev;
int ret, wakeup_fd;
@@ -474,13 +475,14 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
abort();
}
- im->event_ctx = ev;
- im->handler = handler;
- im->private_data = private_data;
- im->handler_name = handler_name;
- im->schedule_location = location;
- im->cancel_fn = NULL;
- im->additional_data = NULL;
+ *im = (struct tevent_immediate) {
+ .event_ctx = ev,
+ .handler = handler,
+ .private_data = private_data,
+ .handler_name = handler_name,
+ .create_location = create_location,
+ .schedule_location = location,
+ };
ret = pthread_mutex_lock(&ev->scheduled_mutex);
if (ret != 0) {
--
2.17.1
From 5dde433b40e35d1f7c14829e73578c28128e1853 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 23 Mar 2018 10:25:27 +0100
Subject: [PATCH 11/37] tevent: use _tevent_schedule_immediate() to move events
from a thread to the main_ev
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/tevent_immediate.c | 8 +++++---
lib/tevent/tevent_threads.c | 14 +++++++++++++-
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c
index 7b4c3e843ded..c640a565b082 100644
--- a/lib/tevent/tevent_immediate.c
+++ b/lib/tevent/tevent_immediate.c
@@ -36,9 +36,11 @@ static void tevent_common_immediate_cancel(struct tevent_immediate *im)
return;
}
- tevent_debug(im->event_ctx, TEVENT_DEBUG_TRACE,
- "Cancel immediate event %p \"%s\"\n",
- im, im->handler_name);
+ if (im->handler_name != NULL) {
+ tevent_debug(im->event_ctx, TEVENT_DEBUG_TRACE,
+ "Cancel immediate event %p \"%s\"\n",
+ im, im->handler_name);
+ }
/* let the backend free im->additional_data */
if (im->cancel_fn) {
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index 728f8416d452..3f91ab8bc2ab 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -532,8 +532,20 @@ void tevent_common_threaded_activate_immediate(struct tevent_context *ev)
while (ev->scheduled_immediates != NULL) {
struct tevent_immediate *im = ev->scheduled_immediates;
+ struct tevent_immediate copy = *im;
+
DLIST_REMOVE(ev->scheduled_immediates, im);
- DLIST_ADD_END(ev->immediate_events, im);
+
+ tevent_debug(ev, TEVENT_DEBUG_TRACE,
+ "Schedule immediate event \"%s\": %p from thread into main\n",
+ im->handler_name, im);
+ im->handler_name = NULL;
+ _tevent_schedule_immediate(im,
+ ev,
+ copy.handler,
+ copy.private_data,
+ copy.handler_name,
+ copy.schedule_location);
}
ret = pthread_mutex_unlock(&ev->scheduled_mutex);
--
2.17.1
From 2d900369275788bf59b6cdbdcc95468cbf67059d Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 23 Mar 2018 10:32:15 +0100
Subject: [PATCH 12/37] tevent: add
tevent_threaded_schedule_immediate_destructor that just aborts
This will be active while the event is part of the ev->scheduled_immediates
list.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/tevent_threads.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index 3f91ab8bc2ab..efdac9856dd1 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -441,6 +441,14 @@ struct tevent_threaded_context *tevent_threaded_context_create(
#endif
}
+static int tevent_threaded_schedule_immediate_destructor(struct tevent_immediate *im)
+{
+ if (im->event_ctx != NULL) {
+ abort();
+ }
+ return 0;
+}
+
void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
struct tevent_immediate *im,
tevent_immediate_handler_t handler,
@@ -484,6 +492,14 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
.schedule_location = location,
};
+ /*
+ * Make sure the event won't be destroyed while
+ * it's part of the ev->scheduled_immediates list.
+ * _tevent_schedule_immediate() will reset the destructor
+ * in tevent_common_threaded_activate_immediate().
+ */
+ talloc_set_destructor(im, tevent_threaded_schedule_immediate_destructor);
+
ret = pthread_mutex_lock(&ev->scheduled_mutex);
if (ret != 0) {
abort();
--
2.17.1
From 9f8dd4db09f525190830af7a7c6e041c3be1be5e Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 17 Apr 2018 16:33:47 +0200
Subject: [PATCH 13/37] tevent: add tevent_common_check_double_free() helper
function
This will be used to generically support TALLOC_FREE() on
event which are currently running.
It aborts on every explicit talloc_free(), but ignores implicit
cleanup when the talloc parent is about to go.
We'll undo the 0.9.36 ABI change on the 0.9.37 release
at the end of this patchset.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/ABI/tevent-0.9.36.sigs | 1 +
lib/tevent/tevent.c | 19 +++++++++++++++++++
lib/tevent/tevent_internal.h | 2 ++
3 files changed, 22 insertions(+)
diff --git a/lib/tevent/ABI/tevent-0.9.36.sigs b/lib/tevent/ABI/tevent-0.9.36.sigs
index 07d6e29fddd4..8a9d1a6ba105 100644
--- a/lib/tevent/ABI/tevent-0.9.36.sigs
+++ b/lib/tevent/ABI/tevent-0.9.36.sigs
@@ -24,6 +24,7 @@ tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *,
tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
tevent_common_check_signal: int (struct tevent_context *)
tevent_common_context_destructor: int (struct tevent_context *)
tevent_common_fd_destructor: int (struct tevent_fd *)
diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index 222a3a1a3ddd..de0436df3736 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -429,6 +429,25 @@ static int tevent_common_context_constructor(struct tevent_context *ev)
return 0;
}
+void tevent_common_check_double_free(TALLOC_CTX *ptr, const char *reason)
+{
+ void *parent_ptr = talloc_parent(ptr);
+ size_t parent_blocks = talloc_total_blocks(parent_ptr);
+
+ if (parent_ptr != NULL && parent_blocks == 0) {
+ /*
+ * This is an implicit talloc free, as we still have a parent
+ * but it's already being destroyed. Note that
+ * talloc_total_blocks(ptr) also just returns 0 if a
+ * talloc_free(ptr) is still in progress of freeing all
+ * children.
+ */
+ return;
+ }
+
+ tevent_abort(NULL, reason);
+}
+
/*
create a event_context structure for a specific implemementation.
This must be the first events call, and all subsequent calls pass
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index b13efedb5d92..7e15a59d3fb4 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -248,6 +248,8 @@ void tevent_debug(struct tevent_context *ev, enum tevent_debug_level level,
void tevent_abort(struct tevent_context *ev, const char *reason);
+void tevent_common_check_double_free(TALLOC_CTX *ptr, const char *reason);
+
struct tevent_context {
/* the specific events implementation */
const struct tevent_ops *ops;
--
2.17.1
From 04e4e6ceef00bca9022af4bd602536bcafabb7d7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 Jul 2014 12:02:45 +0200
Subject: [PATCH 14/37] tevent: simplify
tevent_cleanup_pending_signal_handlers()
Calling tevent_signal_destructor() does the same as se->event_ctx is already
NULL.
This also makes sure we correctly cleanup the SA_SIGINFO array.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/tevent_signal.c | 16 +++-------------
1 file changed, 3 insertions(+), 13 deletions(-)
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index 1283aab48211..6bb69d77d7a5 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -194,6 +194,7 @@ static int tevent_signal_destructor(struct tevent_signal *se)
DLIST_REMOVE(ev->signal_events, se);
}
+ se->additional_data = NULL;
talloc_free(sl);
if (sig_state->sig_handlers[se->signum] == NULL) {
@@ -464,18 +465,7 @@ int tevent_common_check_signal(struct tevent_context *ev)
void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se)
{
- struct tevent_common_signal_list *sl =
- talloc_get_type_abort(se->additional_data,
- struct tevent_common_signal_list);
-
- tevent_common_signal_list_destructor(sl);
-
- if (sig_state->sig_handlers[se->signum] == NULL) {
- if (sig_state->oldact[se->signum]) {
- sigaction(se->signum, sig_state->oldact[se->signum], NULL);
- talloc_free(sig_state->oldact[se->signum]);
- sig_state->oldact[se->signum] = NULL;
- }
- }
+ tevent_signal_destructor(se);
+ talloc_set_destructor(se, NULL);
return;
}
--
2.17.1
From 508ce07113f908210055c606f2327efc27818833 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 27 Mar 2018 14:30:20 +0200
Subject: [PATCH 15/37] tevent: use talloc_zero() in tevent_signal.c
This might not be strictly required, but it might
avoid problems in future...
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/tevent_signal.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index 6bb69d77d7a5..73b8de798f69 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -255,10 +255,10 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
}
}
- se = talloc(mem_ctx?mem_ctx:ev, struct tevent_signal);
+ se = talloc_zero(mem_ctx?mem_ctx:ev, struct tevent_signal);
if (se == NULL) return NULL;
- sl = talloc(se, struct tevent_common_signal_list);
+ sl = talloc_zero(se, struct tevent_common_signal_list);
if (!sl) {
talloc_free(se);
return NULL;
@@ -303,7 +303,7 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
}
}
#endif
- sig_state->oldact[signum] = talloc(sig_state, struct sigaction);
+ sig_state->oldact[signum] = talloc_zero(sig_state, struct sigaction);
if (sig_state->oldact[signum] == NULL) {
talloc_free(se);
return NULL;
--
2.17.1
From 5a3682769847276394e6f41999a222dfe16e8321 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 17 Apr 2018 16:43:54 +0200
Subject: [PATCH 16/37] tevent: simplify tevent_signal_destructor()
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/tevent_signal.c | 19 +++++--------------
1 file changed, 5 insertions(+), 14 deletions(-)
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index 73b8de798f69..ef2302433168 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -184,31 +184,22 @@ static int tevent_common_signal_list_destructor(struct tevent_common_signal_list
*/
static int tevent_signal_destructor(struct tevent_signal *se)
{
- struct tevent_common_signal_list *sl =
- talloc_get_type_abort(se->additional_data,
- struct tevent_common_signal_list);
+ TALLOC_FREE(se->additional_data);
- if (se->event_ctx) {
- struct tevent_context *ev = se->event_ctx;
-
- DLIST_REMOVE(ev->signal_events, se);
+ if (se->event_ctx != NULL) {
+ DLIST_REMOVE(se->event_ctx->signal_events, se);
}
- se->additional_data = NULL;
- talloc_free(sl);
-
if (sig_state->sig_handlers[se->signum] == NULL) {
/* restore old handler, if any */
if (sig_state->oldact[se->signum]) {
sigaction(se->signum, sig_state->oldact[se->signum], NULL);
- talloc_free(sig_state->oldact[se->signum]);
- sig_state->oldact[se->signum] = NULL;
+ TALLOC_FREE(sig_state->oldact[se->signum]);
}
#ifdef SA_SIGINFO
if (se->sa_flags & SA_SIGINFO) {
if (sig_state->sig_info[se->signum]) {
- talloc_free(sig_state->sig_info[se->signum]);
- sig_state->sig_info[se->signum] = NULL;
+ TALLOC_FREE(sig_state->sig_info[se->signum]);
}
}
#endif
--
2.17.1
From a0b3c4672bd0100ba091de01e607ac5a6481f6b1 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 Jul 2014 13:01:01 +0200
Subject: [PATCH 17/37] tevent: split out tevent_common_invoke_signal_handler()
As side effect this avoids tricks with tevent_se_exists_destructor() to
figure out if the event handler removed itself.
We'll undo the 0.9.36 ABI change on the 0.9.37 release
at the end of this patchset.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/ABI/tevent-0.9.36.sigs | 1 +
lib/tevent/tevent_internal.h | 5 ++
lib/tevent/tevent_signal.c | 101 +++++++++++++++++++-----------
3 files changed, 69 insertions(+), 38 deletions(-)
diff --git a/lib/tevent/ABI/tevent-0.9.36.sigs b/lib/tevent/ABI/tevent-0.9.36.sigs
index 8a9d1a6ba105..230f6b9f26b1 100644
--- a/lib/tevent/ABI/tevent-0.9.36.sigs
+++ b/lib/tevent/ABI/tevent-0.9.36.sigs
@@ -32,6 +32,7 @@ tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
tevent_common_loop_immediate: bool (struct tevent_context *)
tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
tevent_common_loop_wait: int (struct tevent_context *, const char *)
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index 7e15a59d3fb4..f36cd219f688 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -216,6 +216,8 @@ struct tevent_immediate {
struct tevent_signal {
struct tevent_signal *prev, *next;
struct tevent_context *event_ctx;
+ bool busy;
+ bool destroyed;
int signum;
int sa_flags;
tevent_signal_handler_t handler;
@@ -378,6 +380,9 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
const char *location);
int tevent_common_check_signal(struct tevent_context *ev);
void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se);
+int tevent_common_invoke_signal_handler(struct tevent_signal *se,
+ int signum, int count, void *siginfo,
+ bool *removed);
bool tevent_standard_init(void);
bool tevent_poll_init(void);
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index ef2302433168..a787f97b9649 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -184,6 +184,12 @@ static int tevent_common_signal_list_destructor(struct tevent_common_signal_list
*/
static int tevent_signal_destructor(struct tevent_signal *se)
{
+ if (se->destroyed) {
+ tevent_common_check_double_free(se, "tevent_signal double free");
+ goto done;
+ }
+ se->destroyed = true;
+
TALLOC_FREE(se->additional_data);
if (se->event_ctx != NULL) {
@@ -205,6 +211,12 @@ static int tevent_signal_destructor(struct tevent_signal *se)
#endif
}
+ se->event_ctx = NULL;
+done:
+ if (se->busy) {
+ return -1;
+ }
+
return 0;
}
@@ -322,13 +334,42 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
return se;
}
-struct tevent_se_exists {
- struct tevent_se_exists **myself;
-};
-
-static int tevent_se_exists_destructor(struct tevent_se_exists *s)
+int tevent_common_invoke_signal_handler(struct tevent_signal *se,
+ int signum, int count, void *siginfo,
+ bool *removed)
{
- *s->myself = NULL;
+ bool remove = false;
+
+ if (removed != NULL) {
+ *removed = false;
+ }
+
+ if (se->event_ctx == NULL) {
+ return 0;
+ }
+
+ se->busy = true;
+ se->handler(se->event_ctx, se, signum, count, siginfo, se->private_data);
+ se->busy = false;
+
+#ifdef SA_RESETHAND
+ if (se->sa_flags & SA_RESETHAND) {
+ remove = true;
+ }
+#endif
+
+ if (se->destroyed) {
+ talloc_set_destructor(se, NULL);
+ remove = true;
+ }
+
+ if (remove) {
+ TALLOC_FREE(se);
+ if (removed != NULL) {
+ *removed = true;
+ }
+ }
+
return 0;
}
@@ -348,6 +389,7 @@ int tevent_common_check_signal(struct tevent_context *ev)
struct tevent_common_signal_list *sl, *next;
struct tevent_sigcounter counter = sig_state->signal_count[i];
uint32_t count = tevent_sig_count(counter);
+ int ret;
#ifdef SA_SIGINFO
/* Ensure we null out any stored siginfo_t entries
* after processing for debugging purposes. */
@@ -359,25 +401,9 @@ int tevent_common_check_signal(struct tevent_context *ev)
}
for (sl=sig_state->sig_handlers[i];sl;sl=next) {
struct tevent_signal *se = sl->se;
- struct tevent_se_exists *exists;
next = sl->next;
- /*
- * We have to be careful to not touch "se"
- * after it was deleted in its handler. Thus
- * we allocate a child whose destructor will
- * tell by nulling out itself that its parent
- * is gone.
- */
- exists = talloc(se, struct tevent_se_exists);
- if (exists == NULL) {
- continue;
- }
- exists->myself = &exists;
- talloc_set_destructor(
- exists, tevent_se_exists_destructor);
-
#ifdef SA_SIGINFO
if (se->sa_flags & SA_SIGINFO) {
uint32_t j;
@@ -391,29 +417,28 @@ int tevent_common_check_signal(struct tevent_context *ev)
* signals in the ringbuffer. */
uint32_t ofs = (counter.seen + j)
% TEVENT_SA_INFO_QUEUE_COUNT;
- se->handler(ev, se, i, 1,
- (void*)&sig_state->sig_info[i][ofs],
- se->private_data);
- if (!exists) {
+ bool removed = false;
+
+ ret = tevent_common_invoke_signal_handler(
+ se, i, 1,
+ (void*)&sig_state->sig_info[i][ofs],
+ &removed);
+ if (ret != 0) {
+ tevent_abort(ev, "tevent_common_invoke_signal_handler() failed");
+ }
+ if (removed) {
break;
}
}
-#ifdef SA_RESETHAND
- if (exists && (se->sa_flags & SA_RESETHAND)) {
- talloc_free(se);
- }
-#endif
- talloc_free(exists);
continue;
}
#endif
- se->handler(ev, se, i, count, NULL, se->private_data);
-#ifdef SA_RESETHAND
- if (exists && (se->sa_flags & SA_RESETHAND)) {
- talloc_free(se);
+
+ ret = tevent_common_invoke_signal_handler(se, i, count,
+ NULL, NULL);
+ if (ret != 0) {
+ tevent_abort(ev, "tevent_common_invoke_signal_handler() failed");
}
-#endif
- talloc_free(exists);
}
#ifdef SA_SIGINFO
--
2.17.1
From 02332c38abb0589e937ec1d02c928394f5146b4e Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 Jul 2014 13:08:42 +0200
Subject: [PATCH 18/37] tevent: split out tevent_common_invoke_timer_handler()
As side effect this avoids tricks with an extra
tevent_common_timed_deny_destructor().
We'll undo the 0.9.36 ABI change on the 0.9.37 release
at the end of this patchset.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/ABI/tevent-0.9.36.sigs | 1 +
lib/tevent/tevent_internal.h | 5 ++
lib/tevent/tevent_timed.c | 110 +++++++++++++++++++-----------
3 files changed, 78 insertions(+), 38 deletions(-)
diff --git a/lib/tevent/ABI/tevent-0.9.36.sigs b/lib/tevent/ABI/tevent-0.9.36.sigs
index 230f6b9f26b1..bb89cc72d1e1 100644
--- a/lib/tevent/ABI/tevent-0.9.36.sigs
+++ b/lib/tevent/ABI/tevent-0.9.36.sigs
@@ -33,6 +33,7 @@ tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
tevent_common_have_events: bool (struct tevent_context *)
tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
tevent_common_loop_immediate: bool (struct tevent_context *)
tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
tevent_common_loop_wait: int (struct tevent_context *, const char *)
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index f36cd219f688..8126414d6836 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -187,6 +187,8 @@ struct tevent_fd {
struct tevent_timer {
struct tevent_timer *prev, *next;
struct tevent_context *event_ctx;
+ bool busy;
+ bool destroyed;
struct timeval next_event;
tevent_timer_handler_t handler;
/* this is private for the specific handler */
@@ -355,6 +357,9 @@ struct tevent_timer *tevent_common_add_timer_v2(struct tevent_context *ev,
const char *handler_name,
const char *location);
struct timeval tevent_common_loop_timer_delay(struct tevent_context *);
+int tevent_common_invoke_timer_handler(struct tevent_timer *te,
+ struct timeval current_time,
+ bool *removed);
void tevent_common_schedule_immediate(struct tevent_immediate *im,
struct tevent_context *ev,
diff --git a/lib/tevent/tevent_timed.c b/lib/tevent/tevent_timed.c
index ae1eb98d8b2a..cb948d4ba29e 100644
--- a/lib/tevent/tevent_timed.c
+++ b/lib/tevent/tevent_timed.c
@@ -133,6 +133,12 @@ struct timeval tevent_timeval_current_ofs(uint32_t secs, uint32_t usecs)
*/
static int tevent_common_timed_destructor(struct tevent_timer *te)
{
+ if (te->destroyed) {
+ tevent_common_check_double_free(te, "tevent_timer double free");
+ goto done;
+ }
+ te->destroyed = true;
+
if (te->event_ctx == NULL) {
return 0;
}
@@ -146,12 +152,13 @@ static int tevent_common_timed_destructor(struct tevent_timer *te)
}
DLIST_REMOVE(te->event_ctx->timer_events, te);
- return 0;
-}
+ te->event_ctx = NULL;
+done:
+ if (te->busy) {
+ return -1;
+ }
-static int tevent_common_timed_deny_destructor(struct tevent_timer *te)
-{
- return -1;
+ return 0;
}
static void tevent_common_insert_timer(struct tevent_context *ev,
@@ -160,6 +167,11 @@ static void tevent_common_insert_timer(struct tevent_context *ev,
{
struct tevent_timer *prev_te = NULL;
+ if (te->destroyed) {
+ tevent_abort(ev, "tevent_timer use after free");
+ return;
+ }
+
/* keep the list ordered */
if (optimize_zero && tevent_timeval_is_zero(&te->next_event)) {
/*
@@ -303,6 +315,57 @@ void tevent_update_timer(struct tevent_timer *te, struct timeval next_event)
tevent_common_insert_timer(ev, te, false);
}
+int tevent_common_invoke_timer_handler(struct tevent_timer *te,
+ struct timeval current_time,
+ bool *removed)
+{
+ if (removed != NULL) {
+ *removed = false;
+ }
+
+ if (te->event_ctx == NULL) {
+ return 0;
+ }
+
+ /*
+ * We need to remove the timer from the list before calling the
+ * handler because in a semi-async inner event loop called from the
+ * handler we don't want to come across this event again -- vl
+ */
+ if (te->event_ctx->last_zero_timer == te) {
+ te->event_ctx->last_zero_timer = DLIST_PREV(te);
+ }
+ DLIST_REMOVE(te->event_ctx->timer_events, te);
+
+ tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
+ "Running timer event %p \"%s\"\n",
+ te, te->handler_name);
+
+ /*
+ * If the timed event was registered for a zero current_time,
+ * then we pass a zero timeval here too! To avoid the
+ * overhead of gettimeofday() calls.
+ *
+ * otherwise we pass the current time
+ */
+ te->busy = true;
+ te->handler(te->event_ctx, te, current_time, te->private_data);
+ te->busy = false;
+
+ tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
+ "Ending timer event %p \"%s\"\n",
+ te, te->handler_name);
+
+ te->event_ctx = NULL;
+ talloc_set_destructor(te, NULL);
+ TALLOC_FREE(te);
+
+ if (removed != NULL) {
+ *removed = true;
+ }
+
+ return 0;
+}
/*
do a single event loop using the events defined in ev
@@ -313,6 +376,7 @@ struct timeval tevent_common_loop_timer_delay(struct tevent_context *ev)
{
struct timeval current_time = tevent_timeval_zero();
struct tevent_timer *te = ev->timer_events;
+ int ret;
if (!te) {
/* have a default tick time of 30 seconds. This guarantees
@@ -344,40 +408,10 @@ struct timeval tevent_common_loop_timer_delay(struct tevent_context *ev)
/*
* ok, we have a timed event that we'll process ...
*/
-
- /* deny the handler to free the event */
- talloc_set_destructor(te, tevent_common_timed_deny_destructor);
-
- /* We need to remove the timer from the list before calling the
- * handler because in a semi-async inner event loop called from the
- * handler we don't want to come across this event again -- vl */
- if (ev->last_zero_timer == te) {
- ev->last_zero_timer = DLIST_PREV(te);
+ ret = tevent_common_invoke_timer_handler(te, current_time, NULL);
+ if (ret != 0) {
+ tevent_abort(ev, "tevent_common_invoke_timer_handler() failed");
}
- DLIST_REMOVE(ev->timer_events, te);
-
- tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
- "Running timer event %p \"%s\"\n",
- te, te->handler_name);
-
- /*
- * If the timed event was registered for a zero current_time,
- * then we pass a zero timeval here too! To avoid the
- * overhead of gettimeofday() calls.
- *
- * otherwise we pass the current time
- */
- te->handler(ev, te, current_time, te->private_data);
-
- /* The destructor isn't necessary anymore, we've already removed the
- * event from the list. */
- talloc_set_destructor(te, NULL);
-
- tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
- "Ending timer event %p \"%s\"\n",
- te, te->handler_name);
-
- talloc_free(te);
return tevent_timeval_zero();
}
--
2.17.1
From b4eb8714b48ea26394d26e630015a137b8089d95 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 Jul 2014 13:08:42 +0200
Subject: [PATCH 19/37] tevent: split out
tevent_common_invoke_immediate_handler()
We'll undo the 0.9.36 ABI change on the 0.9.37 release
at the end of this patchset.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/ABI/tevent-0.9.36.sigs | 1 +
lib/tevent/tevent_immediate.c | 87 +++++++++++++++++++++++--------
lib/tevent/tevent_internal.h | 4 ++
lib/tevent/tevent_threads.c | 6 +++
4 files changed, 75 insertions(+), 23 deletions(-)
diff --git a/lib/tevent/ABI/tevent-0.9.36.sigs b/lib/tevent/ABI/tevent-0.9.36.sigs
index bb89cc72d1e1..451e380688c8 100644
--- a/lib/tevent/ABI/tevent-0.9.36.sigs
+++ b/lib/tevent/ABI/tevent-0.9.36.sigs
@@ -32,6 +32,7 @@ tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
tevent_common_loop_immediate: bool (struct tevent_context *)
diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c
index c640a565b082..0649d1eacf27 100644
--- a/lib/tevent/tevent_immediate.c
+++ b/lib/tevent/tevent_immediate.c
@@ -31,6 +31,12 @@
static void tevent_common_immediate_cancel(struct tevent_immediate *im)
{
const char *create_location = im->create_location;
+ bool busy = im->busy;
+
+ if (im->destroyed) {
+ tevent_abort(im->event_ctx, "tevent_immediate use after free");
+ return;
+ }
if (!im->event_ctx) {
return;
@@ -51,9 +57,12 @@ static void tevent_common_immediate_cancel(struct tevent_immediate *im)
*im = (struct tevent_immediate) {
.create_location = create_location,
+ .busy = busy,
};
- talloc_set_destructor(im, NULL);
+ if (!busy) {
+ talloc_set_destructor(im, NULL);
+ }
}
/*
@@ -61,7 +70,21 @@ static void tevent_common_immediate_cancel(struct tevent_immediate *im)
*/
static int tevent_common_immediate_destructor(struct tevent_immediate *im)
{
+ if (im->destroyed) {
+ tevent_common_check_double_free(im,
+ "tevent_immediate double free");
+ goto done;
+ }
+
tevent_common_immediate_cancel(im);
+
+ im->destroyed = true;
+
+done:
+ if (im->busy) {
+ return -1;
+ }
+
return 0;
}
@@ -76,6 +99,7 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
const char *location)
{
const char *create_location = im->create_location;
+ bool busy = im->busy;
tevent_common_immediate_cancel(im);
@@ -90,6 +114,7 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
.handler_name = handler_name,
.create_location = create_location,
.schedule_location = location,
+ .busy = busy,
};
DLIST_ADD_END(ev->immediate_events, im);
@@ -100,18 +125,14 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
handler_name, im);
}
-/*
- trigger the first immediate event and return true
- if no event was triggered return false
-*/
-bool tevent_common_loop_immediate(struct tevent_context *ev)
+int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
+ bool *removed)
{
- struct tevent_immediate *im = ev->immediate_events;
- tevent_immediate_handler_t handler;
- void *private_data;
+ struct tevent_context *ev = im->event_ctx;
+ struct tevent_immediate cur = *im;
- if (!im) {
- return false;
+ if (removed != NULL) {
+ *removed = false;
}
tevent_debug(ev, TEVENT_DEBUG_TRACE,
@@ -122,21 +143,41 @@ bool tevent_common_loop_immediate(struct tevent_context *ev)
* remember the handler and then clear the event
* the handler might reschedule the event
*/
- handler = im->handler;
- private_data = im->private_data;
- DLIST_REMOVE(im->event_ctx->immediate_events, im);
- im->event_ctx = NULL;
- im->handler = NULL;
- im->private_data = NULL;
- im->handler_name = NULL;
- im->schedule_location = NULL;
- im->cancel_fn = NULL;
- im->additional_data = NULL;
+ im->busy = true;
+ im->handler_name = NULL;
+ tevent_common_immediate_cancel(im);
+ cur.handler(ev, im, cur.private_data);
+ im->busy = false;
+
+ if (im->destroyed) {
+ talloc_set_destructor(im, NULL);
+ TALLOC_FREE(im);
+ if (removed != NULL) {
+ *removed = true;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ trigger the first immediate event and return true
+ if no event was triggered return false
+*/
+bool tevent_common_loop_immediate(struct tevent_context *ev)
+{
+ struct tevent_immediate *im = ev->immediate_events;
+ int ret;
- talloc_set_destructor(im, NULL);
+ if (!im) {
+ return false;
+ }
- handler(ev, im, private_data);
+ ret = tevent_common_invoke_immediate_handler(im, NULL);
+ if (ret != 0) {
+ tevent_abort(ev, "tevent_common_invoke_immediate_handler() failed");
+ }
return true;
}
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index 8126414d6836..d74684c72c2c 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -203,6 +203,8 @@ struct tevent_timer {
struct tevent_immediate {
struct tevent_immediate *prev, *next;
struct tevent_context *event_ctx;
+ bool busy;
+ bool destroyed;
tevent_immediate_handler_t handler;
/* this is private for the specific handler */
void *private_data;
@@ -367,6 +369,8 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
void *private_data,
const char *handler_name,
const char *location);
+int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
+ bool *removed);
bool tevent_common_loop_immediate(struct tevent_context *ev);
void tevent_common_threaded_activate_immediate(struct tevent_context *ev);
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index efdac9856dd1..9410765266e4 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -482,6 +482,12 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
if ((im->event_ctx != NULL) || (handler == NULL)) {
abort();
}
+ if (im->destroyed) {
+ abort();
+ }
+ if (im->busy) {
+ abort();
+ }
*im = (struct tevent_immediate) {
.event_ctx = ev,
--
2.17.1
From eb5aa9dfab7e1e3f49f8bbb7cb4969f9913d7901 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 Jul 2014 14:45:33 +0200
Subject: [PATCH 20/37] tevent: split out tevent_common_invoke_fd_handler()
We'll undo the 0.9.36 ABI change on the 0.9.37 release
at the end of this patchset.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/ABI/tevent-0.9.36.sigs | 1 +
lib/tevent/tevent_epoll.c | 3 +--
lib/tevent/tevent_fd.c | 39 +++++++++++++++++++++++++++++++
lib/tevent/tevent_internal.h | 4 ++++
lib/tevent/tevent_poll.c | 3 +--
lib/tevent/tevent_port.c | 3 +--
6 files changed, 47 insertions(+), 6 deletions(-)
diff --git a/lib/tevent/ABI/tevent-0.9.36.sigs b/lib/tevent/ABI/tevent-0.9.36.sigs
index 451e380688c8..443bb7cb6c92 100644
--- a/lib/tevent/ABI/tevent-0.9.36.sigs
+++ b/lib/tevent/ABI/tevent-0.9.36.sigs
@@ -32,6 +32,7 @@ tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 4147c67af2a0..5f7ef5d83d17 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -725,8 +725,7 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval
*/
flags &= fde->flags;
if (flags) {
- fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
- break;
+ return tevent_common_invoke_fd_handler(fde, flags, NULL);
}
}
diff --git a/lib/tevent/tevent_fd.c b/lib/tevent/tevent_fd.c
index f33ae841b396..7859cbb00ef5 100644
--- a/lib/tevent/tevent_fd.c
+++ b/lib/tevent/tevent_fd.c
@@ -30,6 +30,12 @@
int tevent_common_fd_destructor(struct tevent_fd *fde)
{
+ if (fde->destroyed) {
+ tevent_common_check_double_free(fde, "tevent_fd double free");
+ goto done;
+ }
+ fde->destroyed = true;
+
if (fde->event_ctx) {
DLIST_REMOVE(fde->event_ctx->fd_events, fde);
}
@@ -37,6 +43,13 @@ int tevent_common_fd_destructor(struct tevent_fd *fde)
if (fde->close_fn) {
fde->close_fn(fde->event_ctx, fde, fde->fd, fde->private_data);
fde->fd = -1;
+ fde->close_fn = NULL;
+ }
+
+ fde->event_ctx = NULL;
+done:
+ if (fde->busy) {
+ return -1;
}
return 0;
@@ -92,3 +105,29 @@ void tevent_common_fd_set_close_fn(struct tevent_fd *fde,
{
fde->close_fn = close_fn;
}
+
+int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags,
+ bool *removed)
+{
+ if (removed != NULL) {
+ *removed = false;
+ }
+
+ if (fde->event_ctx == NULL) {
+ return 0;
+ }
+
+ fde->busy = true;
+ fde->handler(fde->event_ctx, fde, flags, fde->private_data);
+ fde->busy = false;
+
+ if (fde->destroyed) {
+ talloc_set_destructor(fde, NULL);
+ TALLOC_FREE(fde);
+ if (removed != NULL) {
+ *removed = true;
+ }
+ }
+
+ return 0;
+}
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index d74684c72c2c..1183b9f7f831 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -170,6 +170,8 @@ struct tevent_req {
struct tevent_fd {
struct tevent_fd *prev, *next;
struct tevent_context *event_ctx;
+ bool busy;
+ bool destroyed;
int fd;
uint16_t flags; /* see TEVENT_FD_* flags */
tevent_fd_handler_t handler;
@@ -343,6 +345,8 @@ void tevent_common_fd_set_close_fn(struct tevent_fd *fde,
tevent_fd_close_fn_t close_fn);
uint16_t tevent_common_fd_get_flags(struct tevent_fd *fde);
void tevent_common_fd_set_flags(struct tevent_fd *fde, uint16_t flags);
+int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags,
+ bool *removed);
struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev,
TALLOC_CTX *mem_ctx,
diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c
index 282f3cf3082c..74c418ca4218 100644
--- a/lib/tevent/tevent_poll.c
+++ b/lib/tevent/tevent_poll.c
@@ -565,8 +565,7 @@ static int poll_event_loop_poll(struct tevent_context *ev,
flags &= fde->flags;
if (flags != 0) {
DLIST_DEMOTE(ev->fd_events, fde);
- fde->handler(ev, fde, flags, fde->private_data);
- return 0;
+ return tevent_common_invoke_fd_handler(fde, flags, NULL);
}
}
diff --git a/lib/tevent/tevent_port.c b/lib/tevent/tevent_port.c
index 8cf9fd1a0de7..e91d442389dc 100644
--- a/lib/tevent/tevent_port.c
+++ b/lib/tevent/tevent_port.c
@@ -600,8 +600,7 @@ static int port_event_loop(struct port_event_context *port_ev, struct timeval *t
*/
flags &= fde->flags;
if (flags) {
- fde->handler(ev, fde, flags, fde->private_data);
- break;
+ return tevent_common_invoke_fd_handler(fde, flags, NULL);
}
}
--
2.17.1
From 2abeb889c45e58fc85dc396e33ce4a0b218f8099 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 May 2018 15:43:12 +0200
Subject: [PATCH 21/37] tevent: make use of #include "system/threads.h"
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/testsuite.c | 2 +-
lib/tevent/tevent_threads.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index 08aa7588acee..dba8f5895f76 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -32,7 +32,7 @@
#include "torture/torture.h"
#include "torture/local/proto.h"
#ifdef HAVE_PTHREAD
-#include <pthread.h>
+#include "system/threads.h"
#include <assert.h>
#endif
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index 9410765266e4..5d4e0c426769 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -28,8 +28,8 @@
#include "tevent_internal.h"
#include "tevent_util.h"
-#if defined(HAVE_PTHREAD)
-#include <pthread.h>
+#ifdef HAVE_PTHREAD
+#include "system/threads.h"
struct tevent_immediate_list {
struct tevent_immediate_list *next, *prev;
--
2.17.1
From f1293fc9cff2ff1baeb862f60b13cc7ac2c0c136 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 22 Jul 2014 16:51:38 +0200
Subject: [PATCH 22/37] tevent: add tevent_context_wrapper_create()
infrastructure
This allows to specify wrapper tevent_contexts, which adds the ability
to run functions before and after the event handler functions.
This can be used to implement impersonation hooks
or advanced debugging/profiling hooks.
We'll undo the 0.9.36 ABI change on the 0.9.37 release
at the end of this patchset.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
lib/tevent/ABI/tevent-0.9.36.sigs | 5 +
lib/tevent/tevent.c | 30 +-
lib/tevent/tevent.h | 260 ++++++++++++++
lib/tevent/tevent_debug.c | 16 +
lib/tevent/tevent_epoll.c | 8 +
lib/tevent/tevent_fd.c | 29 +-
lib/tevent/tevent_immediate.c | 27 +-
lib/tevent/tevent_internal.h | 35 ++
lib/tevent/tevent_poll.c | 2 +
lib/tevent/tevent_signal.c | 32 +-
lib/tevent/tevent_threads.c | 42 ++-
lib/tevent/tevent_timed.c | 32 +-
lib/tevent/tevent_wrapper.c | 568 ++++++++++++++++++++++++++++++
lib/tevent/wscript | 2 +-
14 files changed, 1069 insertions(+), 19 deletions(-)
create mode 100644 lib/tevent/tevent_wrapper.c
diff --git a/lib/tevent/ABI/tevent-0.9.36.sigs b/lib/tevent/ABI/tevent-0.9.36.sigs
index 443bb7cb6c92..ddb2c03b65c2 100644
--- a/lib/tevent/ABI/tevent-0.9.36.sigs
+++ b/lib/tevent/ABI/tevent-0.9.36.sigs
@@ -1,6 +1,9 @@
_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
_tevent_loop_once: int (struct tevent_context *, const char *)
_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
@@ -47,6 +50,8 @@ tevent_common_wakeup_init: int (struct tevent_context *)
tevent_context_init: struct tevent_context *(TALLOC_CTX *)
tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
tevent_fd_get_flags: uint16_t (struct tevent_fd *)
tevent_fd_set_auto_close: void (struct tevent_fd *)
diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index de0436df3736..dbec1821e41c 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -298,10 +298,17 @@ int tevent_common_context_destructor(struct tevent_context *ev)
struct tevent_timer *te, *tn;
struct tevent_immediate *ie, *in;
struct tevent_signal *se, *sn;
-
+ struct tevent_wrapper_glue *gl, *gn;
#ifdef HAVE_PTHREAD
int ret;
+#endif
+
+ if (ev->wrapper.glue != NULL) {
+ tevent_abort(ev,
+ "tevent_common_context_destructor() active on wrapper");
+ }
+#ifdef HAVE_PTHREAD
ret = pthread_mutex_lock(&tevent_contexts_mutex);
if (ret != 0) {
abort();
@@ -345,10 +352,18 @@ int tevent_common_context_destructor(struct tevent_context *ev)
}
#endif
+ for (gl = ev->wrapper.list; gl; gl = gn) {
+ gn = gl->next;
+
+ gl->main_ev = NULL;
+ DLIST_REMOVE(ev->wrapper.list, gl);
+ }
+
tevent_common_wakeup_fini(ev);
for (fd = ev->fd_events; fd; fd = fn) {
fn = fd->next;
+ fd->wrapper = NULL;
fd->event_ctx = NULL;
DLIST_REMOVE(ev->fd_events, fd);
}
@@ -356,12 +371,14 @@ int tevent_common_context_destructor(struct tevent_context *ev)
ev->last_zero_timer = NULL;
for (te = ev->timer_events; te; te = tn) {
tn = te->next;
+ te->wrapper = NULL;
te->event_ctx = NULL;
DLIST_REMOVE(ev->timer_events, te);
}
for (ie = ev->immediate_events; ie; ie = in) {
in = ie->next;
+ ie->wrapper = NULL;
ie->event_ctx = NULL;
ie->cancel_fn = NULL;
DLIST_REMOVE(ev->immediate_events, ie);
@@ -369,6 +386,7 @@ int tevent_common_context_destructor(struct tevent_context *ev)
for (se = ev->signal_events; se; se = sn) {
sn = se->next;
+ se->wrapper = NULL;
se->event_ctx = NULL;
DLIST_REMOVE(ev->signal_events, se);
/*
@@ -675,6 +693,16 @@ struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
void tevent_loop_allow_nesting(struct tevent_context *ev)
{
+ if (ev->wrapper.glue != NULL) {
+ tevent_abort(ev, "tevent_loop_allow_nesting() on wrapper");
+ return;
+ }
+
+ if (ev->wrapper.list != NULL) {
+ tevent_abort(ev, "tevent_loop_allow_nesting() with wrapper");
+ return;
+ }
+
ev->nesting.allowed = true;
}
diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
index 0e2e806ee5c4..d34a03093f36 100644
--- a/lib/tevent/tevent.h
+++ b/lib/tevent/tevent.h
@@ -429,6 +429,12 @@ int _tevent_loop_wait(struct tevent_context *ev, const char *location);
*
* @param[in] fde File descriptor event on which to set the destructor
* @param[in] close_fn Destructor to execute when fde is freed
+ *
+ * @note That the close_fn() on tevent_fd is *NOT* wrapped on contexts
+ * created by tevent_context_wrapper_create()!
+ *
+ * @see tevent_fd_set_close_fn
+ * @see tevent_context_wrapper_create
*/
void tevent_fd_set_close_fn(struct tevent_fd *fde,
tevent_fd_close_fn_t close_fn);
@@ -439,6 +445,8 @@ void tevent_fd_set_close_fn(struct tevent_fd *fde,
* This function calls close(fd) internally.
*
* @param[in] fde File descriptor event to auto-close
+ *
+ * @see tevent_fd_set_close_fn
*/
void tevent_fd_set_auto_close(struct tevent_fd *fde);
@@ -1967,6 +1975,258 @@ bool tevent_register_backend(const char *name, const struct tevent_ops *ops);
/* @} */
+/**
+ * @defgroup tevent_wrapper_ops The tevent wrapper operation functions
+ * @ingroup tevent
+ *
+ * The following structure and registration functions are exclusively
+ * needed for people writing wrapper functions for event handlers
+ * e.g. wrappers can be used for debugging/profiling or impersonation.
+ *
+ * There is nothing useful for normal tevent user in here.
+ *
+ * @note That the close_fn() on tevent_fd is *NOT* wrapped!
+ *
+ * @see tevent_context_wrapper_create
+ * @see tevent_fd_set_auto_close
+ * @{
+ */
+
+struct tevent_wrapper_ops {
+ const char *name;
+
+ bool (*before_use)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ const char *location);
+ void (*after_use)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ const char *location);
+
+ void (*before_fd_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ const char *handler_name,
+ const char *location);
+ void (*after_fd_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ const char *handler_name,
+ const char *location);
+
+ void (*before_timer_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_timer *te,
+ struct timeval requested_time,
+ struct timeval trigger_time,
+ const char *handler_name,
+ const char *location);
+ void (*after_timer_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_timer *te,
+ struct timeval requested_time,
+ struct timeval trigger_time,
+ const char *handler_name,
+ const char *location);
+
+ void (*before_immediate_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_immediate *im,
+ const char *handler_name,
+ const char *location);
+ void (*after_immediate_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_immediate *im,
+ const char *handler_name,
+ const char *location);
+
+ void (*before_signal_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ const char *handler_name,
+ const char *location);
+ void (*after_signal_handler)(struct tevent_context *wrap_ev,
+ void *private_state,
+ struct tevent_context *main_ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ const char *handler_name,
+ const char *location);
+};
+
+#ifdef DOXYGEN
+/**
+ * @brief Create a wrapper tevent_context.
+ *
+ * @param[in] main_ev The main event context to work on.
+ *
+ * @param[in] mem_ctx The talloc memory context to use.
+ *
+ * @param[in] ops The tevent_wrapper_ops function table.
+ *
+ * @param[out] private_state The private state use by the wrapper functions.
+ *
+ * @param[in] private_type The talloc type of the private_state.
+ *
+ * @return The wrapper event context, NULL on error.
+ *
+ * @note Available as of tevent 0.9.37
+ */
+struct tevent_context *tevent_context_wrapper_create(struct tevent_context *main_ev,
+ TALLOC_CTX *mem_ctx,
+ const struct tevent_wrapper_ops *ops,
+ void **private_state,
+ const char *private_type);
+#else
+struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
+ TALLOC_CTX *mem_ctx,
+ const struct tevent_wrapper_ops *ops,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location);
+#define tevent_context_wrapper_create(main_ev, mem_ctx, ops, state, type) \
+ _tevent_context_wrapper_create(main_ev, mem_ctx, ops, \
+ state, sizeof(type), #type, __location__)
+#endif
+
+/**
+ * @brief Check if the event context is a wrapper event context.
+ *
+ * @param[in] ev The event context to work on.
+ *
+ * @return Is a wrapper (true), otherwise (false).
+ *
+ * @see tevent_context_wrapper_create()
+ *
+ * @note Available as of tevent 0.9.37
+ */
+bool tevent_context_is_wrapper(struct tevent_context *ev);
+
+#ifdef DOXYGEN
+/**
+ * @brief Prepare the environment of a (wrapper) event context.
+ *
+ * A caller might call this before passing a wrapper event context
+ * to a tevent_req based *_send() function.
+ *
+ * The wrapper event context might do something like impersonation.
+ *
+ * tevent_context_push_use() must always be used in combination
+ * with tevent_context_pop_use().
+ *
+ * There is a global stack of currently active/busy wrapper event contexts.
+ * Each wrapper can only appear once on that global stack!
+ * The stack size is limited to 32 elements, which should be enough
+ * for all useful scenarios.
+ *
+ * In addition to an explicit tevent_context_push_use() also
+ * the invocation of an immediate, timer or fd handler implicitly
+ * pushes the wrapper on the stack.
+ *
+ * Therefore there are some strict constraints for the usage of
+ * tevent_context_push_use():
+ * - It must not be called from within an event handler
+ * that already acts on the wrapper.
+ * - tevent_context_pop_use() must be called before
+ * leaving the code block that called tevent_context_push_use().
+ * - The caller is responsible ensure the correct stack ordering
+ * - Any violation of these constraints results in calling
+ * the abort handler of the given tevent context.
+ *
+ * Calling tevent_context_push_use() on a raw event context
+ * still consumes an element on the stack, but it's otherwise
+ * a no-op.
+ *
+ * If tevent_context_push_use() returns false, it means
+ * that the wrapper's before_use() hook returned this failure,
+ * in that case you must not call tevent_context_pop_use() as
+ * the wrapper is not pushed onto the stack.
+ *
+ * @param[in] ev The event context to work on.
+ *
+ * @return Success (true) or failure (false).
+ *
+ * @note This is only needed if wrapper event contexts are in use.
+ *
+ * @see tevent_context_pop_use
+ *
+ * @note Available as of tevent 0.9.37
+ */
+bool tevent_context_push_use(struct tevent_context *ev);
+#else
+bool _tevent_context_push_use(struct tevent_context *ev,
+ const char *location);
+#define tevent_context_push_use(ev) \
+ _tevent_context_push_use(ev, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Release the environment of a (wrapper) event context.
+ *
+ * The wrapper event context might undo something like impersonation.
+ *
+ * This must be called after a succesful tevent_context_push_use().
+ * Any ordering violation results in calling
+ * the abort handler of the given tevent context.
+ *
+ * This basically calls the wrapper's after_use() hook.
+ *
+ * @param[in] ev The event context to work on.
+ *
+ * @note This is only needed if wrapper event contexts are in use.
+ *
+ * @see tevent_context_push_use
+ *
+ * @note Available as of tevent 0.9.37
+ */
+void tevent_context_pop_use(struct tevent_context *ev);
+#else
+void _tevent_context_pop_use(struct tevent_context *ev,
+ const char *location);
+#define tevent_context_pop_use(ev) \
+ _tevent_context_pop_use(ev, __location__)
+#endif
+
+/**
+ * @brief Check is the two context pointers belong to the same low level loop
+ *
+ * With the introduction of wrapper contexts it's not trivial
+ * to check if two context pointers belong to the same low level
+ * event loop. Some code may need to know this in order
+ * to make some caching decisions.
+ *
+ * @param[in] ev1 The first event context.
+ * @param[in] ev2 The second event context.
+ *
+ * @return true if both contexts belong to the same (still existing) context
+ * loop, false otherwise.
+ *
+ * @see tevent_context_wrapper_create
+ *
+ * @note Available as of tevent 0.9.37
+ */
+bool tevent_context_same_loop(struct tevent_context *ev1,
+ struct tevent_context *ev2);
+
+/* @} */
+
/**
* @defgroup tevent_compat The tevent compatibility functions
* @ingroup tevent
diff --git a/lib/tevent/tevent_debug.c b/lib/tevent/tevent_debug.c
index 31da7b968366..0a57639076e2 100644
--- a/lib/tevent/tevent_debug.c
+++ b/lib/tevent/tevent_debug.c
@@ -41,6 +41,13 @@ int tevent_set_debug(struct tevent_context *ev,
va_list ap) PRINTF_ATTRIBUTE(3,0),
void *context)
{
+ if (ev->wrapper.glue != NULL) {
+ ev = tevent_wrapper_main_ev(ev);
+ tevent_abort(ev, "tevent_set_debug() on wrapper");
+ errno = EINVAL;
+ return -1;
+ }
+
ev->debug_ops.debug = debug;
ev->debug_ops.context = context;
return 0;
@@ -86,6 +93,9 @@ void tevent_debug(struct tevent_context *ev, enum tevent_debug_level level,
if (!ev) {
return;
}
+ if (ev->wrapper.glue != NULL) {
+ ev = tevent_wrapper_main_ev(ev);
+ }
if (ev->debug_ops.debug == NULL) {
return;
}
@@ -98,6 +108,12 @@ void tevent_set_trace_callback(struct tevent_context *ev,
tevent_trace_callback_t cb,
void *private_data)
{
+ if (ev->wrapper.glue != NULL) {
+ ev = tevent_wrapper_main_ev(ev);
+ tevent_abort(ev, "tevent_set_trace_callback() on wrapper");
+ return;
+ }
+
ev->tracing.callback = cb;
ev->tracing.private_data = private_data;
}
diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 5f7ef5d83d17..9cbe505c98a4 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -323,8 +323,10 @@ static int epoll_add_multiplex_fd(struct epoll_event_context *epoll_ev,
"add_fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
add_fde, mpx_fde, add_fde->fd);
DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
+ mpx_fde->wrapper = NULL;
mpx_fde->event_ctx = NULL;
DLIST_REMOVE(epoll_ev->ev->fd_events, add_fde);
+ add_fde->wrapper = NULL;
add_fde->event_ctx = NULL;
return 0;
} else if (ret != 0) {
@@ -387,9 +389,11 @@ static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_
"fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
fde, mpx_fde, fde->fd);
DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
+ fde->wrapper = NULL;
fde->event_ctx = NULL;
if (mpx_fde != NULL) {
DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
+ mpx_fde->wrapper = NULL;
mpx_fde->event_ctx = NULL;
}
return;
@@ -462,9 +466,11 @@ static void epoll_del_event(struct epoll_event_context *epoll_ev, struct tevent_
"fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
fde, mpx_fde, fde->fd);
DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
+ fde->wrapper = NULL;
fde->event_ctx = NULL;
if (mpx_fde != NULL) {
DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
+ mpx_fde->wrapper = NULL;
mpx_fde->event_ctx = NULL;
}
return;
@@ -511,9 +517,11 @@ static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct tevent_
"fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
fde, mpx_fde, fde->fd);
DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
+ fde->wrapper = NULL;
fde->event_ctx = NULL;
if (mpx_fde != NULL) {
DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
+ mpx_fde->wrapper = NULL;
mpx_fde->event_ctx = NULL;
}
return;
diff --git a/lib/tevent/tevent_fd.c b/lib/tevent/tevent_fd.c
index 7859cbb00ef5..b92c45f1ddde 100644
--- a/lib/tevent/tevent_fd.c
+++ b/lib/tevent/tevent_fd.c
@@ -51,6 +51,7 @@ done:
if (fde->busy) {
return -1;
}
+ fde->wrapper = NULL;
return 0;
}
@@ -109,6 +110,8 @@ void tevent_common_fd_set_close_fn(struct tevent_fd *fde,
int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags,
bool *removed)
{
+ struct tevent_context *handler_ev = fde->event_ctx;
+
if (removed != NULL) {
*removed = false;
}
@@ -118,7 +121,31 @@ int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags,
}
fde->busy = true;
- fde->handler(fde->event_ctx, fde, flags, fde->private_data);
+ if (fde->wrapper != NULL) {
+ handler_ev = fde->wrapper->wrap_ev;
+
+ tevent_wrapper_push_use_internal(handler_ev, fde->wrapper);
+ fde->wrapper->ops->before_fd_handler(
+ fde->wrapper->wrap_ev,
+ fde->wrapper->private_state,
+ fde->wrapper->main_ev,
+ fde,
+ flags,
+ fde->handler_name,
+ fde->location);
+ }
+ fde->handler(handler_ev, fde, flags, fde->private_data);
+ if (fde->wrapper != NULL) {
+ fde->wrapper->ops->after_fd_handler(
+ fde->wrapper->wrap_ev,
+ fde->wrapper->private_state,
+ fde->wrapper->main_ev,
+ fde,
+ flags,
+ fde->handler_name,
+ fde->location);
+ tevent_wrapper_pop_use_internal(handler_ev, fde->wrapper);
+ }
fde->busy = false;
if (fde->destroyed) {
diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c
index 0649d1eacf27..ef7d8a566c0a 100644
--- a/lib/tevent/tevent_immediate.c
+++ b/lib/tevent/tevent_immediate.c
@@ -100,6 +100,7 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
{
const char *create_location = im->create_location;
bool busy = im->busy;
+ struct tevent_wrapper_glue *glue = im->wrapper;
tevent_common_immediate_cancel(im);
@@ -109,6 +110,7 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
*im = (struct tevent_immediate) {
.event_ctx = ev,
+ .wrapper = glue,
.handler = handler,
.private_data = private_data,
.handler_name = handler_name,
@@ -128,6 +130,7 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
bool *removed)
{
+ struct tevent_context *handler_ev = im->event_ctx;
struct tevent_context *ev = im->event_ctx;
struct tevent_immediate cur = *im;
@@ -147,7 +150,29 @@ int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
im->busy = true;
im->handler_name = NULL;
tevent_common_immediate_cancel(im);
- cur.handler(ev, im, cur.private_data);
+ if (cur.wrapper != NULL) {
+ handler_ev = cur.wrapper->wrap_ev;
+
+ tevent_wrapper_push_use_internal(handler_ev, cur.wrapper);
+ cur.wrapper->ops->before_immediate_handler(
+ cur.wrapper->wrap_ev,
+ cur.wrapper->private_state,
+ cur.wrapper->main_ev,
+ im,
+ cur.handler_name,
+ cur.schedule_location);
+ }
+ cur.handler(handler_ev, im, cur.private_data);
+ if (cur.wrapper != NULL) {
+ cur.wrapper->ops->after_immediate_handler(
+ cur.wrapper->wrap_ev,
+ cur.wrapper->private_state,
+ cur.wrapper->main_ev,
+ im,
+ cur.handler_name,
+ cur.schedule_location);
+ tevent_wrapper_pop_use_internal(handler_ev, cur.wrapper);
+ }
im->busy = false;
if (im->destroyed) {
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index 1183b9f7f831..17c195816fae 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -170,6 +170,7 @@ struct tevent_req {
struct tevent_fd {
struct tevent_fd *prev, *next;
struct tevent_context *event_ctx;
+ struct tevent_wrapper_glue *wrapper;
bool busy;
bool destroyed;
int fd;
@@ -189,6 +190,7 @@ struct tevent_fd {
struct tevent_timer {
struct tevent_timer *prev, *next;
struct tevent_context *event_ctx;
+ struct tevent_wrapper_glue *wrapper;
bool busy;
bool destroyed;
struct timeval next_event;
@@ -205,6 +207,7 @@ struct tevent_timer {
struct tevent_immediate {
struct tevent_immediate *prev, *next;
struct tevent_context *event_ctx;
+ struct tevent_wrapper_glue *wrapper;
bool busy;
bool destroyed;
tevent_immediate_handler_t handler;
@@ -222,6 +225,7 @@ struct tevent_immediate {
struct tevent_signal {
struct tevent_signal *prev, *next;
struct tevent_context *event_ctx;
+ struct tevent_wrapper_glue *wrapper;
bool busy;
bool destroyed;
int signum;
@@ -314,6 +318,18 @@ struct tevent_context {
void *private_data;
} tracing;
+ struct {
+ /*
+ * This is used on the main event context
+ */
+ struct tevent_wrapper_glue *list;
+
+ /*
+ * This is used on the wrapper event context
+ */
+ struct tevent_wrapper_glue *glue;
+ } wrapper;
+
/*
* an optimization pointer into timer_events
* used by used by common code via
@@ -397,6 +413,25 @@ int tevent_common_invoke_signal_handler(struct tevent_signal *se,
int signum, int count, void *siginfo,
bool *removed);
+struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev);
+
+struct tevent_wrapper_ops;
+
+struct tevent_wrapper_glue {
+ struct tevent_wrapper_glue *prev, *next;
+ struct tevent_context *wrap_ev;
+ struct tevent_context *main_ev;
+ bool busy;
+ bool destroyed;
+ const struct tevent_wrapper_ops *ops;
+ void *private_state;
+};
+
+void tevent_wrapper_push_use_internal(struct tevent_context *ev,
+ struct tevent_wrapper_glue *wrapper);
+void tevent_wrapper_pop_use_internal(const struct tevent_context *__ev_ptr,
+ struct tevent_wrapper_glue *wrapper);
+
bool tevent_standard_init(void);
bool tevent_poll_init(void);
bool tevent_poll_event_add_fd_internal(struct tevent_context *ev,
diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c
index 74c418ca4218..f4c6c2dbe80f 100644
--- a/lib/tevent/tevent_poll.c
+++ b/lib/tevent/tevent_poll.c
@@ -535,6 +535,7 @@ static int poll_event_loop_poll(struct tevent_context *ev,
poll_ev->fdes[idx] = NULL;
poll_ev->deleted = true;
DLIST_REMOVE(ev->fd_events, fde);
+ fde->wrapper = NULL;
fde->event_ctx = NULL;
continue;
}
@@ -586,6 +587,7 @@ static int poll_event_loop_poll(struct tevent_context *ev,
poll_ev->deleted = true;
if (fde != NULL) {
DLIST_REMOVE(ev->fd_events, fde);
+ fde->wrapper = NULL;
fde->event_ctx = NULL;
}
}
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index a787f97b9649..5ca0b8d2ab11 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -216,6 +216,7 @@ done:
if (se->busy) {
return -1;
}
+ se->wrapper = NULL;
return 0;
}
@@ -338,6 +339,7 @@ int tevent_common_invoke_signal_handler(struct tevent_signal *se,
int signum, int count, void *siginfo,
bool *removed)
{
+ struct tevent_context *handler_ev = se->event_ctx;
bool remove = false;
if (removed != NULL) {
@@ -349,7 +351,35 @@ int tevent_common_invoke_signal_handler(struct tevent_signal *se,
}
se->busy = true;
- se->handler(se->event_ctx, se, signum, count, siginfo, se->private_data);
+ if (se->wrapper != NULL) {
+ handler_ev = se->wrapper->wrap_ev;
+
+ tevent_wrapper_push_use_internal(handler_ev, se->wrapper);
+ se->wrapper->ops->before_signal_handler(
+ se->wrapper->wrap_ev,
+ se->wrapper->private_state,
+ se->wrapper->main_ev,
+ se,
+ signum,
+ count,
+ siginfo,
+ se->handler_name,
+ se->location);
+ }
+ se->handler(handler_ev, se, signum, count, siginfo, se->private_data);
+ if (se->wrapper != NULL) {
+ se->wrapper->ops->after_signal_handler(
+ se->wrapper->wrap_ev,
+ se->wrapper->private_state,
+ se->wrapper->main_ev,
+ se,
+ signum,
+ count,
+ siginfo,
+ se->handler_name,
+ se->location);
+ tevent_wrapper_pop_use_internal(handler_ev, se->wrapper);
+ }
se->busy = false;
#ifdef SA_RESETHAND
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index 5d4e0c426769..21a9b686ba91 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -217,6 +217,18 @@ struct tevent_thread_proxy *tevent_thread_proxy_create(
int pipefds[2];
struct tevent_thread_proxy *tp;
+ if (dest_ev_ctx->wrapper.glue != NULL) {
+ /*
+ * stacking of wrappers is not supported
+ */
+ tevent_debug(dest_ev_ctx->wrapper.glue->main_ev,
+ TEVENT_DEBUG_FATAL,
+ "%s() not allowed on a wrapper context\n",
+ __func__);
+ errno = EINVAL;
+ return NULL;
+ }
+
tp = talloc_zero(dest_ev_ctx, struct tevent_thread_proxy);
if (tp == NULL) {
return NULL;
@@ -375,10 +387,11 @@ void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
static int tevent_threaded_context_destructor(
struct tevent_threaded_context *tctx)
{
+ struct tevent_context *main_ev = tevent_wrapper_main_ev(tctx->event_ctx);
int ret;
- if (tctx->event_ctx != NULL) {
- DLIST_REMOVE(tctx->event_ctx->threaded_contexts, tctx);
+ if (main_ev != NULL) {
+ DLIST_REMOVE(main_ev->threaded_contexts, tctx);
}
/*
@@ -410,10 +423,11 @@ struct tevent_threaded_context *tevent_threaded_context_create(
TALLOC_CTX *mem_ctx, struct tevent_context *ev)
{
#ifdef HAVE_PTHREAD
+ struct tevent_context *main_ev = tevent_wrapper_main_ev(ev);
struct tevent_threaded_context *tctx;
int ret;
- ret = tevent_common_wakeup_init(ev);
+ ret = tevent_common_wakeup_init(main_ev);
if (ret != 0) {
errno = ret;
return NULL;
@@ -431,7 +445,7 @@ struct tevent_threaded_context *tevent_threaded_context_create(
return NULL;
}
- DLIST_ADD(ev->threaded_contexts, tctx);
+ DLIST_ADD(main_ev->threaded_contexts, tctx);
talloc_set_destructor(tctx, tevent_threaded_context_destructor);
return tctx;
@@ -458,7 +472,8 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
{
#ifdef HAVE_PTHREAD
const char *create_location = im->create_location;
- struct tevent_context *ev;
+ struct tevent_context *main_ev = NULL;
+ struct tevent_wrapper_glue *glue = tctx->event_ctx->wrapper.glue;
int ret, wakeup_fd;
ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
@@ -466,9 +481,7 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
abort();
}
- ev = tctx->event_ctx;
-
- if (ev == NULL) {
+ if (tctx->event_ctx == NULL) {
/*
* Our event context is already gone.
*/
@@ -489,8 +502,11 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
abort();
}
+ main_ev = tevent_wrapper_main_ev(tctx->event_ctx);
+
*im = (struct tevent_immediate) {
- .event_ctx = ev,
+ .event_ctx = tctx->event_ctx,
+ .wrapper = glue,
.handler = handler,
.private_data = private_data,
.handler_name = handler_name,
@@ -506,15 +522,15 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
*/
talloc_set_destructor(im, tevent_threaded_schedule_immediate_destructor);
- ret = pthread_mutex_lock(&ev->scheduled_mutex);
+ ret = pthread_mutex_lock(&main_ev->scheduled_mutex);
if (ret != 0) {
abort();
}
- DLIST_ADD_END(ev->scheduled_immediates, im);
- wakeup_fd = ev->wakeup_fd;
+ DLIST_ADD_END(main_ev->scheduled_immediates, im);
+ wakeup_fd = main_ev->wakeup_fd;
- ret = pthread_mutex_unlock(&ev->scheduled_mutex);
+ ret = pthread_mutex_unlock(&main_ev->scheduled_mutex);
if (ret != 0) {
abort();
}
diff --git a/lib/tevent/tevent_timed.c b/lib/tevent/tevent_timed.c
index cb948d4ba29e..b521f096c48a 100644
--- a/lib/tevent/tevent_timed.c
+++ b/lib/tevent/tevent_timed.c
@@ -157,6 +157,7 @@ done:
if (te->busy) {
return -1;
}
+ te->wrapper = NULL;
return 0;
}
@@ -319,6 +320,8 @@ int tevent_common_invoke_timer_handler(struct tevent_timer *te,
struct timeval current_time,
bool *removed)
{
+ struct tevent_context *handler_ev = te->event_ctx;
+
if (removed != NULL) {
*removed = false;
}
@@ -349,13 +352,40 @@ int tevent_common_invoke_timer_handler(struct tevent_timer *te,
* otherwise we pass the current time
*/
te->busy = true;
- te->handler(te->event_ctx, te, current_time, te->private_data);
+ if (te->wrapper != NULL) {
+ handler_ev = te->wrapper->wrap_ev;
+
+ tevent_wrapper_push_use_internal(handler_ev, te->wrapper);
+ te->wrapper->ops->before_timer_handler(
+ te->wrapper->wrap_ev,
+ te->wrapper->private_state,
+ te->wrapper->main_ev,
+ te,
+ te->next_event,
+ current_time,
+ te->handler_name,
+ te->location);
+ }
+ te->handler(handler_ev, te, current_time, te->private_data);
+ if (te->wrapper != NULL) {
+ te->wrapper->ops->after_timer_handler(
+ te->wrapper->wrap_ev,
+ te->wrapper->private_state,
+ te->wrapper->main_ev,
+ te,
+ te->next_event,
+ current_time,
+ te->handler_name,
+ te->location);
+ tevent_wrapper_pop_use_internal(handler_ev, te->wrapper);
+ }
te->busy = false;
tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
"Ending timer event %p \"%s\"\n",
te, te->handler_name);
+ te->wrapper = NULL;
te->event_ctx = NULL;
talloc_set_destructor(te, NULL);
TALLOC_FREE(te);
diff --git a/lib/tevent/tevent_wrapper.c b/lib/tevent/tevent_wrapper.c
new file mode 100644
index 000000000000..05c4c06968aa
--- /dev/null
+++ b/lib/tevent/tevent_wrapper.c
@@ -0,0 +1,568 @@
+/*
+ Infrastructure for event context wrappers
+
+ Copyright (C) Stefan Metzmacher 2014
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#ifdef HAVE_PTHREAD
+#include "system/threads.h"
+#endif
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+static int tevent_wrapper_glue_context_init(struct tevent_context *ev)
+{
+ tevent_abort(ev, "tevent_wrapper_glue_context_init() called");
+ errno = ENOSYS;
+ return -1;
+}
+
+static struct tevent_fd *tevent_wrapper_glue_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 tevent_wrapper_glue *glue = ev->wrapper.glue;
+ struct tevent_fd *fde = NULL;
+
+ if (glue->destroyed) {
+ tevent_abort(ev, "add_fd wrapper use after free");
+ return NULL;
+ }
+
+ if (glue->main_ev == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ fde = _tevent_add_fd(glue->main_ev, mem_ctx, fd, flags,
+ handler, private_data,
+ handler_name, location);
+ if (fde == NULL) {
+ return NULL;
+ }
+
+ fde->wrapper = glue;
+
+ return fde;
+}
+
+static struct tevent_timer *tevent_wrapper_glue_add_timer(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+ struct tevent_timer *te = NULL;
+
+ if (glue->destroyed) {
+ tevent_abort(ev, "add_timer wrapper use after free");
+ return NULL;
+ }
+
+ if (glue->main_ev == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ te = _tevent_add_timer(glue->main_ev, mem_ctx, next_event,
+ handler, private_data,
+ handler_name, location);
+ if (te == NULL) {
+ return NULL;
+ }
+
+ te->wrapper = glue;
+
+ return te;
+}
+
+static void tevent_wrapper_glue_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+
+ if (glue->destroyed) {
+ tevent_abort(ev, "scheduke_immediate wrapper use after free");
+ return;
+ }
+
+ if (glue->main_ev == NULL) {
+ tevent_abort(ev, location);
+ errno = EINVAL;
+ return;
+ }
+
+ _tevent_schedule_immediate(im, glue->main_ev,
+ handler, private_data,
+ handler_name, location);
+
+ im->wrapper = glue;
+
+ return;
+}
+
+static struct tevent_signal *tevent_wrapper_glue_add_signal(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int signum, int sa_flags,
+ tevent_signal_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+ struct tevent_signal *se = NULL;
+
+ if (glue->destroyed) {
+ tevent_abort(ev, "add_signal wrapper use after free");
+ return NULL;
+ }
+
+ if (glue->main_ev == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ se = _tevent_add_signal(glue->main_ev, mem_ctx,
+ signum, sa_flags,
+ handler, private_data,
+ handler_name, location);
+ if (se == NULL) {
+ return NULL;
+ }
+
+ se->wrapper = glue;
+
+ return se;
+}
+
+static int tevent_wrapper_glue_loop_once(struct tevent_context *ev, const char *location)
+{
+ tevent_abort(ev, "tevent_wrapper_glue_loop_once() called");
+ errno = ENOSYS;
+ return -1;
+}
+
+static int tevent_wrapper_glue_loop_wait(struct tevent_context *ev, const char *location)
+{
+ tevent_abort(ev, "tevent_wrapper_glue_loop_wait() called");
+ errno = ENOSYS;
+ return -1;
+}
+
+static const struct tevent_ops tevent_wrapper_glue_ops = {
+ .context_init = tevent_wrapper_glue_context_init,
+ .add_fd = tevent_wrapper_glue_add_fd,
+ .set_fd_close_fn = tevent_common_fd_set_close_fn,
+ .get_fd_flags = tevent_common_fd_get_flags,
+ .set_fd_flags = tevent_common_fd_set_flags,
+ .add_timer = tevent_wrapper_glue_add_timer,
+ .schedule_immediate = tevent_wrapper_glue_schedule_immediate,
+ .add_signal = tevent_wrapper_glue_add_signal,
+ .loop_once = tevent_wrapper_glue_loop_once,
+ .loop_wait = tevent_wrapper_glue_loop_wait,
+};
+
+static int tevent_wrapper_context_destructor(struct tevent_context *wrap_ev)
+{
+ struct tevent_wrapper_glue *glue = wrap_ev->wrapper.glue;
+ struct tevent_context *main_ev = NULL;
+ struct tevent_fd *fd = NULL, *fn = NULL;
+ struct tevent_timer *te = NULL, *tn = NULL;
+ struct tevent_immediate *ie = NULL, *in = NULL;
+ struct tevent_signal *se = NULL, *sn = NULL;
+#ifdef HAVE_PTHREAD
+ struct tevent_threaded_context *tctx = NULL, *tctxn = NULL;
+#endif
+
+ if (glue == NULL) {
+ tevent_abort(wrap_ev,
+ "tevent_wrapper_context_destructor() active on main");
+ }
+
+ if (glue->destroyed && glue->busy) {
+ tevent_common_check_double_free(wrap_ev,
+ "tevent_context wrapper double free");
+ }
+ glue->destroyed = true;
+
+ if (glue->busy) {
+ return -1;
+ }
+
+ main_ev = glue->main_ev;
+ if (main_ev == NULL) {
+ return 0;
+ }
+
+ tevent_debug(wrap_ev, TEVENT_DEBUG_TRACE,
+ "Destroying wrapper context %p \"%s\"\n",
+ wrap_ev, talloc_get_name(glue->private_state));
+
+ glue->main_ev = NULL;
+ DLIST_REMOVE(main_ev->wrapper.list, glue);
+
+#ifdef HAVE_PTHREAD
+ for (tctx = main_ev->threaded_contexts; tctx != NULL; tctx = tctxn) {
+ int ret;
+
+ tctxn = tctx->next;
+
+ if (tctx->event_ctx != glue->wrap_ev) {
+ continue;
+ }
+
+ ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ /*
+ * Indicate to the thread that the tevent_context is
+ * gone. The counterpart of this is in
+ * _tevent_threaded_schedule_immediate, there we read
+ * this under the threaded_context's mutex.
+ */
+
+ tctx->event_ctx = NULL;
+
+ ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+ if (ret != 0) {
+ abort();
+ }
+
+ DLIST_REMOVE(main_ev->threaded_contexts, tctx);
+ }
+#endif
+
+ for (fd = main_ev->fd_events; fd; fd = fn) {
+ fn = fd->next;
+
+ if (fd->wrapper != glue) {
+ continue;
+ }
+
+ tevent_fd_set_flags(fd, 0);
+
+ fd->wrapper = NULL;
+ fd->event_ctx = NULL;
+ DLIST_REMOVE(main_ev->fd_events, fd);
+ }
+
+ for (te = main_ev->timer_events; te; te = tn) {
+ tn = te->next;
+
+ if (te->wrapper != glue) {
+ continue;
+ }
+
+ te->wrapper = NULL;
+ te->event_ctx = NULL;
+
+ if (main_ev->last_zero_timer == te) {
+ main_ev->last_zero_timer = DLIST_PREV(te);
+ }
+ DLIST_REMOVE(main_ev->timer_events, te);
+ }
+
+ for (ie = main_ev->immediate_events; ie; ie = in) {
+ in = ie->next;
+
+ if (ie->wrapper != glue) {
+ continue;
+ }
+
+ ie->wrapper = NULL;
+ ie->event_ctx = NULL;
+ ie->cancel_fn = NULL;
+ DLIST_REMOVE(main_ev->immediate_events, ie);
+ }
+
+ for (se = main_ev->signal_events; se; se = sn) {
+ sn = se->next;
+
+ if (se->wrapper != glue) {
+ continue;
+ }
+
+ se->wrapper = NULL;
+ tevent_cleanup_pending_signal_handlers(se);
+ }
+
+ return 0;
+}
+
+struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
+ TALLOC_CTX *mem_ctx,
+ const struct tevent_wrapper_ops *ops,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location)
+{
+ void **ppstate = (void **)pstate;
+ struct tevent_context *ev = NULL;
+
+ if (main_ev->wrapper.glue != NULL) {
+ /*
+ * stacking of wrappers is not supported
+ */
+ tevent_debug(main_ev->wrapper.glue->main_ev, TEVENT_DEBUG_FATAL,
+ "%s: %s() stacking not allowed\n",
+ __func__, location);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (main_ev->nesting.allowed) {
+ /*
+ * wrappers conflict with nesting
+ */
+ tevent_debug(main_ev->wrapper.glue->main_ev, TEVENT_DEBUG_FATAL,
+ "%s: %s() conflicts with nesting\n",
+ __func__, location);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ ev = talloc_zero(mem_ctx, struct tevent_context);
+ if (ev == NULL) {
+ return NULL;
+ }
+ ev->ops = &tevent_wrapper_glue_ops;
+
+ ev->wrapper.glue = talloc_zero(ev, struct tevent_wrapper_glue);
+ if (ev->wrapper.glue == NULL) {
+ talloc_free(ev);
+ return NULL;
+ }
+
+ talloc_set_destructor(ev, tevent_wrapper_context_destructor);
+
+ ev->wrapper.glue->wrap_ev = ev;
+ ev->wrapper.glue->main_ev = main_ev;
+ ev->wrapper.glue->ops = ops;
+ ev->wrapper.glue->private_state = talloc_size(ev->wrapper.glue, psize);
+ if (ev->wrapper.glue->private_state == NULL) {
+ talloc_free(ev);
+ return NULL;
+ }
+ talloc_set_name_const(ev->wrapper.glue->private_state, type);
+
+ DLIST_ADD_END(main_ev->wrapper.list, ev->wrapper.glue);
+
+ *ppstate = ev->wrapper.glue->private_state;
+ return ev;
+}
+
+bool tevent_context_is_wrapper(struct tevent_context *ev)
+{
+ if (ev->wrapper.glue != NULL) {
+ return true;
+ }
+
+ return false;
+}
+
+_PRIVATE_
+struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
+{
+ if (ev == NULL) {
+ return NULL;
+ }
+
+ if (ev->wrapper.glue == NULL) {
+ return ev;
+ }
+
+ return ev->wrapper.glue->main_ev;
+}
+
+/*
+ * 32 stack elements should be more than enough
+ *
+ * e.g. Samba uses just 8 elements for [un]become_{root,user}()
+ */
+#define TEVENT_WRAPPER_STACK_SIZE 32
+
+static struct tevent_wrapper_stack {
+ const void *ev_ptr;
+ const struct tevent_wrapper_glue *wrapper;
+} wrapper_stack[TEVENT_WRAPPER_STACK_SIZE];
+
+static size_t wrapper_stack_idx;
+
+_PRIVATE_
+void tevent_wrapper_push_use_internal(struct tevent_context *ev,
+ struct tevent_wrapper_glue *wrapper)
+{
+ /*
+ * ev and wrapper need to belong together!
+ * It's also fine to only have a raw ev
+ * without a wrapper.
+ */
+ if (unlikely(ev->wrapper.glue != wrapper)) {
+ tevent_abort(ev, "tevent_wrapper_push_use_internal() invalid arguments");
+ return;
+ }
+
+ if (wrapper != NULL) {
+ if (unlikely(wrapper->busy)) {
+ tevent_abort(ev, "wrapper already busy!");
+ return;
+ }
+ wrapper->busy = true;
+ }
+
+ if (unlikely(wrapper_stack_idx >= TEVENT_WRAPPER_STACK_SIZE)) {
+ tevent_abort(ev, "TEVENT_WRAPPER_STACK_SIZE overflow");
+ return;
+ }
+
+ wrapper_stack[wrapper_stack_idx] = (struct tevent_wrapper_stack) {
+ .ev_ptr = ev,
+ .wrapper = wrapper,
+ };
+ wrapper_stack_idx++;
+}
+
+_PRIVATE_
+void tevent_wrapper_pop_use_internal(const struct tevent_context *__ev_ptr,
+ struct tevent_wrapper_glue *wrapper)
+{
+ struct tevent_context *main_ev = NULL;
+
+ /*
+ * Note that __ev_ptr might a a stale pointer and should not
+ * be touched, we just compare the pointer value in order
+ * to enforce the stack order.
+ */
+
+ if (wrapper != NULL) {
+ main_ev = wrapper->main_ev;
+ }
+
+ if (unlikely(wrapper_stack_idx == 0)) {
+ tevent_abort(main_ev, "tevent_wrapper stack already empty");
+ return;
+ }
+ wrapper_stack_idx--;
+
+ if (wrapper != NULL) {
+ wrapper->busy = false;
+ }
+
+ if (wrapper_stack[wrapper_stack_idx].ev_ptr != __ev_ptr) {
+ tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch ev!");
+ return;
+ }
+ if (wrapper_stack[wrapper_stack_idx].wrapper != wrapper) {
+ tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch wrap!");
+ return;
+ }
+
+ if (wrapper == NULL) {
+ return;
+ }
+
+ if (wrapper->destroyed) {
+ /*
+ * Notice that we can't use TALLOC_FREE()
+ * here because wrapper is a talloc child
+ * of wrapper->wrap_ev.
+ */
+ talloc_free(wrapper->wrap_ev);
+ }
+}
+
+bool _tevent_context_push_use(struct tevent_context *ev,
+ const char *location)
+{
+ bool ok;
+
+ if (ev->wrapper.glue == NULL) {
+ tevent_wrapper_push_use_internal(ev, NULL);
+ return true;
+ }
+
+ if (ev->wrapper.glue->main_ev == NULL) {
+ return false;
+ }
+
+ tevent_wrapper_push_use_internal(ev, ev->wrapper.glue);
+ ok = ev->wrapper.glue->ops->before_use(ev->wrapper.glue->wrap_ev,
+ ev->wrapper.glue->private_state,
+ ev->wrapper.glue->main_ev,
+ location);
+ if (!ok) {
+ tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
+ return false;
+ }
+
+ return true;
+}
+
+void _tevent_context_pop_use(struct tevent_context *ev,
+ const char *location)
+{
+ tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
+
+ if (ev->wrapper.glue == NULL) {
+ return;
+ }
+
+ if (ev->wrapper.glue->main_ev == NULL) {
+ return;
+ }
+
+ ev->wrapper.glue->ops->after_use(ev->wrapper.glue->wrap_ev,
+ ev->wrapper.glue->private_state,
+ ev->wrapper.glue->main_ev,
+ location);
+}
+
+bool tevent_context_same_loop(struct tevent_context *ev1,
+ struct tevent_context *ev2)
+{
+ struct tevent_context *main_ev1 = tevent_wrapper_main_ev(ev1);
+ struct tevent_context *main_ev2 = tevent_wrapper_main_ev(ev2);
+
+ if (main_ev1 == NULL) {
+ return false;
+ }
+
+ if (main_ev1 == main_ev2) {
+ return true;
+ }
+
+ return false;
+}
diff --git a/lib/tevent/wscript b/lib/tevent/wscript
index 94d190f3b605..2395ead9aa93 100644
--- a/lib/tevent/wscript
+++ b/lib/tevent/wscript
@@ -77,7 +77,7 @@ def build(bld):
bld.RECURSE('lib/talloc')
SRC = '''tevent.c tevent_debug.c tevent_fd.c tevent_immediate.c
- tevent_queue.c tevent_req.c
+ tevent_queue.c tevent_req.c tevent_wrapper.c
tevent_poll.c tevent_threads.c
tevent_signal.c tevent_standard.c tevent_timed.c tevent_util.c tevent_wakeup.c'''
--
2.17.1
From 30d5751927f380f6f4896d92fc4c6da58e8e5566 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 16 Jun 2018 14:12:01 +0200
Subject: [PATCH 23/37] tevent: add a simple wrapper test
This checks that for all supported event types the before and after
handlers are called.
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
lib/tevent/testsuite.c | 356 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 356 insertions(+)
diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index dba8f5895f76..946dea53532b 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -696,6 +696,358 @@ static bool test_event_fd2(struct torture_context *tctx,
return true;
}
+struct test_wrapper_state {
+ struct torture_context *tctx;
+ int num_events;
+ int num_wrap_handlers;
+};
+
+static bool test_wrapper_before_use(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+ return true;
+}
+
+static void test_wrapper_after_use(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_before_fd_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_after_fd_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_before_timer_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_timer *te,
+ struct timeval requested_time,
+ struct timeval trigger_time,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_after_timer_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_timer *te,
+ struct timeval requested_time,
+ struct timeval trigger_time,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_before_immediate_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_immediate *im,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_after_immediate_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_immediate *im,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_before_signal_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static void test_wrapper_after_signal_handler(struct tevent_context *wrap_ev,
+ void *private_data,
+ struct tevent_context *main_ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ const char *handler_name,
+ const char *location)
+{
+ struct test_wrapper_state *state =
+ talloc_get_type_abort(private_data,
+ struct test_wrapper_state);
+
+ torture_comment(state->tctx, "%s\n", __func__);
+ state->num_wrap_handlers++;
+}
+
+static const struct tevent_wrapper_ops test_wrapper_ops = {
+ .name = "test_wrapper",
+ .before_use = test_wrapper_before_use,
+ .after_use = test_wrapper_after_use,
+ .before_fd_handler = test_wrapper_before_fd_handler,
+ .after_fd_handler = test_wrapper_after_fd_handler,
+ .before_timer_handler = test_wrapper_before_timer_handler,
+ .after_timer_handler = test_wrapper_after_timer_handler,
+ .before_immediate_handler = test_wrapper_before_immediate_handler,
+ .after_immediate_handler = test_wrapper_after_immediate_handler,
+ .before_signal_handler = test_wrapper_before_signal_handler,
+ .after_signal_handler = test_wrapper_after_signal_handler,
+};
+
+static void test_wrapper_timer_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv,
+ void *private_data)
+{
+ struct test_wrapper_state *state =
+ (struct test_wrapper_state *)private_data;
+
+
+ torture_comment(state->tctx, "timer handler\n");
+
+ state->num_events++;
+ talloc_free(te);
+ return;
+}
+
+static void test_wrapper_fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ unsigned short fd_flags,
+ void *private_data)
+{
+ struct test_wrapper_state *state =
+ (struct test_wrapper_state *)private_data;
+
+ torture_comment(state->tctx, "fd handler\n");
+
+ state->num_events++;
+ talloc_free(fde);
+ return;
+}
+
+static void test_wrapper_immediate_handler(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct test_wrapper_state *state =
+ (struct test_wrapper_state *)private_data;
+
+ state->num_events++;
+ talloc_free(im);
+
+ torture_comment(state->tctx, "immediate handler\n");
+ return;
+}
+
+static void test_wrapper_signal_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ struct test_wrapper_state *state =
+ (struct test_wrapper_state *)private_data;
+
+ torture_comment(state->tctx, "signal handler\n");
+
+ state->num_events++;
+ talloc_free(se);
+ return;
+}
+
+static bool test_wrapper(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct test_wrapper_state *state = NULL;
+ int sock[2] = { -1, -1};
+ uint8_t c = 0;
+ const int num_events = 4;
+ const char *backend = (const char *)test_data;
+ struct tevent_context *ev = NULL;
+ struct tevent_context *wrap_ev = NULL;
+ struct tevent_fd *fde = NULL;
+ struct tevent_timer *te = NULL;
+ struct tevent_signal *se = NULL;
+ struct tevent_immediate *im = NULL;
+ int ret;
+ bool ok = false;
+ bool ret2;
+
+ ev = tevent_context_init_byname(tctx, backend);
+ if (ev == NULL) {
+ torture_skip(tctx, talloc_asprintf(tctx,
+ "event backend '%s' not supported\n",
+ backend));
+ return true;
+ }
+
+ tevent_set_debug_stderr(ev);
+ torture_comment(tctx, "tevent backend '%s'\n", backend);
+
+ wrap_ev = tevent_context_wrapper_create(
+ ev, ev, &test_wrapper_ops, &state, struct test_wrapper_state);
+ torture_assert_not_null_goto(tctx, wrap_ev, ok, done,
+ "tevent_context_wrapper_create failed\n");
+ *state = (struct test_wrapper_state) {
+ .tctx = tctx,
+ };
+
+ ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
+ torture_assert_goto(tctx, ret == 0, ok, done, "socketpair failed\n");
+
+ te = tevent_add_timer(wrap_ev, wrap_ev,
+ timeval_current_ofs(0, 0),
+ test_wrapper_timer_handler, state);
+ torture_assert_not_null_goto(tctx, te, ok, done,
+ "tevent_add_timer failed\n");
+
+ fde = tevent_add_fd(wrap_ev, wrap_ev,
+ sock[1],
+ TEVENT_FD_READ,
+ test_wrapper_fd_handler,
+ state);
+ torture_assert_not_null_goto(tctx, fde, ok, done,
+ "tevent_add_fd failed\n");
+
+ im = tevent_create_immediate(wrap_ev);
+ torture_assert_not_null_goto(tctx, im, ok, done,
+ "tevent_create_immediate failed\n");
+
+ se = tevent_add_signal(wrap_ev, wrap_ev,
+ SIGUSR1,
+ 0,
+ test_wrapper_signal_handler,
+ state);
+ torture_assert_not_null_goto(tctx, se, ok, done,
+ "tevent_add_signal failed\n");
+
+ do_write(sock[0], &c, 1);
+ kill(getpid(), SIGUSR1);
+ tevent_schedule_immediate(im,
+ wrap_ev,
+ test_wrapper_immediate_handler,
+ state);
+
+ ret2 = tevent_context_push_use(wrap_ev);
+ torture_assert_goto(tctx, ret2, ok, done, "tevent_context_push_use(wrap_ev) failed\n");
+ ret2 = tevent_context_push_use(ev);
+ torture_assert_goto(tctx, ret2, ok, pop_use, "tevent_context_push_use(ev) failed\n");
+ tevent_context_pop_use(ev);
+ tevent_context_pop_use(wrap_ev);
+
+ ret = tevent_loop_wait(ev);
+ torture_assert_int_equal_goto(tctx, ret, 0, ok, done, "tevent_loop_wait failed\n");
+
+ torture_comment(tctx, "Num events: %d\n", state->num_events);
+ torture_comment(tctx, "Num wrap handlers: %d\n",
+ state->num_wrap_handlers);
+
+ torture_assert_int_equal_goto(tctx, state->num_events, num_events, ok, done,
+ "Wrong event count\n");
+ torture_assert_int_equal_goto(tctx, state->num_wrap_handlers,
+ num_events*2+2,
+ ok, done, "Wrong wrapper count\n");
+
+ ok = true;
+
+done:
+ TALLOC_FREE(wrap_ev);
+ TALLOC_FREE(ev);
+
+ if (sock[0] != -1) {
+ close(sock[0]);
+ }
+ if (sock[1] != -1) {
+ close(sock[1]);
+ }
+ return ok;
+pop_use:
+ tevent_context_pop_use(wrap_ev);
+ goto done;
+}
+
#ifdef HAVE_PTHREAD
static pthread_mutex_t threaded_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -1280,6 +1632,10 @@ struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
"fd2",
test_event_fd2,
(const void *)list[i]);
+ torture_suite_add_simple_tcase_const(backend_suite,
+ "wrapper",
+ test_wrapper,
+ (const void *)list[i]);
torture_suite_add_suite(suite, backend_suite);
}
--
2.17.1
From 4ee9a22c065d6078d9d77047654e6465c723bac0 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 16 Jun 2018 16:55:44 +0200
Subject: [PATCH 24/37] tevent: add a test that frees wrapper_ev with pending
events
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
lib/tevent/testsuite.c | 157 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 157 insertions(+)
diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index 946dea53532b..b0f58efd0938 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -1048,6 +1048,159 @@ pop_use:
goto done;
}
+static void test_free_wrapper_signal_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ struct torture_context *tctx =
+ talloc_get_type_abort(private_data,
+ struct torture_context);
+
+ torture_comment(tctx, "signal handler\n");
+
+ talloc_free(se);
+
+ /*
+ * signal handlers have highest priority in tevent, so this signal
+ * handler will always be started before the other handlers
+ * below. Freeing the (wrapper) event context here tests that the
+ * wrapper implementation correclty handles the wrapper ev going away
+ * with pending events.
+ */
+ talloc_free(ev);
+ return;
+}
+
+static void test_free_wrapper_fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ unsigned short fd_flags,
+ void *private_data)
+{
+ /*
+ * This should never be called as
+ * test_free_wrapper_signal_handler()
+ * already destroyed the wrapper tevent_context.
+ */
+ abort();
+}
+
+static void test_free_wrapper_immediate_handler(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ /*
+ * This should never be called as
+ * test_free_wrapper_signal_handler()
+ * already destroyed the wrapper tevent_context.
+ */
+ abort();
+}
+
+static void test_free_wrapper_timer_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv,
+ void *private_data)
+{
+ /*
+ * This should never be called as
+ * test_free_wrapper_signal_handler()
+ * already destroyed the wrapper tevent_context.
+ */
+ abort();
+}
+
+static bool test_free_wrapper(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct test_wrapper_state *state = NULL;
+ int sock[2] = { -1, -1};
+ uint8_t c = 0;
+ const char *backend = (const char *)test_data;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev = NULL;
+ struct tevent_context *wrap_ev = NULL;
+ struct tevent_fd *fde = NULL;
+ struct tevent_timer *te = NULL;
+ struct tevent_signal *se = NULL;
+ struct tevent_immediate *im = NULL;
+ int ret;
+ bool ok = false;
+
+ ev = tevent_context_init_byname(frame, backend);
+ if (ev == NULL) {
+ torture_skip(tctx, talloc_asprintf(tctx,
+ "event backend '%s' not supported\n",
+ backend));
+ return true;
+ }
+
+ tevent_set_debug_stderr(ev);
+ torture_comment(tctx, "tevent backend '%s'\n", backend);
+
+ wrap_ev = tevent_context_wrapper_create(
+ ev, ev, &test_wrapper_ops, &state, struct test_wrapper_state);
+ torture_assert_not_null_goto(tctx, wrap_ev, ok, done,
+ "tevent_context_wrapper_create failed\n");
+ *state = (struct test_wrapper_state) {
+ .tctx = tctx,
+ };
+
+ ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
+ torture_assert_goto(tctx, ret == 0, ok, done, "socketpair failed\n");
+
+ fde = tevent_add_fd(wrap_ev, frame,
+ sock[1],
+ TEVENT_FD_READ,
+ test_free_wrapper_fd_handler,
+ NULL);
+ torture_assert_not_null_goto(tctx, fde, ok, done,
+ "tevent_add_fd failed\n");
+
+ te = tevent_add_timer(wrap_ev, frame,
+ timeval_current_ofs(0, 0),
+ test_free_wrapper_timer_handler, NULL);
+ torture_assert_not_null_goto(tctx, te, ok, done,
+ "tevent_add_timer failed\n");
+
+ im = tevent_create_immediate(frame);
+ torture_assert_not_null_goto(tctx, im, ok, done,
+ "tevent_create_immediate failed\n");
+
+ se = tevent_add_signal(wrap_ev, frame,
+ SIGUSR1,
+ 0,
+ test_free_wrapper_signal_handler,
+ tctx);
+ torture_assert_not_null_goto(tctx, se, ok, done,
+ "tevent_add_signal failed\n");
+
+ do_write(sock[0], &c, 1);
+ kill(getpid(), SIGUSR1);
+ tevent_schedule_immediate(im,
+ wrap_ev,
+ test_free_wrapper_immediate_handler,
+ NULL);
+
+ ret = tevent_loop_wait(ev);
+ torture_assert_goto(tctx, ret == 0, ok, done, "tevent_loop_wait failed\n");
+
+ ok = true;
+
+done:
+ TALLOC_FREE(frame);
+
+ if (sock[0] != -1) {
+ close(sock[0]);
+ }
+ if (sock[1] != -1) {
+ close(sock[1]);
+ }
+ return ok;
+}
+
#ifdef HAVE_PTHREAD
static pthread_mutex_t threaded_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -1636,6 +1789,10 @@ struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
"wrapper",
test_wrapper,
(const void *)list[i]);
+ torture_suite_add_simple_tcase_const(backend_suite,
+ "free_wrapper",
+ test_free_wrapper,
+ (const void *)list[i]);
torture_suite_add_suite(suite, backend_suite);
}
--
2.17.1
From 528bce8e557720467c18caff4cb056cccd6a7cb1 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 2 May 2018 14:01:56 +0200
Subject: [PATCH 25/37] tevent: Add tevent_req_profile
This allows detailed reporting where a tevent_req spends its time
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
lib/tevent/ABI/tevent-0.9.36.sigs | 15 +++
lib/tevent/tevent.h | 185 +++++++++++++++++++++++++++
lib/tevent/tevent_internal.h | 19 +++
lib/tevent/tevent_req.c | 203 ++++++++++++++++++++++++++++++
4 files changed, 422 insertions(+)
diff --git a/lib/tevent/ABI/tevent-0.9.36.sigs b/lib/tevent/ABI/tevent-0.9.36.sigs
index ddb2c03b65c2..f6227db5c938 100644
--- a/lib/tevent/ABI/tevent-0.9.36.sigs
+++ b/lib/tevent/ABI/tevent-0.9.36.sigs
@@ -75,11 +75,25 @@ tevent_re_initialise: int (struct tevent_context *)
tevent_register_backend: bool (const char *, const struct tevent_ops *)
tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
tevent_req_received: void (struct tevent_req *)
tevent_req_reset_endtime: void (struct tevent_req *)
tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
@@ -87,6 +101,7 @@ tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
tevent_sa_info_queue_count: size_t (void)
tevent_set_abort_fn: void (void (*)(const char *))
tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
index d34a03093f36..aa6fe0de2020 100644
--- a/lib/tevent/tevent.h
+++ b/lib/tevent/tevent.h
@@ -1348,6 +1348,191 @@ bool tevent_req_is_error(struct tevent_req *req,
*/
void tevent_req_received(struct tevent_req *req);
+/**
+ * @brief Mark a tevent_req for profiling
+ *
+ * This will turn on profiling for this tevent_req an all subreqs that
+ * are directly started as helper requests off this
+ * tevent_req. subreqs are chained by walking up the talloc_parent
+ * hierarchy at a subreq's tevent_req_create. This means to get the
+ * profiling chain right the subreq that needs to be profiled as part
+ * of this tevent_req's profile must be a talloc child of the requests
+ * state variable.
+ *
+ * @param[in] req The request to do tracing for
+ *
+ * @return False if the profile could not be activated
+ */
+bool tevent_req_set_profile(struct tevent_req *req);
+
+struct tevent_req_profile;
+
+/**
+ * @brief Get the a request's profile for inspection
+ *
+ * @param[in] req The request to get the profile from
+ *
+ * @return The request's profile
+ */
+const struct tevent_req_profile *tevent_req_get_profile(
+ struct tevent_req *req);
+
+/**
+ * @brief Move the profile out of a request
+ *
+ * This function detaches the request's profile from the request, so
+ * that the profile can outlive the request in a _recv function.
+ *
+ * @param[in] req The request to move the profile out of
+ * @param[in] mem_ctx The new talloc context for the profile
+ *
+ * @return The moved profile
+ */
+
+struct tevent_req_profile *tevent_req_move_profile(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx);
+
+/**
+ * @brief Get a profile description
+ *
+ * @param[in] profile The profile to be queried
+ * @param[in] req_name The name of the request (state's name)
+ *
+ * "req_name" after this call is still in talloc-posession of "profile"
+ */
+void tevent_req_profile_get_name(const struct tevent_req_profile *profile,
+ const char **req_name);
+
+/**
+ * @brief Get a profile's start event data
+ *
+ * @param[in] profile The profile to be queried
+ * @param[in] start_location The location where this event started
+ * @param[in] start_time The time this event started
+ *
+ * "start_location" after this call is still in talloc-posession of "profile"
+ */
+void tevent_req_profile_get_start(const struct tevent_req_profile *profile,
+ const char **start_location,
+ struct timeval *start_time);
+
+/**
+ * @brief Get a profile's stop event data
+ *
+ * @param[in] profile The profile to be queried
+ * @param[in] stop_location The location where this event stopped
+ * @param[in] stop_time The time this event stopped
+ *
+ * "stop_location" after this call is still in talloc-posession of "profile"
+ */
+void tevent_req_profile_get_stop(const struct tevent_req_profile *profile,
+ const char **stop_location,
+ struct timeval *stop_time);
+
+/**
+ * @brief Get a profile's result data
+ *
+ * @param[in] pid The process where this profile was taken
+ * @param[in] state The status the profile's tevent_req finished with
+ * @param[in] user_error The user error of the profile's tevent_req
+ */
+void tevent_req_profile_get_status(const struct tevent_req_profile *profile,
+ pid_t *pid,
+ enum tevent_req_state *state,
+ uint64_t *user_error);
+
+/**
+ * @brief Retrieve the first subreq's profile from a profile
+ *
+ * @param[in] profile The profile to query
+ *
+ * @return The first tevent subreq's profile
+ */
+const struct tevent_req_profile *tevent_req_profile_get_subprofiles(
+ const struct tevent_req_profile *profile);
+
+/**
+ * @brief Walk the chain of subreqs
+ *
+ * @param[in] profile The subreq's profile to walk
+ *
+ * @return The next subprofile in the list
+ */
+const struct tevent_req_profile *tevent_req_profile_next(
+ const struct tevent_req_profile *profile);
+
+/**
+ * @brief Create a fresh tevent_req_profile
+ *
+ * @param[in] mem_ctx The talloc context to hang the fresh struct off
+ *
+ * @return The fresh struct
+ */
+struct tevent_req_profile *tevent_req_profile_create(TALLOC_CTX *mem_ctx);
+
+/**
+ * @brief Set a profile's name
+ *
+ * @param[in] profile The profile to set the name for
+ * @param[in] name The new name for the profile
+ *
+ * @return True if the internal talloc_strdup succeeded
+ */
+bool tevent_req_profile_set_name(struct tevent_req_profile *profile,
+ const char *name);
+
+/**
+ * @brief Set a profile's start event
+ *
+ * @param[in] profile The profile to set the start data for
+ * @param[in] start_location The new start location
+ * @param[in] start_time The new start time
+ *
+ * @return True if the internal talloc_strdup succeeded
+ */
+bool tevent_req_profile_set_start(struct tevent_req_profile *profile,
+ const char *start_location,
+ struct timeval start_time);
+
+/**
+ * @brief Set a profile's stop event
+ *
+ * @param[in] profile The profile to set the stop data for
+ * @param[in] stop_location The new stop location
+ * @param[in] stop_time The new stop time
+ *
+ * @return True if the internal talloc_strdup succeeded
+ */
+bool tevent_req_profile_set_stop(struct tevent_req_profile *profile,
+ const char *stop_location,
+ struct timeval stop_time);
+
+/**
+ * @brief Set a profile's exit status
+ *
+ * @param[in] profile The profile to set the exit status for
+ * @param[in] pid The process where this profile was taken
+ * @param[in] state The status the profile's tevent_req finished with
+ * @param[in] user_error The user error of the profile's tevent_req
+ */
+void tevent_req_profile_set_status(struct tevent_req_profile *profile,
+ pid_t pid,
+ enum tevent_req_state state,
+ uint64_t user_error);
+
+/**
+ * @brief Add a subprofile to a profile
+ *
+ * @param[in] parent_profile The profile to be modified
+ * @param[in] sub_profile The subreqs profile profile to be added
+ *
+ * "subreq" is talloc_move'ed into "parent_profile", so the talloc
+ * ownership of "sub_profile" changes
+ */
+
+void tevent_req_profile_append_sub(struct tevent_req_profile *parent_profile,
+ struct tevent_req_profile **sub_profile);
+
/**
* @brief Create a tevent subrequest at a given time.
*
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index 17c195816fae..5365fce35336 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -164,9 +164,28 @@ struct tevent_req {
*
*/
struct tevent_timer *timer;
+
+ /**
+ * @brief The place where profiling data is kept
+ */
+ struct tevent_req_profile *profile;
} internal;
};
+struct tevent_req_profile {
+ struct tevent_req_profile *prev, *next;
+ struct tevent_req_profile *parent;
+ const char *req_name;
+ pid_t pid;
+ const char *start_location;
+ struct timeval start_time;
+ const char *stop_location;
+ struct timeval stop_time;
+ enum tevent_req_state state;
+ uint64_t user_error;
+ struct tevent_req_profile *subprofiles;
+};
+
struct tevent_fd {
struct tevent_fd *prev, *next;
struct tevent_context *event_ctx;
diff --git a/lib/tevent/tevent_req.c b/lib/tevent/tevent_req.c
index 15754d361ae0..76e27b8f7e9a 100644
--- a/lib/tevent/tevent_req.c
+++ b/lib/tevent/tevent_req.c
@@ -65,6 +65,7 @@ struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
const char *location)
{
struct tevent_req *req;
+ struct tevent_req *parent;
void **ppdata = (void **)pdata;
void *data;
size_t payload;
@@ -103,6 +104,19 @@ struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
talloc_set_destructor(req, tevent_req_destructor);
+ parent = talloc_get_type(talloc_parent(mem_ctx), struct tevent_req);
+ if ((parent != NULL) && (parent->internal.profile != NULL)) {
+ bool ok = tevent_req_set_profile(req);
+
+ if (!ok) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+ req->internal.profile->parent = parent->internal.profile;
+ DLIST_ADD_END(parent->internal.profile->subprofiles,
+ req->internal.profile);
+ }
+
*ppdata = data;
return req;
}
@@ -148,6 +162,7 @@ static void tevent_req_finish(struct tevent_req *req,
enum tevent_req_state state,
const char *location)
{
+ struct tevent_req_profile *p;
/*
* make sure we do not timeout after
* the request was already finished
@@ -159,6 +174,20 @@ static void tevent_req_finish(struct tevent_req *req,
tevent_req_cleanup(req);
+ p = req->internal.profile;
+
+ if (p != NULL) {
+ p->stop_location = location;
+ p->stop_time = tevent_timeval_current();
+ p->state = state;
+ p->user_error = req->internal.error;
+
+ if (p->parent != NULL) {
+ talloc_steal(p->parent, p);
+ req->internal.profile = NULL;
+ }
+ }
+
_tevent_req_notify_callback(req, location);
}
@@ -363,3 +392,177 @@ void tevent_req_set_cleanup_fn(struct tevent_req *req, tevent_req_cleanup_fn fn)
req->private_cleanup.state = req->internal.state;
req->private_cleanup.fn = fn;
}
+
+static int tevent_req_profile_destructor(struct tevent_req_profile *p);
+
+bool tevent_req_set_profile(struct tevent_req *req)
+{
+ struct tevent_req_profile *p;
+
+ if (req->internal.profile != NULL) {
+ tevent_req_error(req, EINVAL);
+ return false;
+ }
+
+ p = tevent_req_profile_create(req);
+
+ if (tevent_req_nomem(p, req)) {
+ return false;
+ }
+
+ p->req_name = talloc_get_name(req->data);
+ p->start_location = req->internal.create_location;
+ p->start_time = tevent_timeval_current();
+
+ req->internal.profile = p;
+
+ return true;
+}
+
+static int tevent_req_profile_destructor(struct tevent_req_profile *p)
+{
+ if (p->parent != NULL) {
+ DLIST_REMOVE(p->parent->subprofiles, p);
+ p->parent = NULL;
+ }
+
+ while (p->subprofiles != NULL) {
+ p->subprofiles->parent = NULL;
+ DLIST_REMOVE(p->subprofiles, p->subprofiles);
+ }
+
+ return 0;
+}
+
+struct tevent_req_profile *tevent_req_move_profile(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx)
+{
+ return talloc_move(mem_ctx, &req->internal.profile);
+}
+
+const struct tevent_req_profile *tevent_req_get_profile(
+ struct tevent_req *req)
+{
+ return req->internal.profile;
+}
+
+void tevent_req_profile_get_name(const struct tevent_req_profile *profile,
+ const char **req_name)
+{
+ if (req_name != NULL) {
+ *req_name = profile->req_name;
+ }
+}
+
+void tevent_req_profile_get_start(const struct tevent_req_profile *profile,
+ const char **start_location,
+ struct timeval *start_time)
+{
+ if (start_location != NULL) {
+ *start_location = profile->start_location;
+ }
+ if (start_time != NULL) {
+ *start_time = profile->start_time;
+ }
+}
+
+void tevent_req_profile_get_stop(const struct tevent_req_profile *profile,
+ const char **stop_location,
+ struct timeval *stop_time)
+{
+ if (stop_location != NULL) {
+ *stop_location = profile->stop_location;
+ }
+ if (stop_time != NULL) {
+ *stop_time = profile->stop_time;
+ }
+}
+
+void tevent_req_profile_get_status(const struct tevent_req_profile *profile,
+ pid_t *pid,
+ enum tevent_req_state *state,
+ uint64_t *user_error)
+{
+ if (pid != NULL) {
+ *pid = profile->pid;
+ }
+ if (state != NULL) {
+ *state = profile->state;
+ }
+ if (user_error != NULL) {
+ *user_error = profile->user_error;
+ }
+}
+
+const struct tevent_req_profile *tevent_req_profile_get_subprofiles(
+ const struct tevent_req_profile *profile)
+{
+ return profile->subprofiles;
+}
+
+const struct tevent_req_profile *tevent_req_profile_next(
+ const struct tevent_req_profile *profile)
+{
+ return profile->next;
+}
+
+struct tevent_req_profile *tevent_req_profile_create(TALLOC_CTX *mem_ctx)
+{
+ struct tevent_req_profile *result;
+
+ result = talloc_zero(mem_ctx, struct tevent_req_profile);
+ if (result == NULL) {
+ return NULL;
+ }
+ talloc_set_destructor(result, tevent_req_profile_destructor);
+
+ return result;
+}
+
+bool tevent_req_profile_set_name(struct tevent_req_profile *profile,
+ const char *req_name)
+{
+ profile->req_name = talloc_strdup(profile, req_name);
+ return (profile->req_name != NULL);
+}
+
+bool tevent_req_profile_set_start(struct tevent_req_profile *profile,
+ const char *start_location,
+ struct timeval start_time)
+{
+ profile->start_time = start_time;
+
+ profile->start_location = talloc_strdup(profile, start_location);
+ return (profile->start_location != NULL);
+}
+
+bool tevent_req_profile_set_stop(struct tevent_req_profile *profile,
+ const char *stop_location,
+ struct timeval stop_time)
+{
+ profile->stop_time = stop_time;
+
+ profile->stop_location = talloc_strdup(profile, stop_location);
+ return (profile->stop_location != NULL);
+}
+
+void tevent_req_profile_set_status(struct tevent_req_profile *profile,
+ pid_t pid,
+ enum tevent_req_state state,
+ uint64_t user_error)
+{
+ profile->pid = pid;
+ profile->state = state;
+ profile->user_error = user_error;
+}
+
+void tevent_req_profile_append_sub(struct tevent_req_profile *parent_profile,
+ struct tevent_req_profile **sub_profile)
+{
+ struct tevent_req_profile *sub;
+
+ sub = talloc_move(parent_profile, sub_profile);
+
+ sub->parent = parent_profile;
+ DLIST_ADD_END(parent_profile->subprofiles, sub);
+}
--
2.17.1
From e4b3510b6ba8098da65bde47a45f1038cdbe1e23 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 14 Aug 2014 21:51:09 +0200
Subject: [PATCH 26/37] tevent: version 0.9.37
* simplify "poll" and "poll_mt" backends
* make tevent_abort() reachable for backends
* add tevent_common_invoke_*_handler() functions
* add tevent_context_same_loop() function
* add tevent_context_wrapper_create() infrastructure
* add tevent_req_profile infrastructure
Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
lib/tevent/ABI/tevent-0.9.36.sigs | 26 ------
lib/tevent/ABI/tevent-0.9.37.sigs | 126 ++++++++++++++++++++++++++++++
lib/tevent/wscript | 2 +-
3 files changed, 127 insertions(+), 27 deletions(-)
create mode 100644 lib/tevent/ABI/tevent-0.9.37.sigs
diff --git a/lib/tevent/ABI/tevent-0.9.36.sigs b/lib/tevent/ABI/tevent-0.9.36.sigs
index f6227db5c938..8a579c8ee7d0 100644
--- a/lib/tevent/ABI/tevent-0.9.36.sigs
+++ b/lib/tevent/ABI/tevent-0.9.36.sigs
@@ -1,9 +1,6 @@
_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
-_tevent_context_pop_use: void (struct tevent_context *, const char *)
-_tevent_context_push_use: bool (struct tevent_context *, const char *)
-_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
_tevent_loop_once: int (struct tevent_context *, const char *)
_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
@@ -20,14 +17,12 @@ _tevent_req_notify_callback: void (struct tevent_req *, const char *)
_tevent_req_oom: void (struct tevent_req *, const char *)
_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
-tevent_abort: void (struct tevent_context *, const char *)
tevent_backend_list: const char **(TALLOC_CTX *)
tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
-tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
tevent_common_check_signal: int (struct tevent_context *)
tevent_common_context_destructor: int (struct tevent_context *)
tevent_common_fd_destructor: int (struct tevent_fd *)
@@ -35,10 +30,6 @@ tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
tevent_common_have_events: bool (struct tevent_context *)
-tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
-tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
-tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
-tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
tevent_common_loop_immediate: bool (struct tevent_context *)
tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
tevent_common_loop_wait: int (struct tevent_context *, const char *)
@@ -50,8 +41,6 @@ tevent_common_wakeup_init: int (struct tevent_context *)
tevent_context_init: struct tevent_context *(TALLOC_CTX *)
tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
-tevent_context_is_wrapper: bool (struct tevent_context *)
-tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
tevent_fd_get_flags: uint16_t (struct tevent_fd *)
tevent_fd_set_auto_close: void (struct tevent_fd *)
@@ -75,25 +64,11 @@ tevent_re_initialise: int (struct tevent_context *)
tevent_register_backend: bool (const char *, const struct tevent_ops *)
tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
-tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
tevent_req_is_in_progress: bool (struct tevent_req *)
-tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
-tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
-tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
-tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
-tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
-tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
-tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
-tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
-tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
-tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
-tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
-tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
-tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
tevent_req_received: void (struct tevent_req *)
tevent_req_reset_endtime: void (struct tevent_req *)
tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
@@ -101,7 +76,6 @@ tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
-tevent_req_set_profile: bool (struct tevent_req *)
tevent_sa_info_queue_count: size_t (void)
tevent_set_abort_fn: void (void (*)(const char *))
tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
diff --git a/lib/tevent/ABI/tevent-0.9.37.sigs b/lib/tevent/ABI/tevent-0.9.37.sigs
new file mode 100644
index 000000000000..f6227db5c938
--- /dev/null
+++ b/lib/tevent/ABI/tevent-0.9.37.sigs
@@ -0,0 +1,126 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_abort: void (struct tevent_context *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_double_free: void (TALLOC_CTX *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
+tevent_common_invoke_fd_handler: int (struct tevent_fd *, uint16_t, bool *)
+tevent_common_invoke_immediate_handler: int (struct tevent_immediate *, bool *)
+tevent_common_invoke_signal_handler: int (struct tevent_signal *, int, int, void *, bool *)
+tevent_common_invoke_timer_handler: int (struct tevent_timer *, struct timeval, bool *)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_threaded_activate_immediate: void (struct tevent_context *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_fd: int (int)
+tevent_common_wakeup_init: int (struct tevent_context *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_num_signals: size_t (void)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_entry_untrigger: void (struct tevent_queue_entry *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_queue_wait_recv: bool (struct tevent_req *)
+tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_get_profile: const struct tevent_req_profile *(struct tevent_req *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_move_profile: struct tevent_req_profile *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_profile_append_sub: void (struct tevent_req_profile *, struct tevent_req_profile **)
+tevent_req_profile_create: struct tevent_req_profile *(TALLOC_CTX *)
+tevent_req_profile_get_name: void (const struct tevent_req_profile *, const char **)
+tevent_req_profile_get_start: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_status: void (const struct tevent_req_profile *, pid_t *, enum tevent_req_state *, uint64_t *)
+tevent_req_profile_get_stop: void (const struct tevent_req_profile *, const char **, struct timeval *)
+tevent_req_profile_get_subprofiles: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_next: const struct tevent_req_profile *(const struct tevent_req_profile *)
+tevent_req_profile_set_name: bool (struct tevent_req_profile *, const char *)
+tevent_req_profile_set_start: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_profile_set_status: void (struct tevent_req_profile *, pid_t, enum tevent_req_state, uint64_t)
+tevent_req_profile_set_stop: bool (struct tevent_req_profile *, const char *, struct timeval)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_reset_endtime: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_req_set_profile: bool (struct tevent_req *)
+tevent_sa_info_queue_count: size_t (void)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
+tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_update_timer: void (struct tevent_timer *, struct timeval)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/lib/tevent/wscript b/lib/tevent/wscript
index 2395ead9aa93..54330d27cadb 100644
--- a/lib/tevent/wscript
+++ b/lib/tevent/wscript
@@ -1,7 +1,7 @@
#!/usr/bin/env python
APPNAME = 'tevent'
-VERSION = '0.9.36'
+VERSION = '0.9.37'
blddir = 'bin'
--
2.17.1
From 1716e501245474e23e79e01325e90e6cbeb1acb3 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 2 May 2018 13:54:42 +0200
Subject: [PATCH 27/37] lib: Multi-line a long line in wscript_build
Why? I'll add another file in a later commit
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
lib/util/wscript_build | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/lib/util/wscript_build b/lib/util/wscript_build
index ded91f67d9fb..793e24669c95 100644
--- a/lib/util/wscript_build
+++ b/lib/util/wscript_build
@@ -162,7 +162,11 @@ else:
)
bld.SAMBA_LIBRARY('tevent-util',
- source='tevent_unix.c tevent_ntstatus.c tevent_werror.c',
+ source='''
+ tevent_unix.c
+ tevent_ntstatus.c
+ tevent_werror.c
+ ''',
local_include=False,
public_deps='tevent samba-errors',
public_headers='tevent_ntstatus.h tevent_unix.h tevent_werror.h',
--
2.17.1
From 77a343ee761456f458bf7be757c2bc22a00a5226 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 2 May 2018 13:59:57 +0200
Subject: [PATCH 28/37] lib: Add tevent_req_profile helpers
Print and marshall/unmarshall tevent_req_profile structs
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
lib/util/tevent_req_profile.c | 519 ++++++++++++++++++++++++++++++++++
lib/util/tevent_req_profile.h | 50 ++++
lib/util/wscript_build | 1 +
3 files changed, 570 insertions(+)
create mode 100644 lib/util/tevent_req_profile.c
create mode 100644 lib/util/tevent_req_profile.h
diff --git a/lib/util/tevent_req_profile.c b/lib/util/tevent_req_profile.c
new file mode 100644
index 000000000000..522741c5ede8
--- /dev/null
+++ b/lib/util/tevent_req_profile.c
@@ -0,0 +1,519 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Helpers around tevent_req_profile
+ *
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * ** NOTE! The following LGPL license applies to the tevent
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include <tevent.h>
+#include "lib/util/tevent_req_profile.h"
+#include "lib/util/time_basic.h"
+#include "lib/util/memory.h"
+
+int tevent_req_profile_print(const struct tevent_req_profile *profile,
+ FILE *fp,
+ unsigned indent,
+ unsigned max_indent)
+{
+ struct timeval start, stop, diff;
+ struct timeval_buf start_buf, stop_buf;
+ const char *req_name = NULL;
+ const char *start_location = NULL;
+ const char *stop_location = NULL;
+ pid_t pid;
+ enum tevent_req_state state;
+ const char *state_buf = NULL;
+ uint64_t user_error;
+ const struct tevent_req_profile *sub = NULL;
+ int ret;
+
+ tevent_req_profile_get_name(profile, &req_name);
+
+ tevent_req_profile_get_start(profile, &start_location, &start);
+ timeval_str_buf(&start, false, true, &start_buf);
+
+ tevent_req_profile_get_stop(profile, &stop_location, &stop);
+ timeval_str_buf(&stop, false, true, &stop_buf);
+
+ diff = tevent_timeval_until(&start, &stop);
+
+ tevent_req_profile_get_status(profile, &pid, &state, &user_error);
+
+ switch(state) {
+ case TEVENT_REQ_INIT:
+ state_buf = "TEVENT_REQ_INIT";
+ break;
+ case TEVENT_REQ_IN_PROGRESS:
+ state_buf = "TEVENT_REQ_IN_PROGRESS";
+ break;
+ case TEVENT_REQ_DONE:
+ state_buf = "TEVENT_REQ_DONE";
+ break;
+ case TEVENT_REQ_USER_ERROR:
+ state_buf = "TEVENT_REQ_USER_ERROR";
+ break;
+ case TEVENT_REQ_TIMED_OUT:
+ state_buf = "TEVENT_REQ_TIMED_OUT";
+ break;
+ case TEVENT_REQ_NO_MEMORY:
+ state_buf = "TEVENT_REQ_NO_MEMORY";
+ break;
+ case TEVENT_REQ_RECEIVED:
+ state_buf = "TEVENT_REQ_RECEIVED";
+ break;
+ default:
+ state_buf = "unknown";
+ break;
+ }
+
+ ret = fprintf(
+ fp,
+ "%*s[%s] %s [%s] %s [%s] [%ju.%.6ju] -> %s (%d %"PRIu64"))\n",
+ indent,
+ "",
+ req_name,
+ start_location,
+ start_buf.buf,
+ stop_location,
+ stop_buf.buf,
+ (uintmax_t)diff.tv_sec,
+ (uintmax_t)diff.tv_usec,
+ state_buf,
+ (int)state,
+ user_error);
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ indent += 1;
+
+ if (indent >= max_indent) {
+ return ret;
+ }
+
+ for (sub = tevent_req_profile_get_subprofiles(profile);
+ sub != NULL;
+ sub = tevent_req_profile_next(sub)) {
+ int subret;
+
+ subret = tevent_req_profile_print(sub, fp, indent, max_indent);
+ if (subret < 0) {
+ return subret;
+ }
+
+ ret += subret;
+
+ if (ret < subret) {
+ /* overflow */
+ return -1;
+ }
+ }
+
+ return ret;
+}
+
+char *tevent_req_profile_string(const struct tevent_req_profile *profile,
+ TALLOC_CTX *mem_ctx,
+ unsigned indent,
+ unsigned max_indent)
+{
+ FILE *fp = NULL;
+ char *buf = NULL;
+ size_t buflen = 0;
+ char *result = NULL;
+ int ret;
+
+ fp = open_memstream(&buf, &buflen);
+ if (fp == NULL) {
+ return NULL;
+ }
+
+ ret = tevent_req_profile_print(profile, fp, 0, max_indent);
+ if (ret < 0) {
+ goto done;
+ }
+
+ ret = fclose(fp);
+ if (ret != 0) {
+ goto done;
+ }
+
+ /*
+ * A FILE* from open_memstream maintains the 0-byte at the end
+ * beyond the reported length.
+ */
+ result = talloc_memdup(mem_ctx, buf, buflen+1);
+
+done:
+ SAFE_FREE(buf);
+ return result;
+}
+
+static ssize_t tevent_req_profile_pack_one(
+ const struct tevent_req_profile *profile,
+ uint8_t *buf,
+ size_t buflen)
+{
+ const char *req_name = NULL;
+ const char *start_location = NULL;
+ const char *stop_location = NULL;
+ struct timeval start_time, stop_time;
+ pid_t pid;
+ enum tevent_req_state state;
+ uint64_t user_error;
+ size_t pack_len, len;
+ int ret;
+
+ tevent_req_profile_get_name(profile, &req_name);
+ tevent_req_profile_get_start(profile, &start_location, &start_time);
+ tevent_req_profile_get_stop(profile, &stop_location, &stop_time);
+ tevent_req_profile_get_status(profile, &pid, &state, &user_error);
+
+ len = strlen(req_name)+1;
+ if (buflen >= len) {
+ memcpy(buf, req_name, len);
+ buf += len;
+ buflen -= len;
+ }
+
+ pack_len = len;
+
+ len = strlen(start_location)+1;
+ pack_len += len;
+ if (pack_len < len) {
+ return -1; /* overflow */
+ }
+
+ if (buflen >= len) {
+ memcpy(buf, start_location, len);
+ buf += len;
+ buflen -= len;
+ }
+
+ len = strlen(stop_location)+1;
+ pack_len += len;
+ if (pack_len < len) {
+ return -1; /* overflow */
+ }
+
+ if (buflen >= len) {
+ memcpy(buf, stop_location, len);
+ buf += len;
+ buflen -= len;
+ }
+
+ ret = snprintf((char *)buf,
+ buflen,
+ "%ju %ju %ju %ju %d %d %"PRIu64"",
+ (uintmax_t)start_time.tv_sec,
+ (uintmax_t)start_time.tv_usec,
+ (uintmax_t)stop_time.tv_sec,
+ (uintmax_t)stop_time.tv_usec,
+ (int)pid,
+ (int)state,
+ user_error);
+ if (ret < 0) {
+ return -1;
+ }
+
+ /*
+ * Take care of the trailing 0. No overflow check, this would
+ * be a VERY small number of bits for "int".
+ */
+ ret += 1;
+
+ pack_len += ret;
+
+ return pack_len;
+}
+
+ssize_t tevent_req_profile_pack(
+ const struct tevent_req_profile *profile,
+ uint8_t *buf,
+ size_t buflen)
+{
+ const struct tevent_req_profile *sub = NULL;
+ size_t num_sub;
+ ssize_t pack_len, profile_len;
+ int ret;
+
+ num_sub = 0;
+ pack_len = 0;
+
+ for (sub = tevent_req_profile_get_subprofiles(profile);
+ sub != NULL;
+ sub = tevent_req_profile_next(sub)) {
+ num_sub += 1;
+ }
+
+ ret = snprintf((char *)buf, buflen, "%zu ", num_sub);
+ if (ret < 0) {
+ return -1;
+ }
+
+ if (buflen > (size_t)ret) {
+ buf += ret;
+ buflen -= ret;
+ }
+
+ pack_len = ret;
+
+ profile_len = tevent_req_profile_pack_one(profile, buf, buflen);
+ if (profile_len == -1) {
+ return -1;
+ }
+
+ if (buflen >= (size_t)profile_len) {
+ buf += profile_len;
+ buflen -= profile_len;
+ }
+
+ pack_len += profile_len;
+ if (pack_len < profile_len) {
+ return -1; /* overflow */
+ }
+
+ for (sub = tevent_req_profile_get_subprofiles(profile);
+ sub != NULL;
+ sub = tevent_req_profile_next(sub)) {
+
+ profile_len = tevent_req_profile_pack(sub, buf, buflen);
+ if (profile_len == -1) {
+ return -1;
+ }
+
+ if (buflen >= (size_t)profile_len) {
+ buf += profile_len;
+ buflen -= profile_len;
+ }
+
+ pack_len += profile_len;
+ if (pack_len < profile_len) {
+ return -1; /* overflow */
+ }
+ }
+
+ return pack_len;
+}
+
+static bool parse_uintmax(const char *buf,
+ char delimiter,
+ uintmax_t *presult,
+ char **p_endptr)
+{
+ uintmax_t result;
+ char *endptr;
+
+ result = strtoumax(buf, &endptr, 10);
+ if ((result == UINTMAX_MAX) && (errno == ERANGE)) {
+ return false;
+ }
+ if (*endptr != delimiter) {
+ return false;
+ }
+
+ *presult = result;
+ *p_endptr = endptr+1;
+
+ return true;
+}
+
+static ssize_t tevent_req_profile_unpack_one(
+ const uint8_t *buf,
+ size_t buflen,
+ struct tevent_req_profile *profile)
+{
+ const char *orig_buf = (const char *)buf;
+ const char *req_name = NULL;
+ const char *start_location = NULL;
+ const char *stop_location = NULL;
+ uintmax_t start_sec, start_usec, stop_sec, stop_usec, pid, state;
+ uintmax_t user_error;
+ char *next = NULL;
+ size_t len;
+ bool ok;
+
+ if (buflen == 0) {
+ return -1;
+ }
+ if (buf[buflen-1] != '\0') {
+ return -1;
+ }
+
+ req_name = (const char *)buf;
+ len = strlen(req_name)+1;
+
+ buf += len;
+ buflen -= len;
+ if (buflen == 0) {
+ return -1;
+ }
+
+ start_location = (const char *)buf;
+ len = strlen(start_location)+1;
+
+ buf += len;
+ buflen -= len;
+ if (buflen == 0) {
+ return -1;
+ }
+
+ stop_location = (const char *)buf;
+ len = strlen(stop_location)+1;
+
+ buf += len;
+ buflen -= len;
+ if (buflen == 0) {
+ return -1;
+ }
+
+ ok = parse_uintmax((const char *)buf, ' ', &start_sec, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &start_usec, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &stop_sec, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &stop_usec, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &pid, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, ' ', &state, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = parse_uintmax(next, '\0', &user_error, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = tevent_req_profile_set_name(profile, req_name);
+ if (!ok) {
+ return -1;
+ }
+
+ ok = tevent_req_profile_set_start(
+ profile,
+ start_location,
+ (struct timeval){ .tv_sec=start_sec, .tv_usec=start_usec });
+ if (!ok) {
+ return -1;
+ }
+
+ ok = tevent_req_profile_set_stop(
+ profile,
+ stop_location,
+ (struct timeval){ .tv_sec=stop_sec, .tv_usec=stop_usec });
+ if (!ok) {
+ return -1;
+ }
+
+ tevent_req_profile_set_status(
+ profile,
+ pid,
+ (enum tevent_req_state)state,
+ user_error);
+
+ return next - orig_buf;
+}
+
+ssize_t tevent_req_profile_unpack(
+ const uint8_t *buf,
+ size_t buflen,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_req_profile **p_profile)
+{
+ const uint8_t *orig_buf = buf;
+ struct tevent_req_profile *profile = NULL;
+ uintmax_t i, num_subprofiles;
+ char *next = NULL;
+ bool ok;
+ ssize_t len;
+
+ errno = 0;
+
+ if (buf[buflen-1] != '\0') {
+ return -1;
+ }
+
+ ok = parse_uintmax((const char *)buf, ' ', &num_subprofiles, &next);
+ if (!ok) {
+ return -1;
+ }
+
+ len = (next - (const char *)buf);
+
+ buf += len;
+ buflen -= len;
+
+ profile = tevent_req_profile_create(mem_ctx);
+ if (profile == NULL) {
+ return -1;
+ }
+
+ len = tevent_req_profile_unpack_one(buf, buflen, profile);
+ if (len == -1) {
+ TALLOC_FREE(profile);
+ return -1;
+ }
+
+ buf += len;
+ buflen -= len;
+
+ for (i=0; i<num_subprofiles; i++) {
+ struct tevent_req_profile *subprofile;
+
+ len = tevent_req_profile_unpack(
+ buf,
+ buflen,
+ profile,
+ &subprofile);
+ if (len == -1) {
+ TALLOC_FREE(profile);
+ return -1;
+ }
+ buf += len;
+ buflen -= len;
+
+ tevent_req_profile_append_sub(profile, &subprofile);
+ }
+
+ *p_profile = profile;
+
+ return buf - orig_buf;
+}
diff --git a/lib/util/tevent_req_profile.h b/lib/util/tevent_req_profile.h
new file mode 100644
index 000000000000..00dbc5a9cc20
--- /dev/null
+++ b/lib/util/tevent_req_profile.h
@@ -0,0 +1,50 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Helpers around tevent_req_profile
+ *
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * ** NOTE! The following LGPL license applies to the tevent
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIB_UTIL_TEVENT_REQ_PROFILE_UNPACK
+#define __LIB_UTIL_TEVENT_REQ_PROFILE_UNPACK
+
+#include "replace.h"
+#include <tevent.h>
+
+int tevent_req_profile_print(const struct tevent_req_profile *profile,
+ FILE *fp,
+ unsigned indent,
+ unsigned max_indent);
+char *tevent_req_profile_string(const struct tevent_req_profile *profile,
+ TALLOC_CTX *mem_ctx,
+ unsigned indent,
+ unsigned max_indent);
+ssize_t tevent_req_profile_pack(
+ const struct tevent_req_profile *profile,
+ uint8_t *buf,
+ size_t buflen);
+ssize_t tevent_req_profile_unpack(
+ const uint8_t *buf,
+ size_t buflen,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_req_profile **p_profile);
+
+#endif
diff --git a/lib/util/wscript_build b/lib/util/wscript_build
index 793e24669c95..8fc402062fbd 100644
--- a/lib/util/wscript_build
+++ b/lib/util/wscript_build
@@ -166,6 +166,7 @@ else:
tevent_unix.c
tevent_ntstatus.c
tevent_werror.c
+ tevent_req_profile.c
''',
local_include=False,
public_deps='tevent samba-errors',
--
2.17.1
From 8af878e2c5154edb5696d463b1f879bf42f014a0 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 2 May 2018 14:02:18 +0200
Subject: [PATCH 29/37] torture: Test tevent_req_profile
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
lib/tevent/test_req.c | 277 ++++++++++++++++++++++++++++
source4/torture/local/local.c | 1 +
source4/torture/local/wscript_build | 1 +
3 files changed, 279 insertions(+)
create mode 100644 lib/tevent/test_req.c
diff --git a/lib/tevent/test_req.c b/lib/tevent/test_req.c
new file mode 100644
index 000000000000..565ef31024fb
--- /dev/null
+++ b/lib/tevent/test_req.c
@@ -0,0 +1,277 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * testing of some tevent_req aspects
+ *
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * ** NOTE! The following LGPL license applies to the tevent
+ * ** library. This does NOT imply that all of Samba is released
+ * ** under the LGPL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "tevent.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/tevent_req_profile.h"
+#include "lib/util/time_basic.h"
+
+struct tevent_req_create_state {
+ uint8_t val;
+};
+
+static bool test_tevent_req_create(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct tevent_req *req;
+ struct tevent_req_create_state *state;
+
+ req = tevent_req_create(tctx, &state,
+ struct tevent_req_create_state);
+ torture_assert_not_null(tctx, req, "tevent_req_create failed\n");
+ torture_assert_int_equal(tctx, state->val, 0, "state not initialized\n");
+
+ TALLOC_FREE(req);
+
+ return true;
+}
+
+struct profile1_state {
+ uint8_t dummy;
+};
+
+static bool test_tevent_req_profile1(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct tevent_req *req;
+ struct profile1_state *state;
+ const struct tevent_req_profile *p1;
+ struct tevent_req_profile *p2;
+ struct timeval start, stop;
+ bool ok;
+ int cmp;
+
+ req = tevent_req_create(tctx, &state, struct profile1_state);
+ torture_assert_not_null(tctx, req, "tevent_req_create failed\n");
+
+ p1 = tevent_req_get_profile(req);
+ torture_assert(tctx, p1 == NULL, "profile not initialized to NULL\n");
+
+ ok = tevent_req_set_profile(req);
+ torture_assert(tctx, ok, "set_profile failed\n");
+
+ tevent_req_done(req);
+
+ p2 = tevent_req_move_profile(req, tctx);
+ torture_assert_not_null(tctx, p2, "get_profile failed\n");
+
+ /* Demonstrate sure "p2" outlives req */
+ TALLOC_FREE(req);
+
+ tevent_req_profile_get_start(p2, NULL, &start);
+ tevent_req_profile_get_stop(p2, NULL, &stop);
+
+ cmp = tevent_timeval_compare(&start, &stop);
+ torture_assert(tctx, cmp <= 0, "stop before start\n");
+
+ TALLOC_FREE(p2);
+
+ return true;
+}
+
+struct profile2_state {
+ uint8_t dummy;
+};
+
+static void profile2_done(struct tevent_req *subreq);
+
+static struct tevent_req *profile2_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev)
+{
+ struct tevent_req *req, *subreq;
+ struct profile2_state *state;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state, struct profile2_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ ok = tevent_req_set_profile(req);
+ if (!ok) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = tevent_wakeup_send(
+ state,
+ ev,
+ tevent_timeval_current_ofs(0, 1));
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, profile2_done, req);
+
+ return req;
+}
+
+static void profile2_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ bool ok;
+
+ ok = tevent_wakeup_recv(subreq);
+ if (!ok) {
+ tevent_req_oom(req);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static int profile2_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_req_profile **profile)
+{
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ return err;
+ }
+
+ *profile = tevent_req_move_profile(req, mem_ctx);
+
+ return 0;
+}
+
+static bool test_tevent_req_profile2(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ struct tevent_req_profile *p1 = NULL;
+ struct tevent_req_profile *p2 = NULL;
+ const char *str1, *str2;
+ struct timeval tv1, tv2;
+ pid_t pid1, pid2;
+ enum tevent_req_state state1, state2;
+ uint64_t err1, err2;
+ ssize_t pack_len;
+ int err;
+ bool ok;
+
+ ev = samba_tevent_context_init(tctx);
+ torture_assert_not_null(tctx, ev, "samba_tevent_context_init failed\n");
+
+ req = profile2_send(tctx, ev);
+ torture_assert_not_null(tctx, req, "profile2_send failed\n");
+
+ ok = tevent_req_poll_unix(req, ev, &err);
+ torture_assert(tctx, ok, "tevent_req_poll_unix failed\n");
+
+ err = profile2_recv(req, tctx, &p1);
+ torture_assert_int_equal(tctx, err, 0, "profile2_recv failed\n");
+
+ TALLOC_FREE(req);
+ TALLOC_FREE(ev);
+
+ tevent_req_profile_print(p1, stdout, 0, UINT_MAX);
+
+ pack_len = tevent_req_profile_pack(p1, NULL, 0);
+ torture_assert(tctx, pack_len>0, "profile_pack failed\n");
+
+ {
+ uint8_t buf[pack_len];
+ ssize_t unpack_len;
+
+ tevent_req_profile_pack(p1, buf, sizeof(buf));
+ dump_data(10, buf, sizeof(buf));
+
+ unpack_len = tevent_req_profile_unpack(
+ buf,
+ pack_len,
+ tctx,
+ &p2);
+ torture_assert_int_equal(tctx,
+ pack_len,
+ unpack_len,
+ "profile_unpack failed\n");
+ }
+
+ tevent_req_profile_print(p2, stdout, 0, UINT_MAX);
+
+ tevent_req_profile_get_name(p1, &str1);
+ tevent_req_profile_get_name(p2, &str2);
+ torture_assert_str_equal(tctx, str1, str2, "names differ\n");
+
+ tevent_req_profile_get_start(p1, &str1, &tv1);
+ tevent_req_profile_get_start(p2, &str2, &tv2);
+ torture_assert_str_equal(tctx, str1, str2, "start strings differ\n");
+ torture_assert(tctx,
+ tevent_timeval_compare(&tv1, &tv2) == 0,
+ "start times differ\n");
+
+ tevent_req_profile_get_stop(p1, &str1, &tv1);
+ tevent_req_profile_get_stop(p2, &str2, &tv2);
+ torture_assert_str_equal(tctx, str1, str2, "stop strings differ\n");
+ torture_assert(tctx,
+ tevent_timeval_compare(&tv1, &tv2) == 0,
+ "stop times differ\n");
+
+ tevent_req_profile_get_status(p1, &pid1, &state1, &err1);
+ tevent_req_profile_get_status(p2, &pid2, &state2, &err2);
+ torture_assert_int_equal(tctx, pid1, pid2, "pids differ\n");
+ torture_assert_int_equal(tctx, state1, state2, "states differ\n");
+ torture_assert_int_equal(tctx, err1, err2, "user errors differ\n");
+
+ str1 = tevent_req_profile_string(p1, p1, 0, UINT_MAX);
+ torture_assert_not_null(tctx, str1, "profile_string failed\n");
+ str2 = tevent_req_profile_string(p2, p2, 0, UINT_MAX);
+ torture_assert_not_null(tctx, str2, "profile_string failed\n");
+
+ torture_assert_str_equal(tctx, str1, str2, "result strings differ\n");
+
+ TALLOC_FREE(p1);
+ TALLOC_FREE(p2);
+
+ return true;
+}
+
+struct torture_suite *torture_local_tevent_req(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite;
+
+ suite = torture_suite_create(mem_ctx, "tevent_req");
+
+ torture_suite_add_simple_tcase_const(
+ suite,
+ "create",
+ test_tevent_req_create,
+ NULL);
+ torture_suite_add_simple_tcase_const(
+ suite,
+ "profile1",
+ test_tevent_req_profile1,
+ NULL);
+ torture_suite_add_simple_tcase_const(
+ suite,
+ "profile2",
+ test_tevent_req_profile2,
+ NULL);
+
+ return suite;
+}
diff --git a/source4/torture/local/local.c b/source4/torture/local/local.c
index d1c523bdc1f6..69ecc6b6ec81 100644
--- a/source4/torture/local/local.c
+++ b/source4/torture/local/local.c
@@ -64,6 +64,7 @@
torture_local_string_case,
torture_local_compression,
torture_local_event,
+ torture_local_tevent_req,
torture_local_torture,
torture_local_dbspeed,
torture_local_credentials,
diff --git a/source4/torture/local/wscript_build b/source4/torture/local/wscript_build
index 6cbb14d86e48..2dd18193c94d 100644
--- a/source4/torture/local/wscript_build
+++ b/source4/torture/local/wscript_build
@@ -13,6 +13,7 @@ TORTURE_LOCAL_SOURCE = '''../../../lib/util/charset/tests/iconv.c
../../../lib/util/charset/tests/convert_string.c
../../libcli/security/tests/sddl.c ../../../lib/tdr/testsuite.c
../../../lib/tevent/testsuite.c ../../param/tests/share.c
+ ../../../lib/tevent/test_req.c
../../param/tests/loadparm.c ../../../auth/credentials/tests/simple.c local.c
dbspeed.c torture.c ../ldb/ldb.c ../../dsdb/common/tests/dsdb_dn.c
../../dsdb/schema/tests/schema_syntax.c
--
2.17.1
From bcc268270f2c9c79af0a7e3412e46446614b4a24 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 3 May 2018 15:12:55 +0200
Subject: [PATCH 30/37] winbindd: Convert process_request() to tevent_req
Having a central tevent_req per winbind child request is prerequisite
for request profiling
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
source3/winbindd/winbindd.c | 328 ++++++++++++++++++++----------------
1 file changed, 181 insertions(+), 147 deletions(-)
diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c
index f0f0eef7bfc2..56c5b6ed8e2e 100644
--- a/source3/winbindd/winbindd.c
+++ b/source3/winbindd/winbindd.c
@@ -54,8 +54,6 @@
static bool client_is_idle(struct winbindd_cli_state *state);
static void remove_client(struct winbindd_cli_state *state);
static void winbindd_setup_max_fds(void);
-static void request_ok(struct winbindd_cli_state *state);
-static void request_error(struct winbindd_cli_state *state);
static bool opt_nocache = False;
static bool interactive = False;
@@ -660,219 +658,222 @@ static struct winbindd_async_dispatch_table async_priv_table[] = {
{ 0, NULL, NULL, NULL }
};
-static void wb_request_done(struct tevent_req *req);
+struct process_request_state {
+ struct winbindd_cli_state *cli_state;
+ struct tevent_context *ev;
+};
-static void process_request(struct winbindd_cli_state *state)
+static void process_request_done(struct tevent_req *subreq);
+static void process_request_written(struct tevent_req *subreq);
+
+static struct tevent_req *process_request_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct winbindd_cli_state *cli_state)
{
+ struct tevent_req *req, *subreq;
+ struct process_request_state *state;
struct winbindd_async_dispatch_table *atable;
+ enum winbindd_cmd cmd = cli_state->request->cmd;
size_t i;
bool ok;
- state->mem_ctx = talloc_named(state, 0, "winbind request");
- if (state->mem_ctx == NULL)
- return;
+ req = tevent_req_create(mem_ctx, &state,
+ struct process_request_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli_state = cli_state;
+ state->ev = ev;
+
+ SMB_ASSERT(cli_state->mem_ctx == NULL);
+ cli_state->mem_ctx = talloc_named(cli_state, 0, "winbind request");
+ if (tevent_req_nomem(cli_state->mem_ctx, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ cli_state->response = talloc_zero(
+ cli_state->mem_ctx,
+ struct winbindd_response);
+ if (tevent_req_nomem(cli_state->response, req)) {
+ return tevent_req_post(req, ev);
+ }
+ cli_state->response->result = WINBINDD_PENDING;
+ cli_state->response->length = sizeof(struct winbindd_response);
/* Remember who asked us. */
- state->pid = state->request->pid;
+ cli_state->pid = cli_state->request->pid;
- state->cmd_name = "unknown request";
- state->recv_fn = NULL;
- /* client is newest */
- winbindd_promote_client(state);
+ cli_state->cmd_name = "unknown request";
+ cli_state->recv_fn = NULL;
- /* Process command */
+ /* client is newest */
+ winbindd_promote_client(cli_state);
for (atable = async_nonpriv_table; atable->send_req; atable += 1) {
- if (state->request->cmd == atable->cmd) {
+ if (cmd == atable->cmd) {
break;
}
}
- if ((atable->send_req == NULL) && state->privileged) {
+ if ((atable->send_req == NULL) && cli_state->privileged) {
for (atable = async_priv_table; atable->send_req;
atable += 1) {
- if (state->request->cmd == atable->cmd) {
+ if (cmd == atable->cmd) {
break;
}
}
}
if (atable->send_req != NULL) {
- struct tevent_req *req;
-
- state->cmd_name = atable->cmd_name;
- state->recv_fn = atable->recv_req;
+ cli_state->cmd_name = atable->cmd_name;
+ cli_state->recv_fn = atable->recv_req;
DEBUG(10, ("process_request: Handling async request %d:%s\n",
- (int)state->pid, state->cmd_name));
-
- req = atable->send_req(state->mem_ctx, server_event_context(),
- state, state->request);
- if (req == NULL) {
- DEBUG(0, ("process_request: atable->send failed for "
- "%s\n", atable->cmd_name));
- request_error(state);
- return;
+ (int)cli_state->pid, cli_state->cmd_name));
+
+ subreq = atable->send_req(
+ state,
+ state->ev,
+ cli_state,
+ cli_state->request);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
- tevent_req_set_callback(req, wb_request_done, state);
- return;
+ tevent_req_set_callback(subreq, process_request_done, req);
+ return req;
}
- state->response = talloc_zero(state->mem_ctx,
- struct winbindd_response);
- if (state->response == NULL) {
- DEBUG(10, ("talloc failed\n"));
- remove_client(state);
- return;
- }
- state->response->result = WINBINDD_PENDING;
- state->response->length = sizeof(struct winbindd_response);
-
for (i=0; i<ARRAY_SIZE(bool_dispatch_table); i++) {
- if (bool_dispatch_table[i].cmd == state->request->cmd) {
+ if (cmd == bool_dispatch_table[i].cmd) {
break;
}
}
- if (i == ARRAY_SIZE(bool_dispatch_table)) {
- DEBUG(10,("process_request: unknown request fn number %d\n",
- (int)state->request->cmd ));
- request_error(state);
- return;
- }
-
- DBG_DEBUG("process_request: request fn %s\n",
- bool_dispatch_table[i].cmd_name);
-
- ok = bool_dispatch_table[i].fn(state);
+ ok = false;
- if (ok) {
- request_ok(state);
- } else {
- request_error(state);
+ if (i < ARRAY_SIZE(bool_dispatch_table)) {
+ DBG_DEBUG("process_request: request fn %s\n",
+ bool_dispatch_table[i].cmd_name);
+ ok = bool_dispatch_table[i].fn(cli_state);
}
-}
-static void wb_request_done(struct tevent_req *req)
-{
- struct winbindd_cli_state *state = tevent_req_callback_data(
- req, struct winbindd_cli_state);
- NTSTATUS status;
+ cli_state->response->result = ok ? WINBINDD_OK : WINBINDD_ERROR;
- state->response = talloc_zero(state->mem_ctx,
- struct winbindd_response);
- if (state->response == NULL) {
- DEBUG(0, ("wb_request_done[%d:%s]: talloc_zero failed - removing client\n",
- (int)state->pid, state->cmd_name));
- remove_client(state);
- return;
- }
- state->response->result = WINBINDD_PENDING;
- state->response->length = sizeof(struct winbindd_response);
+ TALLOC_FREE(cli_state->io_req);
+ TALLOC_FREE(cli_state->request);
- status = state->recv_fn(req, state->response);
- TALLOC_FREE(req);
+ subreq = wb_resp_write_send(
+ state,
+ state->ev,
+ cli_state->out_queue,
+ cli_state->sock,
+ cli_state->response);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, process_request_written, req);
- DEBUG(10,("wb_request_done[%d:%s]: %s\n",
- (int)state->pid, state->cmd_name, nt_errstr(status)));
+ cli_state->io_req = subreq;
- if (!NT_STATUS_IS_OK(status)) {
- request_error(state);
- return;
- }
- request_ok(state);
+ return req;
}
-/*
- * This is the main event loop of winbind requests. It goes through a
- * state-machine of 3 read/write requests, 4 if you have extra data to send.
- *
- * An idle winbind client has a read request of 4 bytes outstanding,
- * finalizing function is request_len_recv, checking the length. request_recv
- * then processes the packet. The processing function then at some point has
- * to call request_finished which schedules sending the response.
- */
-
-static void request_finished(struct winbindd_cli_state *state);
+static void process_request_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct process_request_state *state = tevent_req_data(
+ req, struct process_request_state);
+ struct winbindd_cli_state *cli_state = state->cli_state;
+ NTSTATUS status;
+ bool ok;
-static void winbind_client_request_read(struct tevent_req *req);
-static void winbind_client_response_written(struct tevent_req *req);
-static void winbind_client_activity(struct tevent_req *req);
+ status = cli_state->recv_fn(subreq, cli_state->response);
+ TALLOC_FREE(subreq);
-static void request_finished(struct winbindd_cli_state *state)
-{
- struct tevent_req *req;
+ DBG_DEBUG("[%d:%s]: %s\n",
+ (int)cli_state->pid,
+ cli_state->cmd_name,
+ nt_errstr(status));
- /* free client socket monitoring request */
- TALLOC_FREE(state->io_req);
+ ok = NT_STATUS_IS_OK(status);
+ cli_state->response->result = ok ? WINBINDD_OK : WINBINDD_ERROR;
- TALLOC_FREE(state->request);
+ TALLOC_FREE(cli_state->io_req);
+ TALLOC_FREE(cli_state->request);
- req = wb_resp_write_send(state, server_event_context(),
- state->out_queue, state->sock,
- state->response);
- if (req == NULL) {
- DEBUG(10,("request_finished[%d:%s]: wb_resp_write_send() failed\n",
- (int)state->pid, state->cmd_name));
- remove_client(state);
+ subreq = wb_resp_write_send(
+ state,
+ state->ev,
+ cli_state->out_queue,
+ cli_state->sock,
+ cli_state->response);
+ if (tevent_req_nomem(subreq, req)) {
return;
}
- tevent_req_set_callback(req, winbind_client_response_written, state);
- state->io_req = req;
+ tevent_req_set_callback(subreq, process_request_written, req);
+
+ cli_state->io_req = subreq;
}
-static void winbind_client_response_written(struct tevent_req *req)
+static void process_request_written(struct tevent_req *subreq)
{
- struct winbindd_cli_state *state = tevent_req_callback_data(
- req, struct winbindd_cli_state);
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct process_request_state *state = tevent_req_data(
+ req, struct process_request_state);
+ struct winbindd_cli_state *cli_state = state->cli_state;
ssize_t ret;
int err;
- state->io_req = NULL;
+ cli_state->io_req = NULL;
- ret = wb_resp_write_recv(req, &err);
- TALLOC_FREE(req);
+ ret = wb_resp_write_recv(subreq, &err);
+ TALLOC_FREE(subreq);
if (ret == -1) {
- close(state->sock);
- state->sock = -1;
- DEBUG(2, ("Could not write response[%d:%s] to client: %s\n",
- (int)state->pid, state->cmd_name, strerror(err)));
- remove_client(state);
+ tevent_req_nterror(req, map_nt_error_from_unix(err));
return;
}
- DEBUG(10,("winbind_client_response_written[%d:%s]: delivered response "
- "to client\n", (int)state->pid, state->cmd_name));
+ DBG_DEBUG("[%d:%s]: delivered response to client\n",
+ (int)cli_state->pid, cli_state->cmd_name);
- TALLOC_FREE(state->mem_ctx);
- state->response = NULL;
- state->cmd_name = "no request";
- state->recv_fn = NULL;
+ TALLOC_FREE(cli_state->mem_ctx);
+ cli_state->response = NULL;
+ cli_state->cmd_name = "no request";
+ cli_state->recv_fn = NULL;
- req = wb_req_read_send(state, server_event_context(), state->sock,
- WINBINDD_MAX_EXTRA_DATA);
- if (req == NULL) {
- remove_client(state);
- return;
- }
- tevent_req_set_callback(req, winbind_client_request_read, state);
- state->io_req = req;
+ tevent_req_done(req);
}
-static void request_error(struct winbindd_cli_state *state)
+static NTSTATUS process_request_recv(struct tevent_req *req)
{
- SMB_ASSERT(state->response->result == WINBINDD_PENDING);
- state->response->result = WINBINDD_ERROR;
- request_finished(state);
-}
+ NTSTATUS status;
-static void request_ok(struct winbindd_cli_state *state)
-{
- SMB_ASSERT(state->response->result == WINBINDD_PENDING);
- state->response->result = WINBINDD_OK;
- request_finished(state);
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
}
+/*
+ * This is the main event loop of winbind requests. It goes through a
+ * state-machine of 3 read/write requests, 4 if you have extra data to send.
+ *
+ * An idle winbind client has a read request of 4 bytes outstanding,
+ * finalizing function is request_len_recv, checking the length. request_recv
+ * then processes the packet. The processing function then at some point has
+ * to call request_finished which schedules sending the response.
+ */
+
+static void winbind_client_request_read(struct tevent_req *req);
+static void winbind_client_activity(struct tevent_req *req);
+static void winbind_client_processed(struct tevent_req *req);
+
/* Process a new connection by adding it to the client connection list */
static void new_connection(int listen_sock, bool privileged)
@@ -970,7 +971,13 @@ static void winbind_client_request_read(struct tevent_req *req)
tevent_req_set_callback(req, winbind_client_activity, state);
state->io_req = req;
- process_request(state);
+ req = process_request_send(state, server_event_context(), state);
+ if (req == NULL) {
+ DBG_ERR("process_request_send failed\n");
+ remove_client(state);
+ return;
+ }
+ tevent_req_set_callback(req, winbind_client_processed, state);
}
static void winbind_client_activity(struct tevent_req *req)
@@ -1004,6 +1011,33 @@ static void winbind_client_activity(struct tevent_req *req)
remove_client(state);
}
+static void winbind_client_processed(struct tevent_req *req)
+{
+ struct winbindd_cli_state *cli_state = tevent_req_callback_data(
+ req, struct winbindd_cli_state);
+ NTSTATUS status;
+
+ status = process_request_recv(req);
+ TALLOC_FREE(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_DEBUG("process_request failed: %s\n", nt_errstr(status));
+ remove_client(cli_state);
+ return;
+ }
+
+ req = wb_req_read_send(
+ cli_state,
+ server_event_context(),
+ cli_state->sock,
+ WINBINDD_MAX_EXTRA_DATA);
+ if (req == NULL) {
+ remove_client(cli_state);
+ return;
+ }
+ tevent_req_set_callback(req, winbind_client_request_read, cli_state);
+ cli_state->io_req = req;
+}
+
/* Remove a client connection from client connection list */
static void remove_client(struct winbindd_cli_state *state)
--
2.17.1
From 6329e00acee3ff4c40828fed0ffec13c3adbd716 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 19 Jun 2018 11:13:19 +0200
Subject: [PATCH 31/37] winbindd: Do request profiling
By default we log a request that takes more than 60 seconds. This can be
changed by setting
winbind:request profile threshold = <seconds>
Another parameter controls the depth of the request hierarchy printed:
winbind:request profile depth = <n>
The default request logged to syslog via DEBUG(0) looks like the
following for a wbinfo -P:
[struct process_request_state] ../source3/winbindd/winbindd.c:683 [2018/06/19 13:33:14.190365] ../source3/winbindd/winbindd.c:853 [2018/06/19 13:33:14.192737] [0.002372] -> TEVENT_REQ_DONE (2 0))
[struct winbindd_ping_dc_state] ../source3/winbindd/winbindd_ping_dc.c:41 [2018/06/19 13:33:14.190369] ../source3/winbindd/winbindd_ping_dc.c:112 [2018/06/19 13:33:14.192681] [0.002312] -> TEVENT_REQ_DONE (2 0))
[struct dcerpc_wbint_PingDc_state] default/librpc/gen_ndr/ndr_winbind_c.c:4335 [2018/06/19 13:33:14.190383] default/librpc/gen_ndr/ndr_winbind_c.c:4396 [2018/06/19 13:33:14.192680] [0.002297] -> TEVENT_REQ_DONE (2 0))
[struct dcerpc_wbint_PingDc_r_state] default/librpc/gen_ndr/ndr_winbind_c.c:4251 [2018/06/19 13:33:14.190385] default/librpc/gen_ndr/ndr_winbind_c.c:4285 [2018/06/19 13:33:14.192678] [0.002293] -> TEVENT_REQ_DONE (2 0))
[struct dcerpc_binding_handle_call_state] ../librpc/rpc/binding_handle.c:371 [2018/06/19 13:33:14.190387] ../librpc/rpc/binding_handle.c:520 [2018/06/19 13:33:14.192675] [0.002288] -> TEVENT_REQ_DONE (2 0))
[struct dcerpc_binding_handle_raw_call_state] ../librpc/rpc/binding_handle.c:149 [2018/06/19 13:33:14.190400] ../librpc/rpc/binding_handle.c:203 [2018/06/19 13:33:14.192646] [0.002246] -> TEVENT_REQ_DONE (2 0))
[struct wbint_bh_raw_call_state] ../source3/winbindd/winbindd_dual_ndr.c:89 [2018/06/19 13:33:14.190402] ../source3/winbindd/winbindd_dual_ndr.c:204 [2018/06/19 13:33:14.192644] [0.002242] -> TEVENT_REQ_DONE (2 0))
[struct wb_domain_request_state] ../source3/winbindd/winbindd_dual.c:473 [2018/06/19 13:33:14.190404] ../source3/winbindd/winbindd_dual.c:708 [2018/06/19 13:33:14.192640] [0.002236] -> TEVENT_REQ_DONE (2 0))
[struct wb_child_request_state] ../source3/winbindd/winbindd_dual.c:198 [2018/06/19 13:33:14.190411] ../source3/winbindd/winbindd_dual.c:273 [2018/06/19 13:33:14.192638] [0.002227] -> TEVENT_REQ_DONE (2 0))
[struct tevent_queue_wait_state] ../lib/tevent/tevent_queue.c:336 [2018/06/19 13:33:14.190412] ../lib/tevent/tevent_queue.c:355 [2018/06/19 13:33:14.190415] [0.000003] -> TEVENT_REQ_DONE (2 0))
[struct wb_simple_trans_state] ../nsswitch/wb_reqtrans.c:375 [2018/06/19 13:33:14.190424] ../nsswitch/wb_reqtrans.c:432 [2018/06/19 13:33:14.192630] [0.002206] -> TEVENT_REQ_DONE (2 0))
[struct req_write_state] ../nsswitch/wb_reqtrans.c:158 [2018/06/19 13:33:14.190425] ../nsswitch/wb_reqtrans.c:194 [2018/06/19 13:33:14.190472] [0.000047] -> TEVENT_REQ_DONE (2 0))
[struct writev_state] ../lib/async_req/async_sock.c:263 [2018/06/19 13:33:14.190432] ../lib/async_req/async_sock.c:412 [2018/06/19 13:33:14.190470] [0.000038] -> TEVENT_REQ_DONE (2 0))
[struct resp_read_state] ../nsswitch/wb_reqtrans.c:222 [2018/06/19 13:33:14.190475] ../nsswitch/wb_reqtrans.c:275 [2018/06/19 13:33:14.192629] [0.002154] -> TEVENT_REQ_DONE (2 0))
[struct read_packet_state] ../lib/async_req/async_sock.c:458 [2018/06/19 13:33:14.190476] ../lib/async_req/async_sock.c:546 [2018/06/19 13:33:14.192626] [0.002150] -> TEVENT_REQ_DONE (2 0))
[struct resp_write_state] ../nsswitch/wb_reqtrans.c:307 [2018/06/19 13:33:14.192693] ../nsswitch/wb_reqtrans.c:344 [2018/06/19 13:33:14.192734] [0.000041] -> TEVENT_REQ_DONE (2 0))
[struct writev_state] ../lib/async_req/async_sock.c:263 [2018/06/19 13:33:14.192694] ../lib/async_req/async_sock.c:412 [2018/06/19 13:33:14.192732] [0.000038] -> TEVENT_REQ_DONE (2 0))
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
source3/winbindd/winbindd.c | 46 +++++++++++++++++++++++++++++++++++--
1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c
index 56c5b6ed8e2e..254d93b344dd 100644
--- a/source3/winbindd/winbindd.c
+++ b/source3/winbindd/winbindd.c
@@ -45,6 +45,7 @@
#include "libsmb/samlogon_cache.h"
#include "libcli/auth/netlogon_creds_cli.h"
#include "passdb.h"
+#include "lib/util/tevent_req_profile.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
@@ -686,6 +687,11 @@ static struct tevent_req *process_request_send(
state->cli_state = cli_state;
state->ev = ev;
+ ok = tevent_req_set_profile(req);
+ if (!ok) {
+ return tevent_req_post(req, ev);
+ }
+
SMB_ASSERT(cli_state->mem_ctx == NULL);
cli_state->mem_ctx = talloc_named(cli_state, 0, "winbind request");
if (tevent_req_nomem(cli_state->mem_ctx, req)) {
@@ -847,7 +853,10 @@ static void process_request_written(struct tevent_req *subreq)
tevent_req_done(req);
}
-static NTSTATUS process_request_recv(struct tevent_req *req)
+static NTSTATUS process_request_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_req_profile **profile)
{
NTSTATUS status;
@@ -856,6 +865,7 @@ static NTSTATUS process_request_recv(struct tevent_req *req)
return status;
}
+ *profile = tevent_req_move_profile(req, mem_ctx);
tevent_req_received(req);
return NT_STATUS_OK;
}
@@ -1015,9 +1025,12 @@ static void winbind_client_processed(struct tevent_req *req)
{
struct winbindd_cli_state *cli_state = tevent_req_callback_data(
req, struct winbindd_cli_state);
+ struct tevent_req_profile *profile = NULL;
+ struct timeval start, stop, diff;
+ int threshold;
NTSTATUS status;
- status = process_request_recv(req);
+ status = process_request_recv(req, cli_state, &profile);
TALLOC_FREE(req);
if (!NT_STATUS_IS_OK(status)) {
DBG_DEBUG("process_request failed: %s\n", nt_errstr(status));
@@ -1025,6 +1038,35 @@ static void winbind_client_processed(struct tevent_req *req)
return;
}
+ tevent_req_profile_get_start(profile, NULL, &start);
+ tevent_req_profile_get_stop(profile, NULL, &stop);
+ diff = tevent_timeval_until(&start, &stop);
+
+ threshold = lp_parm_int(-1, "winbind", "request profile threshold", 60);
+
+ if (diff.tv_sec >= threshold) {
+ int depth;
+ char *str;
+
+ depth = lp_parm_int(
+ -1,
+ "winbind",
+ "request profile depth",
+ INT_MAX);
+
+ DBG_ERR("request took %u.%.6u seconds\n",
+ (unsigned)diff.tv_sec, (unsigned)diff.tv_usec);
+
+ str = tevent_req_profile_string(profile, talloc_tos(), 0, depth);
+ if (str != NULL) {
+ /* No "\n", already contained in "str" */
+ DEBUGADD(0, ("%s", str));
+ }
+ TALLOC_FREE(str);
+ }
+
+ TALLOC_FREE(profile);
+
req = wb_req_read_send(
cli_state,
server_event_context(),
--
2.17.1
From 4043821c684613ac74baef98b5c1eb335bbf1ac5 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 18 May 2018 16:28:47 +0200
Subject: [PATCH 32/37] s3:messages: protect against usage of wrapper
tevent_context objects for messaging
This makes a lot of assumtion easier to understand and the introduction
of wrapper tevent contexts will not change the existing behaviour.
We'll relax this a bit in the next commits.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
source3/lib/messages.c | 23 +++++++++++++++++++++++
source3/lib/messages_ctdb.c | 8 ++++++++
source3/lib/messages_ctdb_ref.c | 12 ++++++++++++
source3/lib/messages_dgm.c | 14 ++++++++++++++
source3/lib/messages_dgm_ref.c | 12 ++++++++++++
5 files changed, 69 insertions(+)
diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index 82a177856f60..1a5ea4659aa4 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -365,6 +365,11 @@ static bool messaging_alert_event_contexts(struct messaging_context *ctx)
* alternatively would be to track whether the
* immediate has already been scheduled. For
* now, avoid that complexity here.
+ *
+ * reg->ev and ctx->event_ctx can't
+ * be wrapper tevent_context pointers
+ * so we don't need to use
+ * tevent_context_same_loop().
*/
if (reg->ev == ctx->event_ctx) {
@@ -493,6 +498,12 @@ static NTSTATUS messaging_init_internal(TALLOC_CTX *mem_ctx,
sec_init();
+ if (tevent_context_is_wrapper(ev)) {
+ /* This is really a programmer error! */
+ DBG_ERR("Should not be used with a wrapper tevent context\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
lck_path = lock_path("msg.lock");
if (lck_path == NULL) {
return NT_STATUS_NO_MEMORY;
@@ -1023,6 +1034,13 @@ struct tevent_req *messaging_filtered_read_send(
state->filter = filter;
state->private_data = private_data;
+ if (tevent_context_is_wrapper(ev)) {
+ /* This is really a programmer error! */
+ DBG_ERR("Wrapper tevent context doesn't use main context.\n");
+ tevent_req_error(req, EINVAL);
+ return tevent_req_post(req, ev);
+ }
+
/*
* We have to defer the callback here, as we might be called from
* within a different tevent_context than state->ev
@@ -1343,6 +1361,11 @@ static void messaging_dispatch_rec(struct messaging_context *msg_ctx,
bool consumed;
size_t i;
+ /*
+ * ev and msg_ctx->event_ctx can't be wrapper tevent_context pointers
+ * so we don't need to use tevent_context_same_loop().
+ */
+
if (ev == msg_ctx->event_ctx) {
consumed = messaging_dispatch_classic(msg_ctx, rec);
if (consumed) {
diff --git a/source3/lib/messages_ctdb.c b/source3/lib/messages_ctdb.c
index d3e2e3f85893..a1aeb37af198 100644
--- a/source3/lib/messages_ctdb.c
+++ b/source3/lib/messages_ctdb.c
@@ -209,6 +209,14 @@ struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
return NULL;
}
+ if (tevent_context_is_wrapper(ev)) {
+ /*
+ * This is really a programmer error!
+ */
+ DBG_ERR("Should not be used with a wrapper tevent context\n");
+ return NULL;
+ }
+
fde = talloc(mem_ctx, struct messaging_ctdb_fde);
if (fde == NULL) {
return NULL;
diff --git a/source3/lib/messages_ctdb_ref.c b/source3/lib/messages_ctdb_ref.c
index 3570ed8ae4c8..47b4b758dac5 100644
--- a/source3/lib/messages_ctdb_ref.c
+++ b/source3/lib/messages_ctdb_ref.c
@@ -52,6 +52,18 @@ void *messaging_ctdb_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
{
struct msg_ctdb_ref *result, *tmp_refs;
+ if (tevent_context_is_wrapper(ev)) {
+ /*
+ * This is really a programmer error!
+ *
+ * The main/raw tevent context should
+ * have been registered first!
+ */
+ DBG_ERR("Should not be used with a wrapper tevent context\n");
+ *err = EINVAL;
+ return NULL;
+ }
+
result = talloc(mem_ctx, struct msg_ctdb_ref);
if (result == NULL) {
*err = ENOMEM;
diff --git a/source3/lib/messages_dgm.c b/source3/lib/messages_dgm.c
index b8878b68b996..1c76615093c0 100644
--- a/source3/lib/messages_dgm.c
+++ b/source3/lib/messages_dgm.c
@@ -993,6 +993,12 @@ int messaging_dgm_init(struct tevent_context *ev,
return EEXIST;
}
+ if (tevent_context_is_wrapper(ev)) {
+ /* This is really a programmer error! */
+ DBG_ERR("Should not be used with a wrapper tevent context\n");
+ return EINVAL;
+ }
+
ctx = talloc_zero(NULL, struct messaging_dgm_context);
if (ctx == NULL) {
goto fail_nomem;
@@ -1673,6 +1679,14 @@ struct messaging_dgm_fde *messaging_dgm_register_tevent_context(
return NULL;
}
+ if (tevent_context_is_wrapper(ev)) {
+ /*
+ * This is really a programmer error!
+ */
+ DBG_ERR("Should not be used with a wrapper tevent context\n");
+ return NULL;
+ }
+
fde = talloc(mem_ctx, struct messaging_dgm_fde);
if (fde == NULL) {
return NULL;
diff --git a/source3/lib/messages_dgm_ref.c b/source3/lib/messages_dgm_ref.c
index 470dfbeabc74..fd1709617468 100644
--- a/source3/lib/messages_dgm_ref.c
+++ b/source3/lib/messages_dgm_ref.c
@@ -55,6 +55,18 @@ void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
{
struct msg_dgm_ref *result, *tmp_refs;
+ if (tevent_context_is_wrapper(ev)) {
+ /*
+ * This is really a programmer error!
+ *
+ * The main/raw tevent context should
+ * have been registered first!
+ */
+ DBG_ERR("Should not be used with a wrapper tevent context\n");
+ *err = EINVAL;
+ return NULL;
+ }
+
result = talloc(mem_ctx, struct msg_dgm_ref);
if (result == NULL) {
*err = ENOMEM;
--
2.17.1
From e97219df2f3a0085e110c3a6a271fb6f2877b2b4 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 23 Mar 2018 14:48:46 +0100
Subject: [PATCH 33/37] s3:messages: allow
messaging_{dgm,ctdb}_register_tevent_context() to use wrapper tevent_context
This is only allowed if the raw tevent context is already registered.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
source3/lib/messages_ctdb.c | 38 ++++++++++++++++++++++++++++---------
source3/lib/messages_dgm.c | 38 ++++++++++++++++++++++++++++---------
2 files changed, 58 insertions(+), 18 deletions(-)
diff --git a/source3/lib/messages_ctdb.c b/source3/lib/messages_ctdb.c
index a1aeb37af198..11fe72661cc3 100644
--- a/source3/lib/messages_ctdb.c
+++ b/source3/lib/messages_ctdb.c
@@ -209,14 +209,6 @@ struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
return NULL;
}
- if (tevent_context_is_wrapper(ev)) {
- /*
- * This is really a programmer error!
- */
- DBG_ERR("Should not be used with a wrapper tevent context\n");
- return NULL;
- }
-
fde = talloc(mem_ctx, struct messaging_ctdb_fde);
if (fde == NULL) {
return NULL;
@@ -234,7 +226,24 @@ struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
*/
continue;
}
- if (fde_ev->ev == ev) {
+
+ /*
+ * We can only have one tevent_fd
+ * per low level tevent_context.
+ *
+ * This means any wrapper tevent_context
+ * needs to share the structure with
+ * the main tevent_context and/or
+ * any sibling wrapper tevent_context.
+ *
+ * This means we need to use tevent_context_same_loop()
+ * instead of just (fde_ev->ev == ev).
+ *
+ * Note: the tevent_context_is_wrapper() check below
+ * makes sure that fde_ev->ev is always a raw
+ * tevent context.
+ */
+ if (tevent_context_same_loop(fde_ev->ev, ev)) {
break;
}
}
@@ -242,6 +251,17 @@ struct messaging_ctdb_fde *messaging_ctdb_register_tevent_context(
if (fde_ev == NULL) {
int sock = ctdbd_conn_get_fd(ctx->conn);
+ if (tevent_context_is_wrapper(ev)) {
+ /*
+ * This is really a programmer error!
+ *
+ * The main/raw tevent context should
+ * have been registered first!
+ */
+ DBG_ERR("Should not be used with a wrapper tevent context\n");
+ return NULL;
+ }
+
fde_ev = talloc(fde, struct messaging_ctdb_fde_ev);
if (fde_ev == NULL) {
return NULL;
diff --git a/source3/lib/messages_dgm.c b/source3/lib/messages_dgm.c
index 1c76615093c0..0ad8f46e09f1 100644
--- a/source3/lib/messages_dgm.c
+++ b/source3/lib/messages_dgm.c
@@ -1679,14 +1679,6 @@ struct messaging_dgm_fde *messaging_dgm_register_tevent_context(
return NULL;
}
- if (tevent_context_is_wrapper(ev)) {
- /*
- * This is really a programmer error!
- */
- DBG_ERR("Should not be used with a wrapper tevent context\n");
- return NULL;
- }
-
fde = talloc(mem_ctx, struct messaging_dgm_fde);
if (fde == NULL) {
return NULL;
@@ -1704,12 +1696,40 @@ struct messaging_dgm_fde *messaging_dgm_register_tevent_context(
*/
continue;
}
- if (fde_ev->ev == ev) {
+
+ /*
+ * We can only have one tevent_fd
+ * per low level tevent_context.
+ *
+ * This means any wrapper tevent_context
+ * needs to share the structure with
+ * the main tevent_context and/or
+ * any sibling wrapper tevent_context.
+ *
+ * This means we need to use tevent_context_same_loop()
+ * instead of just (fde_ev->ev == ev).
+ *
+ * Note: the tevent_context_is_wrapper() check below
+ * makes sure that fde_ev->ev is always a raw
+ * tevent context.
+ */
+ if (tevent_context_same_loop(fde_ev->ev, ev)) {
break;
}
}
if (fde_ev == NULL) {
+ if (tevent_context_is_wrapper(ev)) {
+ /*
+ * This is really a programmer error!
+ *
+ * The main/raw tevent context should
+ * have been registered first!
+ */
+ DBG_ERR("Should not be used with a wrapper tevent context\n");
+ return NULL;
+ }
+
fde_ev = talloc(fde, struct messaging_dgm_fde_ev);
if (fde_ev == NULL) {
return NULL;
--
2.17.1
From 604621acd0f4a35b6493e4563dcfbb6a9d30490b Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 23 Mar 2018 14:48:46 +0100
Subject: [PATCH 34/37] s3:messages: allow messaging_dgm_ref() to use wrapper
tevent_context
This is only allowed if the raw tevent context is already registered.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
source3/lib/messages_dgm_ref.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/source3/lib/messages_dgm_ref.c b/source3/lib/messages_dgm_ref.c
index fd1709617468..12ff21ca6283 100644
--- a/source3/lib/messages_dgm_ref.c
+++ b/source3/lib/messages_dgm_ref.c
@@ -55,18 +55,6 @@ void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
{
struct msg_dgm_ref *result, *tmp_refs;
- if (tevent_context_is_wrapper(ev)) {
- /*
- * This is really a programmer error!
- *
- * The main/raw tevent context should
- * have been registered first!
- */
- DBG_ERR("Should not be used with a wrapper tevent context\n");
- *err = EINVAL;
- return NULL;
- }
-
result = talloc(mem_ctx, struct msg_dgm_ref);
if (result == NULL) {
*err = ENOMEM;
@@ -87,6 +75,18 @@ void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
if (refs == NULL) {
int ret;
+ if (tevent_context_is_wrapper(ev)) {
+ /*
+ * This is really a programmer error!
+ *
+ * The main/raw tevent context should
+ * have been registered first!
+ */
+ DBG_ERR("Should not be used with a wrapper tevent context\n");
+ *err = EINVAL;
+ return NULL;
+ }
+
ret = messaging_dgm_init(ev, unique, socket_dir, lockfile_dir,
msg_dgm_ref_recv, NULL);
DBG_DEBUG("messaging_dgm_init returned %s\n", strerror(ret));
--
2.17.1
From c1dfd1a5516470c6d5ec12249093a1cff5953ff2 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 23 Mar 2018 14:48:46 +0100
Subject: [PATCH 35/37] s3:messages: allow messaging_filtered_read_send() to
use wrapper tevent_context
As it gets 'messaging_context' as argument, we're sure a messaging context
with a raw tevent context already exist.
It means we can allow a wrapper tevent context that wrapps the main tevent
context of the messaging context.
The use of tevent_req_defer_callback() makes sure that the callers
callback function calls messaging_filtered_read_recv() from the
correct "wrapped" environment.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
source3/lib/messages.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index 1a5ea4659aa4..dab53f1c48e3 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -206,7 +206,7 @@ static bool messaging_register_event_context(struct messaging_context *ctx,
continue;
}
- if (reg->ev == ev) {
+ if (tevent_context_same_loop(reg->ev, ev)) {
reg->refcount += 1;
return true;
}
@@ -255,7 +255,7 @@ static bool messaging_deregister_event_context(struct messaging_context *ctx,
continue;
}
- if (reg->ev == ev) {
+ if (tevent_context_same_loop(reg->ev, ev)) {
reg->refcount -= 1;
if (reg->refcount == 0) {
@@ -1034,7 +1034,9 @@ struct tevent_req *messaging_filtered_read_send(
state->filter = filter;
state->private_data = private_data;
- if (tevent_context_is_wrapper(ev)) {
+ if (tevent_context_is_wrapper(ev) &&
+ !tevent_context_same_loop(ev, msg_ctx->event_ctx))
+ {
/* This is really a programmer error! */
DBG_ERR("Wrapper tevent context doesn't use main context.\n");
tevent_req_error(req, EINVAL);
@@ -1043,7 +1045,11 @@ struct tevent_req *messaging_filtered_read_send(
/*
* We have to defer the callback here, as we might be called from
- * within a different tevent_context than state->ev
+ * within a different tevent_context than state->ev.
+ *
+ * This is important for two cases:
+ * 1. nested event contexts, used by blocking ctdb calls
+ * 2. possible impersonation using wrapper tevent contexts.
*/
tevent_req_defer_callback(req, state->ev);
@@ -1339,7 +1345,7 @@ static bool messaging_dispatch_waiters(struct messaging_context *msg_ctx,
state = tevent_req_data(
req, struct messaging_filtered_read_state);
- if ((ev == state->ev) &&
+ if (tevent_context_same_loop(ev, state->ev) &&
state->filter(rec, state->private_data)) {
messaging_filtered_read_done(req, rec);
return true;
--
2.17.1
From 13f826e6700fee77039ef2805004db5aae9f352a Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sat, 19 May 2018 10:14:25 +0200
Subject: [PATCH 36/37] s4:messaging: allow imessaging_post_handler() to free
the messaging context from a handler
In usecases like using messaging_client_init() with irpc processing we may
free the imessaging_context during the messaging handler.
imessaging_post_handler() is not yet really used, but it will change in
the next commits. imessaging_post_state is a child of imessaging_context
and might be implicitly free'ed before the explicit TALLOC_FREE(state).
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
source4/lib/messaging/messaging.c | 33 +++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/source4/lib/messaging/messaging.c b/source4/lib/messaging/messaging.c
index b8d4e50f12c7..8903322bdc7f 100644
--- a/source4/lib/messaging/messaging.c
+++ b/source4/lib/messaging/messaging.c
@@ -433,18 +433,48 @@ fail:
struct imessaging_post_state {
struct imessaging_context *msg_ctx;
+ struct imessaging_post_state **busy_ref;
size_t buf_len;
uint8_t buf[];
};
+static int imessaging_post_state_destructor(struct imessaging_post_state *state)
+{
+ if (state->busy_ref != NULL) {
+ *state->busy_ref = NULL;
+ state->busy_ref = NULL;
+ }
+ return 0;
+}
+
static void imessaging_post_handler(struct tevent_context *ev,
struct tevent_immediate *ti,
void *private_data)
{
struct imessaging_post_state *state = talloc_get_type_abort(
private_data, struct imessaging_post_state);
+
+ /*
+ * In usecases like using messaging_client_init() with irpc processing
+ * we may free the imessaging_context during the messaging handler.
+ * imessaging_post_state is a child of imessaging_context and
+ * might be implicitly free'ed before the explicit TALLOC_FREE(state).
+ *
+ * The busy_ref pointer makes sure the destructor clears
+ * the local 'state' variable.
+ */
+
+ SMB_ASSERT(state->busy_ref == NULL);
+ state->busy_ref = &state;
+
imessaging_dgm_recv(ev, state->buf, state->buf_len, NULL, 0,
state->msg_ctx);
+
+ if (state == NULL) {
+ return;
+ }
+
+ state->busy_ref = NULL;
TALLOC_FREE(state);
}
@@ -461,6 +491,8 @@ static int imessaging_post_self(struct imessaging_context *msg,
}
talloc_set_name_const(state, "struct imessaging_post_state");
+ talloc_set_destructor(state, imessaging_post_state_destructor);
+
ti = tevent_create_immediate(state);
if (ti == NULL) {
TALLOC_FREE(state);
@@ -468,6 +500,7 @@ static int imessaging_post_self(struct imessaging_context *msg,
}
state->msg_ctx = msg;
+ state->busy_ref = NULL;
state->buf_len = buf_len;
memcpy(state->buf, buf, buf_len);
--
2.17.1
From 02c60f05c79b902eeec7597c375ad5b4f5ea63ad Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 18 May 2018 16:28:47 +0200
Subject: [PATCH 37/37] s4:messaging: make sure only imessaging_client_init()
can be used with a wrapper tevent_context wrapper
imessaging_client_init() can be used with a wrapper tevent_context,
but only if a global messaging_dgm_ref() already exist.
All other uses of imessaging_init() and imessaging_client_init()
require a raw tevent_context.
Signed-off-by: Stefan Metzmacher <metze at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
source4/lib/messaging/messaging.c | 28 ++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/source4/lib/messaging/messaging.c b/source4/lib/messaging/messaging.c
index 8903322bdc7f..935951f3fbae 100644
--- a/source4/lib/messaging/messaging.c
+++ b/source4/lib/messaging/messaging.c
@@ -319,7 +319,7 @@ NTSTATUS imessaging_reinit_all(void)
/*
create the listening socket and setup the dispatcher
*/
-struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
+static struct imessaging_context *imessaging_init_internal(TALLOC_CTX *mem_ctx,
struct loadparm_context *lp_ctx,
struct server_id server_id,
struct tevent_context *ev)
@@ -573,6 +573,30 @@ static void imessaging_dgm_recv(struct tevent_context *ev,
}
}
+struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ struct server_id server_id,
+ struct tevent_context *ev)
+{
+ if (ev == NULL) {
+ return NULL;
+ }
+
+ if (tevent_context_is_wrapper(ev)) {
+ /*
+ * This is really a programmer error!
+ *
+ * The main/raw tevent context should
+ * have been registered first!
+ */
+ DBG_ERR("Should not be used with a wrapper tevent context\n");
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return imessaging_init_internal(mem_ctx, lp_ctx, server_id, ev);
+}
+
/*
A hack, for the short term until we get 'client only' messaging in place
*/
@@ -589,7 +613,7 @@ struct imessaging_context *imessaging_client_init(TALLOC_CTX *mem_ctx,
/* This is because we are not in the s3 serverid database */
id.unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
- return imessaging_init(mem_ctx, lp_ctx, id, ev);
+ return imessaging_init_internal(mem_ctx, lp_ctx, id, ev);
}
/*
a list of registered irpc server functions
--
2.17.1
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20180711/d6bc4d18/signature-0001.sig>
More information about the samba-technical
mailing list