~ubuntu-branches/debian/stretch/haproxy/stretch

« back to all changes in this revision

Viewing changes to src/ev_kqueue.c

  • Committer: Package Import Robot
  • Author(s): Apollon Oikonomopoulos
  • Date: 2014-06-20 11:05:17 UTC
  • mfrom: (1.1.15) (15.1.12 experimental)
  • Revision ID: package-import@ubuntu.com-20140620110517-u6q5p9kyy2f3ozw9
Tags: 1.5.0-1
* New upstream stable series. Notable changes since the 1.4 series:
  + Native SSL support on both sides with SNI/NPN/ALPN and OCSP stapling.
  + IPv6 and UNIX sockets are supported everywhere
  + End-to-end HTTP keep-alive for better support of NTLM and improved
    efficiency in static farms
  + HTTP/1.1 response compression (deflate, gzip) to save bandwidth
  + PROXY protocol versions 1 and 2 on both sides
  + Data sampling on everything in request or response, including payload
  + ACLs can use any matching method with any input sample
  + Maps and dynamic ACLs updatable from the CLI
  + Stick-tables support counters to track activity on any input sample
  + Custom format for logs, unique-id, header rewriting, and redirects
  + Improved health checks (SSL, scripted TCP, check agent, ...)
  + Much more scalable configuration supports hundreds of thousands of
    backends and certificates without sweating

* Upload to unstable, merge all 1.5 work from experimental. Most important
  packaging changes since 1.4.25-1 include:
  + systemd support.
  + A more sane default config file.
  + Zero-downtime upgrades between 1.5 releases by gracefully reloading
    HAProxy during upgrades.
  + HTML documentation shipped in the haproxy-doc package.
  + kqueue support for kfreebsd.

* Packaging changes since 1.5~dev26-2:
  + Drop patches merged upstream:
    o Fix-reference-location-in-manpage.patch
    o 0001-BUILD-stats-workaround-stupid-and-bogus-Werror-forma.patch
  + d/watch: look for stable 1.5 releases
  + systemd: respect CONFIG and EXTRAOPTS when specified in
    /etc/default/haproxy.
  + initscript: test the configuration before start or reload.
  + initscript: remove the ENABLED flag and logic.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * FD polling functions for FreeBSD kqueue()
3
3
 *
4
 
 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
 
4
 * Copyright 2000-2014 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
8
8
 * as published by the Free Software Foundation; either version
9
9
 * 2 of the License, or (at your option) any later version.
10
10
 *
11
 
 * Note: not knowing much about kqueue, I had to rely on OpenBSD's detailed man
12
 
 * page and to check how it was implemented in lighttpd to understand it better.
13
 
 * But it is possible that I got things wrong.
14
 
 *
15
11
 */
16
12
 
17
13
#include <unistd.h>
34
30
#include <proto/task.h>
35
31
 
36
32
/* private data */
37
 
static fd_set *fd_evts[2];
38
33
static int kqueue_fd;
39
34
static struct kevent *kev = NULL;
40
35
 
41
 
/* speeds up conversion of DIR_RD/DIR_WR to EVFILT* */
42
 
static const int dir2filt[2] = { EVFILT_READ, EVFILT_WRITE };
43
 
 
44
 
/* completes a change list for deletion */
45
 
REGPRM3 static int kqev_del(struct kevent *kev, const int fd, const int dir)
46
 
{
47
 
        if (FD_ISSET(fd, fd_evts[dir])) {
48
 
                FD_CLR(fd, fd_evts[dir]);
49
 
                EV_SET(kev, fd, dir2filt[dir], EV_DELETE, 0, 0, NULL);
50
 
                return 1;
51
 
        }
52
 
        return 0;
53
 
}
54
 
 
55
 
/*
56
 
 * Returns non-zero if direction <dir> is already set for <fd>.
57
 
 */
58
 
REGPRM2 static int __fd_is_set(const int fd, int dir)
59
 
{
60
 
        return FD_ISSET(fd, fd_evts[dir]);
61
 
}
62
 
 
63
 
REGPRM2 static int __fd_set(const int fd, int dir)
64
 
{
65
 
        /* if the value was set, do nothing */
66
 
        if (FD_ISSET(fd, fd_evts[dir]))
67
 
                return 0;
68
 
 
69
 
        FD_SET(fd, fd_evts[dir]);
70
 
        EV_SET(kev, fd, dir2filt[dir], EV_ADD, 0, 0, NULL);
71
 
        kevent(kqueue_fd, kev, 1, NULL, 0, NULL);
72
 
        return 1;
73
 
}
74
 
 
75
 
REGPRM2 static int __fd_clr(const int fd, int dir)
76
 
{
77
 
        if (!kqev_del(kev, fd, dir))
78
 
                return 0;
79
 
        kevent(kqueue_fd, kev, 1, NULL, 0, NULL);
80
 
        return 1;
81
 
}
82
 
 
83
 
REGPRM1 static void __fd_rem(int fd)
84
 
{
85
 
        int changes = 0;
86
 
 
87
 
        changes += kqev_del(&kev[changes], fd, DIR_RD);
88
 
        changes += kqev_del(&kev[changes], fd, DIR_WR);
89
 
 
90
 
        if (changes)
91
 
                kevent(kqueue_fd, kev, changes, NULL, 0, NULL);
92
 
}
93
 
 
94
 
REGPRM1 static void __fd_clo(int fd)
95
 
{
96
 
        FD_CLR(fd, fd_evts[DIR_RD]);
97
 
        FD_CLR(fd, fd_evts[DIR_WR]);
98
 
}
99
 
 
100
36
/*
101
37
 * kqueue() poller
102
38
 */
105
41
        int status;
106
42
        int count, fd, delta_ms;
107
43
        struct timespec timeout;
 
44
        int updt_idx, en, eo;
 
45
        int changes = 0;
 
46
 
 
47
        /* first, scan the update list to find changes */
 
48
        for (updt_idx = 0; updt_idx < fd_nbupdt; updt_idx++) {
 
49
                fd = fd_updt[updt_idx];
 
50
                fdtab[fd].updated = 0;
 
51
                fdtab[fd].new = 0;
 
52
 
 
53
                if (!fdtab[fd].owner)
 
54
                        continue;
 
55
 
 
56
                eo = fdtab[fd].state;
 
57
                en = fd_compute_new_polled_status(eo);
 
58
 
 
59
                if ((eo ^ en) & FD_EV_POLLED_RW) {
 
60
                        /* poll status changed */
 
61
                        fdtab[fd].state = en;
 
62
 
 
63
                        if ((eo ^ en) & FD_EV_POLLED_R) {
 
64
                                /* read poll status changed */
 
65
                                if (en & FD_EV_POLLED_R) {
 
66
                                        EV_SET(&kev[changes], fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
 
67
                                        changes++;
 
68
                                }
 
69
                                else {
 
70
                                        EV_SET(&kev[changes], fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
 
71
                                        changes++;
 
72
                                }
 
73
                        }
 
74
 
 
75
                        if ((eo ^ en) & FD_EV_POLLED_W) {
 
76
                                /* write poll status changed */
 
77
                                if (en & FD_EV_POLLED_W) {
 
78
                                        EV_SET(&kev[changes], fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
 
79
                                        changes++;
 
80
                                }
 
81
                                else {
 
82
                                        EV_SET(&kev[changes], fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
 
83
                                        changes++;
 
84
                                }
 
85
                        }
 
86
                }
 
87
 
 
88
                fd_alloc_or_release_cache_entry(fd, en);
 
89
        }
 
90
        if (changes)
 
91
                kevent(kqueue_fd, kev, changes, NULL, 0, NULL);
 
92
        fd_nbupdt = 0;
108
93
 
109
94
        delta_ms        = 0;
110
95
        timeout.tv_sec  = 0;
111
96
        timeout.tv_nsec = 0;
112
97
 
113
 
        if (!run_queue && !signal_queue_len) {
 
98
        if (!fd_cache_num && !run_queue && !signal_queue_len) {
114
99
                if (!exp) {
115
100
                        delta_ms        = MAX_DELAY_MS;
116
101
                        timeout.tv_sec  = (MAX_DELAY_MS / 1000);
126
111
        }
127
112
 
128
113
        fd = MIN(maxfd, global.tune.maxpollevents);
 
114
        gettimeofday(&before_poll, NULL);
129
115
        status = kevent(kqueue_fd, // int kq
130
116
                        NULL,      // const struct kevent *changelist
131
117
                        0,         // int nchanges
133
119
                        fd,        // int nevents
134
120
                        &timeout); // const struct timespec *timeout
135
121
        tv_update_date(delta_ms, status);
 
122
        measure_idle();
136
123
 
137
124
        for (count = 0; count < status; count++) {
138
125
                fd = kev[count].ident;
 
126
 
 
127
                if (!fdtab[fd].owner)
 
128
                        continue;
 
129
 
 
130
                fdtab[fd].ev &= FD_POLL_STICKY;
 
131
 
139
132
                if (kev[count].filter ==  EVFILT_READ) {
140
 
                        if (FD_ISSET(fd, fd_evts[DIR_RD])) {
141
 
                                if (fdtab[fd].state == FD_STCLOSE)
142
 
                                        continue;
143
 
                                fdtab[fd].cb[DIR_RD].f(fd);
144
 
                        }
145
 
                } else if (kev[count].filter ==  EVFILT_WRITE) {
146
 
                        if (FD_ISSET(fd, fd_evts[DIR_WR])) {
147
 
                                if (fdtab[fd].state == FD_STCLOSE)
148
 
                                        continue;
149
 
                                fdtab[fd].cb[DIR_WR].f(fd);
150
 
                        }
151
 
                }
 
133
                        if ((fdtab[fd].state & FD_EV_STATUS_R))
 
134
                                fdtab[fd].ev |= FD_POLL_IN;
 
135
                }
 
136
                else if (kev[count].filter ==  EVFILT_WRITE) {
 
137
                        if ((fdtab[fd].state & FD_EV_STATUS_W))
 
138
                                fdtab[fd].ev |= FD_POLL_OUT;
 
139
                }
 
140
 
 
141
                fd_process_polled_events(fd);
152
142
        }
153
143
}
154
144
 
159
149
 */
160
150
REGPRM1 static int _do_init(struct poller *p)
161
151
{
162
 
        __label__ fail_wevt, fail_revt, fail_fd;
163
 
        int fd_set_bytes;
164
 
 
165
152
        p->private = NULL;
166
 
        fd_set_bytes = sizeof(fd_set) * (global.maxsock + FD_SETSIZE - 1) / FD_SETSIZE;
167
153
 
168
154
        kqueue_fd = kqueue();
169
155
        if (kqueue_fd < 0)
170
156
                goto fail_fd;
171
157
 
172
 
        kev = (struct kevent*)calloc(1, sizeof(struct kevent) * global.tune.maxpollevents);
173
 
 
 
158
        /* we can have up to two events per fd (*/
 
159
        kev = (struct kevent*)calloc(1, sizeof(struct kevent) * 2 * global.maxsock);
174
160
        if (kev == NULL)
175
161
                goto fail_kev;
176
162
                
177
 
        if ((fd_evts[DIR_RD] = (fd_set *)calloc(1, fd_set_bytes)) == NULL)
178
 
                goto fail_revt;
179
 
 
180
 
        if ((fd_evts[DIR_WR] = (fd_set *)calloc(1, fd_set_bytes)) == NULL)
181
 
                goto fail_wevt;
182
 
 
183
163
        return 1;
184
164
 
185
 
 fail_wevt:
186
 
        free(fd_evts[DIR_RD]);
187
 
 fail_revt:
188
 
        free(kev);
189
165
 fail_kev:
190
166
        close(kqueue_fd);
191
167
        kqueue_fd = -1;
200
176
 */
201
177
REGPRM1 static void _do_term(struct poller *p)
202
178
{
203
 
        free(fd_evts[DIR_WR]);
204
 
        free(fd_evts[DIR_RD]);
205
179
        free(kev);
206
180
 
207
181
        if (kqueue_fd >= 0) {
263
237
        p->pref = 300;
264
238
        p->private = NULL;
265
239
 
 
240
        p->clo  = NULL;
266
241
        p->test = _do_test;
267
242
        p->init = _do_init;
268
243
        p->term = _do_term;
269
244
        p->poll = _do_poll;
270
245
        p->fork = _do_fork;
271
 
 
272
 
        p->is_set  = __fd_is_set;
273
 
        p->cond_s = p->set = __fd_set;
274
 
        p->cond_c = p->clr = __fd_clr;
275
 
        p->rem = __fd_rem;
276
 
        p->clo = __fd_clo;
277
246
}
278
247
 
279
248