source: vendor/current/lib/tevent/tevent_standard.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 5.8 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 main select loop and event handling
4 Copyright (C) Stefan Metzmacher 2013
5 Copyright (C) Jeremy Allison 2013
6
7 ** NOTE! The following LGPL license applies to the tevent
8 ** library. This does NOT imply that all of Samba is released
9 ** under the LGPL
10
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.
15
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.
20
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/>.
23*/
24
25/*
26 This is SAMBA's default event loop code
27
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()
32*/
33
34#include "replace.h"
35#include "tevent.h"
36#include "tevent_util.h"
37#include "tevent_internal.h"
38
39struct std_event_glue {
40 const struct tevent_ops *epoll_ops;
41 const struct tevent_ops *poll_ops;
42 struct tevent_ops *glue_ops;
43 bool fallback_replay;
44};
45
46static int std_event_context_init(struct tevent_context *ev);
47
48static const struct tevent_ops std_event_ops = {
49 .context_init = std_event_context_init,
50};
51
52/*
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().
56*/
57#ifdef HAVE_EPOLL
58static bool std_fallback_to_poll(struct tevent_context *ev, bool replay)
59{
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);
64 int ret;
65 struct tevent_fd *fde;
66 struct tevent_fd *fde_next;
67
68 glue->fallback_replay = replay;
69
70 /* First switch all the ops to poll. */
71 glue->epoll_ops = NULL;
72
73 /*
74 * Set custom_ops the same as poll.
75 */
76 *glue->glue_ops = *glue->poll_ops;
77 glue->glue_ops->context_init = std_event_context_init;
78
79 /* Next initialize the poll backend. */
80 ret = glue->poll_ops->context_init(ev);
81 if (ret != 0) {
82 return false;
83 }
84
85 /*
86 * Now we have to change all the existing file descriptor
87 * events from the epoll backend to the poll backend.
88 */
89 for (fde = ev->fd_events; fde; fde = fde_next) {
90 /*
91 * We must remove this fde off the ev->fd_events list.
92 */
93 fde_next = fde->next;
94
95 /* Remove from the ev->fd_events list. */
96 DLIST_REMOVE(ev->fd_events, fde);
97
98 /* Re-add this event as a poll backend event. */
99 tevent_poll_event_add_fd_internal(ev, fde);
100 }
101
102 return true;
103}
104#endif
105
106static int std_event_loop_once(struct tevent_context *ev, const char *location)
107{
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);
112 int ret;
113
114 ret = glue->epoll_ops->loop_once(ev, location);
115 if (glue->epoll_ops != NULL) {
116 /* No fallback */
117 return ret;
118 }
119
120 if (!glue->fallback_replay) {
121 /*
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.
125 */
126 return ret;
127 }
128
129 return glue->poll_ops->loop_once(ev, location);
130}
131
132static int std_event_loop_wait(struct tevent_context *ev, const char *location)
133{
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);
138 int ret;
139
140 ret = glue->epoll_ops->loop_wait(ev, location);
141 if (glue->epoll_ops != NULL) {
142 /* No fallback */
143 return ret;
144 }
145
146 return glue->poll_ops->loop_wait(ev, location);
147}
148/*
149 Initialize the epoll backend and allow it to call a
150 switch function if epoll fails at runtime.
151*/
152static int std_event_context_init(struct tevent_context *ev)
153{
154 struct std_event_glue *glue;
155 int ret;
156
157 /*
158 * If this is the first initialization
159 * we need to set up the allocated ops
160 * pointers.
161 */
162
163 if (ev->ops == &std_event_ops) {
164 glue = talloc_zero(ev, struct std_event_glue);
165 if (glue == NULL) {
166 return -1;
167 }
168
169 glue->epoll_ops = tevent_find_ops_byname("epoll");
170
171 glue->poll_ops = tevent_find_ops_byname("poll");
172 if (glue->poll_ops == NULL) {
173 return -1;
174 }
175
176 /*
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.
180 */
181 glue->glue_ops = talloc_zero(glue, struct tevent_ops);
182 if (glue->glue_ops == NULL) {
183 talloc_free(glue);
184 return -1;
185 }
186
187 ev->ops = glue->glue_ops;
188 } else {
189 void *glue_ptr = talloc_parent(ev->ops);
190 glue = talloc_get_type_abort(glue_ptr, struct std_event_glue);
191 }
192
193 if (glue->epoll_ops != NULL) {
194 /*
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.
200 */
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;
205
206 ret = glue->epoll_ops->context_init(ev);
207 if (ret == -1) {
208 goto fallback;
209 }
210#ifdef HAVE_EPOLL
211 tevent_epoll_set_panic_fallback(ev, std_fallback_to_poll);
212#endif
213
214 return ret;
215 }
216
217fallback:
218 glue->epoll_ops = NULL;
219
220 /*
221 * Set custom_ops the same as poll.
222 */
223 *glue->glue_ops = *glue->poll_ops;
224 glue->glue_ops->context_init = std_event_context_init;
225
226 return glue->poll_ops->context_init(ev);
227}
228
229_PRIVATE_ bool tevent_standard_init(void)
230{
231 return tevent_register_backend("standard", &std_event_ops);
232}
Note: See TracBrowser for help on using the repository browser.