Coverage Report

Created: 2018-08-29 13:53

/src/libevent/select.c
Line
Count
Source (jump to first uncovered line)
1
/*  $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
2
3
/*
4
 * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
5
 * Copyright 2007-2012 Niels Provos and Nick Mathewson
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 * 3. The name of the author may not be used to endorse or promote products
16
 *    derived from this software without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 */
29
#include "event2/event-config.h"
30
#include "evconfig-private.h"
31
32
#ifdef EVENT__HAVE_SELECT
33
34
#ifdef __APPLE__
35
/* Apple wants us to define this if we might ever pass more than
36
 * FD_SETSIZE bits to select(). */
37
#define _DARWIN_UNLIMITED_SELECT
38
#endif
39
40
#include <sys/types.h>
41
#ifdef EVENT__HAVE_SYS_TIME_H
42
#include <sys/time.h>
43
#endif
44
#ifdef EVENT__HAVE_SYS_SELECT_H
45
#include <sys/select.h>
46
#endif
47
#include <sys/queue.h>
48
#include <signal.h>
49
#include <stdio.h>
50
#include <stdlib.h>
51
#include <string.h>
52
#include <unistd.h>
53
#include <errno.h>
54
55
#include "event-internal.h"
56
#include "evsignal-internal.h"
57
#include "event2/thread.h"
58
#include "evthread-internal.h"
59
#include "log-internal.h"
60
#include "evmap-internal.h"
61
62
#ifndef EVENT__HAVE_FD_MASK
63
/* This type is mandatory, but Android doesn't define it. */
64
typedef unsigned long fd_mask;
65
#endif
66
67
#ifndef NFDBITS
68
#define NFDBITS (sizeof(fd_mask)*8)
69
#endif
70
71
/* Divide positive x by y, rounding up. */
72
0
#define DIV_ROUNDUP(x, y)   (((x)+((y)-1))/(y))
73
74
/* How many bytes to allocate for N fds? */
75
#define SELECT_ALLOC_SIZE(n) \
76
0
  (DIV_ROUNDUP(n, NFDBITS) * sizeof(fd_mask))
77
78
struct selectop {
79
  int event_fds;    /* Highest fd in fd set */
80
  int event_fdsz;
81
  int resize_out_sets;
82
  fd_set *event_readset_in;
83
  fd_set *event_writeset_in;
84
  fd_set *event_readset_out;
85
  fd_set *event_writeset_out;
86
};
87
88
static void *select_init(struct event_base *);
89
static int select_add(struct event_base *, int, short old, short events, void*);
90
static int select_del(struct event_base *, int, short old, short events, void*);
91
static int select_dispatch(struct event_base *, struct timeval *);
92
static void select_dealloc(struct event_base *);
93
94
const struct eventop selectops = {
95
  "select",
96
  select_init,
97
  select_add,
98
  select_del,
99
  select_dispatch,
100
  select_dealloc,
101
  0, /* doesn't need reinit. */
102
  EV_FEATURE_FDS,
103
  0,
104
};
105
106
static int select_resize(struct selectop *sop, int fdsz);
107
static void select_free_selectop(struct selectop *sop);
108
109
static void *
110
select_init(struct event_base *base)
111
0
{
112
0
  struct selectop *sop;
113
0
114
0
  if (!(sop = mm_calloc(1, sizeof(struct selectop))))
115
0
    return (NULL);
116
0
117
0
  if (select_resize(sop, SELECT_ALLOC_SIZE(32 + 1))) {
118
0
    select_free_selectop(sop);
119
0
    return (NULL);
120
0
  }
121
0
122
0
  evsig_init_(base);
123
0
124
0
  evutil_weakrand_seed_(&base->weakrand_seed, 0);
125
0
126
0
  return (sop);
127
0
}
128
129
#ifdef CHECK_INVARIANTS
130
static void
131
check_selectop(struct selectop *sop)
132
{
133
  /* nothing to be done here */
134
}
135
#else
136
0
#define check_selectop(sop) do { (void) sop; } while (0)
137
#endif
138
139
static int
140
select_dispatch(struct event_base *base, struct timeval *tv)
141
0
{
142
0
  int res=0, i, j, nfds;
143
0
  struct selectop *sop = base->evbase;
144
0
145
0
  check_selectop(sop);
146
0
  if (sop->resize_out_sets) {
147
0
    fd_set *readset_out=NULL, *writeset_out=NULL;
148
0
    size_t sz = sop->event_fdsz;
149
0
    if (!(readset_out = mm_realloc(sop->event_readset_out, sz)))
150
0
      return (-1);
151
0
    sop->event_readset_out = readset_out;
152
0
    if (!(writeset_out = mm_realloc(sop->event_writeset_out, sz))) {
153
0
      /* We don't free readset_out here, since it was
154
0
       * already successfully reallocated. The next time
155
0
       * we call select_dispatch, the realloc will be a
156
0
       * no-op. */
157
0
      return (-1);
158
0
    }
159
0
    sop->event_writeset_out = writeset_out;
160
0
    sop->resize_out_sets = 0;
161
0
  }
162
0
163
0
  memcpy(sop->event_readset_out, sop->event_readset_in,
164
0
         sop->event_fdsz);
165
0
  memcpy(sop->event_writeset_out, sop->event_writeset_in,
166
0
         sop->event_fdsz);
167
0
168
0
  nfds = sop->event_fds+1;
169
0
170
0
  EVBASE_RELEASE_LOCK(base, th_base_lock);
171
0
172
0
  res = select(nfds, sop->event_readset_out,
173
0
      sop->event_writeset_out, NULL, tv);
174
0
175
0
  EVBASE_ACQUIRE_LOCK(base, th_base_lock);
176
0
177
0
  check_selectop(sop);
178
0
179
0
  if (res == -1) {
180
0
    if (errno != EINTR) {
181
0
      event_warn("select");
182
0
      return (-1);
183
0
    }
184
0
185
0
    return (0);
186
0
  }
187
0
188
0
  event_debug(("%s: select reports %d", __func__, res));
189
0
190
0
  check_selectop(sop);
191
0
  i = evutil_weakrand_range_(&base->weakrand_seed, nfds);
192
0
  for (j = 0; j < nfds; ++j) {
193
0
    if (++i >= nfds)
194
0
      i = 0;
195
0
    res = 0;
196
0
    if (FD_ISSET(i, sop->event_readset_out))
197
0
      res |= EV_READ;
198
0
    if (FD_ISSET(i, sop->event_writeset_out))
199
0
      res |= EV_WRITE;
200
0
201
0
    if (res == 0)
202
0
      continue;
203
0
204
0
    evmap_io_active_(base, i, res);
205
0
  }
206
0
  check_selectop(sop);
207
0
208
0
  return (0);
209
0
}
210
211
static int
212
select_resize(struct selectop *sop, int fdsz)
213
0
{
214
0
  fd_set *readset_in = NULL;
215
0
  fd_set *writeset_in = NULL;
216
0
217
0
  if (sop->event_readset_in)
218
0
    check_selectop(sop);
219
0
220
0
  if ((readset_in = mm_realloc(sop->event_readset_in, fdsz)) == NULL)
221
0
    goto error;
222
0
  sop->event_readset_in = readset_in;
223
0
  if ((writeset_in = mm_realloc(sop->event_writeset_in, fdsz)) == NULL) {
224
0
    /* Note that this will leave event_readset_in expanded.
225
0
     * That's okay; we wouldn't want to free it, since that would
226
0
     * change the semantics of select_resize from "expand the
227
0
     * readset_in and writeset_in, or return -1" to "expand the
228
0
     * *set_in members, or trash them and return -1."
229
0
     */
230
0
    goto error;
231
0
  }
232
0
  sop->event_writeset_in = writeset_in;
233
0
  sop->resize_out_sets = 1;
234
0
235
0
  memset((char *)sop->event_readset_in + sop->event_fdsz, 0,
236
0
      fdsz - sop->event_fdsz);
237
0
  memset((char *)sop->event_writeset_in + sop->event_fdsz, 0,
238
0
      fdsz - sop->event_fdsz);
239
0
240
0
  sop->event_fdsz = fdsz;
241
0
  check_selectop(sop);
242
0
243
0
  return (0);
244
0
245
0
 error:
246
0
  event_warn("malloc");
247
0
  return (-1);
248
0
}
249
250
251
static int
252
select_add(struct event_base *base, int fd, short old, short events, void *p)
253
0
{
254
0
  struct selectop *sop = base->evbase;
255
0
  (void) p;
256
0
257
0
  EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
258
0
  check_selectop(sop);
259
0
  /*
260
0
   * Keep track of the highest fd, so that we can calculate the size
261
0
   * of the fd_sets for select(2)
262
0
   */
263
0
  if (sop->event_fds < fd) {
264
0
    int fdsz = sop->event_fdsz;
265
0
266
0
    if (fdsz < (int)sizeof(fd_mask))
267
0
      fdsz = (int)sizeof(fd_mask);
268
0
269
0
    /* In theory we should worry about overflow here.  In
270
0
     * reality, though, the highest fd on a unixy system will
271
0
     * not overflow here. XXXX */
272
0
    while (fdsz < (int) SELECT_ALLOC_SIZE(fd + 1))
273
0
      fdsz *= 2;
274
0
275
0
    if (fdsz != sop->event_fdsz) {
276
0
      if (select_resize(sop, fdsz)) {
277
0
        check_selectop(sop);
278
0
        return (-1);
279
0
      }
280
0
    }
281
0
282
0
    sop->event_fds = fd;
283
0
  }
284
0
285
0
  if (events & EV_READ)
286
0
    FD_SET(fd, sop->event_readset_in);
287
0
  if (events & EV_WRITE)
288
0
    FD_SET(fd, sop->event_writeset_in);
289
0
  check_selectop(sop);
290
0
291
0
  return (0);
292
0
}
293
294
/*
295
 * Nothing to be done here.
296
 */
297
298
static int
299
select_del(struct event_base *base, int fd, short old, short events, void *p)
300
0
{
301
0
  struct selectop *sop = base->evbase;
302
0
  (void)p;
303
0
304
0
  EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
305
0
  check_selectop(sop);
306
0
307
0
  if (sop->event_fds < fd) {
308
0
    check_selectop(sop);
309
0
    return (0);
310
0
  }
311
0
312
0
  if (events & EV_READ)
313
0
    FD_CLR(fd, sop->event_readset_in);
314
0
315
0
  if (events & EV_WRITE)
316
0
    FD_CLR(fd, sop->event_writeset_in);
317
0
318
0
  check_selectop(sop);
319
0
  return (0);
320
0
}
321
322
static void
323
select_free_selectop(struct selectop *sop)
324
0
{
325
0
  if (sop->event_readset_in)
326
0
    mm_free(sop->event_readset_in);
327
0
  if (sop->event_writeset_in)
328
0
    mm_free(sop->event_writeset_in);
329
0
  if (sop->event_readset_out)
330
0
    mm_free(sop->event_readset_out);
331
0
  if (sop->event_writeset_out)
332
0
    mm_free(sop->event_writeset_out);
333
0
334
0
  memset(sop, 0, sizeof(struct selectop));
335
0
  mm_free(sop);
336
0
}
337
338
static void
339
select_dealloc(struct event_base *base)
340
0
{
341
0
  evsig_dealloc_(base);
342
0
343
0
  select_free_selectop(base->evbase);
344
0
}
345
346
#endif /* EVENT__HAVE_SELECT */