[asterisk-commits] trunk r30328 - in /trunk: asterisk.c
include/asterisk/app.h res/res_agi.c
asterisk-commits at lists.digium.com
asterisk-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 asterisk-commits
mailing list