From the not necessarily big news, but still useful department.
The situation: for Very Good Reasons
1, you want to replace your current process by calling
exec(), but you still want to have the chance to do something after the process you exec()ed finishes.
This is a simple technique I just came up with: just before replacing the current process by calling
exec(), you
fork() a process in the background that will wait for the current process id to disappear from the process list, and then does whatever you want to do.
A simple proof-of-concept I wrote is composed of two bash programs:
wrapper and
real.
real is really simple: it just waits a few seconds and then prints its process id to the console:
#!/bin/bash
sleep 5
echo $BASHPID
wrapper is the program that handles the situation we want to exercise: it replaces itself with
real, but still has the chance to do something after
real finishes. In this case,
wrapper notifies the user that
real finished.
#!/bin/bash
echo $BASHPID
real_program_pid=$BASHPID
(
while ps -p "$real_program_pid" >/dev/null; do
sleep 0.1s
done
notify-send 'real program finished'
) &
exec ./real
One nice property that
wrapper explores is that when
exec() starts
real, it really replaces
wrapper, and therefore has the same process id (in this case accessible by bash in the
$BASHPID variable). Because of this, the background process that
wrapper starts just before the
exec() call already knows which process it has to watch for.
The actual code for waiting is not optimal, though. I cannot use
waitpid() (the
wait builtin in bash), since
real is not a child process of
wrapper. I went with a brute force approach here, and I am pretty sure there is a cheaper way to wait for a random
PID without a busy loop (but that wasn t the point here).
1
update: I
am aware of the classic
fork()/
exec() pattern. My Very Good Reasons include the fact that I can t control the flow: I am writing a plugin for a program that calls its plugins in sequence, and after that, calls
exec(), but my plugin is interested in doing some work after
exec() finishes.