1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7 #ifndef _NXT_EVENT_ENGINE_H_INCLUDED_
8 #define _NXT_EVENT_ENGINE_H_INCLUDED_
9
10 /*
11 * An event interface is kernel interface such as kqueue, epoll, etc.
12 * intended to get event notifications about file descriptor state,
13 * signals, etc.
14 */
15
16 #define NXT_FILE_EVENTS 1
17 #define NXT_NO_FILE_EVENTS 0
18
19 #define NXT_SIGNAL_EVENTS 1
20 #define NXT_NO_SIGNAL_EVENTS 0
21
22
23 typedef struct {
24
25 /* The canonical event set name. */
26 const char *name;
27
28 /*
29 * Create an event set. The mchanges argument is a maximum number of
30 * changes to send to the kernel. The mevents argument is a maximum
31 * number of events to retrieve from the kernel at once, if underlying
32 * event facility supports batch operations.
33 */
34 nxt_int_t (*create)(nxt_event_engine_t *engine,
35 nxt_uint_t mchanges, nxt_uint_t mevents);
36
37 /* Close and free an event set. */
38 void (*free)(nxt_event_engine_t *engine);
39
40 /*
41 * Add a file descriptor to an event set and enable the most
42 * effective read and write event notification method provided
43 * by underlying event facility.
44 */
45 void (*enable)(nxt_event_engine_t *engine,
46 nxt_fd_event_t *ev);
47
48 /* Disable file descriptor event notifications. */
49 void (*disable)(nxt_event_engine_t *engine,
50 nxt_fd_event_t *ev);
51
52 /*
53 * Delete a file descriptor from an event set. A possible usage
54 * is a moving of the file descriptor from one event set to another.
55 */
56 void (*delete)(nxt_event_engine_t *engine,
57 nxt_fd_event_t *ev);
58
59 /*
60 * Delete a file descriptor from an event set before closing the
61 * file descriptor. The most event facilities such as Linux epoll,
62 * BSD kqueue, Solaris event ports, AIX pollset, and HP-UX /dev/poll
63 * delete a file descriptor automatically on the file descriptor close.
64 * Some facilities such as Solaris /dev/poll require to delete a file
65 * descriptor explicitly.
66 */
67 nxt_bool_t (*close)(nxt_event_engine_t *engine,
68 nxt_fd_event_t *ev);
69
70 /*
71 * Add a file descriptor to an event set and enable the most effective
72 * read event notification method provided by underlying event facility.
73 */
74 void (*enable_read)(nxt_event_engine_t *engine,
75 nxt_fd_event_t *ev);
76
77 /*
78 * Add a file descriptor to an event set and enable the most effective
79 * write event notification method provided by underlying event facility.
80 */
81 void (*enable_write)(nxt_event_engine_t *engine,
82 nxt_fd_event_t *ev);
83
84 /* Disable file descriptor read event notifications. */
85 void (*disable_read)(nxt_event_engine_t *engine,
86 nxt_fd_event_t *ev);
87
88 /* Disable file descriptor write event notifications. */
89 void (*disable_write)(nxt_event_engine_t *engine,
90 nxt_fd_event_t *ev);
91
92 /* Block file descriptor read event notifications. */
93 void (*block_read)(nxt_event_engine_t *engine,
94 nxt_fd_event_t *ev);
95
96 /* Block file descriptor write event notifications. */
97 void (*block_write)(nxt_event_engine_t *engine,
98 nxt_fd_event_t *ev);
99
100 /*
101 * Add a file descriptor to an event set and enable an oneshot
102 * read event notification method.
103 */
104 void (*oneshot_read)(nxt_event_engine_t *engine,
105 nxt_fd_event_t *ev);
106
107 /*
108 * Add a file descriptor to an event set and enable an oneshot
109 * write event notification method.
110 */
111 void (*oneshot_write)(nxt_event_engine_t *engine,
112 nxt_fd_event_t *ev);
113
114 /*
115 * Add a listening socket descriptor to an event set and enable
116 * a level-triggered read event notification method.
117 */
118 void (*enable_accept)(nxt_event_engine_t *engine,
119 nxt_fd_event_t *ev);
120
121 /*
122 * Add a file to an event set and enable a file change notification
123 * events.
124 */
125 void (*enable_file)(nxt_event_engine_t *engine,
126 nxt_file_event_t *ev);
127
128 /*
129 * Delete a file from an event set before closing the file descriptor.
130 */
131 void (*close_file)(nxt_event_engine_t *engine,
132 nxt_file_event_t *ev);
133
134 /*
135 * Enable post event notifications and set a post handler to handle
136 * the zero signal.
137 */
138 nxt_int_t (*enable_post)(nxt_event_engine_t *engine,
139 nxt_work_handler_t handler);
140
141 /*
142 * Signal an event set. If a signal number is non-zero then
143 * a signal handler added to the event set is called. This is
144 * a way to route Unix signals to an event engine if underlying
145 * event facility does not support signal events.
146 *
147 * If a signal number is zero, then the post_handler of the event
148 * set is called. This has no relation to Unix signals but is
149 * a way to wake up the event set to process works posted to
150 * the event engine locked work queue.
151 */
152 void (*signal)(nxt_event_engine_t *engine,
153 nxt_uint_t signo);
154
155 /* Poll an event set for new event notifications. */
156 void (*poll)(nxt_event_engine_t *engine,
157 nxt_msec_t timeout);
158
159 /* I/O operations suitable to underlying event facility. */
160 nxt_conn_io_t *io;
161
162 /* True if an event facility supports file change event notifications. */
163 uint8_t file_support; /* 1 bit */
164
165 /* True if an event facility supports signal event notifications. */
166 uint8_t signal_support; /* 1 bit */
167 } nxt_event_interface_t;
168
169
170 #if (NXT_HAVE_KQUEUE)
171
172 typedef struct {
173 int fd;
174 int nchanges;
175 int mchanges;
176 int mevents;
177 nxt_pid_t pid;
178
179 nxt_work_handler_t post_handler;
180
181 struct kevent *changes;
182 struct kevent *events;
183 } nxt_kqueue_engine_t;
184
185 extern const nxt_event_interface_t nxt_kqueue_engine;
186
187 #endif
188
189
190 #if (NXT_HAVE_EPOLL)
191
192 typedef struct {
193 int op;
194 struct epoll_event event;
195 } nxt_epoll_change_t;
196
197
198 typedef struct {
199 int fd;
200 uint32_t mode;
201 nxt_uint_t nchanges;
202 nxt_uint_t mchanges;
203 int mevents;
204
205 uint8_t error; /* 1 bit */
206
207 nxt_epoll_change_t *changes;
208 struct epoll_event *events;
209
210 #if (NXT_HAVE_EVENTFD)
211 nxt_work_handler_t post_handler;
212 nxt_fd_event_t eventfd;
213 uint32_t neventfd;
214 #endif
215
216 #if (NXT_HAVE_SIGNALFD)
217 nxt_fd_event_t signalfd;
218 #endif
219 } nxt_epoll_engine_t;
220
221
222 extern const nxt_event_interface_t nxt_epoll_edge_engine;
223 extern const nxt_event_interface_t nxt_epoll_level_engine;
224
225 #endif
226
227
228 #if (NXT_HAVE_EVENTPORT)
229
230 typedef struct {
231 int events;
232 nxt_fd_event_t *event;
233 } nxt_eventport_change_t;
234
235
236 typedef struct {
237 int fd;
238 nxt_uint_t nchanges;
239 nxt_uint_t mchanges;
240 u_int mevents;
241
242 nxt_eventport_change_t *changes;
243 port_event_t *events;
244
245 nxt_work_handler_t post_handler;
246 nxt_work_handler_t signal_handler;
247 } nxt_eventport_engine_t;
248
249 extern const nxt_event_interface_t nxt_eventport_engine;
250
251 #endif
252
253
254 #if (NXT_HAVE_DEVPOLL)
255
256 typedef struct {
257 uint8_t op;
258 short events;
259 nxt_fd_event_t *event;
260 } nxt_devpoll_change_t;
261
262
263 typedef struct {
264 int fd;
265 int nchanges;
266 int mchanges;
267 int mevents;
268
269 nxt_devpoll_change_t *changes;
270 struct pollfd *write_changes;
271 struct pollfd *events;
272 nxt_lvlhsh_t fd_hash;
273 } nxt_devpoll_engine_t;
274
275 extern const nxt_event_interface_t nxt_devpoll_engine;
276
277 #endif
278
279
280 #if (NXT_HAVE_POLLSET)
281
282 typedef struct {
283 uint8_t op;
284 uint8_t cmd;
285 short events;
286 nxt_fd_event_t *event;
287 } nxt_pollset_change_t;
288
289
290 typedef struct {
291 pollset_t ps;
292 int nchanges;
293 int mchanges;
294 int mevents;
295
296 nxt_pollset_change_t *changes;
297 struct poll_ctl *write_changes;
298 struct pollfd *events;
299 nxt_lvlhsh_t fd_hash;
300 } nxt_pollset_engine_t;
301
302 extern const nxt_event_interface_t nxt_pollset_engine;
303
304 #endif
305
306
307 typedef struct {
308 uint8_t op;
309 short events;
310 nxt_fd_event_t *event;
311 } nxt_poll_change_t;
312
313
314 typedef struct {
315 nxt_uint_t max_nfds;
316 nxt_uint_t nfds;
317
318 nxt_uint_t nchanges;
319 nxt_uint_t mchanges;
320
321 nxt_poll_change_t *changes;
322 struct pollfd *set;
323
324 nxt_lvlhsh_t fd_hash;
325 } nxt_poll_engine_t;
326
327 extern const nxt_event_interface_t nxt_poll_engine;
328
329
330 typedef struct {
331 int nfds;
332 uint32_t update_nfds; /* 1 bit */
333
334 nxt_fd_event_t **events;
335
336 fd_set main_read_fd_set;
337 fd_set main_write_fd_set;
338 fd_set work_read_fd_set;
339 fd_set work_write_fd_set;
340 } nxt_select_engine_t;
341
342 extern const nxt_event_interface_t nxt_select_engine;
343
344
345 nxt_int_t nxt_fd_event_hash_add(nxt_lvlhsh_t *lvlhsh, nxt_fd_t fd,
346 nxt_fd_event_t *ev);
347 void *nxt_fd_event_hash_get(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh,
348 nxt_fd_t fd);
349 void nxt_fd_event_hash_delete(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh,
350 nxt_fd_t fd, nxt_bool_t ignore);
351 void nxt_fd_event_hash_destroy(nxt_lvlhsh_t *lvlhsh);
352
353
354 #define nxt_fd_event_disable(engine, ev) \
355 (engine)->event.disable(engine, ev)
356
357
358 #define nxt_fd_event_delete(engine, ev) \
359 (engine)->event.delete(engine, ev)
360
361
362 #define nxt_fd_event_close(engine, ev) \
363 (engine)->event.close(engine, ev)
364
365
366 #define nxt_fd_event_enable_read(engine, ev) \
367 (engine)->event.enable_read(engine, ev)
368
369
370 #define nxt_fd_event_enable_write(engine, ev) \
371 (engine)->event.enable_write(engine, ev)
372
373
374 #define nxt_fd_event_disable_read(engine, ev) \
375 (engine)->event.disable_read(engine, ev)
376
377
378 #define nxt_fd_event_disable_write(engine, ev) \
379 (engine)->event.disable_write(engine, ev)
380
381
382 #define nxt_fd_event_block_read(engine, ev) \
383 do { \
384 if (nxt_fd_event_is_active((ev)->read)) { \
385 (engine)->event.block_read(engine, ev); \
386 } \
387 } while (0)
388
389
390 #define nxt_fd_event_block_write(engine, ev) \
391 do { \
392 if (nxt_fd_event_is_active((ev)->write)) { \
393 (engine)->event.block_write(engine, ev); \
394 } \
395 } while (0)
396
397
398 #define nxt_fd_event_oneshot_read(engine, ev) \
399 (engine)->event.oneshot_read(engine, ev)
400
401
402 #define nxt_fd_event_oneshot_write(engine, ev) \
403 (engine)->event.oneshot_write(engine, ev)
404
405
406 #define nxt_fd_event_enable_accept(engine, ev) \
407 (engine)->event.enable_accept(engine, ev)
408
409
410 #define NXT_ENGINE_FIBERS 1
411
412
413 typedef struct {
414 nxt_fd_t fds[2];
415 nxt_fd_event_t event;
416 } nxt_event_engine_pipe_t;
417
418
419 struct nxt_event_engine_s {
420 nxt_task_t task;
421
422 union {
423 nxt_poll_engine_t poll;
424 nxt_select_engine_t select;
425
426 #if (NXT_HAVE_KQUEUE)
427 nxt_kqueue_engine_t kqueue;
428 #endif
429 #if (NXT_HAVE_EPOLL)
430 nxt_epoll_engine_t epoll;
431 #endif
432 #if (NXT_HAVE_EVENTPORT)
433 nxt_eventport_engine_t eventport;
434 #endif
435 #if (NXT_HAVE_DEVPOLL)
436 nxt_devpoll_engine_t devpoll;
437 #endif
438 #if (NXT_HAVE_POLLSET)
439 nxt_pollset_engine_t pollset;
440 #endif
441 } u;
442
443 nxt_timers_t timers;
444
445 nxt_work_queue_cache_t work_queue_cache;
446 nxt_work_queue_t *current_work_queue;
447 nxt_work_queue_t fast_work_queue;
448 nxt_work_queue_t accept_work_queue;
449 nxt_work_queue_t read_work_queue;
450 nxt_work_queue_t socket_work_queue;
451 nxt_work_queue_t connect_work_queue;
452 nxt_work_queue_t write_work_queue;
453 nxt_work_queue_t shutdown_work_queue;
454 nxt_work_queue_t close_work_queue;
455
456 nxt_locked_work_queue_t locked_work_queue;
457
458 nxt_event_interface_t event;
459
460 /*
461 * A pipe to pass event signals to the engine, if the engine's
462 * underlying event facility does not support user events.
463 */
464 nxt_event_engine_pipe_t *pipe;
465
466 nxt_event_signals_t *signals;
467
468 nxt_fiber_main_t *fibers;
469
470 /* The engine ID, the main engine has ID 0. */
471 uint32_t id;
472
473 uint8_t shutdown; /* 1 bit */
474
475 uint32_t batch;
476 uint32_t connections;
477 uint32_t max_connections;
478
479 nxt_port_t *port;
480 nxt_mp_t *mem_pool;
481 nxt_queue_t joints;
482 nxt_queue_t listen_connections;
483 nxt_queue_t idle_connections;
484 nxt_array_t *mem_cache;
485
486 nxt_atomic_uint_t accepted_conns_cnt;
487 nxt_atomic_uint_t idle_conns_cnt;
488 nxt_atomic_uint_t closed_conns_cnt;
489 nxt_atomic_uint_t requests_cnt;
490
491 nxt_queue_link_t link;
492 // STUB: router link
493 nxt_queue_link_t link0;
494 };
495
496
497 NXT_EXPORT nxt_event_engine_t *nxt_event_engine_create(nxt_task_t *task,
498 const nxt_event_interface_t *interface, const nxt_sig_event_t *signals,
499 nxt_uint_t flags, nxt_uint_t batch);
500 NXT_EXPORT nxt_int_t nxt_event_engine_change(nxt_event_engine_t *engine,
501 const nxt_event_interface_t *interface, nxt_uint_t batch);
502 NXT_EXPORT void nxt_event_engine_free(nxt_event_engine_t *engine);
503 NXT_EXPORT void nxt_event_engine_start(nxt_event_engine_t *engine);
504
505 NXT_EXPORT void nxt_event_engine_post(nxt_event_engine_t *engine,
506 nxt_work_t *work);
507 NXT_EXPORT void nxt_event_engine_signal(nxt_event_engine_t *engine,
508 nxt_uint_t signo);
509
510 #define NXT_EVENT_ENGINE_NO_MEM_HINT 255
511
512 void *nxt_event_engine_mem_alloc(nxt_event_engine_t *engine, uint8_t *hint,
513 size_t size);
514 void nxt_event_engine_mem_free(nxt_event_engine_t *engine, uint8_t hint,
515 void *p, size_t size);
516 void *nxt_event_engine_buf_mem_alloc(nxt_event_engine_t *engine, size_t size);
517 void nxt_event_engine_buf_mem_free(nxt_event_engine_t *engine, nxt_buf_t *b);
518 void nxt_event_engine_buf_mem_completion(nxt_task_t *task, void *obj,
519 void *data);
520
521
522 nxt_inline nxt_event_engine_t *
nxt_thread_event_engine(void)523 nxt_thread_event_engine(void)
524 {
525 nxt_thread_t *thr;
526
527 thr = nxt_thread();
528 return thr->engine;
529 }
530
531 #if (NXT_DEBUG)
532
533 NXT_EXPORT void nxt_event_engine_thread_adopt(nxt_event_engine_t *engine);
534
535 #else
536
537 #define nxt_event_engine_thread_adopt(_engine)
538
539 #endif
540
541
542 #endif /* _NXT_EVENT_ENGINE_H_INCLUDED_ */
543