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
;
71 TALLOC_FREE(ev
->additional_data
);
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
);
105 static int std_event_loop_once(struct tevent_context
*ev
, const char *location
)
107 void *glue_ptr
= talloc_parent(ev
->ops
);
108 struct std_event_glue
*glue
=
109 talloc_get_type_abort(glue_ptr
,
110 struct std_event_glue
);
113 ret
= glue
->epoll_ops
->loop_once(ev
, location
);
114 if (glue
->epoll_ops
!= NULL
) {
119 if (!glue
->fallback_replay
) {
121 * The problem happened while modifying an event.
122 * An event handler was triggered in this case
123 * and there is no need to call loop_once() again.
128 return glue
->poll_ops
->loop_once(ev
, location
);
132 Initialize the epoll backend and allow it to call a
133 switch function if epoll fails at runtime.
135 static int std_event_context_init(struct tevent_context
*ev
)
137 struct std_event_glue
*glue
;
141 * If this is the first initialization
142 * we need to set up the allocated ops
146 if (ev
->ops
== &std_event_ops
) {
147 glue
= talloc_zero(ev
, struct std_event_glue
);
152 glue
->epoll_ops
= tevent_find_ops_byname("epoll");
154 glue
->poll_ops
= tevent_find_ops_byname("poll");
155 if (glue
->poll_ops
== NULL
) {
160 * Allocate space for our custom ops.
161 * Allocate as a child of our epoll_ops pointer
162 * so we can easily get to it using talloc_parent.
164 glue
->glue_ops
= talloc_zero(glue
, struct tevent_ops
);
165 if (glue
->glue_ops
== NULL
) {
170 ev
->ops
= glue
->glue_ops
;
172 void *glue_ptr
= talloc_parent(ev
->ops
);
173 glue
= talloc_get_type_abort(glue_ptr
, struct std_event_glue
);
176 if (glue
->epoll_ops
!= NULL
) {
178 * Set custom_ops the same as epoll,
179 * except re-init using std_event_context_init()
180 * and use std_event_loop_once() to add the
181 * ability to fallback to a poll backend on
182 * epoll runtime error.
184 *glue
->glue_ops
= *glue
->epoll_ops
;
185 glue
->glue_ops
->context_init
= std_event_context_init
;
186 glue
->glue_ops
->loop_once
= std_event_loop_once
;
188 ret
= glue
->epoll_ops
->context_init(ev
);
193 if (!tevent_epoll_set_panic_fallback(ev
, std_fallback_to_poll
)) {
194 TALLOC_FREE(ev
->additional_data
);
203 glue
->epoll_ops
= NULL
;
206 * Set custom_ops the same as poll.
208 *glue
->glue_ops
= *glue
->poll_ops
;
209 glue
->glue_ops
->context_init
= std_event_context_init
;
211 return glue
->poll_ops
->context_init(ev
);
214 _PRIVATE_
bool tevent_standard_init(void)
216 return tevent_register_backend("standard", &std_event_ops
);