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().
58 static bool std_fallback_to_poll(struct tevent_context
*ev
, bool replay
)
60 void *glue_ptr
= talloc_parent(ev
->ops
);
61 struct std_event_glue
*glue
=
62 talloc_get_type_abort(glue_ptr
,
63 struct std_event_glue
);
65 struct tevent_fd
*fde
;
66 struct tevent_fd
*fde_next
;
68 glue
->fallback_replay
= replay
;
70 /* First switch all the ops to poll. */
71 glue
->epoll_ops
= NULL
;
74 * Set custom_ops the same as poll.
76 *glue
->glue_ops
= *glue
->poll_ops
;
77 glue
->glue_ops
->context_init
= std_event_context_init
;
79 /* Next initialize the poll backend. */
80 ret
= glue
->poll_ops
->context_init(ev
);
86 * Now we have to change all the existing file descriptor
87 * events from the epoll backend to the poll backend.
89 for (fde
= ev
->fd_events
; fde
; fde
= fde_next
) {
91 * We must remove this fde off the ev->fd_events list.
95 /* Remove from the ev->fd_events list. */
96 DLIST_REMOVE(ev
->fd_events
, fde
);
98 /* Re-add this event as a poll backend event. */
99 tevent_poll_event_add_fd_internal(ev
, fde
);
106 static int std_event_loop_once(struct tevent_context
*ev
, const char *location
)
108 void *glue_ptr
= talloc_parent(ev
->ops
);
109 struct std_event_glue
*glue
=
110 talloc_get_type_abort(glue_ptr
,
111 struct std_event_glue
);
114 ret
= glue
->epoll_ops
->loop_once(ev
, location
);
115 if (glue
->epoll_ops
!= NULL
) {
120 if (!glue
->fallback_replay
) {
122 * The problem happened while modifying an event.
123 * An event handler was triggered in this case
124 * and there is no need to call loop_once() again.
129 return glue
->poll_ops
->loop_once(ev
, location
);
132 static int std_event_loop_wait(struct tevent_context
*ev
, const char *location
)
134 void *glue_ptr
= talloc_parent(ev
->ops
);
135 struct std_event_glue
*glue
=
136 talloc_get_type_abort(glue_ptr
,
137 struct std_event_glue
);
140 ret
= glue
->epoll_ops
->loop_wait(ev
, location
);
141 if (glue
->epoll_ops
!= NULL
) {
146 return glue
->poll_ops
->loop_wait(ev
, location
);
149 Initialize the epoll backend and allow it to call a
150 switch function if epoll fails at runtime.
152 static int std_event_context_init(struct tevent_context
*ev
)
154 struct std_event_glue
*glue
;
158 * If this is the first initialization
159 * we need to set up the allocated ops
163 if (ev
->ops
== &std_event_ops
) {
164 glue
= talloc_zero(ev
, struct std_event_glue
);
169 glue
->epoll_ops
= tevent_find_ops_byname("epoll");
171 glue
->poll_ops
= tevent_find_ops_byname("poll");
172 if (glue
->poll_ops
== NULL
) {
177 * Allocate space for our custom ops.
178 * Allocate as a child of our epoll_ops pointer
179 * so we can easily get to it using talloc_parent.
181 glue
->glue_ops
= talloc_zero(glue
, struct tevent_ops
);
182 if (glue
->glue_ops
== NULL
) {
187 ev
->ops
= glue
->glue_ops
;
189 void *glue_ptr
= talloc_parent(ev
->ops
);
190 glue
= talloc_get_type_abort(glue_ptr
, struct std_event_glue
);
193 if (glue
->epoll_ops
!= NULL
) {
195 * Set custom_ops the same as epoll,
196 * except re-init using std_event_context_init()
197 * and use std_event_loop_once() to add the
198 * ability to fallback to a poll backend on
199 * epoll runtime error.
201 *glue
->glue_ops
= *glue
->epoll_ops
;
202 glue
->glue_ops
->context_init
= std_event_context_init
;
203 glue
->glue_ops
->loop_once
= std_event_loop_once
;
204 glue
->glue_ops
->loop_wait
= std_event_loop_wait
;
206 ret
= glue
->epoll_ops
->context_init(ev
);
211 tevent_epoll_set_panic_fallback(ev
, std_fallback_to_poll
);
218 glue
->epoll_ops
= NULL
;
221 * Set custom_ops the same as poll.
223 *glue
->glue_ops
= *glue
->poll_ops
;
224 glue
->glue_ops
->context_init
= std_event_context_init
;
226 return glue
->poll_ops
->context_init(ev
);
229 _PRIVATE_
bool tevent_standard_init(void)
231 return tevent_register_backend("standard", &std_event_ops
);