~ubuntu-branches/ubuntu/lucid/nginx/lucid

1 by Jose Parrella
Import upstream version 0.4.12
1
/*
2
 * Copyright (C) Igor Sysoev
3
 */
4
5
6
#include <ngx_config.h>
7
#include <ngx_core.h>
8
#include <ngx_event.h>
9
10
11
#if (NGX_TEST_BUILD_EVENTPORT)
12
13
#define ushort_t  u_short
14
#define uint_t    u_int
15
16
/* Solaris declarations */
17
18
#define PORT_SOURCE_AIO         1
19
#define PORT_SOURCE_TIMER       2
20
#define PORT_SOURCE_USER        3
21
#define PORT_SOURCE_FD          4
22
#define PORT_SOURCE_ALERT       5
23
#define PORT_SOURCE_MQ          6
24
25
#define ETIME                   64
26
27
#define SIGEV_PORT              4
28
29
typedef struct {
30
    int         portev_events;  /* event data is source specific */
31
    ushort_t    portev_source;  /* event source */
32
    ushort_t    portev_pad;     /* port internal use */
33
    uintptr_t   portev_object;  /* source specific object */
34
    void       *portev_user;    /* user cookie */
35
} port_event_t;
36
37
typedef struct  port_notify {
38
    int         portnfy_port;   /* bind request(s) to port */
39
    void       *portnfy_user;   /* user defined */
40
} port_notify_t;
41
42
#if (__FreeBSD_version < 700005)
1.1.7 by Fabio Tranchitella
Import upstream version 0.6.31
43
44
typedef struct itimerspec {     /* definition per POSIX.4 */
1.1.5 by Jose Parrella
Import upstream version 0.5.33
45
    struct timespec it_interval;/* timer period */
46
    struct timespec it_value;   /* timer expiration */
47
} itimerspec_t;
1 by Jose Parrella
Import upstream version 0.4.12
48
49
#endif
1.1.7 by Fabio Tranchitella
Import upstream version 0.6.31
50
51
int port_create(void)
1 by Jose Parrella
Import upstream version 0.4.12
52
{
53
    return -1;
54
}
55
56
int port_associate(int port, int source, uintptr_t object, int events,
57
    void *user)
58
{
59
    return -1;
60
}
61
62
int port_dissociate(int port, int source, uintptr_t object)
63
{
64
    return -1;
65
}
66
67
int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget,
68
    struct timespec *timeout)
69
{
70
    return -1;
71
}
72
73
int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
74
{
75
    return -1;
76
}
77
78
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
79
    struct itimerspec *ovalue)
80
{
81
    return -1;
82
}
83
84
int timer_delete(timer_t timerid)
85
{
86
    return -1;
87
}
88
89
#endif
90
91
92
typedef struct {
93
    ngx_uint_t  events;
1.1.5 by Jose Parrella
Import upstream version 0.5.33
94
} ngx_eventport_conf_t;
1 by Jose Parrella
Import upstream version 0.4.12
95
96
97
static ngx_int_t ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer);
98
static void ngx_eventport_done(ngx_cycle_t *cycle);
99
static ngx_int_t ngx_eventport_add_event(ngx_event_t *ev, ngx_int_t event,
1.1.5 by Jose Parrella
Import upstream version 0.5.33
100
    ngx_uint_t flags);
101
static ngx_int_t ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event,
102
    ngx_uint_t flags);
103
static ngx_int_t ngx_eventport_process_events(ngx_cycle_t *cycle,
1 by Jose Parrella
Import upstream version 0.4.12
104
    ngx_msec_t timer, ngx_uint_t flags);
105
106
static void *ngx_eventport_create_conf(ngx_cycle_t *cycle);
107
static char *ngx_eventport_init_conf(ngx_cycle_t *cycle, void *conf);
108
109
static int            ep = -1;
110
static port_event_t  *event_list;
111
static ngx_uint_t     nevents;
1.1.5 by Jose Parrella
Import upstream version 0.5.33
112
static timer_t        event_timer = (timer_t) -1;
1.1.7 by Fabio Tranchitella
Import upstream version 0.6.31
113
1 by Jose Parrella
Import upstream version 0.4.12
114
static ngx_str_t      eventport_name = ngx_string("eventport");
115
116
117
static ngx_command_t  ngx_eventport_commands[] = {
118
119
    { ngx_string("eventport_events"),
120
      NGX_EVENT_CONF|NGX_CONF_TAKE1,
121
      ngx_conf_set_num_slot,
122
      0,
123
      offsetof(ngx_eventport_conf_t, events),
124
      NULL },
125
126
      ngx_null_command
127
};
128
129
130
ngx_event_module_t  ngx_eventport_module_ctx = {
131
    &eventport_name,
132
    ngx_eventport_create_conf,             /* create configuration */
133
    ngx_eventport_init_conf,               /* init configuration */
134
135
    {
136
        ngx_eventport_add_event,           /* add an event */
137
        ngx_eventport_del_event,           /* delete an event */
138
        ngx_eventport_add_event,           /* enable an event */
139
        ngx_eventport_del_event,           /* disable an event */
140
        NULL,                              /* add an connection */
141
        NULL,                              /* delete an connection */
142
        NULL,                              /* process the changes */
143
        ngx_eventport_process_events,      /* process the events */
144
        ngx_eventport_init,                /* init the events */
145
        ngx_eventport_done,                /* done the events */
146
    }
147
148
};
149
150
ngx_module_t  ngx_eventport_module = {
151
    NGX_MODULE_V1,
152
    &ngx_eventport_module_ctx,             /* module context */
153
    ngx_eventport_commands,                /* module directives */
154
    NGX_EVENT_MODULE,                      /* module type */
155
    NULL,                                  /* init master */
156
    NULL,                                  /* init module */
157
    NULL,                                  /* init process */
158
    NULL,                                  /* init thread */
159
    NULL,                                  /* exit thread */
160
    NULL,                                  /* exit process */
161
    NULL,                                  /* exit master */
162
    NGX_MODULE_V1_PADDING
163
};
164
165
166
static ngx_int_t
167
ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer)
168
{
169
    port_notify_t          pn;
170
    struct itimerspec      its;
171
    struct sigevent        sev;
172
    ngx_eventport_conf_t  *epcf;
173
174
    epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_eventport_module);
175
176
    if (ep == -1) {
177
        ep = port_create();
178
179
        if (ep == -1) {
180
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
181
                          "port_create() failed");
182
            return NGX_ERROR;
183
        }
184
    }
185
186
    if (nevents < epcf->events) {
187
        if (event_list) {
188
            ngx_free(event_list);
189
        }
190
191
        event_list = ngx_alloc(sizeof(port_event_t) * epcf->events,
192
                               cycle->log);
193
        if (event_list == NULL) {
194
            return NGX_ERROR;
195
        }
196
    }
197
198
    ngx_event_flags = NGX_USE_EVENTPORT_EVENT;
199
200
    if (timer) {
201
        ngx_memzero(&pn, sizeof(port_notify_t));
202
        pn.portnfy_port = ep;
203
204
        ngx_memzero(&sev, sizeof(struct sigevent));
205
        sev.sigev_notify = SIGEV_PORT;
206
#if !(NGX_TEST_BUILD_EVENTPORT)
207
        sev.sigev_value.sival_ptr = &pn;
208
#endif
209
210
        if (timer_create(CLOCK_REALTIME, &sev, &event_timer) == -1) {
211
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
212
                          "timer_create() failed");
213
            return NGX_ERROR;
214
        }
215
216
        its.it_interval.tv_sec = timer / 1000;
217
        its.it_interval.tv_nsec = (timer % 1000) * 1000000;
218
        its.it_value.tv_sec = timer / 1000;
219
        its.it_value.tv_nsec = (timer % 1000) * 1000000;
220
221
        if (timer_settime(event_timer, 0, &its, NULL) == -1) {
222
            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
223
                          "timer_settime() failed");
224
            return NGX_ERROR;
225
        }
226
227
        ngx_event_flags |= NGX_USE_TIMER_EVENT;
228
    }
229
230
    nevents = epcf->events;
231
232
    ngx_io = ngx_os_io;
233
234
    ngx_event_actions = ngx_eventport_module_ctx.actions;
235
236
    return NGX_OK;
237
}
238
239
240
static void
241
ngx_eventport_done(ngx_cycle_t *cycle)
242
{
243
    if (event_timer != (timer_t) -1) {
1.1.7 by Fabio Tranchitella
Import upstream version 0.6.31
244
        if (timer_delete(event_timer) == -1) {
1 by Jose Parrella
Import upstream version 0.4.12
245
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
246
                          "timer_delete() failed");
247
        }
248
249
        event_timer = (timer_t) -1;
1.1.7 by Fabio Tranchitella
Import upstream version 0.6.31
250
    }
1 by Jose Parrella
Import upstream version 0.4.12
251
252
    if (close(ep) == -1) {
253
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
254
                      "close() event port failed");
255
    }
256
257
    ep = -1;
258
259
    ngx_free(event_list);
260
261
    event_list = NULL;
262
    nevents = 0;
263
}
264
265
266
static ngx_int_t
267
ngx_eventport_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
1.1.5 by Jose Parrella
Import upstream version 0.5.33
268
{
1 by Jose Parrella
Import upstream version 0.4.12
269
    ngx_int_t          events, prev;
1.1.5 by Jose Parrella
Import upstream version 0.5.33
270
    ngx_event_t       *e;
1 by Jose Parrella
Import upstream version 0.4.12
271
    ngx_connection_t  *c;
272
273
    c = ev->data;
274
275
    events = event;
276
277
    if (event == NGX_READ_EVENT) {
278
        e = c->write;
279
        prev = POLLOUT;
280
#if (NGX_READ_EVENT != POLLIN)
281
        events = POLLIN;
282
#endif
283
284
    } else {
285
        e = c->read;
286
        prev = POLLIN;
287
#if (NGX_WRITE_EVENT != POLLOUT)
288
        events = POLLOUT;
289
#endif
290
    }
291
292
    if (e->oneshot) {
293
        events |= prev;
294
    }
295
296
    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
297
                   "eventport add event: fd:%d ev:%04Xi", c->fd, events);
1.1.5 by Jose Parrella
Import upstream version 0.5.33
298
1 by Jose Parrella
Import upstream version 0.4.12
299
    if (port_associate(ep, PORT_SOURCE_FD, c->fd, events,
300
                       (void *) ((uintptr_t) ev | ev->instance))
301
        == -1)
302
    {
303
        ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
304
                      "port_associate() failed");
305
        return NGX_ERROR;
306
    }
307
308
    ev->active = 1;
309
    ev->oneshot = 1;
310
311
    return NGX_OK;
312
}
313
314
315
static ngx_int_t
316
ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
1.1.5 by Jose Parrella
Import upstream version 0.5.33
317
{
1 by Jose Parrella
Import upstream version 0.4.12
318
    ngx_event_t       *e;
319
    ngx_connection_t  *c;
320
321
    /*
322
     * when the file descriptor is closed, the event port automatically
323
     * dissociates it from the port, so we do not need to dissociate explicity
324
     * the event before the closing the file descriptor
325
     */
326
327
    if (flags & NGX_CLOSE_EVENT) {
328
        ev->active = 0;
329
        ev->oneshot = 0;
330
        return NGX_OK;
331
    }
332
333
    c = ev->data;
334
335
    if (event == NGX_READ_EVENT) {
336
        e = c->write;
337
        event = POLLOUT;
338
339
    } else {
340
        e = c->read;
341
        event = POLLIN;
342
    }
343
344
    if (e->oneshot) {
345
        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
346
                       "eventport change event: fd:%d ev:%04Xi", c->fd, event);
1.1.5 by Jose Parrella
Import upstream version 0.5.33
347
1 by Jose Parrella
Import upstream version 0.4.12
348
        if (port_associate(ep, PORT_SOURCE_FD, c->fd, event,
349
                           (void *) ((uintptr_t) ev | ev->instance))
350
            == -1)
351
        {
352
            ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
353
                          "port_associate() failed");
354
            return NGX_ERROR;
355
        }
356
357
    } else {
358
        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
359
                       "eventport del event: fd:%d", c->fd);
360
361
        if (port_dissociate(ep, PORT_SOURCE_FD, c->fd) == -1) {
362
            ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
363
                          "port_dissociate() failed");
364
            return NGX_ERROR;
365
        }
366
    }
367
368
    ev->active = 0;
369
    ev->oneshot = 0;
370
371
    return NGX_OK;
372
}
373
374
375
ngx_int_t
376
ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
377
    ngx_uint_t flags)
378
{
379
    int                 n, revents;
380
    u_int               events;
381
    ngx_err_t           err;
382
    ngx_int_t           instance;
383
    ngx_uint_t          i, level;
384
    ngx_event_t        *ev, *rev, *wev, **queue;
385
    ngx_connection_t   *c;
386
    struct timespec     ts, *tp;
387
388
    if (timer == NGX_TIMER_INFINITE) {
389
        tp = NULL;
390
391
    } else {
392
        ts.tv_sec = timer / 1000;
393
        ts.tv_nsec = (timer % 1000) * 1000000;
394
        tp = &ts;
395
    }
396
397
    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
398
                   "eventport timer: %M", timer);
399
400
    events = 1;
401
402
    n = port_getn(ep, event_list, (u_int) nevents, &events, tp);
1.1.5 by Jose Parrella
Import upstream version 0.5.33
403
1 by Jose Parrella
Import upstream version 0.4.12
404
    err = ngx_errno;
405
406
    if (flags & NGX_UPDATE_TIME) {
407
        ngx_time_update(0, 0);
408
    }
409
410
    if (n == -1) {
411
        if (err == ETIME) {
412
            if (timer != NGX_TIMER_INFINITE) {
413
                return NGX_OK;
414
            }
415
416
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
417
                          "port_getn() returned no events without timeout");
418
            return NGX_ERROR;
419
        }
420
421
        level = (err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT;
422
        ngx_log_error(level, cycle->log, err, "port_getn() failed");
423
        return NGX_ERROR;
424
    }
425
426
    if (events == 0) {
427
        if (timer != NGX_TIMER_INFINITE) {
428
            return NGX_OK;
429
        }
430
431
        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
432
                      "port_getn() returned no events without timeout");
433
        return NGX_ERROR;
434
    }
435
436
    ngx_mutex_lock(ngx_posted_events_mutex);
437
438
    for (i = 0; i < events; i++) {
439
440
        if (event_list[i].portev_source == PORT_SOURCE_TIMER) {
441
            ngx_time_update(0, 0);
442
            continue;
443
        }
444
445
        ev = event_list[i].portev_user;
446
447
        switch (event_list[i].portev_source) {
448
449
        case PORT_SOURCE_FD:
450
451
            instance = (uintptr_t) ev & 1;
452
            ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);
453
454
            if (ev->closed || ev->instance != instance) {
455
456
                /*
457
                 * the stale event from a file descriptor
458
                 * that was just closed in this iteration
459
                 */
460
461
                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
462
                               "eventport: stale event %p", ev);
463
                continue;
464
            }
465
466
            revents = event_list[i].portev_events;
467
468
            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
469
                           "eventport: fd:%d, ev:%04Xd",
470
                           event_list[i].portev_object, revents);
471
472
            if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
473
                ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
1.1.3 by Jose Parrella
Import upstream version 0.5.18
474
                               "port_getn() error fd:%d ev:%04Xd",
475
                               event_list[i].portev_object, revents);
476
            }
1 by Jose Parrella
Import upstream version 0.4.12
477
478
            if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
479
                ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
480
                              "strange port_getn() events fd:%d ev:%04Xd",
481
                              event_list[i].portev_object, revents);
482
            }
483
484
            if ((revents & (POLLERR|POLLHUP|POLLNVAL))
485
                 && (revents & (POLLIN|POLLOUT)) == 0)
486
            {
487
                /*
488
                 * if the error events were returned without POLLIN or POLLOUT,
489
                 * then add these flags to handle the events at least in one
490
                 * active handler
491
                 */
492
493
                revents |= POLLIN|POLLOUT;
494
            }
495
496
            c = ev->data;
497
            rev = c->read;
498
            wev = c->write;
499
500
            rev->active = 0;
501
            wev->active = 0;
502
503
            if (revents & POLLIN) {
504
505
                if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
506
                    rev->posted_ready = 1;
507
508
                } else {
509
                    rev->ready = 1;
510
                }
511
512
                if (flags & NGX_POST_EVENTS) {
513
                    queue = (ngx_event_t **) (rev->accept ?
514
                               &ngx_posted_accept_events : &ngx_posted_events);
515
516
                    ngx_locked_post_event(rev, queue);
517
518
                } else {
519
                    rev->handler(rev);
520
1.1.5 by Jose Parrella
Import upstream version 0.5.33
521
                    if (ev->closed) {
522
                        continue;
523
                    }
524
                }
1 by Jose Parrella
Import upstream version 0.4.12
525
526
                if (rev->accept) {
527
                    if (ngx_use_accept_mutex) {
528
                        ngx_accept_events = 1;
529
                        continue;
530
                    }
531
532
                    if (port_associate(ep, PORT_SOURCE_FD, c->fd, POLLIN,
533
                                       (void *) ((uintptr_t) ev | ev->instance))
534
                        == -1)
535
                    {
536
                        ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
537
                                      "port_associate() failed");
538
                        return NGX_ERROR;
539
                    }
540
                }
541
            }
542
543
            if (revents & POLLOUT) {
544
545
                if (flags & NGX_POST_THREAD_EVENTS) {
546
                    wev->posted_ready = 1;
547
548
                } else {
549
                    wev->ready = 1;
550
                }
551
552
                if (flags & NGX_POST_EVENTS) {
553
                    ngx_locked_post_event(wev, &ngx_posted_events);
554
555
                } else {
556
                    wev->handler(wev);
557
                }
558
            }
559
560
            continue;
561
562
        default:
563
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
564
                          "unexpected even_port object %d",
565
                          event_list[i].portev_object);
566
            continue;
567
        }
568
    }
569
570
    ngx_mutex_unlock(ngx_posted_events_mutex);
571
572
    return NGX_OK;
573
}
574
575
576
static void *
577
ngx_eventport_create_conf(ngx_cycle_t *cycle)
578
{
579
    ngx_eventport_conf_t  *epcf;
580
581
    epcf = ngx_palloc(cycle->pool, sizeof(ngx_eventport_conf_t));
582
    if (epcf == NULL) {
583
        return NULL;
1.3.4 by Fabio Tranchitella
Import upstream version 0.7.63
584
    }
1 by Jose Parrella
Import upstream version 0.4.12
585
586
    epcf->events = NGX_CONF_UNSET;
587
588
    return epcf;
589
}
590
591
592
static char *
593
ngx_eventport_init_conf(ngx_cycle_t *cycle, void *conf)
594
{
595
    ngx_eventport_conf_t *epcf = conf;
596
597
    ngx_conf_init_uint_value(epcf->events, 32);
598
599
    return NGX_CONF_OK;
600
}
601