2 Unix SMB/CIFS implementation.
3 main select loop and event handling
4 Copyright (C) Stefan Metzmacher 2013
5 Copyright (C) Jeremy Allison 2013
7 ** NOTE! The following LGPL license applies to the tevent
8 ** library. This does NOT imply that all of Samba is released
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 3 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 This is SAMBA's default event loop code
28 - we try to use epoll if configure detected support for it
29 otherwise we use poll()
30 - if epoll is broken on the system or the kernel doesn't support it
31 at runtime we fallback to poll()
36 #include "tevent_util.h"
37 #include "tevent_internal.h"
39 struct std_event_glue
{
40 const struct tevent_ops
*epoll_ops
;
41 const struct tevent_ops
*poll_ops
;
42 struct tevent_ops
*glue_ops
;
46 static int std_event_context_init(struct tevent_context
*ev
);
48 static const struct tevent_ops std_event_ops
= {
49 .context_init
= std_event_context_init
,
53 If this function gets called. epoll failed at runtime.
54 Move us to using poll instead. If we return false here,
55 caller should abort().
57 static bool std_fallback_to_poll(struct tevent_context
*ev
, bool replay
)
59 void *glue_ptr
= talloc_parent(ev
->ops
);
60 struct std_event_glue
*glue
=
61 talloc_get_type_abort(glue_ptr
,
62 struct std_event_glue
);
64 struct tevent_fd
*fde
;
65 struct tevent_fd
*fde_next
;
67 glue
->fallback_replay
= replay
;
69 /* First switch all the ops to poll. */
70 glue
->epoll_ops
= NULL
;
73 * Set custom_ops the same as poll.
75 *glue
->glue_ops
= *glue
->poll_ops
;
76 glue
->glue_ops
->context_init
= std_event_context_init
;
78 /* Next initialize the poll backend. */
79 ret
= glue
->poll_ops
->context_init(ev
);
85 * Now we have to change all the existing file descriptor
86 * events from the epoll backend to the poll backend.
88 for (fde
= ev
->fd_events
; fde
; fde
= fde_next
) {
90 * We must remove this fde off the ev->fd_events list.
94 /* Remove from the ev->fd_events list. */
95 DLIST_REMOVE(ev
->fd_events
, fde
);
97 /* Re-add this event as a poll backend event. */
98 tevent_poll_event_add_fd_internal(ev
, fde
);
104 static int std_event_loop_once(struct tevent_context
*ev
, const char *location
)
106 void *glue_ptr
= talloc_parent(ev
->ops
);
107 struct std_event_glue
*glue
=
108 talloc_get_type_abort(glue_ptr
,
109 struct std_event_glue
);
112 ret
= glue
->epoll_ops
->loop_once(ev
, location
);
113 if (glue
->epoll_ops
!= NULL
) {
118 if (!glue
->fallback_replay
) {
120 * The problem happened while modifying an event.
121 * An event handler was triggered in this case
122 * and there is no need to call loop_once() again.
127 return glue
->poll_ops
->loop_once(ev
, location
);
130 static int std_event_loop_wait(struct tevent_context
*ev
, const char *location
)
132 void *glue_ptr
= talloc_parent(ev
->ops
);
133 struct std_event_glue
*glue
=
134 talloc_get_type_abort(glue_ptr
,
135 struct std_event_glue
);
138 ret
= glue
->epoll_ops
->loop_wait(ev
, location
);
139 if (glue
->epoll_ops
!= NULL
) {
144 return glue
->poll_ops
->loop_wait(ev
, location
);
147 Initialize the epoll backend and allow it to call a
148 switch function if epoll fails at runtime.
150 static int std_event_context_init(struct tevent_context
*ev
)
152 struct std_event_glue
*glue
;
156 * If this is the first initialization
157 * we need to set up the allocated ops
161 if (ev
->ops
== &std_event_ops
) {
162 glue
= talloc_zero(ev
, struct std_event_glue
);
167 glue
->epoll_ops
= tevent_find_ops_byname("epoll");
169 glue
->poll_ops
= tevent_find_ops_byname("poll");
170 if (glue
->poll_ops
== NULL
) {
175 * Allocate space for our custom ops.
176 * Allocate as a child of our epoll_ops pointer
177 * so we can easily get to it using talloc_parent.
179 glue
->glue_ops
= talloc_zero(glue
, struct tevent_ops
);
180 if (glue
->glue_ops
== NULL
) {
185 ev
->ops
= glue
->glue_ops
;
187 void *glue_ptr
= talloc_parent(ev
->ops
);
188 glue
= talloc_get_type_abort(glue_ptr
, struct std_event_glue
);
191 if (glue
->epoll_ops
!= NULL
) {
193 * Set custom_ops the same as epoll,
194 * except re-init using std_event_context_init()
195 * and use std_event_loop_once() to add the
196 * ability to fallback to a poll backend on
197 * epoll runtime error.
199 *glue
->glue_ops
= *glue
->epoll_ops
;
200 glue
->glue_ops
->context_init
= std_event_context_init
;
201 glue
->glue_ops
->loop_once
= std_event_loop_once
;
202 glue
->glue_ops
->loop_wait
= std_event_loop_wait
;
204 ret
= glue
->epoll_ops
->context_init(ev
);
209 if (!tevent_epoll_set_panic_fallback(ev
, std_fallback_to_poll
)) {
210 TALLOC_FREE(ev
->additional_data
);
219 glue
->epoll_ops
= NULL
;
222 * Set custom_ops the same as poll.
224 *glue
->glue_ops
= *glue
->poll_ops
;
225 glue
->glue_ops
->context_init
= std_event_context_init
;
227 return glue
->poll_ops
->context_init(ev
);
230 _PRIVATE_
bool tevent_standard_init(void)
232 return tevent_register_backend("standard", &std_event_ops
);