xref: /unit/src/nxt_port.c (revision 125)
111Sigor@sysoev.ru 
211Sigor@sysoev.ru /*
311Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
411Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
511Sigor@sysoev.ru  */
611Sigor@sysoev.ru 
711Sigor@sysoev.ru #include <nxt_main.h>
820Sigor@sysoev.ru #include <nxt_runtime.h>
911Sigor@sysoev.ru #include <nxt_port.h>
1011Sigor@sysoev.ru 
1111Sigor@sysoev.ru 
1214Sigor@sysoev.ru static void nxt_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg);
1311Sigor@sysoev.ru 
1411Sigor@sysoev.ru 
1511Sigor@sysoev.ru void
1677Smax.romanov@nginx.com nxt_port_create(nxt_task_t *task, nxt_port_t *port,
1714Sigor@sysoev.ru     nxt_port_handler_t *handlers)
1811Sigor@sysoev.ru {
1914Sigor@sysoev.ru     port->pid = nxt_pid;
2077Smax.romanov@nginx.com     port->engine = task->thread->engine->id;
2114Sigor@sysoev.ru     port->handler = nxt_port_handler;
2214Sigor@sysoev.ru     port->data = handlers;
2311Sigor@sysoev.ru 
2477Smax.romanov@nginx.com     nxt_port_read_enable(task, port);
2511Sigor@sysoev.ru }
2611Sigor@sysoev.ru 
2711Sigor@sysoev.ru 
2811Sigor@sysoev.ru void
2920Sigor@sysoev.ru nxt_port_write(nxt_task_t *task, nxt_runtime_t *rt, nxt_uint_t type,
3011Sigor@sysoev.ru     nxt_fd_t fd, uint32_t stream, nxt_buf_t *b)
3111Sigor@sysoev.ru {
3220Sigor@sysoev.ru     nxt_port_t     *port;
3320Sigor@sysoev.ru     nxt_process_t  *process;
3420Sigor@sysoev.ru 
3542Smax.romanov@nginx.com     nxt_runtime_process_each(rt, process)
3642Smax.romanov@nginx.com     {
3742Smax.romanov@nginx.com         if (nxt_pid != process->pid) {
3842Smax.romanov@nginx.com             nxt_process_port_each(process, port) {
3911Sigor@sysoev.ru 
4042Smax.romanov@nginx.com                 (void) nxt_port_socket_write(task, port, type,
4142Smax.romanov@nginx.com                                              fd, stream, 0, b);
4211Sigor@sysoev.ru 
4342Smax.romanov@nginx.com             } nxt_process_port_loop;
4411Sigor@sysoev.ru         }
4511Sigor@sysoev.ru     }
4642Smax.romanov@nginx.com     nxt_runtime_process_loop;
4711Sigor@sysoev.ru }
4811Sigor@sysoev.ru 
4911Sigor@sysoev.ru 
5011Sigor@sysoev.ru static void
5114Sigor@sysoev.ru nxt_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
5211Sigor@sysoev.ru {
5314Sigor@sysoev.ru     nxt_port_handler_t  *handlers;
5411Sigor@sysoev.ru 
55*125Smax.romanov@nginx.com     if (nxt_fast_path(msg->port_msg.type < NXT_PORT_MSG_MAX)) {
5611Sigor@sysoev.ru 
5711Sigor@sysoev.ru         nxt_debug(task, "port %d: message type:%uD",
5842Smax.romanov@nginx.com                   msg->port->socket.fd, msg->port_msg.type);
5911Sigor@sysoev.ru 
6011Sigor@sysoev.ru         handlers = msg->port->data;
6142Smax.romanov@nginx.com         handlers[msg->port_msg.type](task, msg);
6211Sigor@sysoev.ru 
6311Sigor@sysoev.ru         return;
6411Sigor@sysoev.ru     }
6511Sigor@sysoev.ru 
6611Sigor@sysoev.ru     nxt_log(task, NXT_LOG_CRIT, "port %d: unknown message type:%uD",
6742Smax.romanov@nginx.com             msg->port->socket.fd, msg->port_msg.type);
6811Sigor@sysoev.ru }
6911Sigor@sysoev.ru 
7011Sigor@sysoev.ru 
7111Sigor@sysoev.ru void
7214Sigor@sysoev.ru nxt_port_quit_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
7311Sigor@sysoev.ru {
7420Sigor@sysoev.ru     nxt_runtime_quit(task);
7511Sigor@sysoev.ru }
7611Sigor@sysoev.ru 
7711Sigor@sysoev.ru 
7811Sigor@sysoev.ru void
7920Sigor@sysoev.ru nxt_port_send_new_port(nxt_task_t *task, nxt_runtime_t *rt,
8014Sigor@sysoev.ru     nxt_port_t *new_port)
8111Sigor@sysoev.ru {
8281Smax.romanov@nginx.com     nxt_process_t  *process;
8311Sigor@sysoev.ru 
8414Sigor@sysoev.ru     nxt_debug(task, "new port %d for process %PI engine %uD",
8581Smax.romanov@nginx.com               new_port->pair[1], new_port->pid, new_port->engine);
8611Sigor@sysoev.ru 
8742Smax.romanov@nginx.com     nxt_runtime_process_each(rt, process)
8842Smax.romanov@nginx.com     {
8942Smax.romanov@nginx.com         if (process->pid == new_port->pid || process->pid == nxt_pid) {
9011Sigor@sysoev.ru             continue;
9111Sigor@sysoev.ru         }
9211Sigor@sysoev.ru 
9381Smax.romanov@nginx.com         (void) nxt_port_send_port(task, nxt_process_port_first(process),
9481Smax.romanov@nginx.com                                   new_port);
9511Sigor@sysoev.ru     }
9642Smax.romanov@nginx.com     nxt_runtime_process_loop;
9711Sigor@sysoev.ru }
9811Sigor@sysoev.ru 
9911Sigor@sysoev.ru 
10081Smax.romanov@nginx.com nxt_int_t
10181Smax.romanov@nginx.com nxt_port_send_port(nxt_task_t *task, nxt_port_t *port, nxt_port_t *new_port)
10281Smax.romanov@nginx.com {
10381Smax.romanov@nginx.com     nxt_buf_t                *b;
10481Smax.romanov@nginx.com     nxt_port_msg_new_port_t  *msg;
10581Smax.romanov@nginx.com 
106122Smax.romanov@nginx.com     b = nxt_buf_mem_ts_alloc(task, port->mem_pool, sizeof(nxt_port_data_t));
10781Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
10881Smax.romanov@nginx.com         return NXT_ERROR;
10981Smax.romanov@nginx.com     }
11081Smax.romanov@nginx.com 
11181Smax.romanov@nginx.com     nxt_debug(task, "send port %FD to process %PI",
11281Smax.romanov@nginx.com               new_port->pair[1], port->pid);
11381Smax.romanov@nginx.com 
11481Smax.romanov@nginx.com     b->mem.free += sizeof(nxt_port_msg_new_port_t);
11581Smax.romanov@nginx.com     msg = (nxt_port_msg_new_port_t *) b->mem.pos;
11681Smax.romanov@nginx.com 
11781Smax.romanov@nginx.com     msg->id = new_port->id;
11881Smax.romanov@nginx.com     msg->pid = new_port->pid;
11981Smax.romanov@nginx.com     msg->engine = new_port->engine;
12081Smax.romanov@nginx.com     msg->max_size = port->max_size;
12181Smax.romanov@nginx.com     msg->max_share = port->max_share;
12281Smax.romanov@nginx.com     msg->type = new_port->type;
12381Smax.romanov@nginx.com 
12481Smax.romanov@nginx.com     return nxt_port_socket_write(task, port, NXT_PORT_MSG_NEW_PORT,
12581Smax.romanov@nginx.com                                  new_port->pair[1], 0, 0, b);
12681Smax.romanov@nginx.com }
12781Smax.romanov@nginx.com 
12881Smax.romanov@nginx.com 
12911Sigor@sysoev.ru void
13014Sigor@sysoev.ru nxt_port_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
13111Sigor@sysoev.ru {
13265Sigor@sysoev.ru     nxt_mp_t                 *mp;
13311Sigor@sysoev.ru     nxt_port_t               *port;
13420Sigor@sysoev.ru     nxt_process_t            *process;
13520Sigor@sysoev.ru     nxt_runtime_t            *rt;
13614Sigor@sysoev.ru     nxt_port_msg_new_port_t  *new_port_msg;
13711Sigor@sysoev.ru 
13820Sigor@sysoev.ru     rt = task->thread->runtime;
13911Sigor@sysoev.ru 
14042Smax.romanov@nginx.com     new_port_msg = (nxt_port_msg_new_port_t *) msg->buf->mem.pos;
14142Smax.romanov@nginx.com     msg->buf->mem.pos = msg->buf->mem.free;
14242Smax.romanov@nginx.com 
14342Smax.romanov@nginx.com     process = nxt_runtime_process_get(rt, new_port_msg->pid);
14420Sigor@sysoev.ru     if (nxt_slow_path(process == NULL)) {
14520Sigor@sysoev.ru         return;
14620Sigor@sysoev.ru     }
14720Sigor@sysoev.ru 
14842Smax.romanov@nginx.com     port = nxt_process_port_new(process);
14911Sigor@sysoev.ru     if (nxt_slow_path(port == NULL)) {
15011Sigor@sysoev.ru         return;
15111Sigor@sysoev.ru     }
15211Sigor@sysoev.ru 
15365Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
15414Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
15514Sigor@sysoev.ru         return;
15614Sigor@sysoev.ru     }
15711Sigor@sysoev.ru 
15814Sigor@sysoev.ru     port->mem_pool = mp;
15914Sigor@sysoev.ru 
16011Sigor@sysoev.ru     nxt_debug(task, "new port %d received for process %PI engine %uD",
16114Sigor@sysoev.ru               msg->fd, new_port_msg->pid, new_port_msg->engine);
16211Sigor@sysoev.ru 
16342Smax.romanov@nginx.com     port->id = new_port_msg->id;
16414Sigor@sysoev.ru     port->engine = new_port_msg->engine;
16514Sigor@sysoev.ru     port->pair[0] = -1;
16611Sigor@sysoev.ru     port->pair[1] = msg->fd;
16714Sigor@sysoev.ru     port->max_size = new_port_msg->max_size;
16814Sigor@sysoev.ru     port->max_share = new_port_msg->max_share;
16942Smax.romanov@nginx.com     port->type = new_port_msg->type;
17011Sigor@sysoev.ru 
17114Sigor@sysoev.ru     nxt_queue_init(&port->messages);
17214Sigor@sysoev.ru 
17314Sigor@sysoev.ru     port->socket.task = task;
17414Sigor@sysoev.ru 
17542Smax.romanov@nginx.com     nxt_runtime_port_add(rt, port);
17642Smax.romanov@nginx.com 
17711Sigor@sysoev.ru     nxt_port_write_enable(task, port);
17811Sigor@sysoev.ru }
17911Sigor@sysoev.ru 
18011Sigor@sysoev.ru 
18111Sigor@sysoev.ru void
18242Smax.romanov@nginx.com nxt_port_mmap_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
18342Smax.romanov@nginx.com {
18442Smax.romanov@nginx.com     nxt_runtime_t  *rt;
18542Smax.romanov@nginx.com     nxt_process_t  *process;
18642Smax.romanov@nginx.com 
18742Smax.romanov@nginx.com     rt = task->thread->runtime;
18842Smax.romanov@nginx.com 
18942Smax.romanov@nginx.com     if (nxt_slow_path(msg->fd == -1)) {
19042Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "invalid fd passed with mmap message");
19142Smax.romanov@nginx.com 
19242Smax.romanov@nginx.com         return;
19342Smax.romanov@nginx.com     }
19442Smax.romanov@nginx.com 
19542Smax.romanov@nginx.com     process = nxt_runtime_process_get(rt, msg->port_msg.pid);
19642Smax.romanov@nginx.com     if (nxt_slow_path(process == NULL)) {
19742Smax.romanov@nginx.com         nxt_log(task, NXT_LOG_WARN, "failed to get process #%PI",
19842Smax.romanov@nginx.com                 msg->port_msg.pid);
19942Smax.romanov@nginx.com 
20042Smax.romanov@nginx.com         goto fail_close;
20142Smax.romanov@nginx.com     }
20242Smax.romanov@nginx.com 
20342Smax.romanov@nginx.com     nxt_port_incoming_port_mmap(task, process, msg->fd);
20442Smax.romanov@nginx.com 
20542Smax.romanov@nginx.com fail_close:
20642Smax.romanov@nginx.com 
20742Smax.romanov@nginx.com     close(msg->fd);
20842Smax.romanov@nginx.com }
20942Smax.romanov@nginx.com 
21042Smax.romanov@nginx.com 
21142Smax.romanov@nginx.com void
21220Sigor@sysoev.ru nxt_port_change_log_file(nxt_task_t *task, nxt_runtime_t *rt, nxt_uint_t slot,
21320Sigor@sysoev.ru     nxt_fd_t fd)
21411Sigor@sysoev.ru {
21520Sigor@sysoev.ru     nxt_buf_t      *b;
21620Sigor@sysoev.ru     nxt_port_t     *port;
21720Sigor@sysoev.ru     nxt_process_t  *process;
21811Sigor@sysoev.ru 
21914Sigor@sysoev.ru     nxt_debug(task, "change log file #%ui fd:%FD", slot, fd);
22011Sigor@sysoev.ru 
22142Smax.romanov@nginx.com     nxt_runtime_process_each(rt, process)
22242Smax.romanov@nginx.com     {
22342Smax.romanov@nginx.com         if (nxt_pid == process->pid) {
22442Smax.romanov@nginx.com             continue;
22542Smax.romanov@nginx.com         }
22611Sigor@sysoev.ru 
22742Smax.romanov@nginx.com         port = nxt_process_port_first(process);
22811Sigor@sysoev.ru 
22920Sigor@sysoev.ru         b = nxt_buf_mem_alloc(port->mem_pool, sizeof(nxt_port_data_t), 0);
23011Sigor@sysoev.ru         if (nxt_slow_path(b == NULL)) {
23111Sigor@sysoev.ru             continue;
23211Sigor@sysoev.ru         }
23311Sigor@sysoev.ru 
23411Sigor@sysoev.ru         *(nxt_uint_t *) b->mem.pos = slot;
23511Sigor@sysoev.ru         b->mem.free += sizeof(nxt_uint_t);
23611Sigor@sysoev.ru 
23720Sigor@sysoev.ru         (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_CHANGE_FILE,
23842Smax.romanov@nginx.com                                      fd, 0, 0, b);
23911Sigor@sysoev.ru     }
24042Smax.romanov@nginx.com     nxt_runtime_process_loop;
24111Sigor@sysoev.ru }
24211Sigor@sysoev.ru 
24311Sigor@sysoev.ru 
24411Sigor@sysoev.ru void
24514Sigor@sysoev.ru nxt_port_change_log_file_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
24611Sigor@sysoev.ru {
24720Sigor@sysoev.ru     nxt_buf_t      *b;
24820Sigor@sysoev.ru     nxt_uint_t     slot;
24920Sigor@sysoev.ru     nxt_file_t     *log_file;
25020Sigor@sysoev.ru     nxt_runtime_t  *rt;
25111Sigor@sysoev.ru 
25220Sigor@sysoev.ru     rt = task->thread->runtime;
25311Sigor@sysoev.ru 
25411Sigor@sysoev.ru     b = msg->buf;
25511Sigor@sysoev.ru     slot = *(nxt_uint_t *) b->mem.pos;
25611Sigor@sysoev.ru 
25720Sigor@sysoev.ru     log_file = nxt_list_elt(rt->log_files, slot);
25811Sigor@sysoev.ru 
25911Sigor@sysoev.ru     nxt_debug(task, "change log file %FD:%FD", msg->fd, log_file->fd);
26011Sigor@sysoev.ru 
26111Sigor@sysoev.ru     /*
26211Sigor@sysoev.ru      * The old log file descriptor must be closed at the moment when no
26311Sigor@sysoev.ru      * other threads use it.  dup2() allows to use the old file descriptor
26411Sigor@sysoev.ru      * for new log file.  This change is performed atomically in the kernel.
26511Sigor@sysoev.ru      */
26611Sigor@sysoev.ru     if (nxt_file_redirect(log_file, msg->fd) == NXT_OK) {
26711Sigor@sysoev.ru 
26811Sigor@sysoev.ru         if (slot == 0) {
26911Sigor@sysoev.ru             (void) nxt_file_stderr(log_file);
27011Sigor@sysoev.ru         }
27111Sigor@sysoev.ru     }
27211Sigor@sysoev.ru }
27311Sigor@sysoev.ru 
27411Sigor@sysoev.ru 
27511Sigor@sysoev.ru void
27614Sigor@sysoev.ru nxt_port_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
27711Sigor@sysoev.ru {
27842Smax.romanov@nginx.com     size_t     dump_size;
27911Sigor@sysoev.ru     nxt_buf_t  *b;
28011Sigor@sysoev.ru 
28111Sigor@sysoev.ru     b = msg->buf;
28242Smax.romanov@nginx.com     dump_size = b->mem.free - b->mem.pos;
28311Sigor@sysoev.ru 
28442Smax.romanov@nginx.com     if (dump_size > 300) {
28542Smax.romanov@nginx.com         dump_size = 300;
28642Smax.romanov@nginx.com     }
28742Smax.romanov@nginx.com 
28842Smax.romanov@nginx.com     nxt_debug(task, "data: %*s", dump_size, b->mem.pos);
28911Sigor@sysoev.ru 
29011Sigor@sysoev.ru     b->mem.pos = b->mem.free;
29111Sigor@sysoev.ru }
29211Sigor@sysoev.ru 
29311Sigor@sysoev.ru 
29411Sigor@sysoev.ru void
295*125Smax.romanov@nginx.com nxt_port_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
296*125Smax.romanov@nginx.com {
297*125Smax.romanov@nginx.com     nxt_pid_t           pid;
298*125Smax.romanov@nginx.com     nxt_runtime_t       *rt;
299*125Smax.romanov@nginx.com     nxt_process_t       *process;
300*125Smax.romanov@nginx.com 
301*125Smax.romanov@nginx.com     nxt_debug(task, "port remove pid handler");
302*125Smax.romanov@nginx.com 
303*125Smax.romanov@nginx.com     rt = task->thread->runtime;
304*125Smax.romanov@nginx.com     pid = msg->port_msg.stream;
305*125Smax.romanov@nginx.com 
306*125Smax.romanov@nginx.com     process = nxt_runtime_process_find(rt, pid);
307*125Smax.romanov@nginx.com 
308*125Smax.romanov@nginx.com     if (process) {
309*125Smax.romanov@nginx.com         nxt_runtime_process_remove(rt, process);
310*125Smax.romanov@nginx.com     }
311*125Smax.romanov@nginx.com }
312*125Smax.romanov@nginx.com 
313*125Smax.romanov@nginx.com 
314*125Smax.romanov@nginx.com void
31514Sigor@sysoev.ru nxt_port_empty_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
31611Sigor@sysoev.ru {
31711Sigor@sysoev.ru     nxt_debug(task, "port empty handler");
31811Sigor@sysoev.ru }
319