tevent: rename event_set_default_backend() => tevent_set_default_backend()
[ira/wip.git] / lib / tevent / tevent.c
1 /* 
2    Unix SMB/CIFS implementation.
3    main select loop and event handling
4    Copyright (C) Andrew Tridgell 2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /*
21   PLEASE READ THIS BEFORE MODIFYING!
22
23   This module is a general abstraction for the main select loop and
24   event handling. Do not ever put any localised hacks in here, instead
25   register one of the possible event types and implement that event
26   somewhere else.
27
28   There are 2 types of event handling that are handled in this module:
29
30   1) a file descriptor becoming readable or writeable. This is mostly
31      used for network sockets, but can be used for any type of file
32      descriptor. You may only register one handler for each file
33      descriptor/io combination or you will get unpredictable results
34      (this means that you can have a handler for read events, and a
35      separate handler for write events, but not two handlers that are
36      both handling read events)
37
38   2) a timed event. You can register an event that happens at a
39      specific time.  You can register as many of these as you
40      like. They are single shot - add a new timed event in the event
41      handler to get another event.
42
43   To setup a set of events you first need to create a event_context
44   structure using the function event_context_init(); This returns a
45   'struct tevent_context' that you use in all subsequent calls.
46
47   After that you can add/remove events that you are interested in
48   using event_add_*() and talloc_free()
49
50   Finally, you call event_loop_wait_once() to block waiting for one of the
51   events to occor or event_loop_wait() which will loop
52   forever.
53
54 */
55 #include "replace.h"
56 #include "tevent.h"
57 #include "tevent_internal.h"
58 #include "tevent_util.h"
59
60 struct event_ops_list {
61         struct event_ops_list *next, *prev;
62         const char *name;
63         const struct event_ops *ops;
64 };
65
66 /* list of registered event backends */
67 static struct event_ops_list *event_backends = NULL;
68 static char *tevent_default_backend = NULL;
69
70 /*
71   register an events backend
72 */
73 bool event_register_backend(const char *name, const struct event_ops *ops)
74 {
75         struct event_ops_list *e;
76
77         for (e = event_backends; e != NULL; e = e->next) {
78                 if (0 == strcmp(e->name, name)) {
79                         /* already registered, skip it */
80                         return true;
81                 }
82         }
83
84         e = talloc(talloc_autofree_context(), struct event_ops_list);
85         if (e == NULL) return false;
86
87         e->name = name;
88         e->ops = ops;
89         DLIST_ADD(event_backends, e);
90
91         return true;
92 }
93
94 /*
95   set the default event backend
96  */
97 void tevent_set_default_backend(const char *backend)
98 {
99         talloc_free(tevent_default_backend);
100         tevent_default_backend = talloc_strdup(talloc_autofree_context(),
101                                                backend);
102 }
103
104 /*
105   initialise backends if not already done
106 */
107 static void event_backend_init(void)
108 {
109         events_select_init();
110         events_standard_init();
111 #if HAVE_EVENTS_EPOLL
112         events_epoll_init();
113 #endif
114 #if HAVE_LINUX_AIO
115         events_aio_init();
116 #endif
117 }
118
119 /*
120   list available backends
121 */
122 const char **event_backend_list(TALLOC_CTX *mem_ctx)
123 {
124         const char **list = NULL;
125         struct event_ops_list *e;
126
127         event_backend_init();
128
129         for (e=event_backends;e;e=e->next) {
130                 list = ev_str_list_add(list, e->name);
131         }
132
133         talloc_steal(mem_ctx, list);
134
135         return list;
136 }
137
138 /*
139   create a event_context structure for a specific implemementation.
140   This must be the first events call, and all subsequent calls pass
141   this event_context as the first element. Event handlers also
142   receive this as their first argument.
143
144   This function is for allowing third-party-applications to hook in gluecode
145   to their own event loop code, so that they can make async usage of our client libs
146
147   NOTE: use event_context_init() inside of samba!
148 */
149 static struct tevent_context *event_context_init_ops(TALLOC_CTX *mem_ctx, 
150                                                     const struct event_ops *ops)
151 {
152         struct tevent_context *ev;
153         int ret;
154
155         ev = talloc_zero(mem_ctx, struct tevent_context);
156         if (!ev) return NULL;
157
158         ev->ops = ops;
159
160         ret = ev->ops->context_init(ev);
161         if (ret != 0) {
162                 talloc_free(ev);
163                 return NULL;
164         }
165
166         return ev;
167 }
168
169 /*
170   create a event_context structure. This must be the first events
171   call, and all subsequent calls pass this event_context as the first
172   element. Event handlers also receive this as their first argument.
173 */
174 struct tevent_context *event_context_init_byname(TALLOC_CTX *mem_ctx, const char *name)
175 {
176         struct event_ops_list *e;
177
178         event_backend_init();
179
180         if (name == NULL) {
181                 name = tevent_default_backend;
182         }
183         if (name == NULL) {
184                 name = "standard";
185         }
186
187         for (e=event_backends;e;e=e->next) {
188                 if (strcmp(name, e->name) == 0) {
189                         return event_context_init_ops(mem_ctx, e->ops);
190                 }
191         }
192         return NULL;
193 }
194
195
196 /*
197   create a event_context structure. This must be the first events
198   call, and all subsequent calls pass this event_context as the first
199   element. Event handlers also receive this as their first argument.
200 */
201 struct tevent_context *event_context_init(TALLOC_CTX *mem_ctx)
202 {
203         return event_context_init_byname(mem_ctx, NULL);
204 }
205
206 /*
207   add a fd based event
208   return NULL on failure (memory allocation error)
209
210   if flags contains EVENT_FD_AUTOCLOSE then the fd will be closed when
211   the returned fd_event context is freed
212 */
213 struct tevent_fd *event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
214                               int fd, uint16_t flags, event_fd_handler_t handler,
215                               void *private_data)
216 {
217         return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data);
218 }
219
220 /*
221   add a disk aio event
222 */
223 struct aio_event *event_add_aio(struct tevent_context *ev,
224                                 TALLOC_CTX *mem_ctx,
225                                 struct iocb *iocb,
226                                 event_aio_handler_t handler,
227                                 void *private_data)
228 {
229         if (ev->ops->add_aio == NULL) return NULL;
230         return ev->ops->add_aio(ev, mem_ctx, iocb, handler, private_data);
231 }
232
233 /*
234   return the fd event flags
235 */
236 uint16_t event_get_fd_flags(struct tevent_fd *fde)
237 {
238         if (!fde) return 0;
239         return fde->event_ctx->ops->get_fd_flags(fde);
240 }
241
242 /*
243   set the fd event flags
244 */
245 void event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
246 {
247         if (!fde) return;
248         fde->event_ctx->ops->set_fd_flags(fde, flags);
249 }
250
251 /*
252   add a timed event
253   return NULL on failure
254 */
255 struct tevent_timer *event_add_timed(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
256                                     struct timeval next_event, 
257                                     event_timed_handler_t handler, 
258                                     void *private_data)
259 {
260         return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data);
261 }
262
263 /*
264   add a signal event
265
266   sa_flags are flags to sigaction(2)
267
268   return NULL on failure
269 */
270 struct signal_event *event_add_signal(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
271                                       int signum,
272                                       int sa_flags,
273                                       event_signal_handler_t handler, 
274                                       void *private_data)
275 {
276         return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data);
277 }
278
279 /*
280   do a single event loop using the events defined in ev 
281 */
282 int event_loop_once(struct tevent_context *ev)
283 {
284         return ev->ops->loop_once(ev);
285 }
286
287 /*
288   return on failure or (with 0) if all fd events are removed
289 */
290 int event_loop_wait(struct tevent_context *ev)
291 {
292         return ev->ops->loop_wait(ev);
293 }