s6

Mirror/fork of https://skarnet.org/software/s6/
git clone https://ccx.te2000.cz/git/s6
Log | Files | Refs | README | LICENSE

commit ff8493ef9d33e7c348293587637c70f82bb90aba
parent b214f953faf52dc73902d43398959defae54968b
Author: Laurent Bercot <ska-skaware@skarnet.org>
Date:   Fri, 19 Dec 2014 00:25:16 +0000

 s6-notifywhen up now sends U and exits on the first newline.
 Doc updated to reflect it.

Diffstat:
Mdoc/notifywhenup.html | 18+++++++++++++-----
Mdoc/s6-notifywhenup.html | 6+++---
Msrc/daemontools-extras/s6-notifywhenup.c | 21++++++++++-----------
3 files changed, 26 insertions(+), 19 deletions(-)

diff --git a/doc/notifywhenup.html b/doc/notifywhenup.html @@ -54,21 +54,29 @@ is reliably up - because only they know when it is the case. <li> Daemons can use the <tt>ftrigw_notify()</tt> function, provided in <a href="libftrigw.html">the ftrigw library</a>. This is extremely simple and efficient, but requires specific s6 support in the daemon. </li> - <li> Daemons can write something to a file descriptor of their choice, + <li> Daemons can write a line to a file descriptor of their choice, then close that file descriptor, when they're ready to serve. This is a generic mechanism that some daemons already implement, and does not require anything specific in the daemon's code. The administrator can then run the daemon under <a href="s6-notifywhenup.html">s6-notifywhenup</a>, which will properly catch the daemon's message and notify all the subscribers -with a 'U' event, meaning that the service is now up with no possible race -condition. </li> +with a 'U' event, meaning that the service is now up. <br /> <br /> + Note that there is <em>still</em> a small race condition remaining: +if the daemon writes a line then instantly dies, and the supervisor +picks up the death before the <a href="s6-notifywhenup.html">s6-notifywhenup</a> +program picks up the line, it is possible for the event sequence written +to the fifodir to be wrong - 'd' before 'U'. This should be extremely +rare, but unfortunately the race condition is unavoidable. The only +way to be absolutely race-free is to have the daemon perform its +readiness notification itself, which requires specific support. + </li> </ol> <p> The second method should really be implemented in every long-running program providing a service. When it is not the case, it's impossible -to provide race-free startup notifications, and subscribers should be -content with the unreliable 'u' events provided by s6-supervise. +to provide reliable startup notifications, and subscribers should then +be content with the unreliable 'u' events provided by s6-supervise. </p> </body> diff --git a/doc/s6-notifywhenup.html b/doc/s6-notifywhenup.html @@ -37,9 +37,9 @@ needed. <ul> <li> s6-notifywhenup forks and executes <em>prog...</em> as the parent, with a pipe from <em>prog...</em>'s stdout to the child. </li> - <li> The child waits for EOF on the pipe. When it gets it, if there -have been other characters written before the EOF, it sends a 'U' -event to the <tt>./event</tt> fifodir. </li> + <li> The child waits for a newline (<tt>\n</tt>) to be written +on the pipe. When it gets it, it sends a 'U' event to the +<tt>./event</tt> fifodir. </li> <li> The child exits 0. </li> </ul> diff --git a/src/daemontools-extras/s6-notifywhenup.c b/src/daemontools-extras/s6-notifywhenup.c @@ -3,6 +3,7 @@ #include <unistd.h> #include <errno.h> #include <skalibs/uint.h> +#include <skalibs/bytestr.h> #include <skalibs/sgetopt.h> #include <skalibs/strerr2.h> #include <skalibs/allreadwrite.h> @@ -19,25 +20,23 @@ static int run_child (int fd, char const *fifodir, unsigned int timeout) char dummy[4096] ; iopause_fd x = { .fd = fd, .events = IOPAUSE_READ } ; tain_t deadline ; - int haswritten = 0 ; - register int r = 0 ; if (!tain_now_g()) strerr_diefu1sys(111, "tain_now") ; if (timeout) tain_from_millisecs(&deadline, timeout) ; else deadline = tain_infinite_relative ; tain_add_g(&deadline, &deadline) ; - while (!r) + for (;;) { - r = iopause_g(&x, 1, &deadline) ; + register int r = iopause_g(&x, 1, &deadline) ; if (r < 0) strerr_diefu1sys(111, "iopause") ; if (!r) return 99 ; - while (r > 0) - { - r = sanitize_read(fd_read(fd, dummy, 4096)) ; /* talk to the hand */ - if (r > 0) haswritten = 1 ; - } + r = sanitize_read(fd_read(fd, dummy, 4096)) ; + if (r < 0) + if (errno == EPIPE) return 0 ; + else strerr_diefu1sys(111, "read from parent") ; + else if (r) + if (byte_chr(dummy, r, '\n') < r) break ; } - if (errno != EPIPE) strerr_diefu1sys(111, "read from parent") ; - if (haswritten) ftrigw_notify(fifodir, 'U') ; + ftrigw_notify(fifodir, 'U') ; return 0 ; }