~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to lib/tevent/tevent_select.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-2005
 
5
   Copyright (C) Stefan Metzmacher      2005-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
#include "replace.h"
 
26
#include "system/filesys.h"
 
27
#include "system/select.h"
 
28
#include "tevent.h"
 
29
#include "tevent_util.h"
 
30
#include "tevent_internal.h"
 
31
 
 
32
struct select_event_context {
 
33
        /* a pointer back to the generic event_context */
 
34
        struct tevent_context *ev;
 
35
 
 
36
        /* the maximum file descriptor number in fd_events */
 
37
        int maxfd;
 
38
 
 
39
        /* information for exiting from the event loop */
 
40
        int exit_code;
 
41
};
 
42
 
 
43
/*
 
44
  create a select_event_context structure.
 
45
*/
 
46
static int select_event_context_init(struct tevent_context *ev)
 
47
{
 
48
        struct select_event_context *select_ev;
 
49
 
 
50
        select_ev = talloc_zero(ev, struct select_event_context);
 
51
        if (!select_ev) return -1;
 
52
        select_ev->ev = ev;
 
53
 
 
54
        ev->additional_data = select_ev;
 
55
        return 0;
 
56
}
 
57
 
 
58
/*
 
59
  recalculate the maxfd
 
60
*/
 
61
static void calc_maxfd(struct select_event_context *select_ev)
 
62
{
 
63
        struct tevent_fd *fde;
 
64
 
 
65
        select_ev->maxfd = 0;
 
66
        for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
 
67
                if (fde->fd > select_ev->maxfd) {
 
68
                        select_ev->maxfd = fde->fd;
 
69
                }
 
70
        }
 
71
}
 
72
 
 
73
 
 
74
/* to mark the ev->maxfd invalid
 
75
 * this means we need to recalculate it
 
76
 */
 
77
#define EVENT_INVALID_MAXFD (-1)
 
78
 
 
79
/*
 
80
  destroy an fd_event
 
81
*/
 
82
static int select_event_fd_destructor(struct tevent_fd *fde)
 
83
{
 
84
        struct tevent_context *ev = fde->event_ctx;
 
85
        struct select_event_context *select_ev = NULL;
 
86
 
 
87
        if (ev) {
 
88
                select_ev = talloc_get_type(ev->additional_data,
 
89
                                            struct select_event_context);
 
90
 
 
91
                if (select_ev->maxfd == fde->fd) {
 
92
                        select_ev->maxfd = EVENT_INVALID_MAXFD;
 
93
                }
 
94
        }
 
95
 
 
96
        return tevent_common_fd_destructor(fde);
 
97
}
 
98
 
 
99
/*
 
100
  add a fd based event
 
101
  return NULL on failure (memory allocation error)
 
102
*/
 
103
static struct tevent_fd *select_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
 
104
                                             int fd, uint16_t flags,
 
105
                                             tevent_fd_handler_t handler,
 
106
                                             void *private_data,
 
107
                                             const char *handler_name,
 
108
                                             const char *location)
 
109
{
 
110
        struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
 
111
                                                           struct select_event_context);
 
112
        struct tevent_fd *fde;
 
113
 
 
114
        fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
 
115
                                   handler, private_data,
 
116
                                   handler_name, location);
 
117
        if (!fde) return NULL;
 
118
 
 
119
        if (fde->fd > select_ev->maxfd) {
 
120
                select_ev->maxfd = fde->fd;
 
121
        }
 
122
        talloc_set_destructor(fde, select_event_fd_destructor);
 
123
 
 
124
        return fde;
 
125
}
 
126
 
 
127
/*
 
128
  event loop handling using select()
 
129
*/
 
130
static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp)
 
131
{
 
132
        fd_set r_fds, w_fds;
 
133
        struct tevent_fd *fde;
 
134
        int selrtn;
 
135
 
 
136
        /* we maybe need to recalculate the maxfd */
 
137
        if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
 
138
                calc_maxfd(select_ev);
 
139
        }
 
140
 
 
141
        FD_ZERO(&r_fds);
 
142
        FD_ZERO(&w_fds);
 
143
 
 
144
        /* setup any fd events */
 
145
        for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
 
146
                if (fde->flags & TEVENT_FD_READ) {
 
147
                        FD_SET(fde->fd, &r_fds);
 
148
                }
 
149
                if (fde->flags & TEVENT_FD_WRITE) {
 
150
                        FD_SET(fde->fd, &w_fds);
 
151
                }
 
152
        }
 
153
 
 
154
        if (select_ev->ev->signal_events &&
 
155
            tevent_common_check_signal(select_ev->ev)) {
 
156
                return 0;
 
157
        }
 
158
 
 
159
        selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
 
160
 
 
161
        if (selrtn == -1 && errno == EINTR && 
 
162
            select_ev->ev->signal_events) {
 
163
                tevent_common_check_signal(select_ev->ev);
 
164
                return 0;
 
165
        }
 
166
 
 
167
        if (selrtn == -1 && errno == EBADF) {
 
168
                /* the socket is dead! this should never
 
169
                   happen as the socket should have first been
 
170
                   made readable and that should have removed
 
171
                   the event, so this must be a bug. This is a
 
172
                   fatal error. */
 
173
                tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL,
 
174
                             "ERROR: EBADF on select_event_loop_once\n");
 
175
                select_ev->exit_code = EBADF;
 
176
                return -1;
 
177
        }
 
178
 
 
179
        if (selrtn == 0 && tvalp) {
 
180
                /* we don't care about a possible delay here */
 
181
                tevent_common_loop_timer_delay(select_ev->ev);
 
182
                return 0;
 
183
        }
 
184
 
 
185
        if (selrtn > 0) {
 
186
                /* at least one file descriptor is ready - check
 
187
                   which ones and call the handler, being careful to allow
 
188
                   the handler to remove itself when called */
 
189
                for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
 
190
                        uint16_t flags = 0;
 
191
 
 
192
                        if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
 
193
                        if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
 
194
                        if (flags) {
 
195
                                fde->handler(select_ev->ev, fde, flags, fde->private_data);
 
196
                                break;
 
197
                        }
 
198
                }
 
199
        }
 
200
 
 
201
        return 0;
 
202
}
 
203
 
 
204
/*
 
205
  do a single event loop using the events defined in ev 
 
206
*/
 
207
static int select_event_loop_once(struct tevent_context *ev, const char *location)
 
208
{
 
209
        struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
 
210
                                                           struct select_event_context);
 
211
        struct timeval tval;
 
212
 
 
213
        if (ev->signal_events &&
 
214
            tevent_common_check_signal(ev)) {
 
215
                return 0;
 
216
        }
 
217
 
 
218
        if (ev->immediate_events &&
 
219
            tevent_common_loop_immediate(ev)) {
 
220
                return 0;
 
221
        }
 
222
 
 
223
        tval = tevent_common_loop_timer_delay(ev);
 
224
        if (tevent_timeval_is_zero(&tval)) {
 
225
                return 0;
 
226
        }
 
227
 
 
228
        return select_event_loop_select(select_ev, &tval);
 
229
}
 
230
 
 
231
static const struct tevent_ops select_event_ops = {
 
232
        .context_init           = select_event_context_init,
 
233
        .add_fd                 = select_event_add_fd,
 
234
        .set_fd_close_fn        = tevent_common_fd_set_close_fn,
 
235
        .get_fd_flags           = tevent_common_fd_get_flags,
 
236
        .set_fd_flags           = tevent_common_fd_set_flags,
 
237
        .add_timer              = tevent_common_add_timer,
 
238
        .schedule_immediate     = tevent_common_schedule_immediate,
 
239
        .add_signal             = tevent_common_add_signal,
 
240
        .loop_once              = select_event_loop_once,
 
241
        .loop_wait              = tevent_common_loop_wait,
 
242
};
 
243
 
 
244
bool tevent_select_init(void)
 
245
{
 
246
        return tevent_register_backend("select", &select_event_ops);
 
247
}