~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to lib/tevent/tevent.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
   main select loop and event handling
 
4
   Copyright (C) Andrew Tridgell 2003
 
5
   Copyright (C) Stefan Metzmacher 2009
 
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
  PLEASE READ THIS BEFORE MODIFYING!
 
27
 
 
28
  This module is a general abstraction for the main select loop and
 
29
  event handling. Do not ever put any localised hacks in here, instead
 
30
  register one of the possible event types and implement that event
 
31
  somewhere else.
 
32
 
 
33
  There are 2 types of event handling that are handled in this module:
 
34
 
 
35
  1) a file descriptor becoming readable or writeable. This is mostly
 
36
     used for network sockets, but can be used for any type of file
 
37
     descriptor. You may only register one handler for each file
 
38
     descriptor/io combination or you will get unpredictable results
 
39
     (this means that you can have a handler for read events, and a
 
40
     separate handler for write events, but not two handlers that are
 
41
     both handling read events)
 
42
 
 
43
  2) a timed event. You can register an event that happens at a
 
44
     specific time.  You can register as many of these as you
 
45
     like. They are single shot - add a new timed event in the event
 
46
     handler to get another event.
 
47
 
 
48
  To setup a set of events you first need to create a event_context
 
49
  structure using the function tevent_context_init(); This returns a
 
50
  'struct tevent_context' that you use in all subsequent calls.
 
51
 
 
52
  After that you can add/remove events that you are interested in
 
53
  using tevent_add_*() and talloc_free()
 
54
 
 
55
  Finally, you call tevent_loop_wait_once() to block waiting for one of the
 
56
  events to occor or tevent_loop_wait() which will loop
 
57
  forever.
 
58
 
 
59
*/
 
60
#include "replace.h"
 
61
#include "system/filesys.h"
 
62
#define TEVENT_DEPRECATED 1
 
63
#include "tevent.h"
 
64
#include "tevent_internal.h"
 
65
#include "tevent_util.h"
 
66
 
 
67
struct tevent_ops_list {
 
68
        struct tevent_ops_list *next, *prev;
 
69
        const char *name;
 
70
        const struct tevent_ops *ops;
 
71
};
 
72
 
 
73
/* list of registered event backends */
 
74
static struct tevent_ops_list *tevent_backends = NULL;
 
75
static char *tevent_default_backend = NULL;
 
76
 
 
77
/*
 
78
  register an events backend
 
79
*/
 
80
bool tevent_register_backend(const char *name, const struct tevent_ops *ops)
 
81
{
 
82
        struct tevent_ops_list *e;
 
83
 
 
84
        for (e = tevent_backends; e != NULL; e = e->next) {
 
85
                if (0 == strcmp(e->name, name)) {
 
86
                        /* already registered, skip it */
 
87
                        return true;
 
88
                }
 
89
        }
 
90
 
 
91
        e = talloc(talloc_autofree_context(), struct tevent_ops_list);
 
92
        if (e == NULL) return false;
 
93
 
 
94
        e->name = name;
 
95
        e->ops = ops;
 
96
        DLIST_ADD(tevent_backends, e);
 
97
 
 
98
        return true;
 
99
}
 
100
 
 
101
/*
 
102
  set the default event backend
 
103
 */
 
104
void tevent_set_default_backend(const char *backend)
 
105
{
 
106
        talloc_free(tevent_default_backend);
 
107
        tevent_default_backend = talloc_strdup(talloc_autofree_context(),
 
108
                                               backend);
 
109
}
 
110
 
 
111
/*
 
112
  initialise backends if not already done
 
113
*/
 
114
static void tevent_backend_init(void)
 
115
{
 
116
        tevent_select_init();
 
117
        tevent_standard_init();
 
118
#ifdef HAVE_EPOLL
 
119
        tevent_epoll_init();
 
120
#endif
 
121
}
 
122
 
 
123
/*
 
124
  list available backends
 
125
*/
 
126
const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
 
127
{
 
128
        const char **list = NULL;
 
129
        struct tevent_ops_list *e;
 
130
 
 
131
        tevent_backend_init();
 
132
 
 
133
        for (e=tevent_backends;e;e=e->next) {
 
134
                list = ev_str_list_add(list, e->name);
 
135
        }
 
136
 
 
137
        talloc_steal(mem_ctx, list);
 
138
 
 
139
        return list;
 
140
}
 
141
 
 
142
int tevent_common_context_destructor(struct tevent_context *ev)
 
143
{
 
144
        struct tevent_fd *fd, *fn;
 
145
        struct tevent_timer *te, *tn;
 
146
        struct tevent_immediate *ie, *in;
 
147
        struct tevent_signal *se, *sn;
 
148
 
 
149
        if (ev->pipe_fde) {
 
150
                talloc_free(ev->pipe_fde);
 
151
                close(ev->pipe_fds[0]);
 
152
                close(ev->pipe_fds[1]);
 
153
                ev->pipe_fde = NULL;
 
154
        }
 
155
 
 
156
        for (fd = ev->fd_events; fd; fd = fn) {
 
157
                fn = fd->next;
 
158
                fd->event_ctx = NULL;
 
159
                DLIST_REMOVE(ev->fd_events, fd);
 
160
        }
 
161
 
 
162
        for (te = ev->timer_events; te; te = tn) {
 
163
                tn = te->next;
 
164
                te->event_ctx = NULL;
 
165
                DLIST_REMOVE(ev->timer_events, te);
 
166
        }
 
167
 
 
168
        for (ie = ev->immediate_events; ie; ie = in) {
 
169
                in = ie->next;
 
170
                ie->event_ctx = NULL;
 
171
                ie->cancel_fn = NULL;
 
172
                DLIST_REMOVE(ev->immediate_events, ie);
 
173
        }
 
174
 
 
175
        for (se = ev->signal_events; se; se = sn) {
 
176
                sn = se->next;
 
177
                se->event_ctx = NULL;
 
178
                DLIST_REMOVE(ev->signal_events, se);
 
179
                /*
 
180
                 * This is important, Otherwise signals
 
181
                 * are handled twice in child. eg, SIGHUP.
 
182
                 * one added in parent, and another one in
 
183
                 * the child. -- BoYang
 
184
                 */
 
185
                tevent_cleanup_pending_signal_handlers(se);
 
186
        }
 
187
 
 
188
        return 0;
 
189
}
 
190
 
 
191
/*
 
192
  create a event_context structure for a specific implemementation.
 
193
  This must be the first events call, and all subsequent calls pass
 
194
  this event_context as the first element. Event handlers also
 
195
  receive this as their first argument.
 
196
 
 
197
  This function is for allowing third-party-applications to hook in gluecode
 
198
  to their own event loop code, so that they can make async usage of our client libs
 
199
 
 
200
  NOTE: use tevent_context_init() inside of samba!
 
201
*/
 
202
static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
 
203
                                                      const struct tevent_ops *ops)
 
204
{
 
205
        struct tevent_context *ev;
 
206
        int ret;
 
207
 
 
208
        ev = talloc_zero(mem_ctx, struct tevent_context);
 
209
        if (!ev) return NULL;
 
210
 
 
211
        talloc_set_destructor(ev, tevent_common_context_destructor);
 
212
 
 
213
        ev->ops = ops;
 
214
 
 
215
        ret = ev->ops->context_init(ev);
 
216
        if (ret != 0) {
 
217
                talloc_free(ev);
 
218
                return NULL;
 
219
        }
 
220
 
 
221
        return ev;
 
222
}
 
223
 
 
224
/*
 
225
  create a event_context structure. This must be the first events
 
226
  call, and all subsequent calls pass this event_context as the first
 
227
  element. Event handlers also receive this as their first argument.
 
228
*/
 
229
struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
 
230
                                                  const char *name)
 
231
{
 
232
        struct tevent_ops_list *e;
 
233
 
 
234
        tevent_backend_init();
 
235
 
 
236
        if (name == NULL) {
 
237
                name = tevent_default_backend;
 
238
        }
 
239
        if (name == NULL) {
 
240
                name = "standard";
 
241
        }
 
242
 
 
243
        for (e=tevent_backends;e;e=e->next) {
 
244
                if (strcmp(name, e->name) == 0) {
 
245
                        return tevent_context_init_ops(mem_ctx, e->ops);
 
246
                }
 
247
        }
 
248
        return NULL;
 
249
}
 
250
 
 
251
 
 
252
/*
 
253
  create a event_context structure. This must be the first events
 
254
  call, and all subsequent calls pass this event_context as the first
 
255
  element. Event handlers also receive this as their first argument.
 
256
*/
 
257
struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
 
258
{
 
259
        return tevent_context_init_byname(mem_ctx, NULL);
 
260
}
 
261
 
 
262
/*
 
263
  add a fd based event
 
264
  return NULL on failure (memory allocation error)
 
265
 
 
266
  if flags contains TEVENT_FD_AUTOCLOSE then the fd will be closed when
 
267
  the returned fd_event context is freed
 
268
*/
 
269
struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
 
270
                                 TALLOC_CTX *mem_ctx,
 
271
                                 int fd,
 
272
                                 uint16_t flags,
 
273
                                 tevent_fd_handler_t handler,
 
274
                                 void *private_data,
 
275
                                 const char *handler_name,
 
276
                                 const char *location)
 
277
{
 
278
        return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
 
279
                               handler_name, location);
 
280
}
 
281
 
 
282
/*
 
283
  set a close function on the fd event
 
284
*/
 
285
void tevent_fd_set_close_fn(struct tevent_fd *fde,
 
286
                            tevent_fd_close_fn_t close_fn)
 
287
{
 
288
        if (!fde) return;
 
289
        if (!fde->event_ctx) return;
 
290
        fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
 
291
}
 
292
 
 
293
static void tevent_fd_auto_close_fn(struct tevent_context *ev,
 
294
                                    struct tevent_fd *fde,
 
295
                                    int fd,
 
296
                                    void *private_data)
 
297
{
 
298
        close(fd);
 
299
}
 
300
 
 
301
void tevent_fd_set_auto_close(struct tevent_fd *fde)
 
302
{
 
303
        tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
 
304
}
 
305
 
 
306
/*
 
307
  return the fd event flags
 
308
*/
 
309
uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
 
310
{
 
311
        if (!fde) return 0;
 
312
        if (!fde->event_ctx) return 0;
 
313
        return fde->event_ctx->ops->get_fd_flags(fde);
 
314
}
 
315
 
 
316
/*
 
317
  set the fd event flags
 
318
*/
 
319
void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
 
320
{
 
321
        if (!fde) return;
 
322
        if (!fde->event_ctx) return;
 
323
        fde->event_ctx->ops->set_fd_flags(fde, flags);
 
324
}
 
325
 
 
326
bool tevent_signal_support(struct tevent_context *ev)
 
327
{
 
328
        if (ev->ops->add_signal) {
 
329
                return true;
 
330
        }
 
331
        return false;
 
332
}
 
333
 
 
334
static void (*tevent_abort_fn)(const char *reason);
 
335
 
 
336
void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
 
337
{
 
338
        tevent_abort_fn = abort_fn;
 
339
}
 
340
 
 
341
static void tevent_abort(struct tevent_context *ev, const char *reason)
 
342
{
 
343
        tevent_debug(ev, TEVENT_DEBUG_FATAL,
 
344
                     "abort: %s\n", reason);
 
345
 
 
346
        if (!tevent_abort_fn) {
 
347
                abort();
 
348
        }
 
349
 
 
350
        tevent_abort_fn(reason);
 
351
}
 
352
 
 
353
/*
 
354
  add a timer event
 
355
  return NULL on failure
 
356
*/
 
357
struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
 
358
                                       TALLOC_CTX *mem_ctx,
 
359
                                       struct timeval next_event,
 
360
                                       tevent_timer_handler_t handler,
 
361
                                       void *private_data,
 
362
                                       const char *handler_name,
 
363
                                       const char *location)
 
364
{
 
365
        return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
 
366
                                  handler_name, location);
 
367
}
 
368
 
 
369
/*
 
370
  allocate an immediate event
 
371
  return NULL on failure (memory allocation error)
 
372
*/
 
373
struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
 
374
                                                  const char *location)
 
375
{
 
376
        struct tevent_immediate *im;
 
377
 
 
378
        im = talloc(mem_ctx, struct tevent_immediate);
 
379
        if (im == NULL) return NULL;
 
380
 
 
381
        im->prev                = NULL;
 
382
        im->next                = NULL;
 
383
        im->event_ctx           = NULL;
 
384
        im->create_location     = location;
 
385
        im->handler             = NULL;
 
386
        im->private_data        = NULL;
 
387
        im->handler_name        = NULL;
 
388
        im->schedule_location   = NULL;
 
389
        im->cancel_fn           = NULL;
 
390
        im->additional_data     = NULL;
 
391
 
 
392
        return im;
 
393
}
 
394
 
 
395
/*
 
396
  schedule an immediate event
 
397
  return NULL on failure
 
398
*/
 
399
void _tevent_schedule_immediate(struct tevent_immediate *im,
 
400
                                struct tevent_context *ev,
 
401
                                tevent_immediate_handler_t handler,
 
402
                                void *private_data,
 
403
                                const char *handler_name,
 
404
                                const char *location)
 
405
{
 
406
        ev->ops->schedule_immediate(im, ev, handler, private_data,
 
407
                                    handler_name, location);
 
408
}
 
409
 
 
410
/*
 
411
  add a signal event
 
412
 
 
413
  sa_flags are flags to sigaction(2)
 
414
 
 
415
  return NULL on failure
 
416
*/
 
417
struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
 
418
                                         TALLOC_CTX *mem_ctx,
 
419
                                         int signum,
 
420
                                         int sa_flags,
 
421
                                         tevent_signal_handler_t handler,
 
422
                                         void *private_data,
 
423
                                         const char *handler_name,
 
424
                                         const char *location)
 
425
{
 
426
        return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
 
427
                                   handler_name, location);
 
428
}
 
429
 
 
430
void tevent_loop_allow_nesting(struct tevent_context *ev)
 
431
{
 
432
        ev->nesting.allowed = true;
 
433
}
 
434
 
 
435
void tevent_loop_set_nesting_hook(struct tevent_context *ev,
 
436
                                  tevent_nesting_hook hook,
 
437
                                  void *private_data)
 
438
{
 
439
        if (ev->nesting.hook_fn &&
 
440
            (ev->nesting.hook_fn != hook ||
 
441
             ev->nesting.hook_private != private_data)) {
 
442
                /* the way the nesting hook code is currently written
 
443
                   we cannot support two different nesting hooks at the
 
444
                   same time. */
 
445
                tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
 
446
        }
 
447
        ev->nesting.hook_fn = hook;
 
448
        ev->nesting.hook_private = private_data;
 
449
}
 
450
 
 
451
static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
 
452
{
 
453
        const char *reason;
 
454
 
 
455
        reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
 
456
                                 location);
 
457
        if (!reason) {
 
458
                reason = "tevent_loop_once() nesting";
 
459
        }
 
460
 
 
461
        tevent_abort(ev, reason);
 
462
}
 
463
 
 
464
/*
 
465
  do a single event loop using the events defined in ev 
 
466
*/
 
467
int _tevent_loop_once(struct tevent_context *ev, const char *location)
 
468
{
 
469
        int ret;
 
470
        void *nesting_stack_ptr = NULL;
 
471
 
 
472
        ev->nesting.level++;
 
473
 
 
474
        if (ev->nesting.level > 1) {
 
475
                if (!ev->nesting.allowed) {
 
476
                        tevent_abort_nesting(ev, location);
 
477
                        errno = ELOOP;
 
478
                        return -1;
 
479
                }
 
480
        }
 
481
        if (ev->nesting.level > 0) {
 
482
                if (ev->nesting.hook_fn) {
 
483
                        int ret2;
 
484
                        ret2 = ev->nesting.hook_fn(ev,
 
485
                                                   ev->nesting.hook_private,
 
486
                                                   ev->nesting.level,
 
487
                                                   true,
 
488
                                                   (void *)&nesting_stack_ptr,
 
489
                                                   location);
 
490
                        if (ret2 != 0) {
 
491
                                ret = ret2;
 
492
                                goto done;
 
493
                        }
 
494
                }
 
495
        }
 
496
 
 
497
        ret = ev->ops->loop_once(ev, location);
 
498
 
 
499
        if (ev->nesting.level > 0) {
 
500
                if (ev->nesting.hook_fn) {
 
501
                        int ret2;
 
502
                        ret2 = ev->nesting.hook_fn(ev,
 
503
                                                   ev->nesting.hook_private,
 
504
                                                   ev->nesting.level,
 
505
                                                   false,
 
506
                                                   (void *)&nesting_stack_ptr,
 
507
                                                   location);
 
508
                        if (ret2 != 0) {
 
509
                                ret = ret2;
 
510
                                goto done;
 
511
                        }
 
512
                }
 
513
        }
 
514
 
 
515
done:
 
516
        ev->nesting.level--;
 
517
        return ret;
 
518
}
 
519
 
 
520
/*
 
521
  this is a performance optimization for the samba4 nested event loop problems
 
522
*/
 
523
int _tevent_loop_until(struct tevent_context *ev,
 
524
                       bool (*finished)(void *private_data),
 
525
                       void *private_data,
 
526
                       const char *location)
 
527
{
 
528
        int ret = 0;
 
529
        void *nesting_stack_ptr = NULL;
 
530
 
 
531
        ev->nesting.level++;
 
532
 
 
533
        if (ev->nesting.level > 1) {
 
534
                if (!ev->nesting.allowed) {
 
535
                        tevent_abort_nesting(ev, location);
 
536
                        errno = ELOOP;
 
537
                        return -1;
 
538
                }
 
539
        }
 
540
        if (ev->nesting.level > 0) {
 
541
                if (ev->nesting.hook_fn) {
 
542
                        int ret2;
 
543
                        ret2 = ev->nesting.hook_fn(ev,
 
544
                                                   ev->nesting.hook_private,
 
545
                                                   ev->nesting.level,
 
546
                                                   true,
 
547
                                                   (void *)&nesting_stack_ptr,
 
548
                                                   location);
 
549
                        if (ret2 != 0) {
 
550
                                ret = ret2;
 
551
                                goto done;
 
552
                        }
 
553
                }
 
554
        }
 
555
 
 
556
        while (!finished(private_data)) {
 
557
                ret = ev->ops->loop_once(ev, location);
 
558
                if (ret != 0) {
 
559
                        break;
 
560
                }
 
561
        }
 
562
 
 
563
        if (ev->nesting.level > 0) {
 
564
                if (ev->nesting.hook_fn) {
 
565
                        int ret2;
 
566
                        ret2 = ev->nesting.hook_fn(ev,
 
567
                                                   ev->nesting.hook_private,
 
568
                                                   ev->nesting.level,
 
569
                                                   false,
 
570
                                                   (void *)&nesting_stack_ptr,
 
571
                                                   location);
 
572
                        if (ret2 != 0) {
 
573
                                ret = ret2;
 
574
                                goto done;
 
575
                        }
 
576
                }
 
577
        }
 
578
 
 
579
done:
 
580
        ev->nesting.level--;
 
581
        return ret;
 
582
}
 
583
 
 
584
/*
 
585
  return on failure or (with 0) if all fd events are removed
 
586
*/
 
587
int tevent_common_loop_wait(struct tevent_context *ev,
 
588
                            const char *location)
 
589
{
 
590
        /*
 
591
         * loop as long as we have events pending
 
592
         */
 
593
        while (ev->fd_events ||
 
594
               ev->timer_events ||
 
595
               ev->immediate_events ||
 
596
               ev->signal_events) {
 
597
                int ret;
 
598
                ret = _tevent_loop_once(ev, location);
 
599
                if (ret != 0) {
 
600
                        tevent_debug(ev, TEVENT_DEBUG_FATAL,
 
601
                                     "_tevent_loop_once() failed: %d - %s\n",
 
602
                                     ret, strerror(errno));
 
603
                        return ret;
 
604
                }
 
605
        }
 
606
 
 
607
        tevent_debug(ev, TEVENT_DEBUG_WARNING,
 
608
                     "tevent_common_loop_wait() out of events\n");
 
609
        return 0;
 
610
}
 
611
 
 
612
/*
 
613
  return on failure or (with 0) if all fd events are removed
 
614
*/
 
615
int _tevent_loop_wait(struct tevent_context *ev, const char *location)
 
616
{
 
617
        return ev->ops->loop_wait(ev, location);
 
618
}