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
;
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
) {
91 /* Re-add this event as a poll backend event. */
92 ok
= tevent_poll_event_add_fd_internal(ev
, fde
);
102 static int std_event_loop_once(struct tevent_context
*ev
, const char *location
)
104 void *glue_ptr
= talloc_parent(ev
->ops
);
105 struct std_event_glue
*glue
=
106 talloc_get_type_abort(glue_ptr
,
107 struct std_event_glue
);
110 ret
= glue
->epoll_ops
->loop_once(ev
, location
);
112 * If the above hasn't panicked due to an epoll interface failure,
113 * std_fallback_to_poll() wasn't called, and hasn't cleared epoll_ops to
114 * signify fallback to poll_ops.
116 if (glue
->epoll_ops
!= NULL
) {
121 if (!glue
->fallback_replay
) {
123 * The problem happened while modifying an event.
124 * An event handler was triggered in this case
125 * and there is no need to call loop_once() again.
130 return glue
->poll_ops
->loop_once(ev
, location
);
133 static int std_event_loop_wait(struct tevent_context
*ev
, const char *location
)
135 void *glue_ptr
= talloc_parent(ev
->ops
);
136 struct std_event_glue
*glue
=
137 talloc_get_type_abort(glue_ptr
,
138 struct std_event_glue
);
141 ret
= glue
->epoll_ops
->loop_wait(ev
, location
);
143 * If the above hasn't panicked due to an epoll interface failure,
144 * std_fallback_to_poll() wasn't called, and hasn't cleared epoll_ops to
145 * signify fallback to poll_ops.
147 if (glue
->epoll_ops
!= NULL
) {
152 return glue
->poll_ops
->loop_wait(ev
, location
);
155 Initialize the epoll backend and allow it to call a
156 switch function if epoll fails at runtime.
158 static int std_event_context_init(struct tevent_context
*ev
)
160 struct std_event_glue
*glue
;
164 * If this is the first initialization
165 * we need to set up the allocated ops
169 if (ev
->ops
== &std_event_ops
) {
170 glue
= talloc_zero(ev
, struct std_event_glue
);
175 glue
->epoll_ops
= tevent_find_ops_byname("epoll");
177 glue
->poll_ops
= tevent_find_ops_byname("poll");
178 if (glue
->poll_ops
== NULL
) {
183 * Allocate space for our custom ops.
184 * Allocate as a child of our epoll_ops pointer
185 * so we can easily get to it using talloc_parent.
187 glue
->glue_ops
= talloc_zero(glue
, struct tevent_ops
);
188 if (glue
->glue_ops
== NULL
) {
193 ev
->ops
= glue
->glue_ops
;
195 void *glue_ptr
= talloc_parent(ev
->ops
);
196 glue
= talloc_get_type_abort(glue_ptr
, struct std_event_glue
);
199 if (glue
->epoll_ops
!= NULL
) {
201 * Set custom_ops the same as epoll,
202 * except re-init using std_event_context_init()
203 * and use std_event_loop_once() to add the
204 * ability to fallback to a poll backend on
205 * epoll runtime error.
207 *glue
->glue_ops
= *glue
->epoll_ops
;
208 glue
->glue_ops
->context_init
= std_event_context_init
;
209 glue
->glue_ops
->loop_once
= std_event_loop_once
;
210 glue
->glue_ops
->loop_wait
= std_event_loop_wait
;
212 ret
= glue
->epoll_ops
->context_init(ev
);
217 tevent_epoll_set_panic_fallback(ev
, std_fallback_to_poll
);
224 glue
->epoll_ops
= NULL
;
227 * Set custom_ops the same as poll.
229 *glue
->glue_ops
= *glue
->poll_ops
;
230 glue
->glue_ops
->context_init
= std_event_context_init
;
232 return glue
->poll_ops
->context_init(ev
);
235 _PRIVATE_
bool tevent_standard_init(void)
237 return tevent_register_backend("standard", &std_event_ops
);