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
);
116 * If the above hasn't panicked due to an epoll interface failure,
117 * std_fallback_to_poll() wasn't called, and hasn't cleared epoll_ops to
118 * signify fallback to poll_ops.
120 if (glue
->epoll_ops
!= NULL
) {
125 if (!glue
->fallback_replay
) {
127 * The problem happened while modifying an event.
128 * An event handler was triggered in this case
129 * and there is no need to call loop_once() again.
134 return glue
->poll_ops
->loop_once(ev
, location
);
137 static int std_event_loop_wait(struct tevent_context
*ev
, const char *location
)
139 void *glue_ptr
= talloc_parent(ev
->ops
);
140 struct std_event_glue
*glue
=
141 talloc_get_type_abort(glue_ptr
,
142 struct std_event_glue
);
145 ret
= glue
->epoll_ops
->loop_wait(ev
, location
);
147 * If the above hasn't panicked due to an epoll interface failure,
148 * std_fallback_to_poll() wasn't called, and hasn't cleared epoll_ops to
149 * signify fallback to poll_ops.
151 if (glue
->epoll_ops
!= NULL
) {
156 return glue
->poll_ops
->loop_wait(ev
, location
);
159 Initialize the epoll backend and allow it to call a
160 switch function if epoll fails at runtime.
162 static int std_event_context_init(struct tevent_context
*ev
)
164 struct std_event_glue
*glue
;
168 * If this is the first initialization
169 * we need to set up the allocated ops
173 if (ev
->ops
== &std_event_ops
) {
174 glue
= talloc_zero(ev
, struct std_event_glue
);
179 glue
->epoll_ops
= tevent_find_ops_byname("epoll");
181 glue
->poll_ops
= tevent_find_ops_byname("poll");
182 if (glue
->poll_ops
== NULL
) {
187 * Allocate space for our custom ops.
188 * Allocate as a child of our epoll_ops pointer
189 * so we can easily get to it using talloc_parent.
191 glue
->glue_ops
= talloc_zero(glue
, struct tevent_ops
);
192 if (glue
->glue_ops
== NULL
) {
197 ev
->ops
= glue
->glue_ops
;
199 void *glue_ptr
= talloc_parent(ev
->ops
);
200 glue
= talloc_get_type_abort(glue_ptr
, struct std_event_glue
);
203 if (glue
->epoll_ops
!= NULL
) {
205 * Set custom_ops the same as epoll,
206 * except re-init using std_event_context_init()
207 * and use std_event_loop_once() to add the
208 * ability to fallback to a poll backend on
209 * epoll runtime error.
211 *glue
->glue_ops
= *glue
->epoll_ops
;
212 glue
->glue_ops
->context_init
= std_event_context_init
;
213 glue
->glue_ops
->loop_once
= std_event_loop_once
;
214 glue
->glue_ops
->loop_wait
= std_event_loop_wait
;
216 ret
= glue
->epoll_ops
->context_init(ev
);
221 tevent_epoll_set_panic_fallback(ev
, std_fallback_to_poll
);
228 glue
->epoll_ops
= NULL
;
231 * Set custom_ops the same as poll.
233 *glue
->glue_ops
= *glue
->poll_ops
;
234 glue
->glue_ops
->context_init
= std_event_context_init
;
236 return glue
->poll_ops
->context_init(ev
);
239 _PRIVATE_
bool tevent_standard_init(void)
241 return tevent_register_backend("standard", &std_event_ops
);