Skip to content

Commit 900828c

Browse files
mar0xac000
authored andcommitted
Fixing isolated process PID manipulation.
Registering an isolated PID in the global PID hash is wrong because it can be duplicated. Isolated processes are stored only in the children list until the response for the WHOAMI message is processed and the global PID is discovered. To remove isolated siblings, a pointer to the children list is introduced in the nxt_process_init_t struct. This closes #633 issue on GitHub.
1 parent d37b762 commit 900828c

File tree

6 files changed

+108
-25
lines changed

6 files changed

+108
-25
lines changed

docs/changes.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ the ruby application process could crash if it's interrupted by SIGTERM signal.
9393
</para>
9494
</change>
9595

96+
<change type="bugfix">
97+
<para>
98+
when isolated PID numbers reach the prototype process host PID,
99+
the prototype crashed.
100+
</para>
101+
</change>
102+
96103
</changes>
97104

98105

src/nxt_application.c

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@
2323
#endif
2424

2525

26+
#ifdef WCOREDUMP
27+
#define NXT_WCOREDUMP(s) WCOREDUMP(s)
28+
#else
29+
#define NXT_WCOREDUMP(s) 0
30+
#endif
31+
32+
2633
typedef struct {
2734
nxt_app_type_t type;
2835
nxt_str_t version;
@@ -636,6 +643,8 @@ nxt_proto_start_process_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
636643
process->data.app = nxt_app_conf;
637644
process->stream = msg->port_msg.stream;
638645

646+
init->siblings = &nxt_proto_children;
647+
639648
ret = nxt_process_start(task, process);
640649
if (nxt_slow_path(ret == NXT_ERROR)) {
641650
nxt_process_use(task, process, -1);
@@ -711,15 +720,19 @@ nxt_proto_process_created_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
711720
nxt_debug(task, "app process %PI (aka %PI) is created", isolated_pid,
712721
pid);
713722

714-
nxt_runtime_process_remove(task->thread->runtime, process);
715-
716723
process->pid = pid;
717724

718-
nxt_runtime_process_add(task, process);
719-
720725
} else {
721726
nxt_debug(task, "app process %PI is created", isolated_pid);
722727
}
728+
729+
if (!process->registered) {
730+
nxt_assert(!nxt_queue_is_empty(&process->ports));
731+
732+
nxt_runtime_process_add(task, process);
733+
734+
nxt_port_use(task, nxt_process_port_first(process), -1);
735+
}
723736
}
724737

725738

@@ -753,7 +766,11 @@ nxt_proto_sigchld_handler(nxt_task_t *task, void *obj, void *data)
753766
int status;
754767
nxt_err_t err;
755768
nxt_pid_t pid;
769+
nxt_port_t *port;
756770
nxt_process_t *process;
771+
nxt_runtime_t *rt;
772+
773+
rt = task->thread->runtime;
757774

758775
nxt_debug(task, "proto sigchld handler signo:%d (%s)",
759776
(int) (uintptr_t) obj, data);
@@ -783,32 +800,58 @@ nxt_proto_sigchld_handler(nxt_task_t *task, void *obj, void *data)
783800
return;
784801
}
785802

803+
process = nxt_proto_process_remove(task, pid);
804+
786805
if (WTERMSIG(status)) {
787-
#ifdef WCOREDUMP
788-
nxt_alert(task, "app process (isolated %PI) exited on signal %d%s",
789-
pid, WTERMSIG(status),
790-
WCOREDUMP(status) ? " (core dumped)" : "");
791-
#else
792-
nxt_alert(task, "app process (isolated %PI) exited on signal %d",
793-
pid, WTERMSIG(status));
794-
#endif
806+
if (rt->is_pid_isolated) {
807+
nxt_alert(task, "app process %PI (isolated %PI) "
808+
"exited on signal %d%s",
809+
process != NULL ? process->pid : 0,
810+
pid, WTERMSIG(status),
811+
NXT_WCOREDUMP(status) ? " (core dumped)" : "");
812+
813+
} else {
814+
nxt_alert(task, "app process %PI exited on signal %d%s",
815+
pid, WTERMSIG(status),
816+
NXT_WCOREDUMP(status) ? " (core dumped)" : "");
817+
}
795818

796819
} else {
797-
nxt_trace(task, "app process (isolated %PI) exited with code %d",
798-
pid, WEXITSTATUS(status));
820+
if (rt->is_pid_isolated) {
821+
nxt_trace(task, "app process %PI (isolated %PI) "
822+
"exited with code %d",
823+
process != NULL ? process->pid : 0,
824+
pid, WEXITSTATUS(status));
825+
826+
} else {
827+
nxt_trace(task, "app process %PI exited with code %d",
828+
pid, WEXITSTATUS(status));
829+
}
799830
}
800831

801-
process = nxt_proto_process_remove(task, pid);
802832
if (process == NULL) {
803833
continue;
804834
}
805835

836+
if (process->registered) {
837+
port = NULL;
838+
839+
} else {
840+
nxt_assert(!nxt_queue_is_empty(&process->ports));
841+
842+
port = nxt_process_port_first(process);
843+
}
844+
806845
if (process->state != NXT_PROCESS_STATE_CREATING) {
807846
nxt_port_remove_notify_others(task, process);
808847
}
809848

810849
nxt_process_close_ports(task, process);
811850

851+
if (port != NULL) {
852+
nxt_port_use(task, port, -1);
853+
}
854+
812855
if (nxt_proto_exiting && nxt_queue_is_empty(&nxt_proto_children)) {
813856
nxt_process_quit(task, 0);
814857
return;
@@ -1122,7 +1165,7 @@ nxt_proto_process_add(nxt_task_t *task, nxt_process_t *process)
11221165
break;
11231166

11241167
default:
1125-
nxt_debug(task, "process (isolated %PI) failed to add",
1168+
nxt_alert(task, "process (isolated %PI) failed to add",
11261169
process->isolated_pid);
11271170
break;
11281171
}

src/nxt_process.c

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,15 +296,26 @@ nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process)
296296

297297
} nxt_runtime_process_loop;
298298

299+
if (init->siblings != NULL) {
300+
nxt_queue_each(p, init->siblings, nxt_process_t, link) {
301+
302+
nxt_debug(task, "remove sibling process %PI", p->pid);
303+
304+
nxt_process_close_ports(task, p);
305+
306+
} nxt_queue_loop;
307+
}
308+
299309
return NXT_OK;
300310
}
301311

302312

303313
static nxt_pid_t
304314
nxt_process_create(nxt_task_t *task, nxt_process_t *process)
305315
{
306-
nxt_int_t ret;
307-
nxt_pid_t pid;
316+
nxt_int_t ret;
317+
nxt_pid_t pid;
318+
nxt_runtime_t *rt;
308319

309320
#if (NXT_HAVE_CLONE)
310321
pid = nxt_clone(SIGCHLD | process->isolation.clone.flags);
@@ -352,7 +363,20 @@ nxt_process_create(nxt_task_t *task, nxt_process_t *process)
352363
process->pid = pid;
353364
process->isolated_pid = pid;
354365

355-
nxt_runtime_process_add(task, process);
366+
rt = task->thread->runtime;
367+
368+
if (rt->is_pid_isolated) {
369+
/*
370+
* Do not register process in runtime with isolated pid.
371+
* Only global pid can be the key to avoid clash.
372+
*/
373+
nxt_assert(!nxt_queue_is_empty(&process->ports));
374+
375+
nxt_port_use(task, nxt_process_port_first(process), 1);
376+
377+
} else {
378+
nxt_runtime_process_add(task, process);
379+
}
356380

357381
return pid;
358382
}
@@ -960,13 +984,17 @@ nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process)
960984
{
961985
nxt_port_t *port;
962986

987+
nxt_process_use(task, process, 1);
988+
963989
nxt_process_port_each(process, port) {
964990

965991
nxt_port_close(task, port);
966992

967993
nxt_runtime_port_remove(task, port);
968994

969995
} nxt_process_port_loop;
996+
997+
nxt_process_use(task, process, -1);
970998
}
971999

9721000

src/nxt_process.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ typedef struct {
148148

149149
const nxt_port_handlers_t *port_handlers;
150150
const nxt_sig_event_t *signals;
151+
152+
nxt_queue_t *siblings;
151153
} nxt_process_init_t;
152154

153155

src/nxt_runtime.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1408,6 +1408,7 @@ nxt_runtime_process_release(nxt_runtime_t *rt, nxt_process_t *process)
14081408

14091409
nxt_assert(process->use_count == 0);
14101410
nxt_assert(process->registered == 0);
1411+
nxt_assert(nxt_queue_is_empty(&process->ports));
14111412

14121413
nxt_port_mmaps_destroy(&process->incoming, 1);
14131414

@@ -1579,11 +1580,11 @@ nxt_runtime_process_add(nxt_task_t *task, nxt_process_t *process)
15791580

15801581
process->registered = 1;
15811582

1582-
nxt_thread_log_debug("process %PI added", process->pid);
1583+
nxt_debug(task, "process %PI added", process->pid);
15831584
break;
15841585

15851586
default:
1586-
nxt_thread_log_debug("process %PI failed to add", process->pid);
1587+
nxt_alert(task, "process %PI failed to add", process->pid);
15871588
break;
15881589
}
15891590

@@ -1597,6 +1598,8 @@ nxt_runtime_process_remove(nxt_runtime_t *rt, nxt_process_t *process)
15971598
nxt_pid_t pid;
15981599
nxt_lvlhsh_query_t lhq;
15991600

1601+
nxt_assert(process->registered != 0);
1602+
16001603
pid = process->pid;
16011604

16021605
nxt_runtime_process_lhq_pid(&lhq, &pid);
@@ -1608,17 +1611,17 @@ nxt_runtime_process_remove(nxt_runtime_t *rt, nxt_process_t *process)
16081611
switch (nxt_lvlhsh_delete(&rt->processes, &lhq)) {
16091612

16101613
case NXT_OK:
1611-
rt->nprocesses--;
1614+
nxt_assert(lhq.value == process);
16121615

1613-
process = lhq.value;
1616+
rt->nprocesses--;
16141617

16151618
process->registered = 0;
16161619

16171620
nxt_thread_log_debug("process %PI removed", pid);
16181621
break;
16191622

16201623
default:
1621-
nxt_thread_log_debug("process %PI remove failed", pid);
1624+
nxt_thread_log_alert("process %PI remove failed", pid);
16221625
break;
16231626
}
16241627

test/test_tls.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ def test_tls_application_respawn(self, skip_alert):
616616

617617
subprocess.check_output(['kill', '-9', app_id])
618618

619-
skip_alert(r'process .* %s.* exited on signal 9' % app_id)
619+
skip_alert(r'process %s exited on signal 9' % app_id)
620620

621621
self.wait_for_record(
622622
r' (?!' + app_id + r'#)(\d+)#\d+ "mirror" application started'

0 commit comments

Comments
 (0)