[svn-commits] trunk r30328 - in /trunk: asterisk.c include/asterisk/app.h res/res_agi.c

svn-commits at lists.digium.com svn-commits at lists.digium.com
Thu May 25 11:31:20 MST 2006


Author: russell
Date: Thu May 25 13:31:19 2006
New Revision: 30328

URL: http://svn.digium.com/view/asterisk?rev=30328&view=rev
Log:
Add the ability to retrieve the exit code of the forked AGI process.  If there
is an error executing the AGI script, or the AGI script itself returns a
non-zero value, the AGISTATUS variable will now be set to FAILURE instead of
SUCCESS.

Modified:
    trunk/asterisk.c
    trunk/include/asterisk/app.h
    trunk/res/res_agi.c

Modified: trunk/asterisk.c
URL: http://svn.digium.com/view/asterisk/trunk/asterisk.c?rev=30328&r1=30327&r2=30328&view=diff
==============================================================================
--- trunk/asterisk.c (original)
+++ trunk/asterisk.c Thu May 25 13:31:19 2006
@@ -608,8 +608,38 @@
 }
 
 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
+/*! Keep track of how many threads are currently trying to wait*() on
+ *  a child process */
 static unsigned int safe_system_level = 0;
 static void *safe_system_prev_handler;
+
+void ast_replace_sigchld(void)
+{
+	unsigned int level;
+
+	ast_mutex_lock(&safe_system_lock);
+	level = safe_system_level++;
+
+	/* only replace the handler if it has not already been done */
+	if (level == 0)
+		safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
+
+	ast_mutex_unlock(&safe_system_lock);
+}
+
+void ast_unreplace_sigchld(void)
+{
+	unsigned int level;
+
+	ast_mutex_lock(&safe_system_lock);
+	level = --safe_system_level;
+
+	/* only restore the handler if we are the last one */
+	if (level == 0)
+		signal(SIGCHLD, safe_system_prev_handler);
+
+	ast_mutex_unlock(&safe_system_lock);
+}
 
 int ast_safe_system(const char *s)
 {
@@ -618,19 +648,8 @@
 	int res;
 	struct rusage rusage;
 	int status;
-	unsigned int level;
-
-	/* keep track of how many ast_safe_system() functions
-	   are running at this moment
-	*/
-	ast_mutex_lock(&safe_system_lock);
-	level = safe_system_level++;
-
-	/* only replace the handler if it has not already been done */
-	if (level == 0)
-		safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
-
-	ast_mutex_unlock(&safe_system_lock);
+
+	ast_replace_sigchld();
 
 	pid = fork();
 
@@ -656,14 +675,7 @@
 		res = -1;
 	}
 
-	ast_mutex_lock(&safe_system_lock);
-	level = --safe_system_level;
-
-	/* only restore the handler if we are the last one */
-	if (level == 0)
-		signal(SIGCHLD, safe_system_prev_handler);
-
-	ast_mutex_unlock(&safe_system_lock);
+	ast_unreplace_sigchld();
 
 	return res;
 }

Modified: trunk/include/asterisk/app.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/app.h?rev=30328&r1=30327&r2=30328&view=diff
==============================================================================
--- trunk/include/asterisk/app.h (original)
+++ trunk/include/asterisk/app.h Thu May 25 13:31:19 2006
@@ -120,6 +120,27 @@
 int ast_safe_system(const char *s);
 
 /*!
+ * \brief Replace the SIGCHLD handler
+ *
+ * Normally, Asterisk has a SIGCHLD handler that is cleaning up all zombie
+ * processes from forking elsewhere in Asterisk.  However, if you want to
+ * wait*() on the process to retrieve information about it's exit status,
+ * then this signal handler needs to be temporaraly replaced.
+ *
+ * Code that executes this function *must* call ast_unreplace_sigchld()
+ * after it is finished doing the wait*().
+ */
+void ast_replace_sigchld(void);
+
+/*!
+ * \brief Restore the SIGCHLD handler
+ *
+ * This function is called after a call to ast_replace_sigchld.  It restores
+ * the SIGCHLD handler that cleans up any zombie processes.
+ */
+void ast_unreplace_sigchld(void);
+
+/*!
   \brief Send DTMF to a channel
 
   \param chan    The channel that will receive the DTMF frames

Modified: trunk/res/res_agi.c
URL: http://svn.digium.com/view/asterisk/trunk/res/res_agi.c?rev=30328&r1=30327&r2=30328&view=diff
==============================================================================
--- trunk/res/res_agi.c (original)
+++ trunk/res/res_agi.c Thu May 25 13:31:19 2006
@@ -39,6 +39,7 @@
 #include <stdio.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <sys/wait.h>
 
 #include "asterisk.h"
 
@@ -275,9 +276,11 @@
 			return AGI_RESULT_FAILURE;
 		}
 	}
+	ast_replace_sigchld();
 	pid = fork();
 	if (pid < 0) {
 		ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
+		ast_unreplace_sigchld();
 		return AGI_RESULT_FAILURE;
 	}
 	if (!pid) {
@@ -1781,7 +1784,7 @@
 	return 0;
 }
 #define RETRY	3
-static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead)
+static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead)
 {
 	struct ast_channel *c;
 	int outfd;
@@ -1830,6 +1833,7 @@
 					returnstatus = -1;
 				if (option_verbose > 2) 
 					ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
+				waitpid(pid, status, 0);
 				/* No need to kill the pid anymore, since they closed us */
 				pid = -1;
 				break;
@@ -1976,13 +1980,18 @@
 #endif
 	res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
 	if (res == AGI_RESULT_SUCCESS) {
+		int status = 0;
 		agi.fd = fds[1];
 		agi.ctrl = fds[0];
 		agi.audio = efd;
-		res = run_agi(chan, argv[0], &agi, pid, dead);
+		res = run_agi(chan, argv[0], &agi, pid, &status, dead);
+		/* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
+		if (res == AGI_RESULT_SUCCESS && status)
+			res = AGI_RESULT_FAILURE;
 		close(fds[1]);
 		if (efd > -1)
 			close(efd);
+		ast_unreplace_sigchld();
 	}
 	ast_localuser_remove(me, u);
 



More information about the svn-commits mailing list