Recently, I got trapped in a Double Fork trap and landed on this page before I finally found my answer. Symptoms are identical, even if the problem is not the same:
- WYKINWYT: What you are killing is not what you thought.
The minimum test code is shown below using the SNMP daemon as an example.
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> int main(int argc, char* argv[]) { //We omit the -f option (do not Fork) to reproduce the problem char * options[]={"/usr/local/sbin/snmpd",/*"-f","*/-d","--master=agentx", "-Dagentx","--agentXSocket=tcp:localhost:1706", "udp:10161", (char*) NULL}; pid_t pid = fork(); if ( 0 > pid ) return -1; switch(pid) { case 0: { //Child launches SNMP daemon execv(options[0],options); exit(-2); break; } default: { sleep(10); //Simulate "long" activity kill(pid,SIGTERM);//kill what should be child, //ie the SNMP daemon I assume printf("Signal sent to %d\n",pid); sleep(10); //Simulate "long" operation before closing waitpid(pid); printf("SNMP should be now down\n"); getchar();//Blocking (for observation only) break; } } printf("Bye!\n"); }
At the first stage, the main process (7699) starts the SNMP daemon (7700), but we see that it is now Defunct / Zombie. In addition, we can see another process (7702) with the specified options
[nils@localhost ~]$ ps -ef | tail root 7439 2 0 23:00 ? 00:00:00 [kworker/1:0] root 7494 2 0 23:03 ? 00:00:00 [kworker/0:1] root 7544 2 0 23:08 ? 00:00:00 [kworker/0:2] root 7605 2 0 23:10 ? 00:00:00 [kworker/1:2] root 7698 729 0 23:11 ? 00:00:00 sleep 60 nils 7699 2832 0 23:11 pts/0 00:00:00 ./main nils 7700 7699 0 23:11 pts/0 00:00:00 [snmpd] <defunct> nils 7702 1 0 23:11 ? 00:00:00 /usr/local/sbin/snmpd -Lo -d --master=agentx -Dagentx --agentXSocket=tcp:localhost:1706 udp:10161 nils 7727 3706 0 23:11 pts/1 00:00:00 ps -ef nils 7728 3706 0 23:11 pts/1 00:00:00 tail
After simulating 10 seconds, we will try to kill the only process that we know (7700). What we finally achieved waitpid (). But Process 7702 is still here
[nils@localhost ~]$ ps -ef | tail root 7431 2 0 23:00 ? 00:00:00 [kworker/u256:1] root 7439 2 0 23:00 ? 00:00:00 [kworker/1:0] root 7494 2 0 23:03 ? 00:00:00 [kworker/0:1] root 7544 2 0 23:08 ? 00:00:00 [kworker/0:2] root 7605 2 0 23:10 ? 00:00:00 [kworker/1:2] root 7698 729 0 23:11 ? 00:00:00 sleep 60 nils 7699 2832 0 23:11 pts/0 00:00:00 ./main nils 7702 1 0 23:11 ? 00:00:00 /usr/local/sbin/snmpd -Lo -d --master=agentx -Dagentx --agentXSocket=tcp:localhost:1706 udp:10161 nils 7751 3706 0 23:12 pts/1 00:00:00 ps -ef nils 7752 3706 0 23:12 pts/1 00:00:00 tail
After providing the getchar () function character, our main process ends, but the SNMP daemon with pid 7002 is still here
[nils@localhost ~]$ ps -ef | tail postfix 7399 1511 0 22:58 ? 00:00:00 pickup -l -t unix -u root 7431 2 0 23:00 ? 00:00:00 [kworker/u256:1] root 7439 2 0 23:00 ? 00:00:00 [kworker/1:0] root 7494 2 0 23:03 ? 00:00:00 [kworker/0:1] root 7544 2 0 23:08 ? 00:00:00 [kworker/0:2] root 7605 2 0 23:10 ? 00:00:00 [kworker/1:2] root 7698 729 0 23:11 ? 00:00:00 sleep 60 nils 7702 1 0 23:11 ? 00:00:00 /usr/local/sbin/snmpd -Lo -d --master=agentx -Dagentx --agentXSocket=tcp:localhost:1706 udp:10161 nils 7765 3706 0 23:12 pts/1 00:00:00 ps -ef nils 7766 3706 0 23:12 pts/1 00:00:00 tail
Conclusion
The fact that we ignored the double fork mechanism made us think that the kill action did not work. But in fact, we just killed the wrong process.
By adding the -f (Do not (Double) Fork) option, everything goes as expected.