[dwm] [dvtm] [PATCH 2/2] Fix zombie handling

From: Rainer Müller <raimue_AT_codingfarm.de>
Date: Wed, 30 Apr 2008 00:06:24 +0200

Ask waitpid() for all zombies in sigchld_handler and put them in a list for later
destroying. The previous implementation might have lead to zombies when
processes were dying fast.

Signed-off-by: Rainer Müller <raimue_AT_codingfarm.de>

---
 dvtm.c |   52 +++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 43 insertions(+), 9 deletions(-)
diff --git a/dvtm.c b/dvtm.c
index 17ac4a4..6a23ad1 100644
--- a/dvtm.c
+++ b/dvtm.c
@@ -52,6 +52,12 @@ struct Client {
 	Client *prev;
 };
 
+typedef struct ClientList ClientList;
+struct ClientList {
+	Client *client;
+	ClientList *next;
+};
+
 #define ALT(k)      ((k) + (161 - 'a'))
 #ifndef CTRL
   #define CTRL(k)   ((k) & 0x1F)
@@ -134,7 +140,7 @@ Client *sel = NULL;
 Client *msel = NULL;
 double mwfact = MWFACT;
 Layout *layout = layouts;
-Client *client_killed = NULL;
+ClientList *kill_list = NULL;
 int statusfd = -1;
 char stext[512];
 int barpos = BARPOS;
@@ -598,6 +604,21 @@ create(const char *args[]){
 
 void
 destroy(Client *c){
+	ClientList *cl;
+	cl = malloc(sizeof(ClientList));
+	cl->client = c;
+	cl->next = NULL;
+
+	if (kill_list == NULL) {
+		kill_list = cl;
+	} else {
+		cl->next = kill_list;
+		kill_list = cl;
+	}
+}
+
+void
+destroy_really(Client *c){
 	if(sel == c)
 		focusnextnm(NULL);
 	detach(c);
@@ -761,12 +782,23 @@ get_client_by_pid(pid_t pid){
 void
 sigchld_handler(int sig){
 	int errsv = errno;
+	int status;
+	pid_t pid;
 
-	int child_status;
 	signal(SIGCHLD, sigchld_handler);
-	pid_t pid = wait(&child_status);
-	debug("child with pid %d died\n", pid);
-	client_killed = get_client_by_pid(pid);
+
+	while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
+		if (pid == -1) {
+			if (errno == ECHILD) {
+				/* no more child processes */
+				break;
+			}
+			eprint("waitpid: %s\n", strerror(errno));
+			break;
+		}
+		debug("child with pid %d died\n", pid);
+		destroy(get_client_by_pid(pid));
+	}
 
 	errno = errsv;
 }
@@ -927,9 +959,11 @@ main(int argc, char *argv[]) {
 		if(need_screen_resize)
 			resize_screen();
 
-		if(client_killed){
-			destroy(client_killed);
-			client_killed = NULL;
+		while(kill_list) {
+			ClientList *cl = kill_list;
+			destroy_really(cl->client);
+			kill_list = cl->next;
+			free(cl);
 		}
 
 		FD_ZERO(&rd);
@@ -1025,7 +1059,7 @@ main(int argc, char *argv[]) {
 			if(FD_ISSET(c->pty, &rd)){
 				if (madtty_process(c->term) < 0 && errno == EIO) {
 					/* client probably terminated */
-					client_killed = c;
+					destroy(c);
 				}
 				if(c != sel){
 					draw_content(c);
-- 
1.5.5.1
Received on Wed Apr 30 2008 - 00:11:15 UTC

This archive was generated by hypermail 2.2.0 : Sun Jul 13 2008 - 15:36:42 UTC