diff options
2 files changed, 120 insertions, 0 deletions
diff --git a/doc/plan.txt b/doc/plan.txt
new file mode 100644
index 0000000..bea2b14
--- /dev/null
+++ b/doc/plan.txt
@@ -0,0 +1,113 @@
+rustup run nightly cargo install clippy
+rustup run nightly cargo clippy
+x bind sockets
+- [optional] bind rpc server+client
+x register signal handlers
+x populate config
+- [optional] spawn rpc thread
+x spawn initial set of children
+x enter main event loop
+ select!
+rpc mechanism:
+ use JSON-RPC: https://github.com/ethcore/jsonrpc-core
+ worker side receives client request, creates a new reply channel, sends
+ request+channel to event loop, blocks on reply channel. this all
+ happens in per-client thread?
+ event loop selects() on rpc requests. when one is received, processes,
+ sends reply down channel, closes channel
+## Process Lifetime
+process table is pid_t -> offspring
+entries are only removed by SIGCHILD handler, which calls pidwait and thus has reap'd
+entries hold a timer guard, so after they are destroyed the timer shouldn't fire
+ init
+ checkin childhood (seconds) later
+ notified, send USR2
+ checkin shutdown later: if not dead term it, either way reap
+ notified, send TERM
+ checking shutdown later; if not dead kill it
+ dead, send KILL
+upgrade: <some state machine?>
+ spawn new generation; keep 'replaces' linkage
+ when each new generation is health, notify the 'replace-ee' to shut down
+timer: check_alive:
+ healthy; or kill and re-spawn (based on ack mode)
+signal: child died:
+ find which child it was (by pid)
+ if was infancy or health and attempts ok, try to respawn, possibly with backoff
+ otherwise, just reap from brood
+## Most Basic
+x bind to any supplied socket(s)
+x set up environment variables
+x register signal handlers
+x fork() for each child, with some delay in between
+x in each forked copy, execve() to the supplied program
+x in the parent, wait on children, waiting for failures. restart on failure
+- reset signal mask in child processes
+then, probably want to shift to an event-driven (single threaded?) setup
+(including signal handling)
+(event-driven seems like it might not work well, so threads+channels instead)
+- timers
+- signals: chan_signal
+- child termination
+- RPC commands
+- shepard: holds sub-process state machines; chan_select!{} on other threads
+- chan_signal (internal to library)
+? timers ?
+- rpc: workers spawned on socket connects
+ -> line-based? JSON-RPC? gRPC?
+sub-process states (TODO: look at daemontools):
+- healthy
+- dead
+- starting
+## Socket Passing
+fcntl F_GETFD: to get fd flags
+FD_CLOEXEC: flag of whether to keep open ("close on exec", true means it isn't passed)
+-4 and -6 flags (forces IPv4 or IPv6, respectively)
+## Command Socket
+## Child API
+listen for USR2 (graceful shutdown)
+parse environment variables
+## Rust child impl
+Using chan instead of std::sync::mspc because Select/select! is unstable.
diff --git a/doc/spec.txt b/doc/spec.txt
new file mode 100644
index 0000000..e8662fd
--- /dev/null
+++ b/doc/spec.txt
@@ -0,0 +1,7 @@
+Signals to daemon itself:
+ USR2, INT -> graceful shutdown all offspring and exit
+ TERM, QUIT -> terminate all offspring and exit (this is a bit faster)
+ HUP -> upgrade all offspring
+NB: QUIT and ALRM are different from einhorn