Hi Alan, On Mon, Oct 20, 2014 at 02:52:13PM -0600, Alan Robertson wrote: > For the Assimilation code I use the full pathname of the binary from > /proc to tell if it's "one of mine". That's not perfect if you're using > an interpreted language. It works quite well for compiled languages.
Yes, though not perfect, that may be good enough. I supposed that the probability that the very same program gets the same recycled pid is rather low. (Or is it?) Cheers, Dejan > > On 10/20/2014 01:17 PM, Lars Ellenberg wrote: > > Recent discussions with Dejan made me again more prominently aware of a > > few issues we probably all know about, but usually dismis as having not > > much relevance in the real-world. > > > > The facts: > > > > * a pidfile typically only stores a pid > > * a pidfile may "stale", not properly cleaned up > > when the pid it references died. > > * pids are recycled > > > > This is more an issue if kernel.pid_max is small > > wrt the number of processes created per unit time, > > for example on some embeded systems, > > or on some very busy systems. > > > > But it may be an issue on any system, > > even a mostly idle one, given "bad luck^W timing", > > see below. > > > > A common idiom in resource agents is to > > > > kill_that_pid_and_wait_until_dead() > > { > > local pid=$1 > > is_alive $pid || return 0 > > kill -TERM $pid > > while is_alive $pid ; sleep 1; done > > return 0 > > } > > > > The naïve implementation of is_alive() is > > is_alive() { kill -0 $1 ; } > > > > This is the main issue: > > ----------------------- > > > > If the last-used-pid is just a bit smaller then $pid, > > during the sleep 1, $pid may die, > > and the OS may already have created a new process with that exact pid. > > > > Using above "is_alive", kill_that_pid() will not notice that the > > to-be-killed pid has actually terminated while that new process runs. > > Which may be a very long time if that is some other long running daemon. > > > > This may result in stop failure and resulting node level fencing. > > > > The question is, which better way do we have to detect if some pid died > > after we killed it. Or, related, and even better: how to detect if the > > process currently running with some pid is in fact still the process > > referenced by the pidfile. > > > > I have two suggestions. > > > > (I am trying to avoid bashisms in here. > > But maybe I overlook some. > > Also, the code is typed, not sourced from some working script, > > so there may be logic bugs and typos. > > My intent should be obvious enough, though.) > > > > using "cd /proc/$pid; stat ." > > ----------------------------- > > > > # this is most likely linux specific > > kill_that_pid_and_wait_until_dead() > > { > > local pid=$1 > > ( > > cd /proc/$pid || return 0 > > kill -TERM $pid > > while stat . ; sleep 1; done > > ) > > return 0 > > } > > > > Once pid dies, /proc/$pid will become stale (but not completely go away, > > because it is our cwd), and stat . will return "No such process". > > > > Variants: > > > > using test -ef > > -------------- > > > > exec 7</proc/$pid || return 0 > > kill -TERM $pid > > while :; do > > exec 8</proc/$pid || break > > test /proc/self/fd/7 -ef /proc/self/fd/8 || break > > sleep 1 > > done > > exec 7<&- 8<&- > > > > using stat -c %Y /proc/$pid > > --------------------------- > > > > ctime0=$(stat -c %Y /proc/$pid) > > kill -TERM $pid > > while ctime=$(stat -c %Y /proc/$pid) && [ $ctime = $ctime0 ] ; do sleep > > 1; done > > > > > > Why not use the inode number I hear you say. > > Because it is not stable. Sorry. > > Don't believe me? Don't want to read kernel source? > > Try it yourself: > > > > sleep 120 & k=$! > > stat /proc/$k > > echo 3 > /proc/sys/vm/drop_caches > > stat /proc/$k > > > > But that leads me to an other proposal: > > store the starttime together with the pid in a pidfile. > > > > For linux that would be: > > > > (see proc(5) for /proc/pid/stat field meanings. > > note that (comm) may contain both whitespace and ")", > > which is the reason for my sed | cut below) > > > > spawn_create_exclusive_pid_starttime() > > { > > local pidfile=$1 > > shift > > local reset > > case $- in *C*) reset=":";; *) set -C; reset="set +C";; esac > > if ! exec 3>$pidfile ; then > > $reset > > return 1 > > fi > > > > $reset > > setsid sh -c ' > > read pid _ < /proc/self/stat > > starttime=$(sed -e 's/^.*) //' /proc/$pid/stat | cut -d' ' -f > > 20) > > >&3 echo $pid $starttime > > 3>&- exec "$@" > > ' -- "$@" & > > return 0 > > } > > > > It does not seem possible to cycle through all available pids > > within fractions of time smaller than the granularity of starttime, > > so "pid starttime" should be a unique tuple (until the next reboot -- > > at least on linux, starttime is measured as strictly monotonic "uptime"). > > > > > > If we have "pid starttime" in the pidfile, > > we can: > > > > get_proc_pid_starttime() > > { > > proc_pid_starttime=$(sed -e 's/^.*) //' /proc/$pid/stat) || return 1 > > proc_pid_starttime=$(echo "$proc_pid_starttime" | cut -d' ' -f 20) > > } > > > > kill_using_pidfile() > > { > > local pidfile=$1 > > local pid starttime proc_pid_starttime > > > > test -e $pidfile || return # already dead > > read pid starttime <$pidfile || return # unreadable > > > > # check pid and starttime are both present, numeric only, ... > > # I have a version that distinguishes 16 distinct error > > # conditions; this is the short version only... > > > > local i=0 > > while > > get_proc_pid_starttime && > > [ "$starttime" = "$proc_pid_starttime" ] > > do > > : $(( i+=1 )) > > [ $i = 1 ] && kill -TERM $pid > > # MAYBE # [ $i = 30 ] && kill -KILL $pid > > sleep 1 > > done > > > > # it's not (anymore) the process we where looking for > > # remove that pidfile. > > > > rm -f "$pidfile" > > } > > > > In other OSes, ps may be able to give a good enough equivalent? > > > > Any comments? > > > > Thanks, > > Lars > > > > _______________________________________________________ > > Linux-HA-Dev: Linux-HA-Dev@lists.linux-ha.org > > http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev > > Home Page: http://linux-ha.org/ > > _______________________________________________________ > Linux-HA-Dev: Linux-HA-Dev@lists.linux-ha.org > http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev > Home Page: http://linux-ha.org/ _______________________________________________________ Linux-HA-Dev: Linux-HA-Dev@lists.linux-ha.org http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev Home Page: http://linux-ha.org/