Coverage Report

Created: 2024-02-25 06:30

/src/unit/src/nxt_runtime.c
Line
Count
Source (jump to first uncovered line)
1
2
/*
3
 * Copyright (C) Igor Sysoev
4
 * Copyright (C) Valentin V. Bartenev
5
 * Copyright (C) NGINX, Inc.
6
 */
7
8
#include <nxt_main.h>
9
#include <nxt_runtime.h>
10
#include <nxt_port.h>
11
#include <nxt_main_process.h>
12
#include <nxt_router.h>
13
#include <nxt_regex.h>
14
15
16
static nxt_int_t nxt_runtime_inherited_listen_sockets(nxt_task_t *task,
17
    nxt_runtime_t *rt);
18
static nxt_int_t nxt_runtime_systemd_listen_sockets(nxt_task_t *task,
19
    nxt_runtime_t *rt);
20
static nxt_int_t nxt_runtime_event_engines(nxt_task_t *task, nxt_runtime_t *rt);
21
static nxt_int_t nxt_runtime_thread_pools(nxt_thread_t *thr, nxt_runtime_t *rt);
22
static void nxt_runtime_start(nxt_task_t *task, void *obj, void *data);
23
static void nxt_runtime_initial_start(nxt_task_t *task, nxt_uint_t status);
24
static void nxt_runtime_close_idle_connections(nxt_event_engine_t *engine);
25
static void nxt_runtime_stop_all_processes(nxt_task_t *task, nxt_runtime_t *rt);
26
static void nxt_runtime_exit(nxt_task_t *task, void *obj, void *data);
27
static nxt_int_t nxt_runtime_event_engine_change(nxt_task_t *task,
28
    nxt_runtime_t *rt);
29
static nxt_int_t nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt);
30
static nxt_int_t nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt);
31
static nxt_int_t nxt_runtime_hostname(nxt_task_t *task, nxt_runtime_t *rt);
32
static nxt_int_t nxt_runtime_log_files_init(nxt_runtime_t *rt);
33
static nxt_int_t nxt_runtime_log_files_create(nxt_task_t *task,
34
    nxt_runtime_t *rt);
35
static nxt_int_t nxt_runtime_pid_file_create(nxt_task_t *task,
36
    nxt_file_name_t *pid_file);
37
static void nxt_runtime_thread_pool_destroy(nxt_task_t *task, nxt_runtime_t *rt,
38
    nxt_runtime_cont_t cont);
39
static void nxt_runtime_thread_pool_init(void);
40
static void nxt_runtime_thread_pool_exit(nxt_task_t *task, void *obj,
41
    void *data);
42
static nxt_process_t *nxt_runtime_process_get(nxt_runtime_t *rt, nxt_pid_t pid);
43
static void nxt_runtime_port_add(nxt_task_t *task, nxt_port_t *port);
44
45
46
nxt_int_t
47
nxt_runtime_create(nxt_task_t *task)
48
0
{
49
0
    nxt_mp_t               *mp;
50
0
    nxt_int_t              ret;
51
0
    nxt_array_t            *listen_sockets;
52
0
    nxt_runtime_t          *rt;
53
0
    nxt_app_lang_module_t  *lang;
54
55
0
    mp = nxt_mp_create(1024, 128, 256, 32);
56
0
    if (nxt_slow_path(mp == NULL)) {
57
0
        return NXT_ERROR;
58
0
    }
59
60
0
    rt = nxt_mp_zget(mp, sizeof(nxt_runtime_t));
61
0
    if (nxt_slow_path(rt == NULL)) {
62
0
        goto fail;
63
0
    }
64
65
0
    task->thread->runtime = rt;
66
0
    rt->mem_pool = mp;
67
68
0
    nxt_thread_mutex_create(&rt->processes_mutex);
69
70
0
    rt->services = nxt_services_init(mp);
71
0
    if (nxt_slow_path(rt->services == NULL)) {
72
0
        goto fail;
73
0
    }
74
75
0
    rt->languages = nxt_array_create(mp, 1, sizeof(nxt_app_lang_module_t));
76
0
    if (nxt_slow_path(rt->languages == NULL)) {
77
0
        goto fail;
78
0
    }
79
80
    /* Should not fail. */
81
0
    lang = nxt_array_add(rt->languages);
82
0
    lang->type = NXT_APP_EXTERNAL;
83
0
    lang->version = (u_char *) "";
84
0
    lang->file = NULL;
85
0
    lang->module = &nxt_external_module;
86
87
0
    lang->mounts = nxt_array_create(mp, 1, sizeof(nxt_fs_mount_t));
88
0
    if (nxt_slow_path(lang->mounts == NULL)) {
89
0
        goto fail;
90
0
    }
91
92
0
    listen_sockets = nxt_array_create(mp, 1, sizeof(nxt_listen_socket_t));
93
0
    if (nxt_slow_path(listen_sockets == NULL)) {
94
0
        goto fail;
95
0
    }
96
97
0
    rt->listen_sockets = listen_sockets;
98
99
0
    ret = nxt_runtime_inherited_listen_sockets(task, rt);
100
0
    if (nxt_slow_path(ret != NXT_OK)) {
101
0
        goto fail;
102
0
    }
103
104
0
    if (nxt_runtime_hostname(task, rt) != NXT_OK) {
105
0
        goto fail;
106
0
    }
107
108
0
    if (nxt_slow_path(nxt_runtime_log_files_init(rt) != NXT_OK)) {
109
0
        goto fail;
110
0
    }
111
112
0
    if (nxt_runtime_event_engines(task, rt) != NXT_OK) {
113
0
        goto fail;
114
0
    }
115
116
0
    if (nxt_slow_path(nxt_runtime_thread_pools(task->thread, rt) != NXT_OK)) {
117
0
        goto fail;
118
0
    }
119
120
0
    rt->start = nxt_runtime_initial_start;
121
122
0
    if (nxt_runtime_conf_init(task, rt) != NXT_OK) {
123
0
        goto fail;
124
0
    }
125
126
0
    if (nxt_port_rpc_init() != NXT_OK) {
127
0
        goto fail;
128
0
    }
129
130
0
    if (nxt_slow_path(nxt_http_register_variables() != NXT_OK)) {
131
0
        goto fail;
132
0
    }
133
134
0
    if (nxt_slow_path(nxt_var_index_init() != NXT_OK)) {
135
0
        goto fail;
136
0
    }
137
138
0
    nxt_work_queue_add(&task->thread->engine->fast_work_queue,
139
0
                       nxt_runtime_start, task, rt, NULL);
140
141
0
    return NXT_OK;
142
143
0
fail:
144
145
0
    nxt_mp_destroy(mp);
146
147
0
    return NXT_ERROR;
148
0
}
149
150
151
static nxt_int_t
152
nxt_runtime_inherited_listen_sockets(nxt_task_t *task, nxt_runtime_t *rt)
153
0
{
154
0
    u_char               *v, *p;
155
0
    nxt_int_t            type;
156
0
    nxt_array_t          *inherited_sockets;
157
0
    nxt_socket_t         s;
158
0
    nxt_listen_socket_t  *ls;
159
160
0
    v = (u_char *) getenv("NGINX");
161
162
0
    if (v == NULL) {
163
0
        return nxt_runtime_systemd_listen_sockets(task, rt);
164
0
    }
165
166
0
    nxt_alert(task, "using inherited listen sockets: %s", v);
167
168
0
    inherited_sockets = nxt_array_create(rt->mem_pool,
169
0
                                         1, sizeof(nxt_listen_socket_t));
170
0
    if (inherited_sockets == NULL) {
171
0
        return NXT_ERROR;
172
0
    }
173
174
0
    rt->inherited_sockets = inherited_sockets;
175
176
0
    for (p = v; *p != '\0'; p++) {
177
178
0
        if (*p == ';') {
179
0
            s = nxt_int_parse(v, p - v);
180
181
0
            if (nxt_slow_path(s < 0)) {
182
0
                nxt_alert(task, "invalid socket number \"%s\" "
183
0
                          "in NGINX environment variable, "
184
0
                          "ignoring the rest of the variable", v);
185
0
                return NXT_ERROR;
186
0
            }
187
188
0
            v = p + 1;
189
190
0
            ls = nxt_array_zero_add(inherited_sockets);
191
0
            if (nxt_slow_path(ls == NULL)) {
192
0
                return NXT_ERROR;
193
0
            }
194
195
0
            ls->socket = s;
196
197
0
            ls->sockaddr = nxt_getsockname(task, rt->mem_pool, s);
198
0
            if (nxt_slow_path(ls->sockaddr == NULL)) {
199
0
                return NXT_ERROR;
200
0
            }
201
202
0
            type = nxt_socket_getsockopt(task, s, SOL_SOCKET, SO_TYPE);
203
0
            if (nxt_slow_path(type == -1)) {
204
0
                return NXT_ERROR;
205
0
            }
206
207
0
            ls->sockaddr->type = (uint16_t) type;
208
0
        }
209
0
    }
210
211
0
    return NXT_OK;
212
0
}
213
214
215
static nxt_int_t
216
nxt_runtime_systemd_listen_sockets(nxt_task_t *task, nxt_runtime_t *rt)
217
0
{
218
0
    u_char               *nfd, *pid;
219
0
    nxt_int_t            n;
220
0
    nxt_array_t          *inherited_sockets;
221
0
    nxt_socket_t         s;
222
0
    nxt_listen_socket_t  *ls;
223
224
    /*
225
     * Number of listening sockets passed.  The socket
226
     * descriptors start from number 3 and are sequential.
227
     */
228
0
    nfd = (u_char *) getenv("LISTEN_FDS");
229
0
    if (nfd == NULL) {
230
0
        return NXT_OK;
231
0
    }
232
233
    /* The pid of the service process. */
234
0
    pid = (u_char *) getenv("LISTEN_PID");
235
0
    if (pid == NULL) {
236
0
        return NXT_OK;
237
0
    }
238
239
0
    n = nxt_int_parse(nfd, nxt_strlen(nfd));
240
0
    if (n < 0) {
241
0
        return NXT_OK;
242
0
    }
243
244
0
    if (nxt_pid != nxt_int_parse(pid, nxt_strlen(pid))) {
245
0
        return NXT_OK;
246
0
    }
247
248
0
    nxt_log(task, NXT_LOG_INFO, "using %i systemd listen sockets", n);
249
250
0
    inherited_sockets = nxt_array_create(rt->mem_pool,
251
0
                                         n, sizeof(nxt_listen_socket_t));
252
0
    if (inherited_sockets == NULL) {
253
0
        return NXT_ERROR;
254
0
    }
255
256
0
    rt->inherited_sockets = inherited_sockets;
257
258
0
    for (s = 3; s < n; s++) {
259
0
        ls = nxt_array_zero_add(inherited_sockets);
260
0
        if (nxt_slow_path(ls == NULL)) {
261
0
            return NXT_ERROR;
262
0
        }
263
264
0
        ls->socket = s;
265
266
0
        ls->sockaddr = nxt_getsockname(task, rt->mem_pool, s);
267
0
        if (nxt_slow_path(ls->sockaddr == NULL)) {
268
0
            return NXT_ERROR;
269
0
        }
270
271
0
        ls->sockaddr->type = SOCK_STREAM;
272
0
    }
273
274
0
    return NXT_OK;
275
0
}
276
277
278
static nxt_int_t
279
nxt_runtime_event_engines(nxt_task_t *task, nxt_runtime_t *rt)
280
0
{
281
0
    nxt_thread_t                 *thread;
282
0
    nxt_event_engine_t           *engine;
283
0
    const nxt_event_interface_t  *interface;
284
285
0
    interface = nxt_service_get(rt->services, "engine", NULL);
286
287
0
    if (nxt_slow_path(interface == NULL)) {
288
        /* TODO: log */
289
0
        return NXT_ERROR;
290
0
    }
291
292
0
    engine = nxt_event_engine_create(task, interface,
293
0
                                     nxt_main_process_signals, 0, 0);
294
295
0
    if (nxt_slow_path(engine == NULL)) {
296
0
        return NXT_ERROR;
297
0
    }
298
299
0
    thread = task->thread;
300
0
    thread->engine = engine;
301
#if 0
302
    thread->fiber = &engine->fibers->fiber;
303
#endif
304
305
0
    engine->id = rt->last_engine_id++;
306
0
    engine->mem_pool = nxt_mp_create(1024, 128, 256, 32);
307
308
0
    nxt_queue_init(&rt->engines);
309
0
    nxt_queue_insert_tail(&rt->engines, &engine->link);
310
311
0
    return NXT_OK;
312
0
}
313
314
315
static nxt_int_t
316
nxt_runtime_thread_pools(nxt_thread_t *thr, nxt_runtime_t *rt)
317
0
{
318
0
    nxt_int_t    ret;
319
0
    nxt_array_t  *thread_pools;
320
321
0
    thread_pools = nxt_array_create(rt->mem_pool, 1,
322
0
                                    sizeof(nxt_thread_pool_t *));
323
324
0
    if (nxt_slow_path(thread_pools == NULL)) {
325
0
        return NXT_ERROR;
326
0
    }
327
328
0
    rt->thread_pools = thread_pools;
329
0
    ret = nxt_runtime_thread_pool_create(thr, rt, 2, 60000 * 1000000LL);
330
331
0
    if (nxt_slow_path(ret != NXT_OK)) {
332
0
        return NXT_ERROR;
333
0
    }
334
335
0
    return NXT_OK;
336
0
}
337
338
339
static void
340
nxt_runtime_start(nxt_task_t *task, void *obj, void *data)
341
0
{
342
0
    nxt_runtime_t  *rt;
343
344
0
    rt = obj;
345
346
0
    nxt_debug(task, "rt conf done");
347
348
0
    task->thread->log->ctx_handler = NULL;
349
0
    task->thread->log->ctx = NULL;
350
351
0
    if (nxt_runtime_log_files_create(task, rt) != NXT_OK) {
352
0
        goto fail;
353
0
    }
354
355
0
    if (nxt_runtime_event_engine_change(task, rt) != NXT_OK) {
356
0
        goto fail;
357
0
    }
358
359
    /*
360
     * Thread pools should be destroyed before starting worker
361
     * processes, because thread pool semaphores will stick in
362
     * locked state in new processes after fork().
363
     */
364
0
    nxt_runtime_thread_pool_destroy(task, rt, rt->start);
365
366
0
    return;
367
368
0
fail:
369
370
0
    nxt_runtime_quit(task, 1);
371
0
}
372
373
374
static void
375
nxt_runtime_initial_start(nxt_task_t *task, nxt_uint_t status)
376
0
{
377
0
    nxt_int_t                    ret;
378
0
    nxt_thread_t                 *thr;
379
0
    nxt_runtime_t                *rt;
380
0
    const nxt_event_interface_t  *interface;
381
382
0
    thr = task->thread;
383
0
    rt = thr->runtime;
384
385
0
    if (rt->inherited_sockets == NULL && rt->daemon) {
386
387
0
        if (nxt_process_daemon(task) != NXT_OK) {
388
0
            goto fail;
389
0
        }
390
391
        /*
392
         * An event engine should be updated after fork()
393
         * even if an event facility was not changed because:
394
         * 1) inherited kqueue descriptor is invalid,
395
         * 2) the signal thread is not inherited.
396
         */
397
0
        interface = nxt_service_get(rt->services, "engine", rt->engine);
398
0
        if (interface == NULL) {
399
0
            goto fail;
400
0
        }
401
402
0
        ret = nxt_event_engine_change(task->thread->engine, interface,
403
0
                                      rt->batch);
404
0
        if (ret != NXT_OK) {
405
0
            goto fail;
406
0
        }
407
0
    }
408
409
0
    ret = nxt_runtime_pid_file_create(task, rt->pid_file);
410
0
    if (ret != NXT_OK) {
411
0
        goto fail;
412
0
    }
413
414
0
    if (nxt_runtime_event_engine_change(task, rt) != NXT_OK) {
415
0
        goto fail;
416
0
    }
417
418
0
    thr->engine->max_connections = rt->engine_connections;
419
420
0
    if (nxt_main_process_start(thr, task, rt) != NXT_ERROR) {
421
0
        return;
422
0
    }
423
424
0
fail:
425
426
0
    nxt_runtime_quit(task, 1);
427
0
}
428
429
430
void
431
nxt_runtime_quit(nxt_task_t *task, nxt_uint_t status)
432
0
{
433
0
    nxt_bool_t          done;
434
0
    nxt_runtime_t       *rt;
435
0
    nxt_event_engine_t  *engine;
436
437
0
    rt = task->thread->runtime;
438
0
    rt->status |= status;
439
0
    engine = task->thread->engine;
440
441
0
    nxt_debug(task, "exiting");
442
443
0
    done = 1;
444
445
0
    if (!engine->shutdown) {
446
0
        engine->shutdown = 1;
447
448
0
        if (!nxt_array_is_empty(rt->thread_pools)) {
449
0
            nxt_runtime_thread_pool_destroy(task, rt, nxt_runtime_quit);
450
0
            done = 0;
451
0
        }
452
453
0
        if (rt->type == NXT_PROCESS_MAIN) {
454
0
            nxt_runtime_stop_all_processes(task, rt);
455
0
            done = 0;
456
0
        }
457
0
    }
458
459
0
    nxt_runtime_close_idle_connections(engine);
460
461
0
    if (done) {
462
0
        nxt_work_queue_add(&engine->fast_work_queue, nxt_runtime_exit,
463
0
                           task, rt, engine);
464
0
    }
465
0
}
466
467
468
static void
469
nxt_runtime_close_idle_connections(nxt_event_engine_t *engine)
470
0
{
471
0
    nxt_conn_t        *c;
472
0
    nxt_queue_t       *idle;
473
0
    nxt_queue_link_t  *link, *next;
474
475
0
    nxt_debug(&engine->task, "close idle connections");
476
477
0
    idle = &engine->idle_connections;
478
479
0
    for (link = nxt_queue_first(idle);
480
0
         link != nxt_queue_tail(idle);
481
0
         link = next)
482
0
    {
483
0
        next = nxt_queue_next(link);
484
0
        c = nxt_queue_link_data(link, nxt_conn_t, link);
485
486
0
        if (!c->socket.read_ready) {
487
0
            nxt_queue_remove(link);
488
0
            nxt_conn_close(engine, c);
489
0
        }
490
0
    }
491
0
}
492
493
494
void
495
nxt_runtime_stop_app_processes(nxt_task_t *task, nxt_runtime_t *rt)
496
0
{
497
0
    nxt_port_t          *port;
498
0
    nxt_process_t       *process;
499
0
    nxt_process_init_t  *init;
500
501
0
    nxt_runtime_process_each(rt, process) {
502
503
0
        init = nxt_process_init(process);
504
505
0
        if (init->type == NXT_PROCESS_APP
506
0
            || init->type == NXT_PROCESS_PROTOTYPE)
507
0
        {
508
509
0
            nxt_process_port_each(process, port) {
510
511
0
                (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1,
512
0
                                             0, 0, NULL);
513
514
0
            } nxt_process_port_loop;
515
0
        }
516
517
0
    } nxt_runtime_process_loop;
518
0
}
519
520
521
static void
522
nxt_runtime_stop_all_processes(nxt_task_t *task, nxt_runtime_t *rt)
523
0
{
524
0
    nxt_port_t     *port;
525
0
    nxt_process_t  *process;
526
527
0
    nxt_runtime_process_each(rt, process) {
528
529
0
        nxt_process_port_each(process, port) {
530
531
0
            nxt_debug(task, "%d sending quit to %PI", rt->type, port->pid);
532
533
0
            (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0,
534
0
                                         0, NULL);
535
536
0
        } nxt_process_port_loop;
537
538
0
    } nxt_runtime_process_loop;
539
0
}
540
541
542
static void
543
nxt_runtime_exit(nxt_task_t *task, void *obj, void *data)
544
0
{
545
0
    int                 status, engine_count;
546
0
    nxt_runtime_t       *rt;
547
0
    nxt_process_t       *process;
548
0
    nxt_event_engine_t  *engine;
549
550
0
    rt = obj;
551
0
    engine = data;
552
553
0
    nxt_debug(task, "thread pools: %d", rt->thread_pools->nelts);
554
555
0
    if (!nxt_array_is_empty(rt->thread_pools)) {
556
0
        return;
557
0
    }
558
559
0
    if (rt->type == NXT_PROCESS_MAIN) {
560
0
        if (rt->pid_file != NULL) {
561
0
            nxt_file_delete(rt->pid_file);
562
0
        }
563
564
0
#if (NXT_HAVE_UNIX_DOMAIN)
565
0
        {
566
0
            size_t           i;
567
0
            nxt_sockaddr_t   *sa;
568
0
            nxt_file_name_t  *name;
569
570
0
            sa = rt->controller_listen;
571
572
0
            if (sa->u.sockaddr.sa_family == AF_UNIX) {
573
0
                name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path;
574
0
                (void) nxt_file_delete(name);
575
0
            }
576
577
0
            for (i = 0; i < rt->listen_sockets->nelts; i++) {
578
0
                nxt_listen_socket_t  *ls;
579
580
0
                ls = (nxt_listen_socket_t *) rt->listen_sockets->elts + i;
581
0
                sa = ls->sockaddr;
582
583
0
                if (sa->u.sockaddr.sa_family != AF_UNIX
584
0
                    || sa->u.sockaddr_un.sun_path[0] == '\0')
585
0
                {
586
0
                    continue;
587
0
                }
588
589
0
                name = (nxt_file_name_t *) sa->u.sockaddr_un.sun_path;
590
0
                (void) nxt_file_delete(name);
591
0
            }
592
0
        }
593
0
#endif
594
0
    }
595
596
0
    if (!engine->event.signal_support) {
597
0
        nxt_event_engine_signals_stop(engine);
598
0
    }
599
600
0
    nxt_runtime_process_each(rt, process) {
601
602
0
        nxt_runtime_process_remove(rt, process);
603
0
        nxt_process_close_ports(task, process);
604
605
0
    } nxt_runtime_process_loop;
606
607
0
    status = rt->status;
608
609
0
    engine_count = 0;
610
611
0
    nxt_queue_each(engine, &rt->engines, nxt_event_engine_t, link) {
612
613
0
        engine_count++;
614
615
0
    } nxt_queue_loop;
616
617
0
    if (engine_count <= 1) {
618
0
        if (rt->port_by_type[rt->type] != NULL) {
619
0
            nxt_port_use(task, rt->port_by_type[rt->type], -1);
620
0
        }
621
622
0
        nxt_thread_mutex_destroy(&rt->processes_mutex);
623
624
0
        nxt_mp_destroy(rt->mem_pool);
625
0
    }
626
627
0
    nxt_debug(task, "exit: %d", status);
628
629
0
    exit(status);
630
0
    nxt_unreachable();
631
0
}
632
633
634
static nxt_int_t
635
nxt_runtime_event_engine_change(nxt_task_t *task, nxt_runtime_t *rt)
636
0
{
637
0
    nxt_event_engine_t           *engine;
638
0
    const nxt_event_interface_t  *interface;
639
640
0
    engine = task->thread->engine;
641
642
0
    if (engine->batch == rt->batch
643
0
        && nxt_strcmp(engine->event.name, rt->engine) == 0)
644
0
    {
645
0
        return NXT_OK;
646
0
    }
647
648
0
    interface = nxt_service_get(rt->services, "engine", rt->engine);
649
650
0
    if (interface != NULL) {
651
0
        return nxt_event_engine_change(engine, interface, rt->batch);
652
0
    }
653
654
0
    return NXT_ERROR;
655
0
}
656
657
658
void
659
nxt_runtime_event_engine_free(nxt_runtime_t *rt)
660
0
{
661
0
    nxt_queue_link_t    *link;
662
0
    nxt_event_engine_t  *engine;
663
664
0
    link = nxt_queue_first(&rt->engines);
665
0
    nxt_queue_remove(link);
666
667
0
    engine = nxt_queue_link_data(link, nxt_event_engine_t, link);
668
0
    nxt_event_engine_free(engine);
669
0
}
670
671
672
nxt_int_t
673
nxt_runtime_thread_pool_create(nxt_thread_t *thr, nxt_runtime_t *rt,
674
    nxt_uint_t max_threads, nxt_nsec_t timeout)
675
0
{
676
0
    nxt_thread_pool_t   *thread_pool, **tp;
677
678
0
    tp = nxt_array_add(rt->thread_pools);
679
0
    if (tp == NULL) {
680
0
        return NXT_ERROR;
681
0
    }
682
683
0
    thread_pool = nxt_thread_pool_create(max_threads, timeout,
684
0
                                         nxt_runtime_thread_pool_init,
685
0
                                         thr->engine,
686
0
                                         nxt_runtime_thread_pool_exit);
687
688
0
    if (nxt_fast_path(thread_pool != NULL)) {
689
0
        *tp = thread_pool;
690
0
    }
691
692
0
    return NXT_OK;
693
0
}
694
695
696
static void
697
nxt_runtime_thread_pool_destroy(nxt_task_t *task, nxt_runtime_t *rt,
698
    nxt_runtime_cont_t cont)
699
0
{
700
0
    nxt_uint_t         n;
701
0
    nxt_thread_pool_t  **tp;
702
703
0
    rt->continuation = cont;
704
705
0
    n = rt->thread_pools->nelts;
706
707
0
    if (n == 0) {
708
0
        cont(task, 0);
709
0
        return;
710
0
    }
711
712
0
    tp = rt->thread_pools->elts;
713
714
0
    do {
715
0
        nxt_thread_pool_destroy(*tp);
716
717
0
        tp++;
718
0
        n--;
719
0
    } while (n != 0);
720
0
}
721
722
723
static void
724
nxt_runtime_thread_pool_init(void)
725
0
{
726
0
}
727
728
729
static void
730
nxt_runtime_thread_pool_exit(nxt_task_t *task, void *obj, void *data)
731
0
{
732
0
    nxt_uint_t           i, n;
733
0
    nxt_runtime_t        *rt;
734
0
    nxt_thread_pool_t    *tp, **thread_pools;
735
0
    nxt_thread_handle_t  handle;
736
737
0
    tp = obj;
738
739
0
    if (data != NULL) {
740
0
        handle = (nxt_thread_handle_t) (uintptr_t) data;
741
0
        nxt_thread_wait(handle);
742
0
    }
743
744
0
    rt = task->thread->runtime;
745
746
0
    thread_pools = rt->thread_pools->elts;
747
0
    n = rt->thread_pools->nelts;
748
749
0
    nxt_debug(task, "thread pools: %ui", n);
750
751
0
    for (i = 0; i < n; i++) {
752
753
0
        if (tp == thread_pools[i]) {
754
0
            nxt_array_remove(rt->thread_pools, &thread_pools[i]);
755
756
0
            nxt_free(tp);
757
758
0
            if (n == 1) {
759
                /* The last thread pool. */
760
0
                rt->continuation(task, 0);
761
0
            }
762
763
0
            return;
764
0
        }
765
0
    }
766
0
}
767
768
769
static nxt_int_t
770
nxt_runtime_conf_init(nxt_task_t *task, nxt_runtime_t *rt)
771
0
{
772
0
    nxt_int_t                    ret;
773
0
    nxt_str_t                    control;
774
0
    nxt_uint_t                   n;
775
0
    nxt_file_t                   *file;
776
0
    const char                   *slash;
777
0
    nxt_sockaddr_t               *sa;
778
0
    nxt_file_name_str_t          file_name;
779
0
    const nxt_event_interface_t  *interface;
780
781
0
    rt->daemon = 1;
782
0
    rt->engine_connections = 256;
783
0
    rt->auxiliary_threads = 2;
784
0
    rt->user_cred.user = NXT_USER;
785
0
    rt->group = NXT_GROUP;
786
0
    rt->pid = NXT_PID;
787
0
    rt->log = NXT_LOG;
788
0
    rt->modules = NXT_MODULESDIR;
789
0
    rt->state = NXT_STATEDIR;
790
0
    rt->control = NXT_CONTROL_SOCK;
791
0
    rt->tmp = NXT_TMPDIR;
792
793
0
    nxt_memzero(&rt->capabilities, sizeof(nxt_capabilities_t));
794
795
0
    if (nxt_runtime_conf_read_cmd(task, rt) != NXT_OK) {
796
0
        return NXT_ERROR;
797
0
    }
798
799
0
    if (nxt_capability_set(task, &rt->capabilities) != NXT_OK) {
800
0
        return NXT_ERROR;
801
0
    }
802
803
0
    if (rt->capabilities.setid) {
804
0
        ret = nxt_credential_get(task, rt->mem_pool, &rt->user_cred,
805
0
                                rt->group);
806
807
0
        if (nxt_slow_path(ret != NXT_OK)) {
808
0
            return NXT_ERROR;
809
0
        }
810
811
0
    } else {
812
0
        nxt_log(task, NXT_LOG_WARN, "Unit is running unprivileged, then it "
813
0
                "cannot use arbitrary user and group.");
814
0
    }
815
816
    /* An engine's parameters. */
817
818
0
    interface = nxt_service_get(rt->services, "engine", rt->engine);
819
0
    if (interface == NULL) {
820
0
        return NXT_ERROR;
821
0
    }
822
823
0
    rt->engine = interface->name;
824
825
0
    ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%Z", rt->pid);
826
0
    if (nxt_slow_path(ret != NXT_OK)) {
827
0
        return NXT_ERROR;
828
0
    }
829
830
0
    rt->pid_file = file_name.start;
831
832
0
    ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%Z", rt->log);
833
0
    if (nxt_slow_path(ret != NXT_OK)) {
834
0
        return NXT_ERROR;
835
0
    }
836
837
0
    file = nxt_list_first(rt->log_files);
838
0
    file->name = file_name.start;
839
840
0
    slash = "";
841
0
    n = nxt_strlen(rt->modules);
842
843
0
    if (n > 1 && rt->modules[n - 1] != '/') {
844
0
        slash = "/";
845
0
    }
846
847
0
    ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%s*.unit.so%Z",
848
0
                               rt->modules, slash);
849
0
    if (nxt_slow_path(ret != NXT_OK)) {
850
0
        return NXT_ERROR;
851
0
    }
852
853
0
    rt->modules = (char *) file_name.start;
854
855
0
    slash = "";
856
0
    n = nxt_strlen(rt->state);
857
858
0
    if (n > 1 && rt->state[n - 1] != '/') {
859
0
        slash = "/";
860
0
    }
861
862
0
    ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%sversion%Z",
863
0
                               rt->state, slash);
864
0
    if (nxt_slow_path(ret != NXT_OK)) {
865
0
        return NXT_ERROR;
866
0
    }
867
868
0
    rt->ver = (char *) file_name.start;
869
870
0
    ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s.tmp%Z", rt->ver);
871
0
    if (nxt_slow_path(ret != NXT_OK)) {
872
0
        return NXT_ERROR;
873
0
    }
874
875
0
    rt->ver_tmp = (char *) file_name.start;
876
877
0
    ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%sconf.json%Z",
878
0
                               rt->state, slash);
879
0
    if (nxt_slow_path(ret != NXT_OK)) {
880
0
        return NXT_ERROR;
881
0
    }
882
883
0
    rt->conf = (char *) file_name.start;
884
885
0
    ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s.tmp%Z", rt->conf);
886
0
    if (nxt_slow_path(ret != NXT_OK)) {
887
0
        return NXT_ERROR;
888
0
    }
889
890
0
    rt->conf_tmp = (char *) file_name.start;
891
892
0
    ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%scerts/%Z",
893
0
                               rt->state, slash);
894
0
    if (nxt_slow_path(ret != NXT_OK)) {
895
0
        return NXT_ERROR;
896
0
    }
897
898
0
    ret = mkdir((char *) file_name.start, S_IRWXU);
899
900
0
    if (nxt_fast_path(ret == 0 || nxt_errno == EEXIST)) {
901
0
        rt->certs.length = file_name.len;
902
0
        rt->certs.start = file_name.start;
903
904
0
    } else {
905
0
        nxt_alert(task, "Unable to create certificates storage directory: "
906
0
                  "mkdir(%s) failed %E", file_name.start, nxt_errno);
907
0
    }
908
909
0
    ret = nxt_file_name_create(rt->mem_pool, &file_name, "%s%sscripts/%Z",
910
0
                               rt->state, slash);
911
0
    if (nxt_slow_path(ret != NXT_OK)) {
912
0
        return NXT_ERROR;
913
0
    }
914
915
0
    ret = mkdir((char *) file_name.start, S_IRWXU);
916
917
0
    if (nxt_fast_path(ret == 0 || nxt_errno == EEXIST)) {
918
0
        rt->scripts.length = file_name.len;
919
0
        rt->scripts.start = file_name.start;
920
921
0
    } else {
922
0
        nxt_alert(task, "Unable to create scripts storage directory: "
923
0
                  "mkdir(%s) failed %E", file_name.start, nxt_errno);
924
0
    }
925
926
0
    control.length = nxt_strlen(rt->control);
927
0
    control.start = (u_char *) rt->control;
928
929
0
    sa = nxt_sockaddr_parse(rt->mem_pool, &control);
930
0
    if (nxt_slow_path(sa == NULL)) {
931
0
        return NXT_ERROR;
932
0
    }
933
934
0
    sa->type = SOCK_STREAM;
935
936
0
    rt->controller_listen = sa;
937
938
0
    if (nxt_runtime_controller_socket(task, rt) != NXT_OK) {
939
0
        return NXT_ERROR;
940
0
    }
941
942
0
    return NXT_OK;
943
0
}
944
945
946
static nxt_int_t
947
nxt_runtime_conf_read_cmd(nxt_task_t *task, nxt_runtime_t *rt)
948
0
{
949
0
    char    *p, **argv;
950
0
    u_char  *end;
951
0
    u_char  buf[1024];
952
953
0
    static const char  version[] =
954
0
        "unit version: " NXT_VERSION "\n"
955
0
        "configured as ./configure" NXT_CONFIGURE_OPTIONS "\n";
956
957
0
    static const char  no_control[] =
958
0
                       "option \"--control\" requires socket address\n";
959
0
    static const char  no_control_mode[] =
960
0
                        "option \"--control-mode\" requires a mode\n";
961
0
    static const char  no_control_user[] =
962
0
                        "option \"--control-user\" requires a username\n";
963
0
    static const char  no_control_group[] =
964
0
                        "option \"--control-group\" requires a group name\n";
965
0
    static const char  no_user[] = "option \"--user\" requires username\n";
966
0
    static const char  no_group[] = "option \"--group\" requires group name\n";
967
0
    static const char  no_pid[] = "option \"--pid\" requires filename\n";
968
0
    static const char  no_log[] = "option \"--log\" requires filename\n";
969
0
    static const char  no_modules[] =
970
0
                       "option \"--modulesdir\" requires directory\n";
971
0
    static const char  no_state[] =
972
0
                       "option \"--statedir\" requires directory\n";
973
0
    static const char  no_tmp[] = "option \"--tmpdir\" requires directory\n";
974
975
0
    static const char  modules_deprecated[] =
976
0
           "option \"--modules\" is deprecated; use \"--modulesdir\" instead\n";
977
0
    static const char  state_deprecated[] =
978
0
           "option \"--state\" is deprecated; use \"--statedir\" instead\n";
979
0
    static const char  tmp_deprecated[] =
980
0
           "option \"--tmp\" is deprecated; use \"--tmpdir\" instead\n";
981
982
0
    static const char  help[] =
983
0
        "\n"
984
0
        "unit options:\n"
985
0
        "\n"
986
0
        "  --version            print unit version and configure options\n"
987
0
        "\n"
988
0
        "  --no-daemon          run unit in non-daemon mode\n"
989
0
        "\n"
990
0
        "  --control ADDRESS    set address of control API socket\n"
991
0
        "                       default: \"" NXT_CONTROL_SOCK "\"\n"
992
0
        "\n"
993
0
        "  --control-mode MODE  set mode of the control API socket\n"
994
0
        "                       default: 0600\n"
995
0
        "\n"
996
0
        "  --control-user USER    set the owner of the control API socket\n"
997
0
        "\n"
998
0
        "  --control-group GROUP  set the group of the control API socket\n"
999
0
        "\n"
1000
0
        "  --pid FILE           set pid filename\n"
1001
0
        "                       default: \"" NXT_PID "\"\n"
1002
0
        "\n"
1003
0
        "  --log FILE           set log filename\n"
1004
0
        "                       default: \"" NXT_LOG "\"\n"
1005
0
        "\n"
1006
0
        "  --modulesdir DIR     set modules directory name\n"
1007
0
        "                       default: \"" NXT_MODULESDIR "\"\n"
1008
0
        "\n"
1009
0
        "  --statedir DIR       set state directory name\n"
1010
0
        "                       default: \"" NXT_STATEDIR "\"\n"
1011
0
        "\n"
1012
0
        "  --tmpdir DIR         set tmp directory name\n"
1013
0
        "                       default: \"" NXT_TMPDIR "\"\n"
1014
0
        "\n"
1015
0
        "  --modules DIR        [deprecated] synonym for --modulesdir\n"
1016
0
        "  --state DIR          [deprecated] synonym for --statedir\n"
1017
0
        "  --tmp DIR            [deprecated] synonym for --tmpdir\n"
1018
0
        "\n"
1019
0
        "  --user USER          set non-privileged processes to run"
1020
0
                                " as specified user\n"
1021
0
        "                       default: \"" NXT_USER "\"\n"
1022
0
        "\n"
1023
0
        "  --group GROUP        set non-privileged processes to run"
1024
0
                                " as specified group\n"
1025
0
        "                       default: ";
1026
1027
0
    static const char  group[] = "\"" NXT_GROUP "\"\n\n";
1028
0
    static const char  primary[] = "user's primary group\n\n";
1029
1030
0
    argv = &nxt_process_argv[1];
1031
1032
0
    while (*argv != NULL) {
1033
0
        p = *argv++;
1034
1035
0
        if (nxt_strcmp(p, "--control") == 0) {
1036
0
            if (*argv == NULL) {
1037
0
                write(STDERR_FILENO, no_control, nxt_length(no_control));
1038
0
                return NXT_ERROR;
1039
0
            }
1040
1041
0
            p = *argv++;
1042
1043
0
            rt->control = p;
1044
1045
0
            continue;
1046
0
        }
1047
1048
0
        if (nxt_strcmp(p, "--control-mode") == 0) {
1049
0
            if (*argv == NULL) {
1050
0
                write(STDERR_FILENO, no_control_mode,
1051
0
                      nxt_length(no_control_mode));
1052
0
                return NXT_ERROR;
1053
0
            }
1054
1055
0
            p = *argv++;
1056
1057
0
            rt->control_mode = strtoul(p, NULL, 8);
1058
1059
0
            continue;
1060
0
        }
1061
1062
0
        if (nxt_strcmp(p, "--control-user") == 0) {
1063
0
            if (*argv == NULL) {
1064
0
                write(STDERR_FILENO, no_control_user,
1065
0
                      nxt_length(no_control_user));
1066
0
                return NXT_ERROR;
1067
0
            }
1068
1069
0
            p = *argv++;
1070
1071
0
            rt->control_user = p;
1072
1073
0
            continue;
1074
0
        }
1075
1076
0
        if (nxt_strcmp(p, "--control-group") == 0) {
1077
0
            if (*argv == NULL) {
1078
0
                write(STDERR_FILENO, no_control_group,
1079
0
                      nxt_length(no_control_group));
1080
0
                return NXT_ERROR;
1081
0
            }
1082
1083
0
            p = *argv++;
1084
1085
0
            rt->control_group = p;
1086
1087
0
            continue;
1088
0
        }
1089
1090
0
        if (nxt_strcmp(p, "--user") == 0) {
1091
0
            if (*argv == NULL) {
1092
0
                write(STDERR_FILENO, no_user, nxt_length(no_user));
1093
0
                return NXT_ERROR;
1094
0
            }
1095
1096
0
            p = *argv++;
1097
1098
0
            rt->user_cred.user = p;
1099
1100
0
            continue;
1101
0
        }
1102
1103
0
        if (nxt_strcmp(p, "--group") == 0) {
1104
0
            if (*argv == NULL) {
1105
0
                write(STDERR_FILENO, no_group, nxt_length(no_group));
1106
0
                return NXT_ERROR;
1107
0
            }
1108
1109
0
            p = *argv++;
1110
1111
0
            rt->group = p;
1112
1113
0
            continue;
1114
0
        }
1115
1116
0
        if (nxt_strcmp(p, "--pid") == 0) {
1117
0
            if (*argv == NULL) {
1118
0
                write(STDERR_FILENO, no_pid, nxt_length(no_pid));
1119
0
                return NXT_ERROR;
1120
0
            }
1121
1122
0
            p = *argv++;
1123
1124
0
            rt->pid = p;
1125
1126
0
            continue;
1127
0
        }
1128
1129
0
        if (nxt_strcmp(p, "--log") == 0) {
1130
0
            if (*argv == NULL) {
1131
0
                write(STDERR_FILENO, no_log, nxt_length(no_log));
1132
0
                return NXT_ERROR;
1133
0
            }
1134
1135
0
            p = *argv++;
1136
1137
0
            rt->log = p;
1138
1139
0
            continue;
1140
0
        }
1141
1142
0
        if (nxt_strcmp(p, "--modules") == 0) {
1143
0
            write(STDERR_FILENO, modules_deprecated,
1144
0
                  nxt_length(modules_deprecated));
1145
0
            goto modulesdir;
1146
0
        }
1147
1148
0
        if (nxt_strcmp(p, "--modulesdir") == 0) {
1149
0
modulesdir:
1150
0
            if (*argv == NULL) {
1151
0
                write(STDERR_FILENO, no_modules, nxt_length(no_modules));
1152
0
                return NXT_ERROR;
1153
0
            }
1154
1155
0
            p = *argv++;
1156
1157
0
            rt->modules = p;
1158
1159
0
            continue;
1160
0
        }
1161
1162
0
        if (nxt_strcmp(p, "--state") == 0) {
1163
0
            write(STDERR_FILENO, state_deprecated,
1164
0
                  nxt_length(state_deprecated));
1165
0
            goto statedir;
1166
0
        }
1167
1168
0
        if (nxt_strcmp(p, "--statedir") == 0) {
1169
0
statedir:
1170
0
            if (*argv == NULL) {
1171
0
                write(STDERR_FILENO, no_state, nxt_length(no_state));
1172
0
                return NXT_ERROR;
1173
0
            }
1174
1175
0
            p = *argv++;
1176
1177
0
            rt->state = p;
1178
1179
0
            continue;
1180
0
        }
1181
1182
0
        if (nxt_strcmp(p, "--tmp") == 0) {
1183
0
            write(STDERR_FILENO, tmp_deprecated, nxt_length(tmp_deprecated));
1184
0
            goto tmpdir;
1185
0
        }
1186
1187
0
        if (nxt_strcmp(p, "--tmpdir") == 0) {
1188
0
tmpdir:
1189
0
            if (*argv == NULL) {
1190
0
                write(STDERR_FILENO, no_tmp, nxt_length(no_tmp));
1191
0
                return NXT_ERROR;
1192
0
            }
1193
1194
0
            p = *argv++;
1195
1196
0
            rt->tmp = p;
1197
1198
0
            continue;
1199
0
        }
1200
1201
0
        if (nxt_strcmp(p, "--no-daemon") == 0) {
1202
0
            rt->daemon = 0;
1203
0
            continue;
1204
0
        }
1205
1206
0
        if (nxt_strcmp(p, "--version") == 0) {
1207
0
            write(STDERR_FILENO, version, nxt_length(version));
1208
0
            exit(0);
1209
0
        }
1210
1211
0
        if (nxt_strcmp(p, "--help") == 0 || nxt_strcmp(p, "-h") == 0) {
1212
0
            write(STDOUT_FILENO, help, nxt_length(help));
1213
1214
0
            if (sizeof(NXT_GROUP) == 1) {
1215
0
                write(STDOUT_FILENO, primary, nxt_length(primary));
1216
1217
0
            } else {
1218
0
                write(STDOUT_FILENO, group, nxt_length(group));
1219
0
            }
1220
1221
0
            exit(0);
1222
0
        }
1223
1224
0
        end = nxt_sprintf(buf, buf + sizeof(buf), "unknown option \"%s\", "
1225
0
                          "try \"%s -h\" for available options\n",
1226
0
                          p, nxt_process_argv[0]);
1227
1228
0
        write(STDERR_FILENO, buf, end - buf);
1229
1230
0
        return NXT_ERROR;
1231
0
    }
1232
1233
0
    return NXT_OK;
1234
0
}
1235
1236
1237
nxt_listen_socket_t *
1238
nxt_runtime_listen_socket_add(nxt_runtime_t *rt, nxt_sockaddr_t *sa)
1239
0
{
1240
0
    nxt_mp_t             *mp;
1241
0
    nxt_listen_socket_t  *ls;
1242
1243
0
    ls = nxt_array_zero_add(rt->listen_sockets);
1244
0
    if (ls == NULL) {
1245
0
        return NULL;
1246
0
    }
1247
1248
0
    mp = rt->mem_pool;
1249
1250
0
    ls->sockaddr = nxt_sockaddr_create(mp, &sa->u.sockaddr, sa->socklen,
1251
0
                                       sa->length);
1252
0
    if (ls->sockaddr == NULL) {
1253
0
        return NULL;
1254
0
    }
1255
1256
0
    ls->sockaddr->type = sa->type;
1257
1258
0
    nxt_sockaddr_text(ls->sockaddr);
1259
1260
0
    ls->socket = -1;
1261
0
    ls->backlog = NXT_LISTEN_BACKLOG;
1262
1263
0
    return ls;
1264
0
}
1265
1266
1267
static nxt_int_t
1268
nxt_runtime_hostname(nxt_task_t *task, nxt_runtime_t *rt)
1269
0
{
1270
0
    size_t  length;
1271
0
    char    hostname[NXT_MAXHOSTNAMELEN + 1];
1272
1273
0
    if (gethostname(hostname, NXT_MAXHOSTNAMELEN) != 0) {
1274
0
        nxt_alert(task, "gethostname() failed %E", nxt_errno);
1275
0
        return NXT_ERROR;
1276
0
    }
1277
1278
    /*
1279
     * Linux gethostname(2):
1280
     *
1281
     *    If the null-terminated hostname is too large to fit,
1282
     *    then the name is truncated, and no error is returned.
1283
     *
1284
     * For this reason an additional byte is reserved in the buffer.
1285
     */
1286
0
    hostname[NXT_MAXHOSTNAMELEN] = '\0';
1287
1288
0
    length = nxt_strlen(hostname);
1289
0
    rt->hostname.length = length;
1290
1291
0
    rt->hostname.start = nxt_mp_nget(rt->mem_pool, length);
1292
1293
0
    if (rt->hostname.start != NULL) {
1294
0
        nxt_memcpy_lowcase(rt->hostname.start, (u_char *) hostname, length);
1295
0
        return NXT_OK;
1296
0
    }
1297
1298
0
    return NXT_ERROR;
1299
0
}
1300
1301
1302
static nxt_int_t
1303
nxt_runtime_log_files_init(nxt_runtime_t *rt)
1304
0
{
1305
0
    nxt_file_t  *file;
1306
0
    nxt_list_t  *log_files;
1307
1308
0
    log_files = nxt_list_create(rt->mem_pool, 1, sizeof(nxt_file_t));
1309
1310
0
    if (nxt_fast_path(log_files != NULL)) {
1311
0
        rt->log_files = log_files;
1312
1313
        /* Preallocate the main log.  This allocation cannot fail. */
1314
0
        file = nxt_list_zero_add(log_files);
1315
1316
0
        file->fd = NXT_FILE_INVALID;
1317
0
        file->log_level = NXT_LOG_ALERT;
1318
1319
0
        return NXT_OK;
1320
0
    }
1321
1322
0
    return NXT_ERROR;
1323
0
}
1324
1325
1326
nxt_file_t *
1327
nxt_runtime_log_file_add(nxt_runtime_t *rt, nxt_str_t *name)
1328
0
{
1329
0
    nxt_int_t            ret;
1330
0
    nxt_file_t           *file;
1331
0
    nxt_file_name_str_t  file_name;
1332
1333
0
    ret = nxt_file_name_create(rt->mem_pool, &file_name, "V%Z", name);
1334
1335
0
    if (nxt_slow_path(ret != NXT_OK)) {
1336
0
        return NULL;
1337
0
    }
1338
1339
0
    nxt_list_each(file, rt->log_files) {
1340
1341
        /* STUB: hardecoded case sensitive/insensitive. */
1342
1343
0
        if (file->name != NULL
1344
0
            && nxt_file_name_eq(file->name, file_name.start))
1345
0
        {
1346
0
            return file;
1347
0
        }
1348
1349
0
    } nxt_list_loop;
1350
1351
0
    file = nxt_list_zero_add(rt->log_files);
1352
1353
0
    if (nxt_slow_path(file == NULL)) {
1354
0
        return NULL;
1355
0
    }
1356
1357
0
    file->fd = NXT_FILE_INVALID;
1358
0
    file->log_level = NXT_LOG_ALERT;
1359
0
    file->name = file_name.start;
1360
1361
0
    return file;
1362
0
}
1363
1364
1365
static nxt_int_t
1366
nxt_runtime_log_files_create(nxt_task_t *task, nxt_runtime_t *rt)
1367
0
{
1368
0
    nxt_int_t   ret;
1369
0
    nxt_file_t  *file;
1370
1371
0
    nxt_list_each(file, rt->log_files) {
1372
1373
0
        ret = nxt_file_open(task, file, O_WRONLY | O_APPEND, O_CREAT,
1374
0
                            NXT_FILE_OWNER_ACCESS);
1375
1376
0
        if (ret != NXT_OK) {
1377
0
            return NXT_ERROR;
1378
0
        }
1379
1380
0
    } nxt_list_loop;
1381
1382
0
    file = nxt_list_first(rt->log_files);
1383
1384
0
    return nxt_file_stderr(file);
1385
0
}
1386
1387
1388
nxt_int_t
1389
nxt_runtime_listen_sockets_create(nxt_task_t *task, nxt_runtime_t *rt)
1390
0
{
1391
0
    nxt_int_t            ret;
1392
0
    nxt_uint_t           c, p, ncurr, nprev;
1393
0
    nxt_listen_socket_t  *curr, *prev;
1394
1395
0
    curr = rt->listen_sockets->elts;
1396
0
    ncurr = rt->listen_sockets->nelts;
1397
1398
0
    if (rt->inherited_sockets != NULL) {
1399
0
        prev = rt->inherited_sockets->elts;
1400
0
        nprev = rt->inherited_sockets->nelts;
1401
1402
0
    } else {
1403
0
        prev = NULL;
1404
0
        nprev = 0;
1405
0
    }
1406
1407
0
    for (c = 0; c < ncurr; c++) {
1408
1409
0
        for (p = 0; p < nprev; p++) {
1410
1411
0
            if (nxt_sockaddr_cmp(curr[c].sockaddr, prev[p].sockaddr)) {
1412
1413
0
                ret = nxt_listen_socket_update(task, &curr[c], &prev[p]);
1414
0
                if (ret != NXT_OK) {
1415
0
                    return NXT_ERROR;
1416
0
                }
1417
1418
0
                goto next;
1419
0
            }
1420
0
        }
1421
1422
0
        if (nxt_listen_socket_create(task, rt->mem_pool, &curr[c]) != NXT_OK) {
1423
0
            return NXT_ERROR;
1424
0
        }
1425
1426
0
    next:
1427
1428
0
        continue;
1429
0
    }
1430
1431
0
    return NXT_OK;
1432
0
}
1433
1434
1435
nxt_int_t
1436
nxt_runtime_listen_sockets_enable(nxt_task_t *task, nxt_runtime_t *rt)
1437
0
{
1438
0
    nxt_uint_t           i, n;
1439
0
    nxt_listen_socket_t  *ls;
1440
1441
0
    ls = rt->listen_sockets->elts;
1442
0
    n = rt->listen_sockets->nelts;
1443
1444
0
    for (i = 0; i < n; i++) {
1445
0
        if (ls[i].flags == NXT_NONBLOCK) {
1446
0
            if (nxt_listen_event(task, &ls[i]) == NULL) {
1447
0
                return NXT_ERROR;
1448
0
            }
1449
0
        }
1450
0
    }
1451
1452
0
    return NXT_OK;
1453
0
}
1454
1455
1456
nxt_str_t *
1457
nxt_current_directory(nxt_mp_t *mp)
1458
0
{
1459
0
    size_t     length;
1460
0
    u_char     *p;
1461
0
    nxt_str_t  *name;
1462
0
    char       buf[NXT_MAX_PATH_LEN];
1463
1464
0
    length = nxt_dir_current(buf, NXT_MAX_PATH_LEN);
1465
1466
0
    if (nxt_fast_path(length != 0)) {
1467
0
        name = nxt_str_alloc(mp, length + 1);
1468
1469
0
        if (nxt_fast_path(name != NULL)) {
1470
0
            p = nxt_cpymem(name->start, buf, length);
1471
0
            *p = '/';
1472
1473
0
            return name;
1474
0
        }
1475
0
    }
1476
1477
0
    return NULL;
1478
0
}
1479
1480
1481
static nxt_int_t
1482
nxt_runtime_pid_file_create(nxt_task_t *task, nxt_file_name_t *pid_file)
1483
0
{
1484
0
    ssize_t     length;
1485
0
    nxt_int_t   n;
1486
0
    nxt_file_t  file;
1487
0
    u_char      pid[NXT_INT64_T_LEN + nxt_length("\n")];
1488
1489
0
    nxt_memzero(&file, sizeof(nxt_file_t));
1490
1491
0
    file.name = pid_file;
1492
1493
0
    nxt_fs_mkdir_parent(pid_file, 0755);
1494
1495
0
    n = nxt_file_open(task, &file, O_WRONLY, O_CREAT | O_TRUNC,
1496
0
                      NXT_FILE_DEFAULT_ACCESS);
1497
1498
0
    if (n != NXT_OK) {
1499
0
        return NXT_ERROR;
1500
0
    }
1501
1502
0
    length = nxt_sprintf(pid, pid + sizeof(pid), "%PI%n", nxt_pid) - pid;
1503
1504
0
    if (nxt_file_write(&file, pid, length, 0) != length) {
1505
0
        return NXT_ERROR;
1506
0
    }
1507
1508
0
    nxt_file_close(task, &file);
1509
1510
0
    return NXT_OK;
1511
0
}
1512
1513
1514
void
1515
nxt_runtime_process_release(nxt_runtime_t *rt, nxt_process_t *process)
1516
0
{
1517
0
    nxt_process_t  *child;
1518
1519
0
    if (process->registered == 1) {
1520
0
        nxt_runtime_process_remove(rt, process);
1521
0
    }
1522
1523
0
    if (process->link.next != NULL) {
1524
0
        nxt_queue_remove(&process->link);
1525
0
    }
1526
1527
0
    nxt_queue_each(child, &process->children, nxt_process_t, link) {
1528
0
        nxt_queue_remove(&child->link);
1529
0
        child->link.next = NULL;
1530
0
    } nxt_queue_loop;
1531
1532
0
    nxt_assert(process->use_count == 0);
1533
0
    nxt_assert(process->registered == 0);
1534
0
    nxt_assert(nxt_queue_is_empty(&process->ports));
1535
1536
0
    nxt_port_mmaps_destroy(&process->incoming, 1);
1537
1538
0
    nxt_thread_mutex_destroy(&process->incoming.mutex);
1539
1540
    /* processes from nxt_runtime_process_get() have no memory pool */
1541
0
    if (process->mem_pool != NULL) {
1542
0
        nxt_mp_destroy(process->mem_pool);
1543
0
    }
1544
1545
0
    nxt_mp_free(rt->mem_pool, process);
1546
0
}
1547
1548
1549
static nxt_int_t
1550
nxt_runtime_lvlhsh_pid_test(nxt_lvlhsh_query_t *lhq, void *data)
1551
0
{
1552
0
    nxt_process_t  *process;
1553
1554
0
    process = data;
1555
1556
0
    if (lhq->key.length == sizeof(nxt_pid_t)
1557
0
        && *(nxt_pid_t *) lhq->key.start == process->pid)
1558
0
    {
1559
0
        return NXT_OK;
1560
0
    }
1561
1562
0
    return NXT_DECLINED;
1563
0
}
1564
1565
static const nxt_lvlhsh_proto_t  lvlhsh_processes_proto  nxt_aligned(64) = {
1566
    NXT_LVLHSH_DEFAULT,
1567
    nxt_runtime_lvlhsh_pid_test,
1568
    nxt_lvlhsh_alloc,
1569
    nxt_lvlhsh_free,
1570
};
1571
1572
1573
nxt_inline void
1574
nxt_runtime_process_lhq_pid(nxt_lvlhsh_query_t *lhq, nxt_pid_t *pid)
1575
0
{
1576
0
    lhq->key_hash = nxt_murmur_hash2(pid, sizeof(*pid));
1577
0
    lhq->key.length = sizeof(*pid);
1578
0
    lhq->key.start = (u_char *) pid;
1579
0
    lhq->proto = &lvlhsh_processes_proto;
1580
0
}
1581
1582
1583
nxt_process_t *
1584
nxt_runtime_process_find(nxt_runtime_t *rt, nxt_pid_t pid)
1585
0
{
1586
0
    nxt_process_t       *process;
1587
0
    nxt_lvlhsh_query_t  lhq;
1588
1589
0
    process = NULL;
1590
1591
0
    nxt_runtime_process_lhq_pid(&lhq, &pid);
1592
1593
0
    nxt_thread_mutex_lock(&rt->processes_mutex);
1594
1595
0
    if (nxt_lvlhsh_find(&rt->processes, &lhq) == NXT_OK) {
1596
0
        process = lhq.value;
1597
1598
0
    } else {
1599
0
        nxt_thread_log_debug("process %PI not found", pid);
1600
0
    }
1601
1602
0
    nxt_thread_mutex_unlock(&rt->processes_mutex);
1603
1604
0
    return process;
1605
0
}
1606
1607
1608
static nxt_process_t *
1609
nxt_runtime_process_get(nxt_runtime_t *rt, nxt_pid_t pid)
1610
0
{
1611
0
    nxt_process_t       *process;
1612
0
    nxt_lvlhsh_query_t  lhq;
1613
1614
0
    nxt_runtime_process_lhq_pid(&lhq, &pid);
1615
1616
0
    nxt_thread_mutex_lock(&rt->processes_mutex);
1617
1618
0
    if (nxt_lvlhsh_find(&rt->processes, &lhq) == NXT_OK) {
1619
0
        nxt_thread_log_debug("process %PI found", pid);
1620
1621
0
        nxt_thread_mutex_unlock(&rt->processes_mutex);
1622
1623
0
        process = lhq.value;
1624
0
        process->use_count++;
1625
1626
0
        return process;
1627
0
    }
1628
1629
0
    process = nxt_process_new(rt);
1630
0
    if (nxt_slow_path(process == NULL)) {
1631
1632
0
        nxt_thread_mutex_unlock(&rt->processes_mutex);
1633
1634
0
        return NULL;
1635
0
    }
1636
1637
0
    process->pid = pid;
1638
1639
0
    lhq.replace = 0;
1640
0
    lhq.value = process;
1641
0
    lhq.pool = rt->mem_pool;
1642
1643
0
    switch (nxt_lvlhsh_insert(&rt->processes, &lhq)) {
1644
1645
0
    case NXT_OK:
1646
0
        if (rt->nprocesses == 0) {
1647
0
            rt->mprocess = process;
1648
0
        }
1649
1650
0
        rt->nprocesses++;
1651
1652
0
        process->registered = 1;
1653
1654
0
        nxt_thread_log_debug("process %PI insert", pid);
1655
0
        break;
1656
1657
0
    default:
1658
0
        nxt_thread_log_debug("process %PI insert failed", pid);
1659
0
        break;
1660
0
    }
1661
1662
0
    nxt_thread_mutex_unlock(&rt->processes_mutex);
1663
1664
0
    return process;
1665
0
}
1666
1667
1668
void
1669
nxt_runtime_process_add(nxt_task_t *task, nxt_process_t *process)
1670
0
{
1671
0
    nxt_port_t          *port;
1672
0
    nxt_runtime_t       *rt;
1673
0
    nxt_lvlhsh_query_t  lhq;
1674
1675
0
    nxt_assert(process->registered == 0);
1676
1677
0
    rt = task->thread->runtime;
1678
1679
0
    nxt_runtime_process_lhq_pid(&lhq, &process->pid);
1680
1681
0
    lhq.replace = 0;
1682
0
    lhq.value = process;
1683
0
    lhq.pool = rt->mem_pool;
1684
1685
0
    nxt_thread_mutex_lock(&rt->processes_mutex);
1686
1687
0
    switch (nxt_lvlhsh_insert(&rt->processes, &lhq)) {
1688
1689
0
    case NXT_OK:
1690
0
        if (rt->nprocesses == 0) {
1691
0
            rt->mprocess = process;
1692
0
        }
1693
1694
0
        rt->nprocesses++;
1695
1696
0
        nxt_process_port_each(process, port) {
1697
1698
0
            port->pid = process->pid;
1699
1700
0
            nxt_runtime_port_add(task, port);
1701
1702
0
        } nxt_process_port_loop;
1703
1704
0
        process->registered = 1;
1705
1706
0
        nxt_debug(task, "process %PI added", process->pid);
1707
0
        break;
1708
1709
0
    default:
1710
0
        nxt_alert(task, "process %PI failed to add", process->pid);
1711
0
        break;
1712
0
    }
1713
1714
0
    nxt_thread_mutex_unlock(&rt->processes_mutex);
1715
0
}
1716
1717
1718
void
1719
nxt_runtime_process_remove(nxt_runtime_t *rt, nxt_process_t *process)
1720
0
{
1721
0
    nxt_pid_t           pid;
1722
0
    nxt_lvlhsh_query_t  lhq;
1723
1724
0
    nxt_assert(process->registered != 0);
1725
1726
0
    pid = process->pid;
1727
1728
0
    nxt_runtime_process_lhq_pid(&lhq, &pid);
1729
1730
0
    lhq.pool = rt->mem_pool;
1731
1732
0
    nxt_thread_mutex_lock(&rt->processes_mutex);
1733
1734
0
    switch (nxt_lvlhsh_delete(&rt->processes, &lhq)) {
1735
1736
0
    case NXT_OK:
1737
0
        nxt_assert(lhq.value == process);
1738
1739
0
        rt->nprocesses--;
1740
1741
0
        process->registered = 0;
1742
1743
0
        nxt_thread_log_debug("process %PI removed", pid);
1744
0
        break;
1745
1746
0
    default:
1747
0
        nxt_thread_log_alert("process %PI remove failed", pid);
1748
0
        break;
1749
0
    }
1750
1751
0
    nxt_thread_mutex_unlock(&rt->processes_mutex);
1752
0
}
1753
1754
1755
nxt_process_t *
1756
nxt_runtime_process_first(nxt_runtime_t *rt, nxt_lvlhsh_each_t *lhe)
1757
0
{
1758
0
    nxt_lvlhsh_each_init(lhe, &lvlhsh_processes_proto);
1759
1760
0
    return nxt_runtime_process_next(rt, lhe);
1761
0
}
1762
1763
1764
nxt_port_t *
1765
nxt_runtime_process_port_create(nxt_task_t *task, nxt_runtime_t *rt,
1766
    nxt_pid_t pid, nxt_port_id_t id, nxt_process_type_t type)
1767
0
{
1768
0
    nxt_port_t     *port;
1769
0
    nxt_process_t  *process;
1770
1771
0
    process = nxt_runtime_process_get(rt, pid);
1772
0
    if (nxt_slow_path(process == NULL)) {
1773
0
        return NULL;
1774
0
    }
1775
1776
0
    port = nxt_port_new(task, id, pid, type);
1777
0
    if (nxt_slow_path(port == NULL)) {
1778
0
        nxt_process_use(task, process, -1);
1779
0
        return NULL;
1780
0
    }
1781
1782
0
    nxt_process_port_add(task, process, port);
1783
1784
0
    nxt_process_use(task, process, -1);
1785
1786
0
    nxt_runtime_port_add(task, port);
1787
1788
0
    nxt_port_use(task, port, -1);
1789
1790
0
    return port;
1791
0
}
1792
1793
1794
static void
1795
nxt_runtime_port_add(nxt_task_t *task, nxt_port_t *port)
1796
0
{
1797
0
    nxt_int_t      res;
1798
0
    nxt_runtime_t  *rt;
1799
1800
0
    rt = task->thread->runtime;
1801
1802
0
    res = nxt_port_hash_add(&rt->ports, port);
1803
1804
0
    if (res != NXT_OK) {
1805
0
        return;
1806
0
    }
1807
1808
0
    rt->port_by_type[port->type] = port;
1809
1810
0
    nxt_port_use(task, port, 1);
1811
0
}
1812
1813
1814
void
1815
nxt_runtime_port_remove(nxt_task_t *task, nxt_port_t *port)
1816
0
{
1817
0
    nxt_int_t      res;
1818
0
    nxt_runtime_t  *rt;
1819
1820
0
    rt = task->thread->runtime;
1821
1822
0
    res = nxt_port_hash_remove(&rt->ports, port);
1823
1824
0
    if (res != NXT_OK) {
1825
0
        return;
1826
0
    }
1827
1828
0
    if (rt->port_by_type[port->type] == port) {
1829
0
        rt->port_by_type[port->type] = NULL;
1830
0
    }
1831
1832
0
    nxt_port_use(task, port, -1);
1833
0
}
1834
1835
1836
nxt_port_t *
1837
nxt_runtime_port_find(nxt_runtime_t *rt, nxt_pid_t pid,
1838
    nxt_port_id_t port_id)
1839
0
{
1840
0
    return nxt_port_hash_find(&rt->ports, pid, port_id);
1841
0
}