From 09c4a54dad3167e5185dcea14d109c8aff36ffab Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sat, 20 Aug 2022 16:05:12 +0100 Subject: [PATCH] prefork-interp: diagrams Signed-off-by: Ian Jackson --- cprogs/prefork-interp.c | 441 ++++++++++++++++++++-------------------- 1 file changed, 223 insertions(+), 218 deletions(-) diff --git a/cprogs/prefork-interp.c b/cprogs/prefork-interp.c index 105f21c..2e7f42e 100644 --- a/cprogs/prefork-interp.c +++ b/cprogs/prefork-interp.c @@ -15,235 +15,240 @@ */ /* - - - +*************************************************************************** + State during service execution, process parentage and key fds - ---- pipes, sockets - 012 descriptors - -==- fds shared - || process parentage - && session leader (daemon) - & process group leader - - CALLER - || - || + ---- pipes, sockets + 012 descriptors + -==- fds shared + || process parentage + && session leader (daemon) + & process group leader + + + CALLER + || + || || listen watch-err/in - || call (accept) \ ,------2 - || ,-----------------------------. SERVER -----0 WATCHER(C) + || call (accept) \ ,------2 + || ,-----------------------------. SERVER -----0 WATCHER(C) CLIENT 2--=fdpassed>=---------. \ || && | && - (C) 1--=fdpassed>=---------. \ \ || inotify - 0--=fdpassed>=---------. \ \ \ || sockpath - \ \ \ \ || - | | |\ | || - | | | \ | || + (C) 1--=fdpassed>=---------. \ \ || inotify + 0--=fdpassed>=---------. \ \ \ || sockpath + \ \ \ \ || + | | |\ | || + | | | \ | || | \ | \ \ || \ \ \ \ MONITOR & - \ \ \ `12 || | - \ \ \ || | + \ \ \ `12 || | + \ \ \ || | \ \ \ || |execterm - \ \ \ || | - \ \ \ || | - \ \ 2 || | - \ 1 EXECUTOR - 0 - - Control flow and causality - - | - \ / process control flow - ... causes mediated by fds or other IPC etc. + \ \ \ || | + \ \ \ || | + \ \ 2 || | + \ 1 EXECUTOR + 0 + +*************************************************************************** + + Control flow and causality + + | - \ / process control flow + ... < > causes mediated by fds or other IPC etc. && session leader (daemon) & process group leader - - CALLER - | - |fork/exec - | - CLIENT(C) - | + # language/implementation boundary + *1 line continued elsewhere + event? condition + ______ process termination (after reaping, if shown) + + + CALLER + | + |fork/exec + | + CLIENT + | attempt to connect, and read greeting - |failure? \success? - | \ - tidy up stale /run entries continue from send_fds, below - acquire lock - | - retry attempt to connect, and read greeting - |failure? \success? - | \ - create listening socket release lock - | \ - fork/daemonise continue from send_fds, below - | `------------------. + |failure? \success? + | \ + tidy up stale /run entries *1 (continue from send_fds, below) + acquire lock + | + retry attempt to connect, and read greeting + |failure? \success? + | \ + create listening socket release lock + | \ + fork/daemonise *1 + | `------------------. | WATCHER(C) && - | - make "fake" initial call socketpair - | C prefork-interp - fork/exec + + + + + + + + + + + + + + + + + + + + + + + + + + + + - | `------. Perl, application - | + SCRIPT (setup) - | + | - | + script initialisation - | + | Perl, application - | + + + +| + + + + + + + + + + + + + + + + + + + + + + + + - | + | Perl, prefork-interp - | + identify fds from envirnment - | + open syslog - | + | - | + dzemonize - | ,...../ | - waitpid + | - | + fork for initial service - | + |child |parent - | + | | - | + | SCRIPT [server] && - | + | | - | + | ** accept / event loop ** - | + | / \ \ \ - | + | accepted? \ \ \idle timeout? - | + | | \ \ \ - | + | fork child \ \ \ - | + | _________/ watch | |watch stderr eof? - | + |/ stderr| | | - | + SCRIPT [monitor] | | | - | + | log msg | | - | + setpgrpt & | | | - | + | | | | - | + send greeting | | | - read greeting | exit - | + | - release lock | from read greeting success, above - | ________ | ________/ - | / + | - send fds.... | - | + receive fds - | + | - | + fork for executor - | + p |parent \child Perl, prefork-interp - | + | + + + + \+ + + + + + + + + + + + + + + + - | + | + execute service Perl, application - | + | + | - | +wait for read + | - | + (select) + | - | + | | + | - | + | + exits - | + | + kernel closes execterm - | + | ,.........../| - | + execterm? + | - | + | + zombie - | + | ,........../ - | + waitpid + - | + | + - | ,..,..send status + - read status + + - + + - - Or, if client is killed - - | | | - | wait for read | - | (select) | - | | | | - exits | | - | | | - kernel closes | | - \....| | - call? | - | | - kill whole pgrp... | - | killled - | zombie - | ,..... ./ - waitpid - | - send exit status - die due to SIGPIPE - - - */ -/* - * Process structure: - * client (C wrapper) connects to server - * (including reading ack byte) - * if fails or garbage - * === acquires lock === - * makes new listening socket - * makes watcher pipes - * forks watcher and awaits - * makes first-instance socketpair - * forks setup (script, sock fds indicated in env) - * fd0, fd1, fd2: from-outer - * other fd: call(client-end)(fake) - * reaps setup (and reports error) - * (implicitly releases lock) - * - * watcher fd[012]: watcher pipes - * starts watch on socket path - * sets stderr to line buffered - * sets stdin to nonblocking - * daemonises (one fork, becomes session leader) - * when socket stat changes, quit - * - * setup (pre-exec) fd0: null, - * fd[12]: fd2-from-outer - * env fds: listener, call(server-end)(fake), - * watcher read, watcher write - * close fd: lockfile - * possibly clean env, argv - * - * setup (script) runs initialisation parts of the script - * at prefork establishment point: - * setup (pm) [1] opens syslog - * forks for server - * [2] exits - * - * server (pm) [1] [fd0: null], - * [fd[12]: fd2-from-outer] - * setsid - * right away, forks init monitor - * [2] closes outer caller fds and call(fake) - * [server (pm)] fd[012]: null - * other fds: listener, syslog - * runs in loop accepting and forking, - * reaping and limiting children (incl init monitor) - * reports failures of monitors to syslog - * - * [client (C wrapper)] if client connect succeeds: - * now fd: call(client-end) - * sends message with: cmdline, env - * sends fds - * - * [server (script)] accepts, forks subseq monitor - * - * monitor [1] [fd0: null] - * (init [fd[12]: init: fd2-from-outer; subseq: null] - * or errors: init: fd2; subseq: syslog - * subseq) other fds: syslog, call(server-end) - * sends ack byte - * receives args, env, fds - * forks executor - * - * executor sorts out fds: - * fd0, fd1, fd2: from-outer - * close fds: call(server-end) - * retained fds: syslog - * - * sets cmdline, env - * runs main part of script - * exits normally - * - * [monitor] [fd[012]: null] - * [fd[12]: init: fd2-from-outer; subseq: null] - * [errors: init: fd2; subseq: syslog] - * reaps executor - * reports status via socket - * - * [client (C wrapper)] [fd0, fd1, fd2: from-outer] - * [other fd: call(client-end)] - * receives status, exits appropriately - * (if was bad signal, reports to stderr, exits 127) - */ + | + make "fake" initial call socketpair (C) + | prefork-interp + fork/exec ######################################################### + | `-------------. application + | # SCRIPT (setup) + | # | + | # script initialisation + | # | application + | # ########|############################################# + | # | prefork-interp + | # identify fds from envirnment (Perl) + | # open syslog + | # | + | # dzemonize + | ,.....<....../ | + waitpid # fork for initial service + | # |child? |parent? + | # | | + | # | SCRIPT [server] && + | # | | + | # | ** accept / event loop ** + | # | accepted? \ \ \ + | # | / \ watch\ \idle + | # | fork child \stderr\ \timeout? + | # | _________/ | | | + | # |/ |read? | | + | # SCRIPT [monitor] | eof?| | + | # setpgrpt & | | | + | # | log msg | | + read ,....<.....send greeting | | | + greeting # | ___________________ + | # | + release # | + lock *1 # | + | / # | + send fds.....>.... | + | # \receive fds + | # | + | # fork for executor (Perl) + | # |parent? \child? prefork-interp + | # | ######\############################ + | # | # SCRIPT (executor) application + | # | # execute service + | # wait for read # | + | # (select) # terminates + | # | | # | + | # | # kernel closes execterm + | # | ,......<....../| + | # execterm? # | + | # | # zombie + | # | | ,......<...../ + | # waitpid # _______________ + | # | # + | ,....<....,..send status # + read status # ________________ # + _____________ # + + + ********** Or, if client is killed ********** + + | # | # execute service + terminates # wait for read # | + | # (select) # | + kernel # | | # | + closes call # | # | + \..>......_ | # | + _____________ # \|call? # | + # | # | + # kill whole pgrp... # killled + # | # zombie + # | | ,......<....../ + # waitpid # _______________ + # | # + # send exit status # + # _____SIGPIPE______ # + +*************************************************************************** + + Sequence of events and fd pluming. + NB INCOMPLETE - does not cover execterm, cleanup + + client (C wrapper) connects to server + (including reading ack byte) + if fails or garbage + === acquires lock === + makes new listening socket + makes watcher pipes + forks watcher and awaits + makes first-instance socketpair + forks setup (script, sock fds indicated in env) + fd0, fd1, fd2: from-outer + other fd: call(client-end)(fake) + reaps setup (and reports error) + (implicitly releases lock) + + watcher fd[012]: watcher pipes + starts watch on socket path + sets stderr to line buffered + sets stdin to nonblocking + daemonises (one fork, becomes session leader) + when socket stat changes, quit + + setup (pre-exec) fd0: null, + fd[12]: fd2-from-outer + env fds: listener, call(server-end)(fake), + watcher read, watcher write + close fd: lockfile + possibly clean env, argv + + setup (script) runs initialisation parts of the script + at prefork establishment point: + setup (pm) [1] opens syslog + forks for server + [2] exits + + server (pm) [1] [fd0: null], + [fd[12]: fd2-from-outer] + setsid + right away, forks init monitor + [2] closes outer caller fds and call(fake) + [server (pm)] fd[012]: null + other fds: listener, syslog + runs in loop accepting and forking, + reaping and limiting children (incl init monitor) + reports failures of monitors to syslog + + [client (C wrapper)] if client connect succeeds: + now fd: call(client-end) + sends message with: cmdline, env + sends fds + + [server (script)] accepts, forks subseq monitor + + monitor [1] [fd0: null] + (init [fd[12]: init: fd2-from-outer; subseq: null] + or errors: init: fd2; subseq: syslog + subseq) other fds: syslog, call(server-end) + sends ack byte + receives args, env, fds + forks executor + + executor sorts out fds: + fd0, fd1, fd2: from-outer + close fds: call(server-end) + retained fds: syslog + + sets cmdline, env + runs main part of script + exits normally + + [monitor] [fd[012]: null] + [fd[12]: init: fd2-from-outer; subseq: null] + [errors: init: fd2; subseq: syslog] + reaps executor + reports status via socket + + [client (C wrapper)] [fd0, fd1, fd2: from-outer] + [other fd: call(client-end)] + receives status, exits appropriately + (if was bad signal, reports to stderr, exits 127) + +*************************************************************************** + +*/ #include -- 2.30.2