~ubuntu-branches/ubuntu/trusty/haproxy/trusty-updates

« back to all changes in this revision

Viewing changes to src/ev_sepoll.c

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Cornet
  • Date: 2010-04-15 20:00:34 UTC
  • mfrom: (1.2.6 upstream)
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: james.westby@ubuntu.com-20100415200034-mtlky4sy39tk0dfi
Tags: upstream-1.4.4
ImportĀ upstreamĀ versionĀ 1.4.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * FD polling functions for Speculative I/O combined with Linux epoll()
3
3
 *
4
 
 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
 
4
 * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
5
5
 *
6
6
 * This program is free software; you can redistribute it and/or
7
7
 * modify it under the terms of the GNU General Public License
149
149
 */
150
150
#define MIN_RETURN_EVENTS       25
151
151
 
152
 
/* descriptor of one FD.
153
 
 * FIXME: should be a bit field */
154
 
struct fd_status {
155
 
        unsigned int e:4;       // read and write events status.
156
 
        unsigned int s1:28;     // Position in spec list+1. 0=not in list. Should be last.
157
 
};
158
 
 
159
152
static int nbspec = 0;          // current size of the spec list
160
153
static int absmaxevents = 0;    // absolute maximum amounts of polled events
161
154
static int fd_created = 0;      // fd creation detector, reset upon poll() entry.
162
155
 
163
 
static struct fd_status *fd_list = NULL;        // list of FDs
164
156
static unsigned int *spec_list = NULL;  // speculative I/O list
165
157
 
166
158
/* private data */
173
165
static struct epoll_event ev;
174
166
 
175
167
 
176
 
REGPRM1 static void alloc_spec_entry(const int fd)
 
168
REGPRM1 static inline void alloc_spec_entry(const int fd)
177
169
{
178
 
        if (fd_list[fd].s1)
 
170
        if (fdtab[fd].spec.s1)
 
171
                /* sometimes the entry already exists for the other direction */
179
172
                return;
180
 
        fd_list[fd].s1 = nbspec + 1;
 
173
        fdtab[fd].spec.s1 = nbspec + 1;
181
174
        spec_list[nbspec] = fd;
182
175
        nbspec++;
183
176
}
184
177
 
185
178
/* Removes entry used by fd <fd> from the spec list and replaces it with the
186
 
 * last one. The fd_list is adjusted to match the back reference if needed.
 
179
 * last one. The fdtab.spec is adjusted to match the back reference if needed.
187
180
 * If the fd has no entry assigned, return immediately.
188
181
 */
189
182
REGPRM1 static void release_spec_entry(int fd)
190
183
{
191
184
        unsigned int pos;
192
185
 
193
 
        pos = fd_list[fd].s1;
 
186
        pos = fdtab[fd].spec.s1;
194
187
        if (!pos)
195
188
                return;
196
189
 
197
 
        fd_list[fd].s1 = 0;
 
190
        fdtab[fd].spec.s1 = 0;
198
191
        pos--;
199
192
        /* we have spec_list[pos]==fd */
200
193
 
204
197
 
205
198
        /* we replace current FD by the highest one, which may sometimes be the same */
206
199
        fd = spec_list[nbspec];
207
 
        fd_list[fd].s1 = pos + 1;
208
200
        spec_list[pos] = fd;
 
201
        fdtab[fd].spec.s1 = pos + 1;
209
202
}
210
203
 
211
204
/*
221
214
                ABORT_NOW();
222
215
        }
223
216
#endif
224
 
        ret = ((unsigned)fd_list[fd].e >> dir) & FD_EV_MASK_DIR;
 
217
        ret = ((unsigned)fdtab[fd].spec.e >> dir) & FD_EV_MASK_DIR;
225
218
        return (ret == FD_EV_SPEC || ret == FD_EV_WAIT);
226
219
}
227
220
 
231
224
 */
232
225
REGPRM2 static int __fd_set(const int fd, int dir)
233
226
{
234
 
        __label__ switch_state;
235
227
        unsigned int i;
236
228
 
237
229
#if DEBUG_DEV
240
232
                ABORT_NOW();
241
233
        }
242
234
#endif
243
 
        i = ((unsigned)fd_list[fd].e >> dir) & FD_EV_MASK_DIR;
 
235
        i = ((unsigned)fdtab[fd].spec.e >> dir) & FD_EV_MASK_DIR;
244
236
 
245
 
        if (i == FD_EV_IDLE) {
 
237
        if (i != FD_EV_STOP) {
 
238
                if (unlikely(i != FD_EV_IDLE))
 
239
                        return 0;
246
240
                // switch to SPEC state and allocate a SPEC entry.
247
241
                fd_created++;
248
242
                alloc_spec_entry(fd);
249
 
        switch_state:
250
 
                fd_list[fd].e ^= (unsigned int)(FD_EV_IN_SL << dir);
251
 
                return 1;
252
 
        }
253
 
        else if (i == FD_EV_STOP) {
254
 
                // switch to WAIT state
255
 
                goto switch_state;
256
 
        }
257
 
        else
258
 
                return 0;
 
243
        }
 
244
        fdtab[fd].spec.e ^= (unsigned int)(FD_EV_IN_SL << dir);
 
245
        return 1;
259
246
}
260
247
 
261
248
REGPRM2 static int __fd_clr(const int fd, int dir)
262
249
{
263
 
        __label__ switch_state;
264
250
        unsigned int i;
265
251
 
266
252
#if DEBUG_DEV
269
255
                ABORT_NOW();
270
256
        }
271
257
#endif
272
 
        i = ((unsigned)fd_list[fd].e >> dir) & FD_EV_MASK_DIR;
 
258
        i = ((unsigned)fdtab[fd].spec.e >> dir) & FD_EV_MASK_DIR;
273
259
 
274
 
        if (i == FD_EV_SPEC) {
275
 
                // switch to IDLE state
276
 
                goto switch_state;
277
 
        }
278
 
        else if (likely(i == FD_EV_WAIT)) {
 
260
        if (i != FD_EV_SPEC) {
 
261
                if (unlikely(i != FD_EV_WAIT))
 
262
                        return 0;
279
263
                // switch to STOP state
280
264
                /* We will create a queue entry for this one because we want to
281
265
                 * process it later in order to merge it with other events on
282
266
                 * the same FD.
283
267
                 */
284
268
                alloc_spec_entry(fd);
285
 
        switch_state:
286
 
                fd_list[fd].e ^= (unsigned int)(FD_EV_IN_SL << dir);
287
 
                return 1;
288
269
        }
289
 
        return 0;
 
270
        fdtab[fd].spec.e ^= (unsigned int)(FD_EV_IN_SL << dir);
 
271
        return 1;
290
272
}
291
273
 
292
274
/* normally unused */
303
285
REGPRM1 static void __fd_clo(int fd)
304
286
{
305
287
        release_spec_entry(fd);
306
 
        fd_list[fd].e &= ~(FD_EV_MASK);
 
288
        fdtab[fd].spec.e &= ~(FD_EV_MASK);
307
289
}
308
290
 
309
291
/*
336
318
 
337
319
                spec_idx--;
338
320
                fd = spec_list[spec_idx];
339
 
                eo = fd_list[fd].e;  /* save old events */
 
321
                eo = fdtab[fd].spec.e;  /* save old events */
340
322
 
341
323
                if (looping && --fd_created < 0) {
342
324
                        /* we were just checking the newly created FDs */
354
336
 
355
337
#ifdef DEBUG_DEV
356
338
                if (fdtab[fd].state == FD_STCLOSE) {
357
 
                        fprintf(stderr,"fd=%d, fdtab[].ev=%x, fd_list[].e=%x, .s=%d, idx=%d\n",
358
 
                                fd, fdtab[fd].ev, fd_list[fd].e, fd_list[fd].s1, spec_idx);
 
339
                        fprintf(stderr,"fd=%d, fdtab[].ev=%x, fdtab[].spec.e=%x, .s=%d, idx=%d\n",
 
340
                                fd, fdtab[fd].ev, fdtab[fd].spec.e, fdtab[fd].spec.s1, spec_idx);
359
341
                }
360
342
#endif
361
343
                done = 0;
366
348
                                /* Pretend there is something to read */
367
349
                                fdtab[fd].ev |= FD_POLL_IN;
368
350
                                if (!fdtab[fd].cb[DIR_RD].f(fd))
369
 
                                        fd_list[fd].e ^= (FD_EV_WAIT_R ^ FD_EV_SPEC_R);
 
351
                                        fdtab[fd].spec.e ^= (FD_EV_WAIT_R ^ FD_EV_SPEC_R);
370
352
                                else
371
353
                                        done = 1;
372
354
                        }
373
355
                }
374
356
                else if ((eo & FD_EV_MASK_R) == FD_EV_STOP_R) {
375
357
                        /* This FD was being polled and is now being removed. */
376
 
                        fd_list[fd].e &= ~FD_EV_MASK_R;
 
358
                        fdtab[fd].spec.e &= ~FD_EV_MASK_R;
377
359
                }
378
360
                
379
361
                if ((eo & FD_EV_MASK_W) == FD_EV_SPEC_W) {
382
364
                                /* Pretend there is something to write */
383
365
                                fdtab[fd].ev |= FD_POLL_OUT;
384
366
                                if (!fdtab[fd].cb[DIR_WR].f(fd))
385
 
                                        fd_list[fd].e ^= (FD_EV_WAIT_W ^ FD_EV_SPEC_W);
 
367
                                        fdtab[fd].spec.e ^= (FD_EV_WAIT_W ^ FD_EV_SPEC_W);
386
368
                                else
387
369
                                        done = 1;
388
370
                        }
389
371
                }
390
372
                else if ((eo & FD_EV_MASK_W) == FD_EV_STOP_W) {
391
373
                        /* This FD was being polled and is now being removed. */
392
 
                        fd_list[fd].e &= ~FD_EV_MASK_W;
 
374
                        fdtab[fd].spec.e &= ~FD_EV_MASK_W;
393
375
                }
394
376
 
395
377
                status += done;
403
385
                 * have opposite changes for READ and WRITE too.
404
386
                 */
405
387
 
406
 
                if ((eo ^ fd_list[fd].e) & FD_EV_RW_PL) {
 
388
                if ((eo ^ fdtab[fd].spec.e) & FD_EV_RW_PL) {
407
389
                        /* poll status changed*/
408
 
                        if ((fd_list[fd].e & FD_EV_RW_PL) == 0) {
 
390
                        if ((fdtab[fd].spec.e & FD_EV_RW_PL) == 0) {
409
391
                                /* fd removed from poll list */
410
392
                                opcode = EPOLL_CTL_DEL;
411
393
                        }
420
402
 
421
403
                        /* construct the epoll events based on new state */
422
404
                        ev.events = 0;
423
 
                        if (fd_list[fd].e & FD_EV_WAIT_R)
 
405
                        if (fdtab[fd].spec.e & FD_EV_WAIT_R)
424
406
                                ev.events |= EPOLLIN;
425
407
 
426
 
                        if (fd_list[fd].e & FD_EV_WAIT_W)
 
408
                        if (fdtab[fd].spec.e & FD_EV_WAIT_W)
427
409
                                ev.events |= EPOLLOUT;
428
410
 
429
411
                        ev.data.fd = fd;
431
413
                }
432
414
 
433
415
 
434
 
                if (!(fd_list[fd].e & FD_EV_RW_SL)) {
 
416
                if (!(fdtab[fd].spec.e & FD_EV_RW_SL)) {
435
417
                        /* This fd switched to combinations of either WAIT or
436
418
                         * IDLE. It must be removed from the spec list.
437
419
                         */
525
507
                        ((e & EPOLLERR) ? FD_POLL_ERR : 0) |
526
508
                        ((e & EPOLLHUP) ? FD_POLL_HUP : 0);
527
509
                
528
 
                if ((fd_list[fd].e & FD_EV_MASK_R) == FD_EV_WAIT_R) {
 
510
                if ((fdtab[fd].spec.e & FD_EV_MASK_R) == FD_EV_WAIT_R) {
529
511
                        if (fdtab[fd].state == FD_STCLOSE || fdtab[fd].state == FD_STERROR)
530
512
                                continue;
531
513
                        if (fdtab[fd].ev & (FD_POLL_IN|FD_POLL_HUP|FD_POLL_ERR))
532
514
                                fdtab[fd].cb[DIR_RD].f(fd);
533
515
                }
534
516
 
535
 
                if ((fd_list[fd].e & FD_EV_MASK_W) == FD_EV_WAIT_W) {
 
517
                if ((fdtab[fd].spec.e & FD_EV_MASK_W) == FD_EV_WAIT_W) {
536
518
                        if (fdtab[fd].state == FD_STCLOSE || fdtab[fd].state == FD_STERROR)
537
519
                                continue;
538
520
                        if (fdtab[fd].ev & (FD_POLL_OUT|FD_POLL_ERR))
560
542
 */
561
543
REGPRM1 static int _do_init(struct poller *p)
562
544
{
563
 
        __label__ fail_fd_list, fail_spec, fail_ee, fail_fd;
 
545
        __label__ fail_spec, fail_ee, fail_fd;
564
546
 
565
547
        p->private = NULL;
566
548
 
579
561
        if ((spec_list = (uint32_t *)calloc(1, sizeof(uint32_t) * global.maxsock)) == NULL)
580
562
                goto fail_spec;
581
563
 
582
 
        fd_list = (struct fd_status *)calloc(1, sizeof(struct fd_status) * global.maxsock);
583
 
        if (fd_list == NULL)
584
 
                goto fail_fd_list;
585
 
 
586
564
        return 1;
587
565
 
588
 
 fail_fd_list:
589
 
        free(spec_list);
590
566
 fail_spec:
591
567
        free(epoll_events);
592
568
 fail_ee:
603
579
 */
604
580
REGPRM1 static void _do_term(struct poller *p)
605
581
{
606
 
        free(fd_list);
607
582
        free(spec_list);
608
583
        free(epoll_events);
609
584
 
612
587
                epoll_fd = -1;
613
588
        }
614
589
 
615
 
        fd_list = NULL;
616
590
        spec_list = NULL;
617
591
        epoll_events = NULL;
618
592