xref: /unit/src/nxt_event_engine.h (revision 318:c2442f5e054d)
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     nxt_epoll_change_t            *changes;
206     struct epoll_event            *events;
207 
208 #if (NXT_HAVE_EVENTFD)
209     nxt_work_handler_t            post_handler;
210     nxt_fd_event_t                eventfd;
211     uint32_t                      neventfd;
212 #endif
213 
214 #if (NXT_HAVE_SIGNALFD)
215     nxt_fd_event_t                signalfd;
216 #endif
217 } nxt_epoll_engine_t;
218 
219 
220 extern const nxt_event_interface_t  nxt_epoll_edge_engine;
221 extern const nxt_event_interface_t  nxt_epoll_level_engine;
222 
223 #endif
224 
225 
226 #if (NXT_HAVE_EVENTPORT)
227 
228 typedef struct {
229     int                           events;
230     nxt_fd_event_t                *event;
231 } nxt_eventport_change_t;
232 
233 
234 typedef struct {
235     int                           fd;
236     nxt_uint_t                    nchanges;
237     nxt_uint_t                    mchanges;
238     u_int                         mevents;
239 
240     nxt_eventport_change_t        *changes;
241     port_event_t                  *events;
242 
243     nxt_work_handler_t            post_handler;
244     nxt_work_handler_t            signal_handler;
245 } nxt_eventport_engine_t;
246 
247 extern const nxt_event_interface_t  nxt_eventport_engine;
248 
249 #endif
250 
251 
252 #if (NXT_HAVE_DEVPOLL)
253 
254 typedef struct {
255     uint8_t                       op;
256     short                         events;
257     nxt_fd_event_t                *event;
258 } nxt_devpoll_change_t;
259 
260 
261 typedef struct {
262     int                           fd;
263     int                           nchanges;
264     int                           mchanges;
265     int                           mevents;
266 
267     nxt_devpoll_change_t          *changes;
268     struct pollfd                 *write_changes;
269     struct pollfd                 *events;
270     nxt_lvlhsh_t                  fd_hash;
271 } nxt_devpoll_engine_t;
272 
273 extern const nxt_event_interface_t  nxt_devpoll_engine;
274 
275 #endif
276 
277 
278 #if (NXT_HAVE_POLLSET)
279 
280 typedef struct {
281     uint8_t                       op;
282     uint8_t                       cmd;
283     short                         events;
284     nxt_fd_event_t                *event;
285 } nxt_pollset_change_t;
286 
287 
288 typedef struct {
289     pollset_t                     ps;
290     int                           nchanges;
291     int                           mchanges;
292     int                           mevents;
293 
294     nxt_pollset_change_t          *changes;
295     struct poll_ctl               *write_changes;
296     struct pollfd                 *events;
297     nxt_lvlhsh_t                  fd_hash;
298 } nxt_pollset_engine_t;
299 
300 extern const nxt_event_interface_t  nxt_pollset_engine;
301 
302 #endif
303 
304 
305 typedef struct {
306     uint8_t                       op;
307     short                         events;
308     nxt_fd_event_t                *event;
309 } nxt_poll_change_t;
310 
311 
312 typedef struct {
313     nxt_uint_t                    max_nfds;
314     nxt_uint_t                    nfds;
315 
316     nxt_uint_t                    nchanges;
317     nxt_uint_t                    mchanges;
318 
319     nxt_poll_change_t             *changes;
320     struct pollfd                 *set;
321 
322     nxt_lvlhsh_t                  fd_hash;
323 } nxt_poll_engine_t;
324 
325 extern const nxt_event_interface_t  nxt_poll_engine;
326 
327 
328 typedef struct {
329     int                           nfds;
330     uint32_t                      update_nfds;  /* 1 bit */
331 
332     nxt_fd_event_t                **events;
333 
334     fd_set                        main_read_fd_set;
335     fd_set                        main_write_fd_set;
336     fd_set                        work_read_fd_set;
337     fd_set                        work_write_fd_set;
338 } nxt_select_engine_t;
339 
340 extern const nxt_event_interface_t  nxt_select_engine;
341 
342 
343 nxt_int_t nxt_fd_event_hash_add(nxt_lvlhsh_t *lvlhsh, nxt_fd_t fd,
344     nxt_fd_event_t *ev);
345 void *nxt_fd_event_hash_get(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh,
346     nxt_fd_t fd);
347 void nxt_fd_event_hash_delete(nxt_task_t *task, nxt_lvlhsh_t *lvlhsh,
348     nxt_fd_t fd, nxt_bool_t ignore);
349 void nxt_fd_event_hash_destroy(nxt_lvlhsh_t *lvlhsh);
350 
351 
352 #define                                                                       \
353 nxt_fd_event_disable(engine, ev)                                              \
354     (engine)->event.disable(engine, ev)
355 
356 
357 #define                                                                       \
358 nxt_fd_event_delete(engine, ev)                                               \
359     (engine)->event.delete(engine, ev)
360 
361 
362 #define                                                                       \
363 nxt_fd_event_close(engine, ev)                                                \
364     (engine)->event.close(engine, ev)
365 
366 
367 #define                                                                       \
368 nxt_fd_event_enable_read(engine, ev)                                          \
369     (engine)->event.enable_read(engine, ev)
370 
371 
372 #define                                                                       \
373 nxt_fd_event_enable_write(engine, ev)                                         \
374     (engine)->event.enable_write(engine, ev)
375 
376 
377 #define                                                                       \
378 nxt_fd_event_disable_read(engine, ev)                                         \
379     (engine)->event.disable_read(engine, ev)
380 
381 
382 #define                                                                       \
383 nxt_fd_event_disable_write(engine, ev)                                        \
384     (engine)->event.disable_write(engine, ev)
385 
386 
387 #define                                                                       \
388 nxt_fd_event_block_read(engine, ev)                                           \
389     do {                                                                      \
390         if (nxt_fd_event_is_active((ev)->read)) {                             \
391             (engine)->event.block_read(engine, ev);                           \
392         }                                                                     \
393     } while (0)
394 
395 
396 #define                                                                       \
397 nxt_fd_event_block_write(engine, ev)                                          \
398     do {                                                                      \
399         if (nxt_fd_event_is_active((ev)->write)) {                            \
400             (engine)->event.block_write(engine, ev);                          \
401         }                                                                     \
402     } while (0)
403 
404 
405 #define                                                                       \
406 nxt_fd_event_oneshot_read(engine, ev)                                         \
407     (engine)->event.oneshot_read(engine, ev)
408 
409 
410 #define                                                                       \
411 nxt_fd_event_oneshot_write(engine, ev)                                        \
412     (engine)->event.oneshot_write(engine, ev)
413 
414 
415 #define                                                                       \
416 nxt_fd_event_enable_accept(engine, ev)                                        \
417     (engine)->event.enable_accept(engine, ev)
418 
419 
420 #define NXT_ENGINE_FIBERS      1
421 
422 
423 typedef struct {
424     nxt_fd_t                   fds[2];
425     nxt_fd_event_t             event;
426 } nxt_event_engine_pipe_t;
427 
428 
429 struct nxt_event_engine_s {
430     nxt_task_t                 task;
431 
432     union {
433         nxt_poll_engine_t      poll;
434         nxt_select_engine_t    select;
435 
436 #if (NXT_HAVE_KQUEUE)
437         nxt_kqueue_engine_t    kqueue;
438 #endif
439 #if (NXT_HAVE_EPOLL)
440         nxt_epoll_engine_t     epoll;
441 #endif
442 #if (NXT_HAVE_EVENTPORT)
443         nxt_eventport_engine_t eventport;
444 #endif
445 #if (NXT_HAVE_DEVPOLL)
446         nxt_devpoll_engine_t   devpoll;
447 #endif
448 #if (NXT_HAVE_POLLSET)
449         nxt_pollset_engine_t   pollset;
450 #endif
451     } u;
452 
453     nxt_timers_t               timers;
454 
455     nxt_work_queue_cache_t     work_queue_cache;
456     nxt_work_queue_t           *current_work_queue;
457     nxt_work_queue_t           fast_work_queue;
458     nxt_work_queue_t           accept_work_queue;
459     nxt_work_queue_t           read_work_queue;
460     nxt_work_queue_t           socket_work_queue;
461     nxt_work_queue_t           connect_work_queue;
462     nxt_work_queue_t           write_work_queue;
463     nxt_work_queue_t           shutdown_work_queue;
464     nxt_work_queue_t           close_work_queue;
465 
466     nxt_locked_work_queue_t    locked_work_queue;
467 
468     nxt_event_interface_t      event;
469 
470     /*
471      * A pipe to pass event signals to the engine, if the engine's
472      * underlying event facility does not support user events.
473      */
474     nxt_event_engine_pipe_t    *pipe;
475 
476     nxt_event_signals_t        *signals;
477 
478     nxt_fiber_main_t           *fibers;
479 
480     /* The engine ID, the main engine has ID 0. */
481     uint32_t                   id;
482 
483     uint8_t                    shutdown;  /* 1 bit */
484 
485     uint32_t                   batch;
486     uint32_t                   connections;
487     uint32_t                   max_connections;
488 
489     nxt_port_t                 *port;
490     nxt_mp_t                   *mem_pool;
491     nxt_queue_t                joints;
492     nxt_queue_t                listen_connections;
493     nxt_queue_t                idle_connections;
494 
495     nxt_queue_link_t           link;
496     // STUB: router link
497     nxt_queue_link_t           link0;
498 };
499 
500 
501 NXT_EXPORT nxt_event_engine_t *nxt_event_engine_create(nxt_task_t *task,
502     const nxt_event_interface_t *interface, const nxt_sig_event_t *signals,
503     nxt_uint_t flags, nxt_uint_t batch);
504 NXT_EXPORT nxt_int_t nxt_event_engine_change(nxt_event_engine_t *engine,
505     const nxt_event_interface_t *interface, nxt_uint_t batch);
506 NXT_EXPORT void nxt_event_engine_free(nxt_event_engine_t *engine);
507 NXT_EXPORT void nxt_event_engine_start(nxt_event_engine_t *engine);
508 
509 NXT_EXPORT void nxt_event_engine_post(nxt_event_engine_t *engine,
510     nxt_work_t *work);
511 NXT_EXPORT void nxt_event_engine_signal(nxt_event_engine_t *engine,
512     nxt_uint_t signo);
513 
514 
515 nxt_inline nxt_event_engine_t *
516 nxt_thread_event_engine(void)
517 {
518     nxt_thread_t  *thr;
519 
520     thr = nxt_thread();
521     return thr->engine;
522 }
523 
524 #if (NXT_DEBUG)
525 
526 NXT_EXPORT void nxt_event_engine_thread_adopt(nxt_event_engine_t *engine);
527 
528 #else
529 
530 #define nxt_event_engine_thread_adopt(_engine)
531 
532 #endif
533 
534 
535 #endif /* _NXT_EVENT_ENGINE_H_INCLUDED_ */
536