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